[{"filename":"SphyxOS/basic/doGetServerCurSec.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getServerSecurityLevel(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/doGetServerMaxMoney.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getServerMaxMoney(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/doGetServerMinSec.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getServerMinSecurityLevel(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/doSCP.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const result = ns.scp(ns.args[0], ns.args[1], \\\"home\\\")\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getHackTime.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getHackTime(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getHasRootAccs.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const result = ns.hasRootAccess(ns.args[0])\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getHostname.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.getHostname()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getIsRunning.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.isRunning(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getMoneyAvail.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.getServerMoneyAvailable(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getMoneySources.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getMoneySources()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getPlay.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getPlayer()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getResetInfo.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.getResetInfo()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/getScriptRam.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const result = ns.getScriptRam(ns.args[0], \\\"home\\\")\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}\""},{"filename":"SphyxOS/basic/getServer.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const server = ns.getServer(ns.args[0])\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(server))\\n}\""},{"filename":"SphyxOS/basic/getServerAvailRam.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.getServerMaxRam(ns.args[0]) - ns.getServerUsedRam(ns.args[0])\\n ns.atExit(() => port.write(ns.args[0] === \\\"home\\\" ? result + 1.7 : result))\\n}\""},{"filename":"SphyxOS/basic/getbnmults.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,//Old\\n \\\"CloudServerCost\\\": 1,//New\\n \\\"CloudServerSoftcap\\\": 1,//Old\\n \\\"CloudServerSoftcap\\\": 1,//New\\n \\\"CloudServerLimit\\\": 1,//Old\\n \\\"CloudServerLimit\\\": 1,//New\\n \\\"CloudServerMaxRam\\\": 1,//Old\\n \\\"CloudServerMaxRam\\\": 1,//New\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n ns.atExit(() => port.write(mults))\\n}\\n\""},{"filename":"SphyxOS/basic/grow.js","file":"\"export const growReady = true\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n await ns.grow(ns.args[0], { additionalMsec: ns.args[1] })\\n //ns.tprintf(\\\"Grow\\\")\\n}\""},{"filename":"SphyxOS/basic/hack.js","file":"\"export const hackReady = true\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n await ns.hack(ns.args[0], { additionalMsec: ns.args[1] })\\n}\""},{"filename":"SphyxOS/basic/kill.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.kill(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/basic/scriptKill.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n const result = ns.scriptKill(ns.args[0], ns.args[1])\\n}\""},{"filename":"SphyxOS/basic/share.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n while (true) {\\n await ns.share()\\n }\\n}\""},{"filename":"SphyxOS/basic/weaken.js","file":"\"export const weakenReady = true\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n await ns.weaken(ns.args[0], { additionalMsec: ns.args[1] })\\n}\""},{"filename":"SphyxOS/basic/weakenStr.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.weakenAnalyze(1)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bins/LoaderSphyxOS.jsx","file":"\"/**Author:\\n * Discord: Sphyxis\\n */\\nimport { getResetInf, getOwnedSF, runIt, proxy, getServersLight, getServerAvailRam, getSyms, getPosi } from \\\"SphyxOS/util.js\\\"\\nconst version = \\\"v3.0.5.7\\\"\\nconst loaderConfigFile = \\\"SphyxOSUserData/loaderData/config.txt\\\"\\nconst currentJSON = \\\"SphyxOSUserData/loaderData/SphyxOS.txt\\\"\\nconst updatedJSON = \\\"SphyxOSUserData/loaderData/SphyxOSNew.txt\\\"\\nconst hashKeyFileName = \\\"SphyxOS/special/hashKey.txt\\\"\\nconst discordInviteUrl = \\\"https://discord.gg/BScc48TK8Z\\\"\\nconst gitHubIssueUrl = \\\"https://github.com/Sphyxis/SphyxOS/issues\\\"\\nconst openDB = new Set\\nlet optionsDB = {}\\nlet resetInfo\\nlet sourceFiles\\nlet wnd\\n/*Static port numbers for comms:\\n * 1 - this script (loader) receive\\n * 2 - puppetMini: emit pid\\n * 3 - puppetMini: emit bestTarget\\n * 4 - stocks: emit pid\\n * 5 - ipvgo: emit pid\\n * 6 - gangs: emit pid\\n * 7 - sleeves: emit pid\\n * 8 - BB: emit pid\\n * 9 - corps: emit pid\\n * 10 - casino: emit pid\\n * 11 - stanek: emit pid\\n * 12 - puppetMini receive\\n * 13 - stocks receive\\n * 15 - ipvgo receive\\n * 16 - gangs receive\\n * 17 - sleeves receive\\n * 18 - BB receive\\n * 19 - corps receive\\n * 20 - grafting: emit pid\\n * 21 - autopilot: emit pid\\n * 22 - autopilot receive\\n * 23 - grafting basic/adv: receive\\n * 24 - darknet kill switch port\\n * 25 - darknet receive\\n * 26 - darknet emit active\\n * 27 - minesweeper: emit pid\\n * 28 - theme editor: emit pid\\n * 29 - timberman: emit pid\\n * 30 - autoInfil\\n */\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n const gameInfo = ns.ui.getGameInfo()\\n const staticInfo = {\\n versionNum: gameInfo?.versionNumber ?? \\\"<=43\\\",\\n versionName: gameInfo.version,\\n versionCommit: gameInfo.commit,\\n platform: gameInfo.platform\\n }\\n\\n\\n await ns.asleep(10) //Give stuff time to end. Issues when updating.\\n writeProxyAuth(ns) //Get our proxyAuth script for copying over the darknet script.\\n resetInfo = await getResetInf(ns)\\n sourceFiles = await getOwnedSF(ns)\\n if (hasBN(resetInfo, sourceFiles, 13)) await proxy(ns, \\\"stanek.acceptGift\\\")\\n //optionsDB = []\\n if (globalThis[\\\"document\\\"].autopilot) optionsDB[\\\"AutoPilotMoveOn\\\"] = globalThis[\\\"document\\\"].autopilot\\n await loadLoaderConfig(ns)\\n ns.atExit(() => {\\n saveLoaderConfig(ns)\\n })\\n\\n if (ns.args.includes(\\\"BBRestart\\\")) { //Restart from BB\\n if (hasBN(resetInfo, sourceFiles, 10)) { //Sleeves\\n optionsDB[\\\"SleeveMode\\\"] = \\\"BB\\\"\\n optionsDB[\\\"BBFinisher\\\"] = true\\n await buttonBBStart(ns)\\n await buttonBatcherStart(ns)\\n }\\n }\\n if (ns.args.includes(\\\"autoPilot\\\")) { //Restart from autoPilot\\n if (hasBN(resetInfo, sourceFiles, 4, 2)) {\\n ns.writePort(22, \\\"silent\\\")\\n ns.writePort(22, optionsDB[\\\"AutoPilotMoveOn\\\"] ? \\\"moveon\\\" : \\\"nomoveon\\\")\\n await runIt(ns, \\\"SphyxOS/bins/autopilot.js\\\", true, [])\\n }\\n }\\n wnd = globalThis[\\\"window\\\"]\\n ns.clearLog()\\n ns.ui.openTail()\\n if (optionsDB[\\\"DisplayToggleAutoUpdate\\\"]) buttonDisplayUpdate(ns)\\n ns.printRaw( )\\n await new Promise(() => { })\\n}\\n/** @param {NS} ns */\\nasync function buttonDisplayUpdate(ns, pressed = false, destructive = false) {\\n async function updateNow() {\\n await buttonDisplayClearActive(ns)\\n if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === \\\"Stable\\\") await ns.wget(\\\"https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOS.txt\\\", updatedJSON)\\n else if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === \\\"Beta\\\") await ns.wget(\\\"https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOSBeta.txt\\\", updatedJSON)\\n if (ns.read(updatedJSON) === \\\"\\\") {\\n ns.toast(\\\"Aborted update. Could not download update files.\\\", \\\"WARNING\\\", 3000)\\n return\\n }\\n await ns.asleep(100)\\n await proxy(ns, \\\"rm\\\", currentJSON)\\n ns.mv(ns.self().server, updatedJSON, currentJSON)\\n if (ns.self().server !== \\\"home\\\") await proxy(ns, \\\"rm\\\", currentJSON, \\\"home\\\")\\n await ns.asleep(4)\\n ns.scp(currentJSON, \\\"home\\\")\\n await ns.asleep(4)\\n ns.exec(\\\"SphyxOS/extras/update.js\\\", \\\"home\\\")\\n ns.ui.closeTail()\\n ns.exit()\\n }\\n if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === \\\"Stable\\\") await ns.wget(\\\"https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOSHash.txt\\\", \\\"hash.txt\\\")\\n else if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === \\\"Beta\\\") await ns.wget(\\\"https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOSBetaHash.txt\\\", \\\"hash.txt\\\")\\n ns.scp(hashKeyFileName, ns.self().server, \\\"home\\\")\\n const current = ns.read(hashKeyFileName)\\n const update = ns.read(\\\"hash.txt\\\")\\n if (pressed && update === \\\"\\\") {\\n ns.toast(\\\"Update hash failed to download\\\", \\\"WARNING\\\", 3000)\\n return\\n }\\n else if (update === \\\"\\\") return\\n\\n if (pressed && current === \\\"\\\") {\\n const answer = await ns.prompt(\\\"No baseline detected. Would you like to stop everything, update and set your baseline build?\\\", { type: \\\"boolean\\\" })\\n if (answer === true) await updateNow()\\n }\\n else if (current !== update) {\\n const answer = await ns.prompt(\\\"An update is available. Would you like stop everything and update?\\\", { type: \\\"boolean\\\" })\\n if (answer === true) await updateNow()\\n }\\n else if (pressed) {\\n const answer = await ns.prompt(\\\"No update found. Would you like stop everything and refresh your install?\\\", { type: \\\"boolean\\\" })\\n if (answer === true) await updateNow()\\n }\\n}\\n/** @param {NS} ns */\\nasync function buildSnapshot(ns) {\\n processCommands(ns)// First pull in any cross-script messages that were sent to the loader on port 1.\\n wnd = globalThis[\\\"window\\\"]// Refresh our cached window reference because some status flags live on the browser window.\\n const hasCorp = await proxy(ns, \\\"corporation.hasCorporation\\\")// Do we have a Corp?\\n const hasBB = await proxy(ns, \\\"bladeburner.inBladeburner\\\")// Are we in BladeBurner?\\n const corp = hasCorp ? await proxy(ns, \\\"corporation.getCorporation\\\") : false// If we have a Corp, get it\\n const player = await proxy(ns, \\\"getPlayer\\\")// Refresh the Player\\n resetInfo = await getResetInf(ns)//Refresh this info\\n sourceFiles = await getOwnedSF(ns)//Refresh this info\\n const ownedSFValue = resetInfo.ownedSF?.has(resetInfo.currentNode) ? resetInfo.ownedSF.get(resetInfo.currentNode) : 0\\n return {\\n options: { ...optionsDB },// Clone optionsDB into a new object so React receives a fresh immutable value.\\n ports: {// Cache all relevant port reads in one place so render code can stay simple.\\n batcher: ns.peek(2),\\n batcherTarget: ns.peek(3),\\n stocks: ns.peek(4),\\n ipvgo: ns.peek(5),\\n gangs: ns.peek(6),\\n sleeves: ns.peek(7),\\n bb: ns.peek(8),\\n corp: ns.peek(9),\\n casino: ns.peek(10),\\n stanek: ns.peek(11),\\n grafting: ns.peek(20),\\n autopilot: ns.peek(21),\\n darknet: ns.peek(26),\\n minesweeper: ns.peek(27),\\n themeEditor: ns.peek(28),\\n timberman: ns.peek(29)\\n },\\n // Feature availability flags used for conditional rendering / button color.\\n //currentBN: String(resetInfo.currentNode) + \\\".\\\" + String(resetInfo.currentNode !== 12 ? Math.max(3, Math.min(resetInfo.ownedSF.get(resetInfo.currentNode) + 1, 1)) : String(resetInfo.ownedSF.get(resetInfo.currentNode) + 1 ?? 1)),\\n currentBN: String(resetInfo.currentNode) + \\\".\\\" + String(resetInfo.currentNode !== 12 ? Math.max(1, Math.min(ownedSFValue + 1, 3)) : String(ownedSFValue + 1)),\\n hasCorp,\\n hasBB,\\n corp,\\n player,\\n keepAlive: !!wnd?.keepAlive,// Some features are tracked outside Netscript ports, so we snapshot those too.\\n autoInfilRunning: !!wnd?.tmrAutoInf\\n }\\n}\\nasync function getDarknetStockChoices(ns) {\\n const stocks = []\\n const symbols = await getSyms(ns)\\n for (const sym of symbols) {\\n let owned = false\\n const position = await getPosi(ns, sym)\\n owned = (position?.[0] ?? 0) > 0 || (position?.[2] ?? 0) > 0\\n stocks.push({ sym, owned })\\n }\\n return stocks\\n}\\nfunction buildDarknetStockSelection(syms = []) {\\n const cleanSyms = [...new Set((Array.isArray(syms) ? syms : []).filter((sym) => typeof sym === \\\"string\\\" && sym !== \\\"\\\"))]\\n return { syms: cleanSyms }\\n}\\nfunction normalizeDarknetStockSelection(selection) {\\n if (selection && typeof selection === \\\"object\\\" && !Array.isArray(selection))\\n return buildDarknetStockSelection(selection.syms)\\n if (Array.isArray(selection))\\n return buildDarknetStockSelection(selection)\\n if (selection === \\\"All\\\")\\n return buildDarknetStockSelection()\\n if (typeof selection === \\\"string\\\" && selection !== \\\"\\\")\\n return buildDarknetStockSelection([selection])\\n return buildDarknetStockSelection()\\n}\\nfunction isDarknetStockAllSelection(selection, stocks) {\\n const normalizedSelection = normalizeDarknetStockSelection(selection)\\n return stocks.length > 0\\n && normalizedSelection.syms.length === stocks.length\\n && stocks.every((stock) => normalizedSelection.syms.includes(stock.sym))\\n}\\nfunction getDarknetStockSelectionLabel(selection, stocks = []) {\\n const normalizedSelection = normalizeDarknetStockSelection(selection)\\n if (normalizedSelection.syms.length === 0) return \\\"None\\\"\\n if (isDarknetStockAllSelection(normalizedSelection, stocks)) return \\\"All\\\"\\n if (normalizedSelection.syms.length === 1) return normalizedSelection.syms[0] ?? \\\"None\\\"\\n if (normalizedSelection.syms.length > 1) return \\\"Multi\\\"\\n return \\\"None\\\"\\n}\\nfunction normalizeHashAutoTarget(target) {\\n const hashTarget = typeof target === \\\"string\\\" ? target : \\\"None\\\"\\n return hashAutoTargetOptions.some((option) => option.value === hashTarget) ? hashTarget : \\\"None\\\"\\n}\\nfunction getHashAutoTargetLabel(target) {\\n const hashTarget = normalizeHashAutoTarget(target)\\n return hashAutoTargetOptions.find((option) => option.value === hashTarget)?.label ?? \\\"None\\\"\\n}\\nfunction normalizeSleeveTrainingSelection(selection) {\\n if (selection === \\\"Idle\\\") return \\\"None\\\"\\n const sleeveTraining = typeof selection === \\\"string\\\" ? selection : \\\"None\\\"\\n return sleeveTrainingOptions.some((option) => option.value === sleeveTraining) ? sleeveTraining : \\\"None\\\"\\n}\\nfunction getSleeveTrainingLabel(selection) {\\n const sleeveTraining = normalizeSleeveTrainingSelection(selection)\\n return sleeveTrainingOptions.find((option) => option.value === sleeveTraining)?.label ?? \\\"None\\\"\\n}\\nfunction isSleeveTrainingAvailable(selection) {\\n const sleeveTraining = normalizeSleeveTrainingSelection(selection)\\n return sleeveTraining !== \\\"Int\\\" || hasBN(resetInfo, sourceFiles, 10, 1)\\n}\\nfunction normalizeSleeveToggleMode(mode) {\\n if (mode === \\\"None\\\") return \\\"Idle\\\"\\n return mode\\n}\\nfunction isHashAutoTargetAvailable(target, snapshot = {}) {\\n switch (normalizeHashAutoTarget(target)) {\\n case \\\"min\\\":\\n case \\\"max\\\":\\n return !!snapshot?.ports?.batcherTarget && snapshot.ports.batcherTarget !== \\\"NULL PORT DATA\\\"\\n case \\\"corp\\\":\\n case \\\"research\\\":\\n return !!snapshot?.hasCorp\\n case \\\"bbrank\\\":\\n case \\\"bbsp\\\":\\n return !!snapshot?.hasBB\\n case \\\"None\\\":\\n return false\\n default:\\n return true\\n }\\n}\\nfunction getReactLib() {\\n //Lets be safe here. Grab current react\\n return globalThis[\\\"React\\\"] ?? globalThis[\\\"window\\\"]?.React\\n}\\nfunction isForceHidden(title) {\\n return openDB.has(\\\"forceHide-\\\" + title)\\n}\\nfunction toggleForceHide(title) {\\n const key = \\\"forceHide-\\\" + title\\n if (openDB.has(key))\\n openDB.delete(key)\\n else\\n openDB.add(key)\\n}\\nfunction clearForceHidden() {\\n for (const key of [...openDB]) {\\n if (key.startsWith(\\\"forceHide-\\\"))\\n openDB.delete(key)\\n }\\n}\\nfunction normalizeHoverButtonLabel(label) {\\n //Returns the regular lable name always\\n const trimmedLabel = (label ?? \\\"\\\").trim()\\n if (trimmedLabel.startsWith(\\\"Stock:\\\"))\\n return \\\"Stock\\\"\\n if (trimmedLabel.startsWith(\\\"Training:\\\"))\\n return \\\"Training\\\"\\n switch (trimmedLabel) {\\n case \\\"De-Activate\\\":\\n return \\\"Activate\\\"\\n case \\\"Unshare Ram\\\":\\n return \\\"Share Ram\\\"\\n case \\\"Bribe Unavailable\\\":\\n return \\\"Bribe\\\"\\n case \\\"Pls Wait\\\":\\n return \\\"Charge\\\"\\n case \\\"Money\\\":\\n case \\\"MinSec\\\":\\n case \\\"MaxMoney\\\":\\n case \\\".cct's\\\":\\n case \\\"C-Money\\\":\\n case \\\"C-Research\\\":\\n case \\\"BBRank\\\":\\n case \\\"BBSp\\\":\\n case \\\"Study\\\":\\n case \\\"Train\\\":\\n case \\\"Job Favor\\\":\\n return \\\"No AutoHash\\\"\\n default:\\n return trimmedLabel\\n }\\n}\\nfunction getButtonHelp(rowTitle, label) {\\n const normalizedLabel = normalizeHoverButtonLabel(label)\\n const rowHelp = hoverHelpDB[rowTitle] ?? {}\\n return rowHelp[normalizedLabel] ?? `No hover help has been written yet for ${rowTitle} / ${normalizedLabel}.`\\n}\\nfunction HoverHelp({ text, position, enabled }) {\\n const React = getReactLib()\\n React.useEffect(() => {\\n const doc = globalThis[\\\"document\\\"]\\n if (!doc?.body) return\\n let node = doc.getElementById(\\\"sphyxos-hover-help\\\")\\n if (!node) {\\n node = doc.createElement(\\\"div\\\")\\n node.id = \\\"sphyxos-hover-help\\\"\\n doc.body.appendChild(node)\\n }\\n if (!enabled || !text) {\\n node.style.display = \\\"none\\\"\\n node.innerText = \\\"\\\"\\n return\\n }\\n node.style.position = \\\"fixed\\\"\\n node.style.zIndex = \\\"9999\\\"\\n node.style.left = `${position.x}px`\\n node.style.top = `${position.y}px`\\n node.style.maxWidth = \\\"360px\\\"\\n node.style.minWidth = \\\"220px\\\"\\n node.style.padding = \\\"10px 12px\\\"\\n node.style.border = \\\"1px solid #3f6b99\\\"\\n node.style.borderRadius = \\\"6px\\\"\\n node.style.background = \\\"rgba(0, 0, 0, 0.96)\\\"\\n node.style.boxShadow = \\\"0 8px 24px rgba(0, 0, 0, 0.35)\\\"\\n node.style.color = \\\"#f5f7fa\\\"\\n node.style.fontFamily = \\\"monospace\\\"\\n node.style.fontSize = \\\"13px\\\"\\n node.style.lineHeight = \\\"1.35\\\"\\n node.style.whiteSpace = \\\"pre-wrap\\\"\\n node.style.pointerEvents = \\\"none\\\"\\n node.style.transform = \\\"translateY(-100%)\\\"\\n node.style.display = \\\"block\\\"\\n node.innerText = text\\n return () => {\\n node.style.display = \\\"none\\\";\\n node.innerText = \\\"\\\";\\n }\\n }, [text, position.x, position.y, enabled])\\n return \\\"\\\"\\n}\\nfunction LoaderApp({ ns, staticInfo }) {\\n //Get our current React lib\\n const React = getReactLib()\\n // If React is missing, render a small fallback message instead of crashing on hook usage. Be safe\\n if (!React) return
{\\\"React runtime unavailable in this Bitburner session.\\\"}
\\n // This is the component's central piece of state\\n // snapshot stores the latest game/UI data gathered by buildSnapshot(ns)\\n // Whenever this state changes, React rerenders the Loader UI automatically\\n const [snapshot, setSnapshot] = React.useState(null)\\n const [hoverHelp, setHoverHelp] = React.useState(\\\"\\\")\\n const [hoverPosition, setHoverPosition] = React.useState({ x: 0, y: 0 })\\n const [activeToolbarMenu, setActiveToolbarMenu] = React.useState(\\\"\\\")\\n const [rowVisibilityVersion, setRowVisibilityVersion] = React.useState(0)\\n const [displayViewMode, setDisplayViewMode] = React.useState(optionsDB[\\\"DisplayViewMode\\\"] ?? \\\"Mini\\\")\\n const [miniSelectedRows, setMiniSelectedRows] = React.useState(Array.isArray(optionsDB[\\\"MiniSelectedRows\\\"]) ? [...optionsDB[\\\"MiniSelectedRows\\\"]] : [])\\n const runAction = async (action) => {\\n // Run the underlying loader action (toggle option, start script, etc)\\n const actionResult = await action()\\n if (actionResult === \\\"refreshRows\\\")\\n setRowVisibilityVersion((value) => value + 1)\\n // Refresh state right after the action so the user sees the update immediately\\n setSnapshot(await buildSnapshot(ns))\\n }\\n // This effect starts the live refresh loop for the UI\\n // It runs once for this ns instance, then keeps polling game state on a timer\\n React.useEffect(() => {\\n // cancelled prevents setState calls after unmount, which would cause warnings\\n // or leave background polling running after the UI is gone\\n let cancelled = false\\n // We keep the timer id so we can cancel the scheduled refresh during cleanup\\n let timer\\n // tick performs one full state refresh cycle:\\n // 1. read live game/script state\\n // 2. push it into React state\\n // 3. schedule the next refresh\\n const tick = async () => {\\n // Build one immutable snapshot of everything the UI needs right now\\n const next = await buildSnapshot(ns)\\n // Only update React state if the component is still mounted\\n // This rerender is what makes the UI visually update\\n if (!cancelled) setSnapshot(next)\\n //Autohashing goes here since we need a current snapshot and to constantly run it\\n if (optionsDB[\\\"HashAutoTarget\\\"] !== \\\"None\\\" && isHashAutoTargetAvailable(optionsDB[\\\"HashAutoTarget\\\"], next)) await buttonHashing(ns, optionsDB[\\\"HashAutoTarget\\\"])\\n\\n // Schedule the next polling pass. Using setTimeout instead of setInterval\\n // avoids overlapping refreshes if a snapshot read takes longer than expected\\n if (!cancelled) timer = setTimeout(tick, 200)\\n }\\n // Start the polling loop immediately when the component mounts. No await so it's async in the background\\n tick()\\n // Cleanup runs when the component unmounts or if ns ever changes\\n // It stops future rerenders and cancels the pending timer\\n return () => {\\n cancelled = true\\n if (timer) clearTimeout(timer)\\n }\\n // The effect only depends on ns, so it behaves like \\\"mount once per script instance\\\"\\n }, [ns])\\n React.useEffect(() => {\\n if (snapshot && !snapshot.options[\\\"DisplayToggleHelper\\\"] && hoverHelp)\\n setHoverHelp(\\\"\\\")\\n }, [snapshot?.options[\\\"DisplayToggleHelper\\\"]])\\n React.useEffect(() => {\\n optionsDB[\\\"DisplayViewMode\\\"] = displayViewMode\\n }, [displayViewMode])\\n React.useEffect(() => {\\n optionsDB[\\\"MiniSelectedRows\\\"] = [...miniSelectedRows]\\n }, [miniSelectedRows])\\n React.useEffect(() => {\\n if (!snapshot) return\\n const savedDisplayViewMode = snapshot.options[\\\"DisplayViewMode\\\"] ?? \\\"Mini\\\"\\n if (savedDisplayViewMode !== displayViewMode)\\n setDisplayViewMode(savedDisplayViewMode)\\n const savedMiniSelectedRows = Array.isArray(snapshot.options[\\\"MiniSelectedRows\\\"]) ? snapshot.options[\\\"MiniSelectedRows\\\"] : []\\n if (savedMiniSelectedRows.length !== miniSelectedRows.length || savedMiniSelectedRows.some((title, index) => title !== miniSelectedRows[index]))\\n setMiniSelectedRows([...savedMiniSelectedRows])\\n }, [snapshot?.options[\\\"DisplayViewMode\\\"], snapshot?.options[\\\"MiniSelectedRows\\\"]])\\n const rows = snapshot ? buildRows(ns, snapshot, runAction, staticInfo) : []\\n const visibleRows = rows.filter((row) => !isForceHidden(row[0]))\\n const unlockedVisibleRows = visibleRows.filter((row) => rowUnlocked(row))\\n React.useEffect(() => {\\n if (snapshot === null) return\\n if (unlockedVisibleRows.length === 0) {\\n if (miniSelectedRows.length > 0) setMiniSelectedRows([])\\n return\\n }\\n const unlockedRowTitles = unlockedVisibleRows.map((row) => row[0].toString())\\n const validSelectedRows = miniSelectedRows.filter((title) => unlockedRowTitles.includes(title))\\n if (validSelectedRows.length !== miniSelectedRows.length)\\n setMiniSelectedRows(validSelectedRows)\\n }, [snapshot, miniSelectedRows, unlockedVisibleRows])\\n // On the very first render we have not collected game state yet,\\n // so show a temporary loading message until we have that info\\n if (snapshot === null) return {\\\"Loading SphyxOS...\\\"}
\\n const handleRowHideToggle = (title) => {\\n toggleForceHide(title)\\n setRowVisibilityVersion((value) => value + 1)\\n }\\n const handleUnhideAll = () => {\\n clearForceHidden()\\n setRowVisibilityVersion((value) => value + 1)\\n }\\n const handleHoverCapture = (event) => {\\n if (!snapshot?.options[\\\"DisplayToggleHelper\\\"]) return\\n const button = event.target.closest?.(\\\"button\\\")\\n if (!button) return\\n if (button.dataset?.nohover === \\\"true\\\") return\\n const rowElement = button.closest?.(\\\"[data-row]\\\")\\n const rowTitle = rowElement?.dataset?.row ?? \\\"Display\\\"\\n const label = button.textContent?.trim() ?? \\\"\\\"\\n setHoverPosition({ x: (event.clientX ?? 0) + 8, y: (event.clientY ?? 0) - 8 })\\n setHoverHelp(getButtonHelp(rowTitle, label))\\n }\\n const handleHoverOutCapture = (event) => {\\n const button = event.target.closest?.(\\\"button\\\")\\n if (!button) return\\n const nextButton = event.relatedTarget?.closest?.(\\\"button\\\")\\n if (!nextButton) setHoverHelp(\\\"\\\")\\n }\\n const handleMouseMoveCapture = (event) => {\\n if (!hoverHelp || !snapshot?.options[\\\"DisplayToggleHelper\\\"]) return\\n setHoverPosition({ x: (event.clientX ?? 0) + 8, y: (event.clientY ?? 0) - 8 })\\n }\\n const handleMouseDownCapture = (event) => {\\n if (!activeToolbarMenu) return\\n const insideToolbarMenu = event.target.closest?.(\\\"[data-toolbar-menu='true']\\\")\\n if (!insideToolbarMenu) setActiveToolbarMenu(\\\"\\\")\\n }\\n // Render the full application:\\n // 1. header/version info\\n // 2. global display/action buttons\\n // 3. all unlocked control rows\\n return (\\n \\n {/* Global controls use the same snapshot and action wrapper as the row buttons. */}\\n \\n \\n {/* For each configured row:\\n 1. check whether the player has access to it in the current BitNode / Source-File setup\\n 2. render the row if unlocked*/}\\n {displayViewMode === \\\"Mini\\\"\\n ? setMiniSelectedRows((currentRows) => currentRows.includes(title) ? currentRows.filter((rowTitle) => rowTitle !== title) : [...currentRows, title])} onHideToggle={handleRowHideToggle} onMiniRowContextHide={handleRowHideToggle} rowVisibilityVersion={rowVisibilityVersion}> \\n : displayViewMode === \\\"List\\\" ? unlockedVisibleRows.map((row) =>
)\\n : \\\"New Display Mode Here!!\\\"}\\n
\\n )\\n}\\nfunction DisplayButtons({ ns, snapshot, runAction, onUnhideAll, staticInfo, activeToolbarMenu, setActiveToolbarMenu, setHoverHelp, displayViewMode, setDisplayViewMode }) {\\n // Pull the options object out once so the JSX below stays readable\\n const options = snapshot.options\\n const hiddenCount = [...openDB].filter((key) => key.startsWith(\\\"forceHide-\\\")).length\\n const displayViews = [\\\"List\\\", \\\"Mini\\\"]\\n const actionsMenuLabels = [\\\"Join Discord!!\\\", \\\"Create GitHub Issue\\\", \\\"Clear Active\\\", \\\"Open Logs\\\", \\\"Update\\\", \\\"Change Log\\\", \\\"REMOVE PROGRAM\\\"]\\n const actionsMenuWidth = `${Math.max(...actionsMenuLabels.map((label) => label.length)) + 2}ch`\\n const runToolbarAction = async (action) => {\\n setActiveToolbarMenu(\\\"\\\")\\n setHoverHelp(\\\"\\\")\\n await runAction(action)\\n }\\n const toggleToolbarMenu = (menuName) => {\\n setActiveToolbarMenu(activeToolbarMenu === menuName ? \\\"\\\" : menuName)\\n }\\n const cycleDisplayViewMode = () => {\\n const currentIndex = displayViews.indexOf(displayViewMode)\\n const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % displayViews.length\\n setDisplayViewMode(displayViews[nextIndex])\\n }\\n const currentViewButtonStyle = displayViewMode === \\\"Mini\\\" ? viewModeMiniActiveStyle : viewModeButtonActiveStyle\\n // Render the global toolbar for the loader\\n // Every button goes through runAction so React state refreshes immediately after a click\\n return (\\n \\n
\\n
\\n
{\\\"SphyxOS \\\" + version}
\\n
{\\\"Game: \\\" + staticInfo.versionName + \\\" (v\\\" + staticInfo.versionNum + \\\" - \\\" + staticInfo.versionCommit + \\\")\\\"}
\\n
{staticInfo.platform + (snapshot.currentBN !== \\\"1.1\\\" ? \\\" BN: \\\" + snapshot.currentBN : \\\"\\\")}
\\n
runAction(() => buttonDisplayToggleAutoUpdate(ns))}>{\\\"Auto Update \\\" + (options[\\\"DisplayToggleAutoUpdate\\\"] ? \\\"On\\\" : \\\"Off\\\")} \\n
runAction(() => buttonDisplayToggleUpdateVersion(ns))}>{options[\\\"DisplayToggleUpdateVersion\\\"]} \\n\\n
\\n
\\n runAction(() => buttonThemeEditorStart(ns))}>{\\\"Theme Editor\\\"} \\n runAction(() => buttonDisplayToggleHelper(ns))}>{\\\"Helper \\\" + (options[\\\"DisplayToggleHelper\\\"] ? \\\"On\\\" : \\\"Off\\\")} \\n 0 ? displayStatusWarnStyle : displayStatusMutedStyle} onClick={onUnhideAll}>{\\\"Hidden \\\" + hiddenCount} \\n
\\n
\\n
\\n
\\n
toggleToolbarMenu(\\\"Actions\\\")}>{\\\"Actions\\\"} \\n {activeToolbarMenu === \\\"Actions\\\" &&
\\n
{\\\"System Actions\\\"}
\\n
runToolbarAction(() => buttonJoinDiscord(ns))}>{\\\"Join Discord!!\\\"} \\n
runToolbarAction(() => buttonCreateGitHubIssue(ns))}>{\\\"Create GitHub Issue\\\"} \\n
runToolbarAction(() => buttonDisplayClearActive(ns))}>{\\\"Clear Active\\\"} \\n
runToolbarAction(() => buttonDisplayOpenLogs(ns))}>{\\\"Open Logs\\\"} \\n
runToolbarAction(() => buttonDisplayUpdate(ns, true))}>{\\\"Update\\\"} \\n
runToolbarAction(() => buttonChangeLog(ns))}>{\\\"Change Log\\\"} \\n
runToolbarAction(() => buttonDisplayRemove(ns))}>{\\\"REMOVE PROGRAM\\\"} \\n
}\\n
\\n
\\n {\\\"View:\\\"} \\n {displayViewMode} \\n
\\n
\\n
\\n )\\n}\\nfunction DarknetStockSelector({ ns, snapshot, runAction } = {}) {\\n const React = getReactLib()\\n const [open, setOpen] = React.useState(false)\\n const [stocks, setStocks] = React.useState([])\\n const [loadingStocks, setLoadingStocks] = React.useState(false)\\n const wrapRef = React.useRef(null)\\n const stockSelection = normalizeDarknetStockSelection(snapshot?.options?.[\\\"DarknetPromoteStock\\\"])\\n const selectedSyms = stockSelection.syms\\n const selectedSymSet = new Set(selectedSyms)\\n const allStocksSelected = isDarknetStockAllSelection(stockSelection, stocks)\\n const stockSelectionLabel = getDarknetStockSelectionLabel(stockSelection, stocks)\\n const stockSelectionOwned = selectedSyms.length > 0 && (allStocksSelected || selectedSyms.length > 1 || selectedSyms.every((sym) => stocks.find((stock) => stock.sym === sym)?.owned))\\n const buttonStyle = {\\n ...darknetStockButtonStyle,\\n ...(stockSelectionOwned ? greenStyle : redStyle)\\n }\\n const stockSymbolWidth = `${Math.max(3, ...stocks.map((stock) => stock.sym.length)) + 2}ch`\\n const menuWidth = `calc(${stockSymbolWidth} * 4 + 12px)`\\n const getStockOptionStyle = (stock) => ({\\n ...(stock.owned ? darknetStockOwnedStyle : darknetStockUnownedStyle),\\n ...(selectedSymSet.has(stock.sym) ? darknetStockSelectedStyle : {})\\n })\\n const openStockSelector = async () => {\\n if (open) {\\n setOpen(false)\\n return\\n }\\n setOpen(true)\\n setStocks([])\\n setLoadingStocks(true)\\n const freshStocks = ns ? await getDarknetStockChoices(ns) : []\\n setStocks(freshStocks)\\n setLoadingStocks(false)\\n }\\n const selectStockSelection = async (selection, closeAfterSelect = true) => {\\n if (closeAfterSelect) setOpen(false)\\n if (ns && runAction)\\n await runAction(() => buttonDarknet(ns, \\\"stock\\\", selection))\\n }\\n const toggleStock = async (sym) => {\\n const nextSyms = selectedSymSet.has(sym) ? selectedSyms.filter((selectedSym) => selectedSym !== sym)\\n : [...selectedSyms, sym]\\n await selectStockSelection(buildDarknetStockSelection(nextSyms), false)\\n }\\n React.useEffect(() => {\\n if (!open) return\\n const closeOnOutsideClick = (event) => {\\n if (!wrapRef.current?.contains?.(event.target))\\n setOpen(false)\\n }\\n globalThis[\\\"document\\\"]?.addEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n return () => globalThis[\\\"document\\\"]?.removeEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n }, [open])\\n return (\\n \\n {\\\"Stock: \\\" + stockSelectionLabel} \\n {open && \\n
selectStockSelection(buildDarknetStockSelection())}>{\\\"None\\\"} \\n
selectStockSelection(buildDarknetStockSelection(stocks.map((stock) => stock.sym)))}>{\\\"All\\\"} \\n {loadingStocks &&
{\\\"Loading\\\"} }\\n {stocks.length > 0 &&
\\n {stocks.map((stock) => toggleStock(stock.sym)}>{stock.sym} )}\\n
}\\n {!loadingStocks && stocks.length === 0 &&
{\\\"No Stocks\\\"} }\\n
}\\n \\n )\\n}\\nfunction HashAutoTargetSelector({ snapshot, runAction } = {}) {\\n const React = getReactLib()\\n const [open, setOpen] = React.useState(false)\\n const wrapRef = React.useRef(null)\\n const selectedHashTarget = normalizeHashAutoTarget(snapshot?.options?.[\\\"HashAutoTarget\\\"])\\n const selectedHashLabel = getHashAutoTargetLabel(selectedHashTarget)\\n const selectedHashAvailable = isHashAutoTargetAvailable(selectedHashTarget, snapshot)\\n const buttonStyle = {\\n ...darknetStockButtonStyle,\\n ...(selectedHashAvailable ? greenStyle : redStyle)\\n }\\n const hashOptionWidth = `${Math.max(...hashAutoTargetOptions.map((option) => option.label.length)) + 2}ch`\\n const menuWidth = `calc(${hashOptionWidth} * 2 + 20px)`\\n const getHashOptionStyle = (option) => ({\\n ...(isHashAutoTargetAvailable(option.value, snapshot) ? darknetStockAllStyle : darknetStockNoneStyle),\\n ...(selectedHashTarget === option.value ? darknetStockSelectedStyle : {})\\n })\\n const selectHashTarget = async (target) => {\\n setOpen(false)\\n if (runAction)\\n await runAction(() => buttonHashAutoTarget(target))\\n }\\n React.useEffect(() => {\\n if (!open) return\\n const closeOnOutsideClick = (event) => {\\n if (!wrapRef.current?.contains?.(event.target))\\n setOpen(false)\\n }\\n globalThis[\\\"document\\\"]?.addEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n return () => globalThis[\\\"document\\\"]?.removeEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n }, [open])\\n return (\\n \\n setOpen(!open)}>{selectedHashLabel === \\\"None\\\" ? \\\"No AutoHash\\\" : selectedHashLabel} \\n {open && \\n
\\n {hashAutoTargetOptions.map((option) => selectHashTarget(option.value)}>{option.label} )}\\n
\\n
}\\n \\n )\\n}\\nfunction SleeveTrainingSelector({ ns, snapshot, runAction } = {}) {\\n const React = getReactLib()\\n const [open, setOpen] = React.useState(false)\\n const wrapRef = React.useRef(null)\\n const selectedTraining = normalizeSleeveTrainingSelection(snapshot?.options?.[\\\"SleeveMode\\\"])\\n const selectedTrainingLabel = getSleeveTrainingLabel(selectedTraining)\\n const selectedTrainingAvailable = selectedTraining !== \\\"None\\\" && isSleeveTrainingAvailable(selectedTraining)\\n const buttonStyle = {\\n ...darknetStockButtonStyle,\\n ...(selectedTrainingAvailable ? greenStyle : redStyle)\\n }\\n const optionWidth = `${Math.max(...sleeveTrainingOptions.map((option) => option.label.length)) + 2}ch`\\n const menuWidth = `calc(${optionWidth} * 3 + 24px)`\\n const getTrainingOptionStyle = (option) => ({\\n ...(option.value !== \\\"None\\\" && isSleeveTrainingAvailable(option.value) ? darknetStockAllStyle : darknetStockNoneStyle),\\n ...(selectedTraining === option.value ? darknetStockSelectedStyle : {})\\n })\\n const selectTraining = async (selection) => {\\n const nextTraining = normalizeSleeveTrainingSelection(selection)\\n setOpen(false)\\n if (nextTraining === selectedTraining || !isSleeveTrainingAvailable(nextTraining)) return\\n if (ns && runAction)\\n await runAction(() => buttonSleevesToggle(ns, nextTraining))\\n }\\n React.useEffect(() => {\\n if (!open) return\\n const closeOnOutsideClick = (event) => {\\n if (!wrapRef.current?.contains?.(event.target))\\n setOpen(false)\\n }\\n globalThis[\\\"document\\\"]?.addEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n return () => globalThis[\\\"document\\\"]?.removeEventListener?.(\\\"mousedown\\\", closeOnOutsideClick)\\n }, [open])\\n return (\\n \\n setOpen(!open)}>{selectedTraining === \\\"None\\\" ? \\\"Training\\\" : \\\"Training: \\\" + selectedTrainingLabel} \\n {open && \\n
\\n {sleeveTrainingOptions.map((option) => selectTraining(option.value)}>{option.label} )}\\n
\\n
}\\n \\n )\\n}\\nfunction buildRows(ns, snapshot, runAction, staticInfo) {\\n // Pull the current option snapshot out for shorter access in the row builders\\n const options = snapshot.options\\n // rows is the final ordered list returned to LoaderApp\\n // Each entry is [title, requiredBN, requiredLevel, jsxButtons]\\n const rows = []\\n // Build reusable button fragments once so we can insert them into the row JSX below\\n // without repeating the same unlock checks several times.\\n const batcherUseHacknet = hasBN(resetInfo, sourceFiles, 9, 1) ? runAction(() => buttonBatcherUseHacknet(ns))}>{\\\"Use Hacknet\\\"} : \\\"\\\"\\n const batcherAutoHash = hasBN(resetInfo, sourceFiles, 9, 1) ? runAction(() => buttonBatcherAutoHash(ns))}>{\\\"Auto Hash\\\"} : \\\"\\\"\\n const batcherChargeStanek = hasBN(resetInfo, sourceFiles, 13) ? runAction(() => buttonBatcherToggleStanek(ns))}>{\\\"Charge Stanek\\\"} : \\\"\\\"\\n const batcherAutoBuyHacknet = hasBN(resetInfo, sourceFiles, 9, 1) ? runAction(() => buttonBatcherAutoBuyHacknet(ns))}>{\\\"Batcher: AutoBuy\\\"} : \\\"\\\"\\n const miscBackdoorBasic = !hasBN(resetInfo, sourceFiles, 4, 2) ? runAction(() => buttonMiscBackdoorBasic(ns))}>{\\\"Backdoor\\\"} : \\\"\\\"\\n const miscBackdoorSingBasic = hasBN(resetInfo, sourceFiles, 4, 2) ? runAction(() => buttonMiscBackdoorSing(ns))}>{\\\"Backdoor Basic\\\"} : \\\"\\\"\\n const miscBackdoorSingAll = hasBN(resetInfo, sourceFiles, 4, 2) ? runAction(() => buttonMiscBackdoorSing(ns, true))}>{\\\"Backdoor All\\\"} : \\\"\\\"\\n const gangSleeves = hasBN(resetInfo, sourceFiles, 10, 1) ? runAction(() => buttonSleevesToggle(ns, \\\"Gangs\\\"))}>{\\\"Sleeves\\\"} : \\\"\\\"\\n const bbSleeves = hasBN(resetInfo, sourceFiles, 10, 1) ? runAction(() => buttonSleevesToggle(ns, \\\"BB\\\"))}>{\\\"Sleeves\\\"} : \\\"\\\"\\n const bbInfilOnly = hasBN(resetInfo, sourceFiles, 10, 1) ? runAction(() => buttonBBInfilOnly(ns))}>{\\\"Infil Only\\\"} : \\\"\\\"\\n const darknetShowMap = hasBN(resetInfo, sourceFiles, 15, 1) ? runAction(() => buttonDarknet(ns, \\\"map\\\"))}>{\\\"Show Lab Map\\\"} : \\\"\\\"\\n // KeepAlive only exists off Steam\\n const keepAlive = staticInfo.platform !== \\\"Steam\\\" ? runAction(() => buttonMiscKeepAlive(ns))}>{\\\"Keep Tab Alive\\\"} : \\\"\\\"\\n // Corp bribe availability depends on valuation and faction membership, so compute\\n // the label once before creating the corp row\\n let corpBribeName = \\\"Bribe Unavailable\\\"\\n if (snapshot.corp && snapshot.corp.valuation >= 100000000000000 && snapshot.player.factions.length > 0) corpBribeName = \\\"Bribe\\\"\\n // From here down, each rows.push(...) creates one visible section in the loader UI\\n // The title and BN fields are later used by rowUnlocked(...) to decide whether to render it\\n\\n // Batcher controls\\n rows.push([\\\"Batcher\\\", true, true, \\n runAction(() => buttonBatcherStart(ns))}>{snapshot.ports.batcher === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonBatcherAutoBuyServers(ns))}>{\\\"Auto-Buy Servers\\\"} \\n {batcherUseHacknet}\\n {batcherAutoHash} \\n runAction(() => buttonBatcherToggleMoney(ns))}>{\\\"Money Mode\\\"} \\n runAction(() => buttonBatcherToggleXP(ns))}>{\\\"XP Mode\\\"} \\n {batcherChargeStanek}\\n runAction(() => buttonBatcherPad(ns))}>{\\\"Pad Grows\\\"} \\n runAction(() => buttonBatcherLog(ns))}>{\\\"LogErrors\\\"} \\n runAction(() => buttonPopout(ns, \\\"Batcher\\\"))}>{\\\"Pop Out\\\"} ])\\n // Hacknet controls\\n rows.push([\\\"Hacknet\\\", true, true, \\n runAction(() => buttonHacknetBuyHacknet(ns))}>{\\\"Buy Hacknet\\\"} \\n {batcherAutoBuyHacknet} ])\\n // Hash spending controls\\n rows.push([\\\"Hashing\\\", 9, 1, \\n runAction(() => buttonHashing(ns, \\\"money\\\"))}>{\\\"Money\\\"} \\n runAction(() => buttonHashing(ns, \\\"min\\\"))}>{\\\"Reduce Min Sec\\\"} \\n runAction(() => buttonHashing(ns, \\\"max\\\"))}>{\\\"Boost Max Money\\\"} \\n runAction(() => buttonHashing(ns, \\\"coding\\\"))}>{\\\"Generate Contract\\\"} \\n runAction(() => buttonHashing(ns, \\\"corp\\\"))}>{\\\"Corp Money\\\"} \\n runAction(() => buttonHashing(ns, \\\"research\\\"))}>{\\\"Corp Research\\\"} \\n runAction(() => buttonHashing(ns, \\\"bbrank\\\"))}>{\\\"Boost BB Rank\\\"} \\n runAction(() => buttonHashing(ns, \\\"bbsp\\\"))}>{\\\"Boost BB SP\\\"} \\n \\n runAction(() => buttonHashing(ns, \\\"study\\\"))}>{\\\"Boost Study\\\"} \\n runAction(() => buttonHashing(ns, \\\"train\\\"))}>{\\\"Boost Train\\\"} \\n runAction(() => buttonHashing(ns, \\\"favor\\\"))}>{\\\"Boost Job Favor\\\"} ])\\n // Stock trading controls and automation toggles\\n rows.push([\\\"Stocks\\\", true, true, \\n runAction(() => buttonStocksStart(ns))}>{snapshot.ports.stocks === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonStocksBuy(ns))}>{\\\"Buy\\\"} \\n runAction(() => buttonStocksSell(ns))}>{\\\"Sell\\\"} \\n runAction(() => buttonStocksToggleAutoBuy(ns))}>{\\\"Toggle AutoBuy\\\"} \\n runAction(() => buttonStocksReset(ns))}>{\\\"Reset Stats\\\"} \\n runAction(() => buttonPopout(ns, \\\"Stocks\\\"))}>{\\\"Pop Out\\\"} ])\\n // Misc utility actions like backdooring, contract solving, RAM sharing, and keepalive\\n rows.push([\\\"Misc\\\", true, true, \\n {miscBackdoorBasic}\\n {miscBackdoorSingBasic}\\n {miscBackdoorSingAll}\\n runAction(() => buttonMiscTeleport(ns))}>{\\\"Teleport\\\"} \\n runAction(() => buttonMiscSolveContracts(ns))}>{\\\"Solve Contracts\\\"} \\n runAction(() => buttonMiscShareRam(ns))}>{options[\\\"ShareMode\\\"] ? \\\"Unshare Ram\\\" : \\\"Share Ram\\\"} \\n {keepAlive} ])\\n // Singularity\\n rows.push([\\\"Singularity\\\", 4, 2, \\n runAction(() => buttonSingDumpMoney(ns))}>{\\\"Dump Money\\\"} \\n runAction(() => buttonAutoPilot(ns))}>{\\\"AutoPilot\\\"} \\n runAction(() => buttonAutoPilotMoveOn(ns))}>{\\\"Start On Next\\\"} \\n runAction(() => buttonPopout(ns, \\\"AutoPilot\\\"))}>{\\\"Pop Out\\\"} ])\\n // Dark net\\n rows.push([\\\"DarkNet\\\", true, true, \\n runAction(() => buttonDarknet(ns, \\\"start\\\"))}>{snapshot.ports.darknet === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonDarknet(ns, \\\"storm\\\"))}>{\\\"WebStorm\\\"} \\n {darknetShowMap} \\n \\n runAction(() => buttonDarknet(ns, \\\"phishing\\\"))}>{\\\"Phishing\\\"} \\n runAction(() => buttonDarknet(ns, \\\"inducing\\\"))}>{\\\"Inducing\\\"} \\n runAction(() => buttonDarknet(ns, \\\"sharing\\\"))}>{\\\"Sharing\\\"} ])\\n // IPvGo management\\n rows.push([\\\"IPvGo\\\", true, true, \\n runAction(() => buttonIPvGoStart(ns))}>{snapshot.ports.ipvgo === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonIPvGoPlayWhite(ns))}>{\\\"Play White\\\"} \\n runAction(() => buttonIPvGoRepeat(ns))}>{\\\"Repeat\\\"} \\n runAction(() => buttonIPvGoCheats(ns))}>{\\\"Cheats\\\"} \\n runAction(() => buttonIPvGoLogging(ns))}>{\\\"Logging\\\"} \\n runAction(() => buttonIPvGoNetburners(ns))}>{\\\"Netburners\\\"} \\n runAction(() => buttonIPvGoSlumSnakes(ns))}>{\\\"Slum Snakes\\\"} \\n runAction(() => buttonIPvGoTheBlackHand(ns))}>{\\\"The Black Hand\\\"} \\n runAction(() => buttonIPvGoTetrads(ns))}>{\\\"Tetrads\\\"} \\n runAction(() => buttonIPvGoDaedalus(ns))}>{\\\"Daedalus\\\"} \\n runAction(() => buttonIPvGoIlluminati(ns))}>{\\\"Illuminati\\\"} \\n runAction(() => buttonIPvGoUnknown(ns))}>{\\\"????????\\\"} \\n runAction(() => buttonIPvGoNoAI(ns))}>{\\\"No AI\\\"} \\n runAction(() => buttonIPvGoSlowMode(ns))}>{\\\"SlowMode\\\"} \\n runAction(() => buttonPopout(ns, \\\"IPvGo\\\"))}>{\\\"Pop Out\\\"} ])\\n // Gang automation controls\\n rows.push([\\\"Gangs\\\", 2, 1, \\n runAction(() => buttonGangStart(ns))}>{snapshot.ports.gangs === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonGangAutoAscend(ns))}>{\\\"Auto-Ascend\\\"} \\n runAction(() => buttonGangAutoEQ(ns))}>{\\\"Auto-EQ\\\"} \\n {gangSleeves} \\n runAction(() => buttonGangMode(ns, \\\"AutoMode\\\"))}>{\\\"AutoMode\\\"} \\n runAction(() => buttonGangMode(ns, \\\"Respect\\\"))}>{\\\"Respect\\\"} \\n runAction(() => buttonGangMode(ns, \\\"Money\\\"))}>{\\\"Money\\\"} \\n runAction(() => buttonGangMode(ns, \\\"Training\\\"))}>{\\\"Training\\\"} \\n \\n runAction(() => buttonGangBuyEQ(ns))}>{\\\"Buy EQ All\\\"} \\n runAction(() => buttonGangAscend(ns))}>{\\\"Ascend All\\\"} \\n runAction(() => buttonPopout(ns, \\\"Gang\\\"))}>{\\\"Pop Out\\\"} ])\\n // Corporation startup\\n rows.push([\\\"Corps\\\", 3, 3, \\n runAction(() => buttonCorpStart(ns))}>{snapshot.ports.corp === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonCorpResetTAII(ns))}>{\\\"Reset TAII\\\"} \\n runAction(() => buttonCorpBribe(ns))}>{corpBribeName} \\n runAction(() => buttonPopout(ns, \\\"Corp\\\"))}>{\\\"Pop Out\\\"} ])\\n // Bladeburner controls\\n rows.push([\\\"BladeBurner\\\", 6, 1, \\n runAction(() => buttonBBStart(ns))}>{snapshot.ports.bb === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonBBFinisher(ns))}>{\\\"Finisher\\\"} \\n runAction(() => buttonBBIntMode(ns))}>{\\\"Int Mode\\\"} \\n {bbSleeves}\\n {bbInfilOnly}\\n runAction(() => buttonPopout(ns, \\\"BB\\\"))}>{\\\"Pop Out\\\"} ])\\n // Stanek\\n rows.push([\\\"Stanek\\\", 13, 1, \\n runAction(() => buttonStanekStart(ns))}>{snapshot.ports.stanek === \\\"NULL PORT DATA\\\" ? \\\"Charge\\\" : \\\"Pls Wait\\\"} \\n runAction(() => buttonStanekSaveConfig(ns))}>{\\\"Save Config\\\"} \\n runAction(() => buttonStanekLoadConfig(ns))}>{\\\"Load Config\\\"} \\n runAction(() => buttonStanekDeleteConfig(ns))}>{\\\"Delete Config\\\"} \\n runAction(() => buttonStanekUseDefault(ns))}>{\\\"Defaults\\\"} ])\\n // Sleeve manager controls\\n rows.push([\\\"Sleeves\\\", 10, 1, \\n runAction(() => buttonSleeveStart(ns))}>{snapshot.ports.sleeves === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonSleevesToggle(ns, \\\"Recovery\\\"))}>{\\\"Recovery\\\"} \\n runAction(() => buttonSleevesToggle(ns, \\\"Sync\\\"))}>{\\\"Sync\\\"} \\n runAction(() => buttonSleevesInstallAugments(ns))}>{\\\"Install Augments\\\"} \\n runAction(() => buttonPopout(ns, \\\"Sleeve\\\"))}>{\\\"Pop Out\\\"} \\n \\n runAction(() => buttonSleevesToggle(ns, \\\"Money\\\"))}>{\\\"Cash\\\"} \\n runAction(() => buttonSleevesToggle(ns, \\\"Karma\\\"))}>{\\\"Karma\\\"} \\n runAction(() => buttonSleevesToggle(ns, \\\"Idle\\\"))}>{\\\"Idle\\\"} \\n ])\\n // Auto-grafting\\n rows.push([\\\"Grafting\\\", 10, 1, \\n runAction(() => buttonGrafting(ns))}>{snapshot.ports.grafting === \\\"NULL PORT DATA\\\" ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonPopout(ns, \\\"Grafting\\\"))}>{\\\"Pop Out\\\"} ])\\n // Auto-grafting\\n rows.push([\\\"Games\\\", true, true, \\n runAction(() => buttonGameDoom(ns))}>{\\\"DOOM\\\"} \\n runAction(() => buttonGameMinesweeper(ns))}>{\\\"Minesweeper\\\"} \\n runAction(() => buttonGameTimberman(ns))}>{\\\"Timberman\\\"} ])\\n // Developer / cheat utilities\\n rows.push([\\\"Cheats\\\", true, true, \\n {\\\"Dev/Unlocks\\\" + getBuffer(11)} runAction(() => buttonDevMenu(ns))}>{\\\"Dev Menu\\\"} \\n runAction(() => buttonNotDevMenu(ns))}>{\\\"NOT the Dev Menu\\\"} \\n runAction(() => buttonUnlockAll(ns))}>{\\\"Unlock All Achievements\\\"} \\n {\\\"Casino\\\" + getBuffer(6)} runAction(() => buttonCasinoStart(ns))}>{\\\"Casino\\\"} \\n {\\\"AutoInfil\\\" + getBuffer(9)} runAction(() => buttonAutoInfilStart(ns))}>{!snapshot.autoInfilRunning ? \\\"Activate\\\" : \\\"De-Activate\\\"} \\n runAction(() => buttonAutoInfilAuto(ns))}>{\\\"Auto\\\"} \\n runAction(() => buttonAutoInfilMoney(ns))}>{\\\"Money\\\"} \\n runAction(() => buttonAutoInfilFaction(ns))}>{\\\"Faction\\\"} {options[\\\"AutoInfilFaction\\\"]} ])\\n // Return the completed row list to LoaderApp for filtering and rendering.\\n return rows\\n}\\nfunction rowUnlocked([sendTitle, bn, lvl]) {\\n if (bn === true && lvl === true) return true\\n else if (bn === false && lvl === false) return false\\n return hasBN(resetInfo, sourceFiles, bn, lvl)\\n || (bn === 6 && hasBN(resetInfo, sourceFiles, 7, lvl))\\n}\\nconst commandHandlers = {\\n \\\"puppet money on\\\": () => { optionsDB[\\\"BatcherMoney\\\"] = true },\\n \\\"puppet money off\\\": () => { optionsDB[\\\"BatcherMoney\\\"] = false },\\n \\\"puppet xp on\\\": () => { optionsDB[\\\"BatcherXP\\\"] = true },\\n \\\"puppet xp off\\\": () => { optionsDB[\\\"BatcherXP\\\"] = false },\\n \\\"puppet autobuyservers on\\\": () => { optionsDB[\\\"BatcherAutoBuyServers\\\"] = true },\\n \\\"puppet autobuyservers off\\\": () => { optionsDB[\\\"BatcherAutoBuyServers\\\"] = false },\\n \\\"puppet autohash on\\\": () => { optionsDB[\\\"BatcherAutoHash\\\"] = true },\\n \\\"puppet autohash off\\\": () => { optionsDB[\\\"BatcherAutoHash\\\"] = false },\\n \\\"puppet stanek on\\\": () => { optionsDB[\\\"BatcherStanek\\\"] = true },\\n \\\"puppet stanek off\\\": () => { optionsDB[\\\"BatcherStanek\\\"] = false },\\n \\\"puppet hacknet on\\\": () => { optionsDB[\\\"BatcherUseHacknet\\\"] = true },\\n \\\"puppet hacknet off\\\": () => { optionsDB[\\\"BatcherUseHacknet\\\"] = false },\\n \\\"puppet autobuyhacknet on\\\": () => { optionsDB[\\\"BatcherAutoBuyHacknet\\\"] = true },\\n \\\"puppet autobuyhacknet off\\\": () => { optionsDB[\\\"BatcherAutoBuyHacknet\\\"] = false },\\n \\\"puppet popout off\\\": () => { optionsDB[\\\"BatcherPopout\\\"] = false },\\n \\\"puppet log on\\\": () => { optionsDB[\\\"BatcherLog\\\"] = true },\\n \\\"puppet log off\\\": () => { optionsDB[\\\"BatcherLog\\\"] = false },\\n \\\"puppet pad on\\\": () => { optionsDB[\\\"BatcherPad\\\"] = true },\\n \\\"puppet pad off\\\": () => { optionsDB[\\\"BatcherPad\\\"] = false },\\n \\\"ipvgo repeat on\\\": () => { optionsDB[\\\"IPvGoRepeat\\\"] = true },\\n \\\"ipvgo repeat off\\\": () => { optionsDB[\\\"IPvGoRepeat\\\"] = false },\\n \\\"ipvgo playaswhite off\\\": () => { optionsDB[\\\"IPvGoPlayAsWhite\\\"] = false },\\n \\\"ipvgo playaswhite on\\\": () => { optionsDB[\\\"IPvGoPlayAsWhite\\\"] = true },\\n \\\"ipvgo cheats on\\\": () => { optionsDB[\\\"IPvGoCheats\\\"] = true },\\n \\\"ipvgo cheats off\\\": () => { optionsDB[\\\"IPvGoCheats\\\"] = false },\\n \\\"ipvgo logging on\\\": () => { optionsDB[\\\"IPvGoLogging\\\"] = true },\\n \\\"ipvgo logging off\\\": () => { optionsDB[\\\"IPvGoLogging\\\"] = false },\\n \\\"ipvgo net on\\\": () => { optionsDB[\\\"IPvGoNetburners\\\"] = true },\\n \\\"ipvgo net off\\\": () => { optionsDB[\\\"IPvGoNetburners\\\"] = false },\\n \\\"ipvgo slum on\\\": () => { optionsDB[\\\"IPvGoSlumSnakes\\\"] = true },\\n \\\"ipvgo slum off\\\": () => { optionsDB[\\\"IPvGoSlumSnakes\\\"] = false },\\n \\\"ipvgo bh on\\\": () => { optionsDB[\\\"IPvGoTheBlackHand\\\"] = true },\\n \\\"ipvgo bh off\\\": () => { optionsDB[\\\"IPvGoTheBlackHand\\\"] = false },\\n \\\"ipvgo tetrad on\\\": () => { optionsDB[\\\"IPvGoTetrads\\\"] = true },\\n \\\"ipvgo tetrad off\\\": () => { optionsDB[\\\"IPvGoTetrads\\\"] = false },\\n \\\"ipvgo daed on\\\": () => { optionsDB[\\\"IPvGoDaedalus\\\"] = true },\\n \\\"ipvgo daed off\\\": () => { optionsDB[\\\"IPvGoDaedalus\\\"] = false },\\n \\\"ipvgo illum on\\\": () => { optionsDB[\\\"IPvGoIlluminati\\\"] = true },\\n \\\"ipvgo illum off\\\": () => { optionsDB[\\\"IPvGoIlluminati\\\"] = false },\\n \\\"ipvgo ???? on\\\": () => { optionsDB[\\\"IPvGoUnknown\\\"] = true },\\n \\\"ipvgo ???? off\\\": () => { optionsDB[\\\"IPvGoUnknown\\\"] = false },\\n \\\"ipvgo noai on\\\": () => { optionsDB[\\\"IPvGoNoAI\\\"] = true },\\n \\\"ipvgo noai off\\\": () => { optionsDB[\\\"IPvGoNoAI\\\"] = false },\\n \\\"ipvgo slowmode on\\\": () => { optionsDB[\\\"IPvGoSlowMode\\\"] = true },\\n \\\"ipvgo slowmode off\\\": () => { optionsDB[\\\"IPvGoSlowMode\\\"] = false },\\n \\\"ipvgo popout off\\\": () => { optionsDB[\\\"IPvGoPopOut\\\"] = false },\\n \\\"gang autoascend on\\\": () => { optionsDB[\\\"GangAutoAscend\\\"] = true },\\n \\\"gang autoascend off\\\": () => { optionsDB[\\\"GangAutoAscend\\\"] = false },\\n \\\"gang autoeq on\\\": () => { optionsDB[\\\"GangAutoEQ\\\"] = true },\\n \\\"gang autoeq off\\\": () => { optionsDB[\\\"GangAutoEQ\\\"] = false },\\n \\\"gang mode automode\\\": () => { optionsDB[\\\"GangMode\\\"] = \\\"AutoMode\\\" },\\n \\\"gang mode respect\\\": () => { optionsDB[\\\"GangMode\\\"] = \\\"Respect\\\" },\\n \\\"gang mode money\\\": () => { optionsDB[\\\"GangMode\\\"] = \\\"Money\\\" },\\n \\\"gang popout off\\\": () => { optionsDB[\\\"GangPopOut\\\"] = false },\\n \\\"sleeves idle\\\": () => { optionsDB[\\\"SleeveMode\\\"] = \\\"Idle\\\" },\\n \\\"sleeves popout off\\\": () => { optionsDB[\\\"SleevePopOut\\\"] = false },\\n \\\"stocks popout off\\\": () => { optionsDB[\\\"StocksPopOut\\\"] = false },\\n \\\"stocks autobuy off\\\": () => { optionsDB[\\\"StocksToggleAutoBuy\\\"] = false },\\n \\\"stocks autobuy on\\\": () => { optionsDB[\\\"StocksToggleAutoBuy\\\"] = true },\\n \\\"autopilot popout off\\\": () => { optionsDB[\\\"AutoPilotPopOut\\\"] = false },\\n \\\"bb finisher off\\\": () => { optionsDB[\\\"BBFinisher\\\"] = false },\\n \\\"bb int mode off\\\": () => { optionsDB[\\\"BBIntMode\\\"] = false },\\n \\\"bb sleeves on\\\": () => { optionsDB[\\\"SleeveMode\\\"] = \\\"BB\\\" },\\n \\\"bb sleeves off\\\": () => { optionsDB[\\\"SleeveMode\\\"] = \\\"Idle\\\" },\\n \\\"bb sleeve infil off\\\": () => { optionsDB[\\\"BBInfilOnly\\\"] = false },\\n \\\"bb popout off\\\": () => { optionsDB[\\\"BBPopOut\\\"] = false },\\n \\\"grafting popout off\\\": () => { optionsDB[\\\"GraftingPopOut\\\"] = false },\\n \\\"darknet storm off\\\": () => { optionsDB[\\\"DarknetStorm\\\"] = false },\\n \\\"darknet map off\\\": () => { optionsDB[\\\"DarknetShowMap\\\"] = false },\\n \\\"dnetStocks\\\": (sym) => { optionsDB[\\\"DarknetPromoteStock\\\"] = normalizeDarknetStockSelection(sym) }\\n}\\nfunction processCommands(ns) {\\n while (ns.peek(1) !== \\\"NULL PORT DATA\\\") {\\n const result = ns.readPort(1)\\n if (result === 1 || result === true) continue // 1 and true were used to just cycle the display, anythign else is state communication\\n if (result.startsWith(\\\"dnetStocks:\\\")) commandHandlers[\\\"dnetStocks\\\"](result.split(\\\":\\\")[1])\\n if (commandHandlers[result]) commandHandlers[result]()\\n else ns.tprintf(\\\"Invalid response received in Loader: %s\\\", result);\\n }\\n}\\nfunction getBuffer(startValue, endValue = 12) {\\n let buffer = \\\"\\\"\\n for (let i = startValue; i < endValue; i++)\\n buffer += \\\" \\\"\\n buffer += \\\":\\\"\\n return buffer\\n}\\nfunction buttonDisplayToggleHelper(ns) {\\n optionsDB[\\\"DisplayToggleHelper\\\"] = !optionsDB[\\\"DisplayToggleHelper\\\"]\\n}\\nfunction buttonDisplayToggleAutoUpdate(ns) {\\n optionsDB[\\\"DisplayToggleAutoUpdate\\\"] = !optionsDB[\\\"DisplayToggleAutoUpdate\\\"]\\n if (optionsDB[\\\"DisplayToggleAutoUpdate\\\"]) buttonDisplayUpdate(ns)\\n}\\nfunction buttonDisplayToggleUpdateVersion(ns) {\\n if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === \\\"Beta\\\") optionsDB[\\\"DisplayToggleUpdateVersion\\\"] = \\\"Stable\\\"\\n else optionsDB[\\\"DisplayToggleUpdateVersion\\\"] = \\\"Beta\\\"\\n if (optionsDB[\\\"DisplayToggleAutoUpdate\\\"]) buttonDisplayUpdate(ns)\\n}\\nfunction buttonDisplayOpenLogs(ns) {\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(2)) // Puppet\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(4)) // Stocks\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(5)) // IPvGo\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(6)) // Gangs\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(7)) // Sleeves\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(8)) // BB\\n if (ns.peek(9) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(9)) // Corps\\n if (ns.peek(10) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(10)) // Casino\\n if (ns.peek(20) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(20)) // Grafting\\n if (ns.peek(27) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(27)) // Minesweeper\\n if (ns.peek(28) !== \\\"NULL PORT DATA\\\") ns.ui.openTail(ns.peek(28)) // Theme Editor\\n}\\nasync function buttonDisplayClearActive(ns) {\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\" && ns.peek(2) > 0) await proxy(ns, \\\"kill\\\", ns.peek(2))// Puppet\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\" && ns.peek(4) > 0) await proxy(ns, \\\"kill\\\", ns.peek(4))// Stocks\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\" && ns.peek(5) > 0) await proxy(ns, \\\"kill\\\", ns.peek(5))// IPvGo\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\" && ns.peek(6) > 0) await proxy(ns, \\\"kill\\\", ns.peek(6))// Gangs\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\" && ns.peek(7) > 0) await proxy(ns, \\\"kill\\\", ns.peek(7))// Sleeves\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\" && ns.peek(8) > 0) await proxy(ns, \\\"kill\\\", ns.peek(8))// BB\\n if (ns.peek(9) !== \\\"NULL PORT DATA\\\" && ns.peek(9) > 0) await proxy(ns, \\\"kill\\\", ns.peek(9))// Corps\\n if (ns.peek(10) !== \\\"NULL PORT DATA\\\" && ns.peek(10) > 0) await proxy(ns, \\\"kill\\\", ns.peek(10))// Casino\\n if (ns.peek(20) !== \\\"NULL PORT DATA\\\" && ns.peek(20) > 0) await proxy(ns, \\\"kill\\\", ns.peek(20))// Grafting\\n if (ns.peek(26) !== \\\"NULL PORT DATA\\\" && ns.peek(26) > 0) await proxy(ns, \\\"writePort\\\", 24, true)// Darknet Kill Switch\\n if (ns.peek(27) !== \\\"NULL PORT DATA\\\" && ns.peek(27) > 0) await proxy(ns, \\\"kill\\\", ns.peek(27))// Minesweeper\\n if (ns.peek(28) !== \\\"NULL PORT DATA\\\" && ns.peek(28) > 0) await proxy(ns, \\\"kill\\\", ns.peek(28))// Theme Editor\\n if (ns.peek(29) !== \\\"NULL PORT DATA\\\" && ns.peek(29) > 0) await proxy(ns, \\\"kill\\\", ns.peek(29))// Timberman\\n if (wnd?.tmrAutoInf) await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, []) //Stop it, Autoinfil\\n if (optionsDB[\\\"ShareMode\\\"]) {\\n optionsDB[\\\"ShareMode\\\"] = false\\n await runIt(ns, \\\"SphyxOS/bins/startShare.js\\\", false, [\\\"stop\\\"])\\n }\\n ns.clearPort(2)// Puppet\\n ns.clearPort(4)// Stocks\\n ns.clearPort(5)// IPvGo\\n ns.clearPort(6)// Gangs\\n ns.clearPort(7)// Sleeves\\n ns.clearPort(8)// BB\\n ns.clearPort(9)// Corps\\n ns.clearPort(10)//Casino\\n ns.clearPort(11)//Stanek\\n ns.clearPort(20)//Grafting\\n ns.clearPort(24) //Clear the kill switch port. Resolved promise still happens\\n ns.clearPort(26)//Darknet\\n ns.clearPort(27)//Minesweeper \\n ns.clearPort(28)//Theme Editor\\n ns.clearPort(29)//Timberman\\n\\n}\\nfunction buttonChangeLog(ns) {\\n const updatePid = ns.exec(\\\"SphyxOS/bins/changeLog.js\\\", \\\"home\\\")\\n if (updatePid === 0) ns.tprintf(\\\"Error: Not enough RAM to open change log.\\\")\\n}\\nfunction buttonJoinDiscord(ns) {\\n globalThis[\\\"window\\\"]?.open?.(discordInviteUrl, \\\"_blank\\\", \\\"noopener,noreferrer\\\")\\n ns.tprintf(\\\"Discord invite: %s\\\", discordInviteUrl)\\n}\\nfunction buttonCreateGitHubIssue(ns) {\\n globalThis[\\\"window\\\"]?.open?.(gitHubIssueUrl, \\\"_blank\\\", \\\"noopener,noreferrer\\\")\\n ns.tprintf(\\\"GitHub Issues Link: %s\\\", gitHubIssueUrl)\\n}\\nfunction buildLoaderConfigPayload() {\\n return {\\n optionsDB: { ...optionsDB },\\n openDB: [...openDB]\\n }\\n}\\nfunction restoreLoaderConfig(payload) {\\n optionsDB = { ...(payload?.optionsDB ?? {}) }\\n openDB.clear()\\n for (const key of payload?.openDB ?? []) {\\n if (typeof key === \\\"string\\\")\\n openDB.add(key)\\n }\\n}\\nfunction saveLoaderConfig(ns) {\\n ns.write(loaderConfigFile, JSON.stringify(buildLoaderConfigPayload()), \\\"w\\\")\\n ns.scp(loaderConfigFile, \\\"home\\\")\\n}\\nasync function loadLoaderConfig(ns) {\\n if (ns.scp(loaderConfigFile, ns.self().server, \\\"home\\\")) {\\n try {\\n restoreLoaderConfig(JSON.parse(ns.read(loaderConfigFile)))\\n await setOptionsDB(ns)\\n }\\n catch { await setOptionsDB(ns) }\\n }\\n else await setOptionsDB(ns)\\n}\\nasync function buttonThemeEditorStart(ns) {\\n if (ns.peek(28) !== \\\"NULL PORT DATA\\\") {\\n ns.ui.openTail(ns.peek(28))\\n await ns.asleep(0)\\n ns.ui.resizeTail(640, 840, ns.peek(28))\\n }\\n else await runIt(ns, \\\"SphyxOS/bins/themeEditor.jsx\\\", false, [])\\n}\\nasync function buttonDisplayRemove(ns) {\\n return //Safety for myself\\n const result = await ns.prompt(\\\"Are you sure?\\\", { type: \\\"boolean\\\" })\\n if (result === true) {\\n const localStorage = !!await ns.prompt(\\\"Local Storage(Stanek loadouts, etc) too?\\\", { type: \\\"boolean\\\" })\\n ns.tprintf(\\\"Deleting SphyxOS.\\\")\\n await buttonDisplayClearActive(ns)\\n await ns.asleep(4)\\n writeRemoval(ns)\\n await ns.asleep(4)\\n const servers = await getServersLight(ns)\\n const scriptRam = 2.8\\n ns.tprintf(\\\"RAM: %s\\\", scriptRam)\\n for (const server of servers) {\\n if (server === \\\"home\\\") continue\\n const ram = await getServerAvailRam(ns, server)\\n if (ram < scriptRam) continue\\n ns.scp(\\\"SphyxOSRemoval.js\\\", server)\\n await ns.asleep(4)\\n ns.exec(\\\"SphyxOSRemoval.js\\\", server, 1, localStorage)\\n await proxy(ns, \\\"rm\\\", \\\"SphyxOSRemoval.js\\\")\\n ns.tprintf(\\\"Server: %s\\\", server)\\n ns.exit()\\n }\\n ns.toast(\\\"Not enough free RAM to run the removal script.\\\", \\\"error\\\", 3000)\\n }\\n}\\n/** @param {NS} ns */\\nfunction writeRemoval(ns) {\\n const data = `\\nexport async function main(ns) {\\n const localRemoval = ns.args[0]\\n ns.rm(\\\"SphyxOS.txt\\\", \\\"home\\\")\\n const files = ns.ls(\\\"home\\\", \\\"SphyxOS/\\\")\\n if (localRemoval) files.push(...ns.ls(\\\"home\\\", \\\"SphyxOSUserData/\\\"))\\n files.push(\\\"Loader.js\\\")\\n for (const file of files)\\n ns.rm(file, \\\"home\\\")\\n}`\\n ns.write(\\\"SphyxOSRemoval.js\\\", data, \\\"w\\\")\\n}\\nasync function buttonPopout(ns, program) {\\n switch (program) {\\n case \\\"Batcher\\\":\\n optionsDB[\\\"BatcherPopout\\\"] = !optionsDB[\\\"BatcherPopout\\\"]\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\")\\n optionsDB[\\\"BatcherPopout\\\"] === true ? ns.writePort(12, \\\"popout\\\") : ns.writePort(12, \\\"nopopout\\\")\\n break\\n case \\\"AutoPilot\\\":\\n optionsDB[\\\"AutoPilotPopOut\\\"] = !optionsDB[\\\"AutoPilotPopOut\\\"]\\n if (ns.peek(21) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(22, optionsDB[\\\"AutoPilotPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"Stocks\\\":\\n optionsDB[\\\"StocksPopOut\\\"] = !optionsDB[\\\"StocksPopOut\\\"]\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(13, optionsDB[\\\"StocksPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"IPvGo\\\":\\n optionsDB[\\\"IPvGoPopOut\\\"] = !optionsDB[\\\"IPvGoPopOut\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"BB\\\":\\n optionsDB[\\\"BBPopOut\\\"] = !optionsDB[\\\"BBPopOut\\\"]\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(18, optionsDB[\\\"BBPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"Gang\\\":\\n optionsDB[\\\"GangPopOut\\\"] = !optionsDB[\\\"GangPopOut\\\"]\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(16, optionsDB[\\\"GangPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"Grafting\\\":\\n optionsDB[\\\"GraftingPopOut\\\"] = !optionsDB[\\\"GraftingPopOut\\\"]\\n if (ns.peek(20) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(23, optionsDB[\\\"GraftingPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"Sleeve\\\":\\n optionsDB[\\\"SleevePopOut\\\"] = !optionsDB[\\\"SleevePopOut\\\"]\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(17, optionsDB[\\\"SleevePopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n case \\\"Corp\\\":\\n optionsDB[\\\"CorpPopOut\\\"] = !optionsDB[\\\"CorpPopOut\\\"]\\n if (ns.peek(9) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(19, optionsDB[\\\"CorpPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n break\\n default:\\n ns.tprintf(\\\"Invalid program for popout: \\\" + program)\\n break\\n }\\n}\\nasync function buttonBatcherStart(ns) {\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(2))\\n }\\n else {\\n const commands = []\\n if (optionsDB[\\\"BatcherUseHacknet\\\"]) commands.push(\\\"usehacknet\\\")\\n if (optionsDB[\\\"BatcherAutoHash\\\"]) commands.push(\\\"autohash\\\")\\n if (!optionsDB[\\\"BatcherAutoBuyServers\\\"]) commands.push(\\\"nopurchase\\\")\\n if (optionsDB[\\\"BatcherAutoBuyHacknet\\\"]) commands.push(\\\"autobuyhacknet\\\")\\n if (!optionsDB[\\\"BatcherMoney\\\"]) commands.push(\\\"nomoney\\\")\\n if (!optionsDB[\\\"BatcherXP\\\"]) commands.push(\\\"noxp\\\")\\n if (optionsDB[\\\"BatcherStanek\\\"]) commands.push(\\\"stanek\\\")\\n ns.writePort(12, \\\"silent\\\")\\n optionsDB[\\\"BatcherPopout\\\"] === true ? ns.writePort(12, \\\"popout\\\") : ns.writePort(12, \\\"nopopout\\\")\\n optionsDB[\\\"BatcherLog\\\"] === true ? ns.writePort(12, \\\"log\\\") : ns.writePort(12, \\\"nolog\\\")\\n optionsDB[\\\"BatcherPad\\\"] === true ? ns.writePort(12, \\\"pad\\\") : ns.writePort(12, \\\"nopad\\\")\\n await runIt(ns, \\\"SphyxOS/bins/puppetMini.js\\\", true, commands)\\n }\\n}\\nfunction buttonBatcherAutoBuyServers(ns) {\\n optionsDB[\\\"BatcherAutoBuyServers\\\"] = !optionsDB[\\\"BatcherAutoBuyServers\\\"]\\n if (optionsDB[\\\"BatcherAutoBuyServers\\\"] && ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"purchaseservers\\\")\\n }\\n else if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n }\\n}\\nfunction buttonBatcherUseHacknet(ns) {\\n optionsDB[\\\"BatcherUseHacknet\\\"] = !optionsDB[\\\"BatcherUseHacknet\\\"]\\n if (optionsDB[\\\"BatcherUseHacknet\\\"] && ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"hacknet\\\")\\n }\\n else if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"nohacknet\\\")\\n }\\n}\\nfunction buttonBatcherAutoHash(ns) {\\n optionsDB[\\\"BatcherAutoHash\\\"] = !optionsDB[\\\"BatcherAutoHash\\\"]\\n if (optionsDB[\\\"BatcherAutoHash\\\"] && ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"autohash\\\")\\n }\\n else if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"noautohash\\\")\\n }\\n}\\nfunction buttonBatcherAutoBuyHacknet(ns) {\\n optionsDB[\\\"BatcherAutoBuyHacknet\\\"] = !optionsDB[\\\"BatcherAutoBuyHacknet\\\"]\\n if (optionsDB[\\\"BatcherAutoBuyHacknet\\\"] && ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"autobuyhacknet\\\")\\n }\\n else if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, \\\"noautobuyhacknet\\\")\\n }\\n}\\nfunction buttonBatcherToggleMoney(ns) {\\n optionsDB[\\\"BatcherMoney\\\"] = !optionsDB[\\\"BatcherMoney\\\"]\\n if (!optionsDB[\\\"BatcherMoney\\\"] && !optionsDB[\\\"BatcherXP\\\"])\\n optionsDB[\\\"BatcherMoney\\\"] = true\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, optionsDB[\\\"BatcherMoney\\\"] ? \\\"money\\\" : \\\"nomoney\\\")\\n }\\n}\\nfunction buttonBatcherToggleXP(ns) {\\n optionsDB[\\\"BatcherXP\\\"] = !optionsDB[\\\"BatcherXP\\\"]\\n if (!optionsDB[\\\"BatcherMoney\\\"] && !optionsDB[\\\"BatcherXP\\\"])\\n optionsDB[\\\"BatcherMoney\\\"] = true\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, optionsDB[\\\"BatcherXP\\\"] ? \\\"xp\\\" : \\\"noxp\\\")\\n }\\n}\\nasync function buttonBatcherToggleStanek(ns) {\\n const frags = await proxy(ns, \\\"stanek.activeFragments\\\")\\n if (frags.length === 0) {\\n ns.toast(\\\"Please select a loadout first\\\", \\\"error\\\", 3000)\\n optionsDB[\\\"BatcherStanek\\\"] = false\\n return\\n }\\n optionsDB[\\\"BatcherStanek\\\"] = !optionsDB[\\\"BatcherStanek\\\"]\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, optionsDB[\\\"BatcherStanek\\\"] ? \\\"stanek\\\" : \\\"nostanek\\\")\\n }\\n}\\nasync function buttonBatcherLog(ns) {\\n optionsDB[\\\"BatcherLog\\\"] = !optionsDB[\\\"BatcherLog\\\"]\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, optionsDB[\\\"BatcherLog\\\"] ? \\\"log\\\" : \\\"nolog\\\")\\n }\\n}\\nasync function buttonBatcherPad(ns) {\\n optionsDB[\\\"BatcherPad\\\"] = !optionsDB[\\\"BatcherPad\\\"]\\n if (ns.peek(2) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(12, optionsDB[\\\"BatcherPad\\\"] ? \\\"pad\\\" : \\\"nopad\\\")\\n }\\n}\\nasync function buttonHacknetBuyHacknet(ns) {\\n await runIt(ns, \\\"SphyxOS/bins/hacknetPurchaser.js\\\", false, [])\\n}\\nasync function buttonMiscBackdoorBasic(ns) {\\n await runIt(ns, \\\"SphyxOS/extras/crawl-Basic.js\\\", true, [])\\n}\\nasync function buttonMiscBackdoorSing(ns, all = false) {\\n await runIt(ns, \\\"SphyxOS/bins/singularityBackdoor.js\\\", true, [all ? \\\"all\\\" : \\\"\\\"])\\n}\\nasync function buttonMiscTeleport(ns) {\\n await runIt(ns, \\\"SphyxOS/extras/teleport.js\\\", false, [])\\n}\\nasync function buttonMiscSolveContracts(ns) {\\n await runIt(ns, \\\"SphyxOS/bins/codingContracts.js\\\", false, [])\\n}\\nasync function buttonMiscShareRam(ns) {\\n optionsDB[\\\"ShareMode\\\"] = !optionsDB[\\\"ShareMode\\\"]\\n if (optionsDB[\\\"ShareMode\\\"]) await runIt(ns, \\\"SphyxOS/bins/startShare.js\\\", false, [])\\n else await runIt(ns, \\\"SphyxOS/bins/startShare.js\\\", false, [\\\"stop\\\"])\\n}\\nasync function buttonMiscKeepAlive(ns) {\\n if (wnd.keepAlive) {\\n wnd.keepAlive.close()\\n delete wnd.keepAlive\\n }\\n else {\\n const ctx = new AudioContext({ latencyHint: \\\"playback\\\" })\\n const osc = ctx.createOscillator()\\n // 1Hz - far too low to be audible\\n osc.frequency.setValueAtTime(1, ctx.currentTime)\\n const ctxGain = ctx.createGain()\\n // This is just above the threshold where playback is considered \\\"silent\\\".\\n ctxGain.gain.setValueAtTime(0.001, ctx.currentTime)\\n // Have to avoid picking up the RAM cost of singularity.connect\\n osc[\\\"connect\\\"](ctxGain)\\n ctxGain[\\\"connect\\\"](ctx.destination)\\n osc.start()\\n wnd.keepAlive = ctx\\n }\\n}\\nfunction buttonHashAutoTarget(target) {\\n optionsDB[\\\"HashAutoTarget\\\"] = normalizeHashAutoTarget(target)\\n}\\nasync function buttonHashing(ns, mode) {\\n const p = await runIt(ns, \\\"SphyxOS/extras/hashIt.js\\\", false, [mode])\\n if (p > 0) await ns.nextPortWrite(p)\\n ns.clearPort(p)\\n}\\nasync function buttonStocksStart(ns) {\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(4))\\n }\\n else {\\n const commands = []\\n if (optionsDB[\\\"StocksToggleAutoBuy\\\"]) commands.push(\\\"autobuy\\\")\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, optionsDB[\\\"StocksPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n await runIt(ns, \\\"SphyxOS/bins/tStocks.js\\\", true, commands)\\n }\\n}\\nfunction buttonStocksBuy(ns) {\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\") ns.writePort(13, \\\"buy\\\")\\n}\\nfunction buttonStocksSell(ns) {\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\") ns.writePort(13, \\\"sell\\\")\\n}\\nfunction buttonStocksToggleAutoBuy(ns) {\\n optionsDB[\\\"StocksToggleAutoBuy\\\"] = !optionsDB[\\\"StocksToggleAutoBuy\\\"]\\n if (optionsDB[\\\"StocksToggleAutoBuy\\\"] && ns.peek(4) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(13, \\\"autobuy\\\")\\n }\\n else if (ns.peek(4) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(13, \\\"autobuyoff\\\")\\n }\\n}\\nfunction buttonStocksReset(ns) {\\n if (ns.peek(4) !== \\\"NULL PORT DATA\\\") {\\n ns.writePort(13, \\\"reset\\\")\\n }\\n}\\nasync function buttonAutoPilot(ns) {\\n if (ns.peek(21) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(21))\\n }\\n else {\\n ns.writePort(22, \\\"silent\\\")\\n ns.writePort(22, optionsDB[\\\"AutoPilotPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n ns.writePort(22, optionsDB[\\\"AutoPilotMoveOn\\\"] ? \\\"moveon\\\" : \\\"nomoveon\\\")\\n globalThis[\\\"document\\\"].autopilot = optionsDB[\\\"AutoPilotMoveOn\\\"]\\n await runIt(ns, \\\"SphyxOS/bins/autopilot.js\\\", true, [])\\n }\\n}\\nasync function buttonAutoPilotMoveOn(ns) {\\n optionsDB[\\\"AutoPilotMoveOn\\\"] = !optionsDB[\\\"AutoPilotMoveOn\\\"]\\n if (ns.peek(21) !== \\\"NULL PORT DATA\\\") {\\n globalThis[\\\"document\\\"].autopilot = optionsDB[\\\"AutoPilotMoveOn\\\"]\\n ns.writePort(22, optionsDB[\\\"AutoPilotMoveOn\\\"] ? \\\"moveon\\\" : \\\"nomoveon\\\")\\n }\\n}\\n/** @param {NS} ns */\\nasync function buttonDarknet(ns, mode, selectedStock = \\\"\\\") {\\n const running = ns.peek(26) === \\\"NULL PORT DATA\\\" ? false : true\\n if (mode === \\\"start\\\") {\\n if (!await proxy(ns, \\\"fileExists\\\", \\\"DarkscapeNavigator.exe\\\", \\\"home\\\")) {\\n ns.toast(\\\"Buy 'DarkscapeNavigator.exe' from the darkweb to start this.\\\", \\\"Warning\\\", 3000)\\n return\\n }\\n if (running) {\\n ns.writePort(24, true) //Kill port\\n ns.clearPort(24) //Clear it after use. The resolved promise still happens\\n ns.clearPort(26)\\n }\\n else {\\n ns.writePort(25, \\\"silent\\\")\\n ns.writePort(25, optionsDB[\\\"DarknetPhishing\\\"] ? \\\"phishingOn\\\" : \\\"phishingOff\\\")\\n ns.writePort(25, optionsDB[\\\"DarknetInducing\\\"] ? \\\"inducingOn\\\" : \\\"inducingOff\\\")\\n ns.writePort(25, optionsDB[\\\"DarknetSharing\\\"] ? \\\"sharingOn\\\" : \\\"sharingOff\\\")\\n ns.writePort(25, optionsDB[\\\"DarknetShowMap\\\"] ? \\\"showmapOn\\\" : \\\"showmapOff\\\")\\n ns.writePort(25, optionsDB[\\\"DarknetStorm\\\"] ? \\\"stormOn\\\" : \\\"stormOff\\\")\\n ns.writePort(25, normalizeDarknetStockSelection(optionsDB[\\\"DarknetPromoteStock\\\"]))\\n await proxyAuth(ns, \\\"darkweb\\\", \\\"\\\", \\\"scp\\\", \\\"SphyxOS/bins/darknet.jsx\\\", \\\"darkweb\\\", \\\"home\\\")\\n await proxyAuth(ns, \\\"darkweb\\\", \\\"\\\", \\\"exec\\\", \\\"SphyxOS/bins/darknet.jsx\\\", \\\"darkweb\\\")\\n }\\n }\\n else if (mode === \\\"phishing\\\") {\\n optionsDB[\\\"DarknetPhishing\\\"] = !optionsDB[\\\"DarknetPhishing\\\"]\\n if (running) ns.writePort(25, optionsDB[\\\"DarknetPhishing\\\"] ? \\\"phishingOn\\\" : \\\"phishingOff\\\")\\n }\\n else if (mode === \\\"inducing\\\") {\\n optionsDB[\\\"DarknetInducing\\\"] = !optionsDB[\\\"DarknetInducing\\\"]\\n if (running) ns.writePort(25, optionsDB[\\\"DarknetInducing\\\"] ? \\\"inducingOn\\\" : \\\"inducingOff\\\")\\n }\\n else if (mode === \\\"sharing\\\") {\\n optionsDB[\\\"DarknetSharing\\\"] = !optionsDB[\\\"DarknetSharing\\\"]\\n if (running) ns.writePort(25, optionsDB[\\\"DarknetSharing\\\"] ? \\\"sharingOn\\\" : \\\"sharingOff\\\")\\n }\\n else if (mode === \\\"map\\\") {\\n optionsDB[\\\"DarknetShowMap\\\"] = !optionsDB[\\\"DarknetShowMap\\\"]\\n if (running) ns.writePort(25, optionsDB[\\\"DarknetShowMap\\\"] ? \\\"showmapOn\\\" : \\\"showmapOff\\\")\\n }\\n else if (mode === \\\"storm\\\") {\\n optionsDB[\\\"DarknetStorm\\\"] = !optionsDB[\\\"DarknetStorm\\\"]\\n if (running) ns.writePort(25, optionsDB[\\\"DarknetStorm\\\"] ? \\\"stormOn\\\" : \\\"stormOff\\\")\\n }\\n else if (mode === \\\"stock\\\") {\\n const stockSelection = normalizeDarknetStockSelection(selectedStock)\\n optionsDB[\\\"DarknetPromoteStock\\\"] = stockSelection\\n if (running) ns.writePort(25, stockSelection)\\n }\\n}\\nasync function buttonIPvGoStart(ns) {\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(5))\\n }\\n else {\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoRepeat\\\"] ? \\\"Repeat On\\\" : \\\"Repeat Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoPlayAsWhite\\\"] ? \\\"Play as White On\\\" : \\\"Play as White Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoCheats\\\"] ? \\\"Cheats On\\\" : \\\"Cheats Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoLogging\\\"] ? \\\"Logging On\\\" : \\\"Logging Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoNetburners\\\"] ? \\\"Net On\\\" : \\\"Net Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoSlumSnakes\\\"] ? \\\"Slum On\\\" : \\\"Slum Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoTheBlackHand\\\"] ? \\\"BH On\\\" : \\\"BH Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoTetrads\\\"] ? \\\"Tetrad On\\\" : \\\"Tetrad Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoDaedalus\\\"] ? \\\"Daed On\\\" : \\\"Daed Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoIlluminati\\\"] ? \\\"Illum On\\\" : \\\"Illum Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoUnknown\\\"] ? \\\"???? On\\\" : \\\"???? Off\\\")\\n ns.writePort(15, optionsDB[\\\"IPvGoNoAI\\\"] ? \\\"No AI On\\\" : \\\"No AI Off\\\")\\n await runIt(ns, \\\"SphyxOS/bins/go.js\\\", true, [])\\n }\\n}\\nfunction buttonIPvGoPlayWhite(ns) {\\n optionsDB[\\\"IPvGoPlayAsWhite\\\"] = !optionsDB[\\\"IPvGoPlayAsWhite\\\"]\\n if (!optionsDB[\\\"IPvGoPlayAsWhite\\\"]) {\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"Play as White Off\\\")\\n }\\n else {\\n optionsDB[\\\"IPvGoNoAI\\\"] = true\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"Play as White On\\\")\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"No AI On\\\")\\n }\\n}\\nfunction buttonIPvGoRepeat(ns) {\\n optionsDB[\\\"IPvGoRepeat\\\"] = !optionsDB[\\\"IPvGoRepeat\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoRepeat\\\"] ? \\\"Repeat On\\\" : \\\"Repeat Off\\\")\\n}\\nfunction buttonIPvGoCheats(ns) {\\n optionsDB[\\\"IPvGoCheats\\\"] = !optionsDB[\\\"IPvGoCheats\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoCheats\\\"] ? \\\"Cheats On\\\" : \\\"Cheats Off\\\")\\n}\\nfunction buttonIPvGoLogging(ns) {\\n optionsDB[\\\"IPvGoLogging\\\"] = !optionsDB[\\\"IPvGoLogging\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoLogging\\\"] ? \\\"Logging On\\\" : \\\"Logging Off\\\")\\n}\\nfunction buttonIPvGoNetburners(ns) {\\n optionsDB[\\\"IPvGoNetburners\\\"] = !optionsDB[\\\"IPvGoNetburners\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoNetburners\\\"] ? \\\"Net On\\\" : \\\"Net Off\\\")\\n}\\nfunction buttonIPvGoSlumSnakes(ns) {\\n optionsDB[\\\"IPvGoSlumSnakes\\\"] = !optionsDB[\\\"IPvGoSlumSnakes\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoSlumSnakes\\\"] ? \\\"Slum On\\\" : \\\"Slum Off\\\")\\n}\\nfunction buttonIPvGoTheBlackHand(ns) {\\n optionsDB[\\\"IPvGoTheBlackHand\\\"] = !optionsDB[\\\"IPvGoTheBlackHand\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoTheBlackHand\\\"] ? \\\"BH On\\\" : \\\"BH Off\\\")\\n}\\nfunction buttonIPvGoTetrads(ns) {\\n optionsDB[\\\"IPvGoTetrads\\\"] = !optionsDB[\\\"IPvGoTetrads\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoTetrads\\\"] ? \\\"Tetrad On\\\" : \\\"Tetrad Off\\\")\\n}\\nfunction buttonIPvGoDaedalus(ns) {\\n optionsDB[\\\"IPvGoDaedalus\\\"] = !optionsDB[\\\"IPvGoDaedalus\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoDaedalus\\\"] ? \\\"Daed On\\\" : \\\"Daed Off\\\")\\n}\\nfunction buttonIPvGoIlluminati(ns) {\\n optionsDB[\\\"IPvGoIlluminati\\\"] = !optionsDB[\\\"IPvGoIlluminati\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoIlluminati\\\"] ? \\\"Illum On\\\" : \\\"Illum Off\\\")\\n}\\nfunction buttonIPvGoUnknown(ns) {\\n optionsDB[\\\"IPvGoUnknown\\\"] = !optionsDB[\\\"IPvGoUnknown\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoUnknown\\\"] ? \\\"???? On\\\" : \\\"???? Off\\\")\\n}\\nfunction buttonIPvGoNoAI(ns) {\\n optionsDB[\\\"IPvGoNoAI\\\"] = !optionsDB[\\\"IPvGoNoAI\\\"]\\n if (!optionsDB[\\\"IPvGoNoAI\\\"]) {\\n optionsDB[\\\"IPvGoPlayAsWhite\\\"] = false\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"Play as White Off\\\")\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"No AI Off\\\")\\n }\\n else {\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoPlayAsWhite\\\"] ? \\\"Play as White On\\\" : \\\"Play as White Off\\\")\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, \\\"No AI On\\\")\\n }\\n}\\nfunction buttonIPvGoSlowMode(ns) {\\n optionsDB[\\\"IPvGoSlowMode\\\"] = !optionsDB[\\\"IPvGoSlowMode\\\"]\\n if (ns.peek(5) !== \\\"NULL PORT DATA\\\") ns.writePort(15, optionsDB[\\\"IPvGoSlowMode\\\"] ? \\\"SlowMode On\\\" : \\\"SlowMode Off\\\")\\n}\\nasync function buttonGangStart(ns) {\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(6))\\n }\\n else {\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, optionsDB[\\\"GangAutoAscend\\\"] ? \\\"AutoAscend On\\\" : \\\"AutoAscend Off\\\")\\n ns.writePort(16, optionsDB[\\\"GangAutoEQ\\\"] ? \\\"AutoEQ On\\\" : \\\"AutoEQ Off\\\")\\n ns.writePort(16, optionsDB[\\\"GangMode\\\"])\\n ns.writePort(16, optionsDB[\\\"SleeveMode\\\"] === \\\"Gangs\\\" ? \\\"Sleeves On\\\" : \\\"Sleeves Off\\\")\\n const port = await runIt(ns, \\\"SphyxOS/bins/gang.js\\\", true, [])\\n if (port) ns.writePort(6, port)\\n }\\n}\\nfunction buttonGangAutoAscend(ns) {\\n optionsDB[\\\"GangAutoAscend\\\"] = !optionsDB[\\\"GangAutoAscend\\\"]\\n ns.writePort(16, optionsDB[\\\"GangAutoAscend\\\"] ? \\\"AutoAscend On\\\" : \\\"AutoAscend Off\\\")\\n}\\nfunction buttonGangAutoEQ(ns) {\\n optionsDB[\\\"GangAutoEQ\\\"] = !optionsDB[\\\"GangAutoEQ\\\"]\\n ns.writePort(16, optionsDB[\\\"GangAutoEQ\\\"] ? \\\"AutoEQ On\\\" : \\\"AutoEQ Off\\\")\\n}\\nfunction buttonGangMode(ns, mode) {\\n optionsDB[\\\"GangMode\\\"] = mode\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(16, optionsDB[\\\"GangMode\\\"])\\n}\\nfunction buttonGangBuyEQ(ns) {\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") ns.writePort(16, \\\"Buy EQ\\\")\\n}\\nfunction buttonGangAscend(ns) {\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") ns.writePort(16, \\\"Ascend\\\")\\n}\\nasync function buttonCorpStart(ns) {\\n if (ns.peek(9) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(9))\\n }\\n else {\\n ns.writePort(19, optionsDB[\\\"CorpPopOut\\\"] ? \\\"popout\\\" : \\\"nopopout\\\")\\n await runIt(ns, \\\"SphyxOS/bins/corp.js\\\", true, [])\\n }\\n}\\nfunction buttonCorpResetTAII(ns) {\\n if (ns.peek(9) !== \\\"NULL PORT DATA\\\") ns.writePort(19, \\\"Reset TAII\\\")\\n}\\nasync function buttonCorpBribe(ns) {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.factions.length === 0) return\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n if (corp && corp.valuation >= 100000000000000) {\\n const faction = await ns.prompt(\\\"Choose a faction to bribe:\\\", { type: \\\"select\\\", choices: player.factions })\\n if (faction === \\\"\\\") return\\n await proxy(ns, \\\"corporation.bribe\\\", faction, corp.funds / 100)\\n ns.tprintf(\\\"Corp: Attempted to bribe: %s\\\", faction)\\n }\\n}\\nasync function buttonSingDumpMoney(ns) {\\n await runIt(ns, \\\"SphyxOS/bins/dumpMoney.js\\\", false, [])\\n}\\nasync function buttonSleeveStart(ns) {\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(7))\\n }\\n else {\\n ns.writePort(17, \\\"Silent\\\")\\n ns.writePort(17, optionsDB[\\\"SleeveMode\\\"])\\n ns.writePort(17, optionsDB[\\\"SleeveInstall\\\"] ? \\\"Install On\\\" : \\\"Install Off\\\")\\n await runIt(ns, \\\"SphyxOS/bins/tSleeves.js\\\", true, [])\\n }\\n}\\nfunction buttonSleevesInstallAugments(ns) {\\n optionsDB[\\\"SleeveInstall\\\"] = !optionsDB[\\\"SleeveInstall\\\"]\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\") ns.writePort(17, optionsDB[\\\"SleeveInstall\\\"] ? \\\"Install On\\\" : \\\"Install Off\\\")\\n}\\nasync function buttonSleevesToggle(ns, mode) {\\n mode = normalizeSleeveToggleMode(mode)\\n switch (mode) {//optionsDB[\\\"SleeveMode\\\"]) { // Turn off the one that's on since it's changing\\n case \\\"Gangs\\\":\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") ns.writePort(16, \\\"Sleeves Off\\\")\\n break\\n case \\\"BB\\\":\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.writePort(18, \\\"sleeves off\\\")\\n break\\n case \\\"All\\\":\\n case \\\"Hack\\\":\\n case \\\"Str\\\":\\n case \\\"Def\\\":\\n case \\\"Dex\\\":\\n case \\\"Agi\\\":\\n case \\\"Cha\\\":\\n case \\\"Recovery\\\":\\n case \\\"Sync\\\":\\n case \\\"Money\\\":\\n case \\\"Karma\\\":\\n case \\\"Idle\\\":\\n case \\\"Int\\\":\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\"\\n && !sleeveLocalModes.includes(mode)) await proxy(ns, \\\"kill\\\", ns.peek(7))\\n break\\n\\n default:\\n ns.tprintf(\\\"Invalid Sleeve mode: %s\\\", optionsDB[\\\"SleeveMode\\\"])\\n }\\n const numSleeves = await proxy(ns, \\\"sleeve.getNumSleeves\\\")\\n if (optionsDB[\\\"SleeveMode\\\"] === mode || mode === \\\"Idle\\\") { //turn it off and set to idle if it's the same one\\n //Switch all sleeves to idle\\n for (let slv = 0; slv < numSleeves; slv++)\\n await proxy(ns, \\\"sleeve.setToIdle\\\", slv)\\n if (optionsDB[\\\"SleeveMode\\\"] !== \\\"Idle\\\" && mode === \\\"Idle\\\" && ns.peek(7) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(17, mode)\\n optionsDB[\\\"SleeveMode\\\"] = \\\"Idle\\\"\\n }\\n else {\\n switch (mode) { // Turn on the new one\\n case \\\"Gangs\\\":\\n if (ns.peek(6) !== \\\"NULL PORT DATA\\\") ns.writePort(16, \\\"Sleeves On\\\")\\n break\\n case \\\"BB\\\":\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.writePort(18, \\\"sleeves on\\\")\\n break\\n case \\\"All\\\":\\n case \\\"Hack\\\":\\n case \\\"Str\\\":\\n case \\\"Def\\\":\\n case \\\"Dex\\\":\\n case \\\"Agi\\\":\\n case \\\"Cha\\\":\\n case \\\"Recovery\\\":\\n case \\\"Sync\\\":\\n case \\\"Money\\\":\\n case \\\"Karma\\\":\\n case \\\"Int\\\":\\n if (ns.peek(7) !== \\\"NULL PORT DATA\\\")\\n ns.writePort(17, mode)\\n break\\n case \\\"Idle\\\":\\n for (let i = 0; i < numSleeves; i++)\\n await proxy(ns, \\\"sleeve.setToIdle\\\", i)\\n break\\n default:\\n ns.tprintf(\\\"Invalid Sleeve mode: %s\\\", mode)\\n }\\n optionsDB[\\\"SleeveMode\\\"] = mode\\n }\\n}\\nasync function buttonGrafting(ns) {\\n if (ns.peek(20) !== \\\"NULL PORT DATA\\\") await proxy(ns, \\\"kill\\\", ns.peek(20))\\n else {\\n resetInfo = await getResetInf(ns)\\n sourceFiles = await getOwnedSF(ns)\\n const hasSing = hasBN(resetInfo, sourceFiles, 4, 2)\\n if (hasSing) await runIt(ns, \\\"SphyxOS/bins/graftingAdv.js\\\", true, [])\\n else await runIt(ns, \\\"SphyxOS/bins/graftingBasic.js\\\", true, [])\\n }\\n}\\nasync function buttonBBStart(ns) {\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(8))\\n }\\n else {\\n ns.writePort(18, \\\"quiet\\\")\\n ns.writePort(18, optionsDB[\\\"BBFinisher\\\"] ? \\\"finisher on\\\" : \\\"finisher off\\\")\\n ns.writePort(18, optionsDB[\\\"BBIntMode\\\"] ? \\\"int mode on\\\" : \\\"int mode off\\\")\\n ns.writePort(18, optionsDB[\\\"SleeveMode\\\"] === \\\"BB\\\" ? \\\"sleeves on\\\" : \\\"sleeves off\\\")\\n ns.writePort(18, optionsDB[\\\"BBInfilOnly\\\"] ? \\\"sleeve infil on\\\" : \\\"sleeve infil off\\\")\\n const value = await runIt(ns, \\\"SphyxOS/bins/bb.js\\\", true, [])\\n if (value > 0) ns.writePort(8, value)\\n }\\n}\\nfunction buttonBBFinisher(ns) {\\n optionsDB[\\\"BBFinisher\\\"] = !optionsDB[\\\"BBFinisher\\\"]\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.writePort(18, optionsDB[\\\"BBFinisher\\\"] ? \\\"finisher on\\\" : \\\"finisher off\\\")\\n}\\nfunction buttonBBIntMode(ns) {\\n optionsDB[\\\"BBIntMode\\\"] = !optionsDB[\\\"BBIntMode\\\"]\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.writePort(18, optionsDB[\\\"BBIntMode\\\"] ? \\\"int mode on\\\" : \\\"int mode off\\\")\\n}\\nfunction buttonBBInfilOnly(ns) {\\n optionsDB[\\\"BBInfilOnly\\\"] = !optionsDB[\\\"BBInfilOnly\\\"]\\n if (ns.peek(8) !== \\\"NULL PORT DATA\\\") ns.writePort(18, optionsDB[\\\"BBInfilOnly\\\"] ? \\\"sleeve infil on\\\" : \\\"sleeve infil off\\\")\\n}\\n/** @param {NS} ns */\\nasync function buttonStanekStart(ns) {\\n if (ns.peek(11) === \\\"NULL PORT DATA\\\") {\\n const frags = await proxy(ns, \\\"stanek.activeFragments\\\")\\n\\n if (frags?.length > 0) {\\n const val = await runIt(ns, \\\"SphyxOS/stanek/startCharge.js\\\", true, [])\\n if (val > 0) ns.writePort(11, val)\\n }\\n else ns.toast(\\\"Please select a loadout first\\\", \\\"error\\\", 3000)\\n }\\n}\\nasync function buttonStanekSaveConfig(ns) {\\n ns.exec(\\\"SphyxOS/stanek/saveStanek.js\\\", \\\"home\\\", 1)\\n}\\nasync function buttonStanekDeleteConfig(ns) {\\n ns.exec(\\\"SphyxOS/stanek/deleteStanek.js\\\", \\\"home\\\", 1)\\n}\\nfunction buttonStanekLoadConfig(ns) {\\n if (optionsDB[\\\"StanekDefault\\\"])\\n ns.exec(\\\"SphyxOS/stanek/loadStanek.js\\\", \\\"home\\\", 1, \\\"default\\\")\\n else\\n ns.exec(\\\"SphyxOS/stanek/loadStanek.js\\\", \\\"home\\\", 1)\\n}\\nfunction buttonStanekUseDefault(ns) {\\n optionsDB[\\\"StanekDefault\\\"] = !optionsDB[\\\"StanekDefault\\\"]\\n}\\nasync function buttonGameMinesweeper(ns) {\\n if (ns.peek(27) === \\\"NULL PORT DATA\\\")\\n await runIt(ns, \\\"SphyxOS/games/minesweeper.jsx\\\", false, []) //Games will use up home ram so they can always run\\n}\\nasync function buttonGameDoom(ns) {\\n await runIt(ns, \\\"SphyxOS/games/doom.jsx\\\", false, []) //Games will use up home ram so they can always run\\n}\\nasync function buttonGameTimberman(ns) {\\n if (ns.peek(29) === \\\"NULL PORT DATA\\\")\\n await runIt(ns, \\\"SphyxOS/games/timberman.js\\\", false, []) //Games will use up home ram so they can always run\\n}\\nasync function buttonDevMenu(ns) {\\n await runIt(ns, \\\"SphyxOS/cheats/devMenu.js\\\", false, [])\\n}\\nasync function buttonNotDevMenu(ns) {\\n await runIt(ns, \\\"SphyxOS/cheats/notTheDevMenu.jsx\\\", false, [])\\n}\\nasync function buttonUnlockAll(ns) {\\n const result = await ns.prompt(\\\"Are you sure?\\\", { type: \\\"boolean\\\" })\\n if (!result || result === \\\"\\\") return\\n await runIt(ns, \\\"SphyxOS/cheats/achievements.js\\\", false, [])\\n}\\nasync function buttonCasinoStart(ns) {\\n if (ns.peek(10) !== \\\"NULL PORT DATA\\\") {\\n await proxy(ns, \\\"kill\\\", ns.peek(10))\\n }\\n else {\\n await runIt(ns, \\\"SphyxOS/cheats/casino.js\\\", true, [])\\n }\\n}\\nasync function buttonAutoInfilStart(ns) {\\n if (wnd.tmrAutoInf) { //Stop it\\n await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [])\\n ns.clearPort(30)\\n }\\n else { //Start it\\n if (!optionsDB[\\\"AutoInfilAuto\\\"]) ns.writePort(30, await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, []))\\n else if (optionsDB[\\\"AutoInfilMoneyMode\\\"]) ns.writePort(30, await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--auto\\\"]))\\n else ns.writePort(30, await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--auto\\\", \\\"--faction\\\", optionsDB[\\\"AutoInfilFaction\\\"]]))\\n }\\n}\\nasync function buttonAutoInfilAuto(ns) {\\n optionsDB[\\\"AutoInfilAuto\\\"] = !optionsDB[\\\"AutoInfilAuto\\\"]\\n if (!optionsDB[\\\"AutoInfilAuto\\\"]) { //Turn it off\\n optionsDB[\\\"AutoInfilFaction\\\"] = \\\"\\\"\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = false\\n if (wnd.tmrAutoInf) await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--update\\\", \\\"--quiet\\\"])\\n }\\n else { //Turn it on\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = true\\n optionsDB[\\\"AutoInfilFaction\\\"] = \\\"\\\"\\n if (wnd.tmrAutoInf) await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--auto\\\", \\\"--update\\\", \\\"--quiet\\\"])\\n }\\n}\\nasync function buttonAutoInfilMoney(ns) {\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = !optionsDB[\\\"AutoInfilMoneyMode\\\"]\\n if (optionsDB[\\\"AutoInfilMoneyMode\\\"]) { //Already on, just abort\\n return\\n }\\n else { //Turn it on\\n optionsDB[\\\"AutoInfilAuto\\\"] = true\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = true\\n optionsDB[\\\"AutoInfilFaction\\\"] = \\\"\\\"\\n optionsDB[\\\"AutoInfilFactionMode\\\"] = false\\n if (wnd.tmrAutoInf) await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--auto\\\", \\\"--update\\\", \\\"--quiet\\\"])\\n }\\n}\\nasync function buttonAutoInfilFaction(ns) {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n let gangFac = \\\"\\\"\\n const mygang = await proxy(ns, \\\"gang.getGangInformation\\\")\\n if (mygang) gangFac = mygang.faction\\n\\n const factions = player.factions.filter((f) => ![gangFac, \\\"Bladeburners\\\", \\\"Church of the Machine God\\\", \\\"Shadows of Anarchy\\\"].includes(f))\\n if (factions.length === 0) {\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = true\\n optionsDB[\\\"AutoInfilFactionMode\\\"] = false\\n return\\n }\\n else if (factions.length > 1)\\n optionsDB[\\\"AutoInfilFaction\\\"] = await ns.prompt(\\\"Select Faction\\\", { type: \\\"select\\\", choices: factions })\\n else\\n optionsDB[\\\"AutoInfilFaction\\\"] = factions.pop()\\n\\n if (optionsDB[\\\"AutoInfilFaction\\\"] === \\\"\\\") {\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = true\\n optionsDB[\\\"AutoInfilFactionMode\\\"] = false\\n return\\n }\\n optionsDB[\\\"AutoInfilAuto\\\"] = true\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = false\\n optionsDB[\\\"AutoInfilFactionMode\\\"] = true\\n if (wnd.tmrAutoInf) await runIt(ns, \\\"SphyxOS/cheats/autoInfil.js\\\", false, [\\\"--auto\\\", \\\"--faction\\\", optionsDB[\\\"AutoInfilFaction\\\"], \\\"--update\\\", \\\"--quiet\\\"])\\n}\\n/** @param {NS} ns */\\nasync function setOptionsDB(ns) {\\n if (optionsDB[\\\"BatcherUseHacknet\\\"] === undefined)\\n optionsDB[\\\"BatcherUseHacknet\\\"] = false\\n if (optionsDB[\\\"BatcherAutoHash\\\"] === undefined)\\n optionsDB[\\\"BatcherAutoHash\\\"] = false\\n if (optionsDB[\\\"BatcherAutoBuyServers\\\"] === undefined)\\n optionsDB[\\\"BatcherAutoBuyServers\\\"] = true\\n if (optionsDB[\\\"BatcherAutoBuyHacknet\\\"] === undefined)\\n optionsDB[\\\"BatcherAutoBuyHacknet\\\"] = false\\n if (optionsDB[\\\"BatcherMoney\\\"] === undefined)\\n optionsDB[\\\"BatcherMoney\\\"] = true\\n if (optionsDB[\\\"BatcherXP\\\"] === undefined)\\n optionsDB[\\\"BatcherXP\\\"] = true\\n if (optionsDB[\\\"BatcherStanek\\\"] === undefined)\\n optionsDB[\\\"BatcherStanek\\\"] = false\\n if (optionsDB[\\\"BatcherPad\\\"] === undefined)\\n optionsDB[\\\"BatcherPad\\\"] = false\\n if (optionsDB[\\\"BatcherLog\\\"] === undefined)\\n optionsDB[\\\"BatcherLog\\\"] = false\\n if (optionsDB[\\\"BatcherPopout\\\"] === undefined)\\n optionsDB[\\\"BatcherPopout\\\"] = false\\n if (optionsDB[\\\"DisplayToggleHelper\\\"] === undefined)\\n optionsDB[\\\"DisplayToggleHelper\\\"] = true\\n if (optionsDB[\\\"DisplayToggleAutoUpdate\\\"] === undefined)\\n optionsDB[\\\"DisplayToggleAutoUpdate\\\"] = true\\n if (optionsDB[\\\"DisplayToggleUpdateVersion\\\"] === undefined)\\n optionsDB[\\\"DisplayToggleUpdateVersion\\\"] = \\\"Stable\\\"\\n if (optionsDB[\\\"DisplayViewMode\\\"] === undefined)\\n optionsDB[\\\"DisplayViewMode\\\"] = \\\"Mini\\\"\\n if (!Array.isArray(optionsDB[\\\"MiniSelectedRows\\\"]))\\n optionsDB[\\\"MiniSelectedRows\\\"] = []\\n if (optionsDB[\\\"StocksToggleAutoBuy\\\"] === undefined)\\n optionsDB[\\\"StocksToggleAutoBuy\\\"] = false\\n if (optionsDB[\\\"StocksPopOut\\\"] === undefined)\\n optionsDB[\\\"StocksPopOut\\\"] = false\\n if (optionsDB[\\\"DarknetPhishing\\\"] === undefined)\\n optionsDB[\\\"DarknetPhishing\\\"] = true\\n if (optionsDB[\\\"DarknetInducing\\\"] === undefined)\\n optionsDB[\\\"DarknetInducing\\\"] = false\\n if (optionsDB[\\\"DarknetSharing\\\"] === undefined)\\n optionsDB[\\\"DarknetSharing\\\"] = true\\n if (optionsDB[\\\"DarknetShowMap\\\"] === undefined)\\n optionsDB[\\\"DarknetShowMap\\\"] = true\\n if (optionsDB[\\\"DarknetStorm\\\"] === undefined)\\n optionsDB[\\\"DarknetStorm\\\"] = false\\n if (optionsDB[\\\"DarknetPromoteStock\\\"] === undefined)\\n optionsDB[\\\"DarknetPromoteStock\\\"] = buildDarknetStockSelection()\\n else\\n optionsDB[\\\"DarknetPromoteStock\\\"] = normalizeDarknetStockSelection(optionsDB[\\\"DarknetPromoteStock\\\"])\\n if (optionsDB[\\\"IPvGoPlayAsWhite\\\"] === undefined)\\n optionsDB[\\\"IPvGoPlayAsWhite\\\"] = false\\n if (optionsDB[\\\"IPvGoRepeat\\\"] === undefined)\\n optionsDB[\\\"IPvGoRepeat\\\"] = true\\n if (optionsDB[\\\"IPvGoCheats\\\"] === undefined)\\n optionsDB[\\\"IPvGoCheats\\\"] = true\\n if (optionsDB[\\\"IPvGoLogging\\\"] === undefined)\\n optionsDB[\\\"IPvGoLogging\\\"] = false\\n if (optionsDB[\\\"IPvGoNetburners\\\"] === undefined)\\n optionsDB[\\\"IPvGoNetburners\\\"] = true\\n if (optionsDB[\\\"IPvGoSlumSnakes\\\"] === undefined)\\n optionsDB[\\\"IPvGoSlumSnakes\\\"] = true\\n if (optionsDB[\\\"IPvGoTheBlackHand\\\"] === undefined)\\n optionsDB[\\\"IPvGoTheBlackHand\\\"] = true\\n if (optionsDB[\\\"IPvGoTetrads\\\"] === undefined)\\n optionsDB[\\\"IPvGoTetrads\\\"] = true\\n if (optionsDB[\\\"IPvGoDaedalus\\\"] === undefined)\\n optionsDB[\\\"IPvGoDaedalus\\\"] = true\\n if (optionsDB[\\\"IPvGoIlluminati\\\"] === undefined)\\n optionsDB[\\\"IPvGoIlluminati\\\"] = true\\n if (optionsDB[\\\"IPvGoUnknown\\\"] === undefined)\\n optionsDB[\\\"IPvGoUnknown\\\"] = true\\n if (optionsDB[\\\"IPvGoNoAI\\\"] === undefined)\\n optionsDB[\\\"IPvGoNoAI\\\"] = false\\n if (optionsDB[\\\"IPvGoSlowMode\\\"] === undefined)\\n optionsDB[\\\"IPvGoSlowMode\\\"] = false\\n if (optionsDB[\\\"IPvGoPopOut\\\"] === undefined)\\n optionsDB[\\\"IPvGoPopOut\\\"] = false\\n if (optionsDB[\\\"GangAutoAscend\\\"] === undefined)\\n optionsDB[\\\"GangAutoAscend\\\"] = true\\n if (optionsDB[\\\"GangAutoEQ\\\"] === undefined)\\n optionsDB[\\\"GangAutoEQ\\\"] = true\\n if (optionsDB[\\\"GangMode\\\"] === undefined)\\n optionsDB[\\\"GangMode\\\"] = \\\"AutoMode\\\"\\n if (optionsDB[\\\"GangPopOut\\\"] === undefined)\\n optionsDB[\\\"GangPopOut\\\"] = false\\n if (optionsDB[\\\"CorpPopOut\\\"] === undefined)\\n optionsDB[\\\"CorpPopOut\\\"] = false\\n if (optionsDB[\\\"SleeveMode\\\"] === undefined) {\\n if (hasBN(resetInfo, sourceFiles, 10, 1)) {\\n const slvs = await proxy(ns, \\\"sleeve.getNumSleeves\\\")\\n if (slvs)\\n for (let i = 0; i < slvs; i++)\\n await proxy(ns, \\\"sleeve.setToIdle\\\", i)\\n optionsDB[\\\"SleeveMode\\\"] = \\\"Idle\\\"\\n if (optionsDB[\\\"SleeveInstall\\\"] === undefined)\\n optionsDB[\\\"SleeveInstall\\\"] = false\\n if (optionsDB[\\\"SleevePopOut\\\"] === undefined)\\n optionsDB[\\\"SleevePopOut\\\"] = false\\n }\\n }\\n if (optionsDB[\\\"BBFinisher\\\"] === undefined)\\n optionsDB[\\\"BBFinisher\\\"] = false\\n if (optionsDB[\\\"BBIntMode\\\"] === undefined)\\n optionsDB[\\\"BBIntMode\\\"] = false\\n if (optionsDB[\\\"BBInfilOnly\\\"] === undefined)\\n optionsDB[\\\"BBInfilOnly\\\"] = false\\n if (optionsDB[\\\"BBPopOut\\\"] === undefined)\\n optionsDB[\\\"BBPopOut\\\"] = false\\n if (optionsDB[\\\"AutoInfilAuto\\\"] === undefined)\\n optionsDB[\\\"AutoInfilAuto\\\"] = true\\n if (optionsDB[\\\"AutoInfilMoneyMode\\\"] === undefined)\\n optionsDB[\\\"AutoInfilMoneyMode\\\"] = true\\n if (optionsDB[\\\"AutoInfilFactionMode\\\"] === undefined)\\n optionsDB[\\\"AutoInfilFactionMode\\\"] = false\\n if (optionsDB[\\\"AutoInfilFaction\\\"] === undefined)\\n optionsDB[\\\"AutoInfilFaction\\\"] = \\\"\\\"\\n if (optionsDB[\\\"ShareMode\\\"] === undefined)\\n optionsDB[\\\"ShareMode\\\"] = false\\n if (optionsDB[\\\"StanekDefault\\\"] === undefined)\\n optionsDB[\\\"StanekDefault\\\"] = true\\n if (optionsDB[\\\"AutoPilotMoveOn\\\"] === undefined)\\n optionsDB[\\\"AutoPilotMoveOn\\\"] = false\\n if (optionsDB[\\\"AutoPilotPopOut\\\"] === undefined)\\n optionsDB[\\\"AutoPilotPopOut\\\"] = false\\n if (optionsDB[\\\"GraftingPopOut\\\"] === undefined)\\n optionsDB[\\\"GraftingPopOut\\\"] = false\\n optionsDB[\\\"HashAutoTarget\\\"] = normalizeHashAutoTarget(optionsDB[\\\"HashAutoTarget\\\"])\\n}\\nfunction hasBN(resetInfo, sourceFiles, bn, sfLvl = 1) {\\n if (resetInfo.currentNode === bn) return true\\n try {\\n for (const sf of sourceFiles) if (sf.n === bn && sf.lvl >= sfLvl) return true\\n return false\\n }\\n catch { return false }\\n}\\nfunction normalizeRowContent(node) {\\n const React = getReactLib()\\n if (!React || node === null || node === undefined || typeof node === \\\"boolean\\\")\\n return node\\n if (typeof node === \\\"string\\\" || typeof node === \\\"number\\\")\\n return node\\n if (!React.isValidElement(node))\\n return node\\n const childProps = node.props ?? {}\\n const normalizedChildren = React.Children.map(childProps.children, (child) => normalizeRowContent(child))\\n if (typeof node.type === \\\"string\\\" && node.type.toLowerCase() === \\\"button\\\") {\\n return React.cloneElement(node, {\\n ...childProps,\\n style: { ...rowButtonBaseStyle, ...(childProps.style ?? {}) }\\n }, normalizedChildren)\\n }\\n return React.cloneElement(node, childProps, normalizedChildren)\\n}\\nfunction Row({ title, buttons, onHideToggle }) {\\n const normalizedButtons = normalizeRowContent(buttons)\\n const hideToggle = e.stopPropagation()}\\n onMouseDown={(e) => e.stopPropagation()}\\n onChange={() => onHideToggle(title)}\\n />\\n const titleWithHide = {title}{hideToggle} \\n if (openDB.has(title))\\n return (\\n \\n
{\\n if (e.currentTarget.open)\\n openDB.add(title)\\n else\\n openDB.delete(title)\\n }}>\\n {titleWithHide} \\n {normalizedButtons}
\\n \\n
\\n )\\n else\\n return (\\n \\n
{\\n if (e.currentTarget.open)\\n openDB.add(title)\\n else\\n openDB.delete(title)\\n }}>\\n {titleWithHide} \\n {normalizedButtons}
\\n \\n\\n
\\n )\\n}\\nfunction MiniView({ rows, selectedRows, onToggleRow, onHideToggle, onMiniRowContextHide, rowVisibilityVersion }) {\\n const openRows = rows.filter((row) => selectedRows.includes(row[0].toString()))\\n if (rows.length === 0)\\n return {\\\"No rows are currently available in Mini view.\\\"}
\\n return (\\n \\n
{\\\"Left Click to enable. Right Click to hide.\\\"}
\\n
\\n {rows.map((row) => onToggleRow(row[0].toString())} onContextMenu={(event) => {\\n event.preventDefault()\\n onMiniRowContextHide(row[0].toString())\\n }}>{row[0]} )}\\n
\\n {openRows.length === 0\\n ?
{\\\"Select one or more rows above to show them here.\\\"}
\\n : openRows.map((row) =>
)}\\n
\\n )\\n}\\nfunction MiniRowPanel({ title, buttons, onHideToggle }) {\\n const normalizedButtons = normalizeRowContent(buttons)\\n return (\\n \\n
\\n
\\n
{title}
\\n
\\n onHideToggle(title)} />\\n {\\\"Visible\\\"}\\n \\n
\\n
\\n
{normalizedButtons}
\\n
\\n )\\n}\\nconst greenStyle = {\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst redStyle = {\\n backgroundColor: \\\"var(--bb-theme-error)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst rowHideCheckboxStyle = {\\n marginLeft: 8,\\n verticalAlign: \\\"middle\\\"\\n}\\nconst rowBodyStyle = {\\n paddingTop: 6,\\n paddingBottom: 2\\n}\\nconst rowButtonBaseStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"center\\\",\\n width: 74,\\n height: 28,\\n padding: \\\"2px 6px\\\",\\n marginRight: 4,\\n marginBottom: 4,\\n borderRadius: 4,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n boxShadow: \\\"inset 0 1px 0 rgba(255,255,255,0.05)\\\",\\n textAlign: \\\"center\\\",\\n whiteSpace: \\\"normal\\\",\\n fontSize: 12,\\n lineHeight: 1.05,\\n overflow: \\\"hidden\\\",\\n verticalAlign: \\\"middle\\\"\\n}\\nconst alwaysOnStyle = {\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst topPanelWrapStyle = {\\n position: \\\"relative\\\",\\n marginBottom: 10,\\n padding: \\\"10px 12px 12px 12px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.02))\\\"\\n}\\nconst topPanelInfoStyle = {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n alignItems: \\\"center\\\",\\n gap: 10,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 10\\n}\\nconst topPanelTitleStyle = {\\n fontSize: 18,\\n fontWeight: \\\"bold\\\",\\n letterSpacing: \\\"0.02em\\\"\\n}\\nconst topPanelMetaStyle = {\\n opacity: 0.8,\\n fontSize: 12,\\n lineHeight: 1.3\\n}\\nconst displayStatusTrayStyle = {\\n display: \\\"flex\\\",\\n gap: 6,\\n flexWrap: \\\"wrap\\\"\\n}\\nconst displayStatusBaseStyle = {\\n appearance: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n padding: \\\"3px 8px\\\",\\n borderRadius: 999,\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\"\\n}\\nconst displayStatusOnStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-infodark)\\\",\\n color: \\\"var(--bb-theme-secondarylight)\\\"\\n}\\nconst displayStatusOffStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-errordark)\\\",\\n color: \\\"var(--bb-theme-secondarylight)\\\"\\n}\\nconst displayStatusWarnStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"rgba(200, 143, 31, 0.38)\\\", //Burnt orange\\n color: \\\"var(--bb-theme-secondarylight)\\\"\\n}\\nconst displayStatusMutedStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-infodark)\\\",\\n color: \\\"var(--bb-theme-secondarylight)\\\"\\n}\\nconst displayThemeEditorStyle = {\\n ...displayStatusBaseStyle,\\n ...alwaysOnStyle\\n}\\nconst toolbarBarStyle = {\\n display: \\\"flex\\\",\\n gap: 8,\\n alignItems: \\\"center\\\",\\n flexWrap: \\\"wrap\\\",\\n paddingTop: 8,\\n borderTop: \\\"1px solid rgba(255,255,255,0.08)\\\"\\n}\\nconst viewModeToggleWrapStyle = {\\n display: \\\"inline-flex\\\",\\n gap: 6,\\n alignItems: \\\"center\\\",\\n padding: 3,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n background: \\\"rgba(255,255,255,0.04)\\\"\\n}\\nconst viewModeLabelStyle = {\\n fontSize: 12,\\n fontWeight: \\\"bold\\\",\\n opacity: 0.82,\\n paddingLeft: 4\\n}\\nconst viewModeButtonStyle = {\\n appearance: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n borderRadius: 6,\\n padding: \\\"7px 12px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.06)\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n fontWeight: \\\"bold\\\"\\n}\\nconst viewModeButtonActiveStyle = {\\n ...viewModeButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst viewModeMiniActiveStyle = {\\n ...viewModeButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst toolbarMenuStyle = {\\n position: \\\"relative\\\"\\n}\\nconst toolbarSummaryStyle = {\\n appearance: \\\"none\\\",\\n listStyle: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n userSelect: \\\"none\\\",\\n borderRadius: 6,\\n padding: \\\"7px 12px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"var(--bb-theme-secondarylight)\\\",\\n fontWeight: \\\"bold\\\"\\n}\\nconst toolbarSummaryOpenStyle = {\\n ...toolbarSummaryStyle,\\n backgroundColor: \\\"var(--bb-theme-info)\\\",\\n border: \\\"1px solid rgba(138, 180, 255, 0.38)\\\"\\n}\\nconst toolbarDropdownStyle = {\\n position: \\\"absolute\\\",\\n top: \\\"50%\\\",\\n left: \\\"calc(100% + 4px)\\\",\\n transform: \\\"translateY(-50%)\\\",\\n display: \\\"flex\\\",\\n flexDirection: \\\"column\\\",\\n gap: 8,\\n padding: 10,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n backgroundColor: \\\"rgba(10, 12, 18, 0.96)\\\",\\n boxShadow: \\\"0 14px 30px rgba(0,0,0,0.35)\\\",\\n zIndex: 40,\\n maxHeight: 360,\\n overflowY: \\\"auto\\\"\\n}\\nconst toolbarSectionTitleStyle = {\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n letterSpacing: \\\"0.08em\\\",\\n textTransform: \\\"uppercase\\\",\\n opacity: 0.72\\n}\\nconst toolbarHintStyle = {\\n fontSize: 12,\\n opacity: 0.72,\\n paddingLeft: 4\\n}\\nconst displayButtonBaseStyle = {\\n display: \\\"block\\\",\\n width: \\\"100%\\\",\\n textAlign: \\\"left\\\",\\n borderRadius: 6,\\n padding: \\\"6px 10px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n boxShadow: \\\"inset 0 1px 0 rgba(255,255,255,0.05)\\\"\\n}\\nconst miniRowSelectorWrapStyle = {\\n display: \\\"flex\\\",\\n flexWrap: \\\"wrap\\\",\\n gap: 4,\\n marginBottom: 4,\\n padding: \\\"4px 6px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.025))\\\"\\n}\\nconst miniHintStyle = {\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n opacity: 0.72,\\n marginBottom: 2,\\n paddingLeft: 2,\\n lineHeight: 1.1\\n}\\nconst miniRowSelectorButtonStyle = {\\n appearance: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n borderRadius: 999,\\n padding: \\\"3px 9px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.05)\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n fontSize: 11,\\n fontWeight: \\\"bold\\\"\\n}\\nconst miniRowSelectorActiveStyle = {\\n ...miniRowSelectorButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst miniRowPanelStyle = {\\n marginBottom: 2,\\n padding: 0,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.02))\\\"\\n}\\nconst miniRowPanelHeaderStyle = {\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"flex-start\\\",\\n gap: 4,\\n flexWrap: \\\"wrap\\\"\\n}\\nconst miniRowTitleWrapStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n gap: 6,\\n flexWrap: \\\"wrap\\\"\\n}\\nconst miniRowPanelTitleStyle = {\\n fontSize: 15,\\n fontWeight: \\\"bold\\\"\\n}\\nconst miniRowHideWrapStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n fontSize: 11,\\n opacity: 0.85\\n}\\nconst miniRowHideCheckboxStyle = {\\n marginLeft: 0,\\n marginRight: 4,\\n verticalAlign: \\\"middle\\\"\\n}\\nconst miniEmptyStateStyle = {\\n padding: \\\"6px 8px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.03)\\\",\\n opacity: 0.8\\n}\\nconst displayPrimaryActiveStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst displayPrimaryInactiveStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"rgba(176, 66, 66, 0.9)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst displaySecondaryStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\"\\n}\\nconst displayDangerStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-error)\\\",\\n color: \\\"var(--bb-theme-white)\\\"\\n}\\nconst darknetStockSelectorWrapStyle = {\\n position: \\\"relative\\\",\\n display: \\\"inline-flex\\\",\\n verticalAlign: \\\"middle\\\"\\n}\\nconst darknetStockButtonStyle = {\\n ...rowButtonBaseStyle,\\n whiteSpace: \\\"nowrap\\\",\\n textOverflow: \\\"ellipsis\\\"\\n}\\nconst darknetStockDropdownStyle = {\\n ...toolbarDropdownStyle,\\n top: \\\"auto\\\",\\n bottom: 0,\\n transform: \\\"none\\\",\\n boxSizing: \\\"border-box\\\",\\n gap: 4,\\n padding: 8,\\n maxHeight: 420\\n}\\nconst darknetStockGridStyle = {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"repeat(4, minmax(0, 1fr))\\\",\\n gap: 4\\n}\\nconst hashAutoTargetGridStyle = {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"repeat(2, minmax(0, 1fr))\\\",\\n gap: 4\\n}\\nconst sleeveTrainingGridStyle = {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"repeat(3, minmax(0, 1fr))\\\",\\n gap: 4\\n}\\nconst darknetStockOptionStyle = {\\n ...displayButtonBaseStyle,\\n boxSizing: \\\"border-box\\\",\\n border: \\\"2px solid transparent\\\",\\n width: \\\"100%\\\",\\n height: \\\"auto\\\",\\n minHeight: 28,\\n padding: \\\"5px 6px\\\",\\n marginRight: 0,\\n marginBottom: 0,\\n whiteSpace: \\\"nowrap\\\"\\n}\\nconst darknetStockNoneStyle = {\\n ...darknetStockOptionStyle,\\n ...redStyle\\n}\\nconst darknetStockAllStyle = {\\n ...darknetStockOptionStyle,\\n ...greenStyle\\n}\\nconst darknetStockOwnedStyle = {\\n ...darknetStockOptionStyle,\\n ...greenStyle\\n}\\nconst darknetStockUnownedStyle = {\\n ...darknetStockOptionStyle,\\n ...redStyle\\n}\\nconst darknetStockSelectedStyle = {\\n borderColor: \\\"var(--bb-theme-white)\\\",\\n boxShadow: \\\"0 0 0 1px rgba(0,0,0,0.65), inset 0 1px 0 rgba(255,255,255,0.22)\\\"\\n}\\nconst hoverHelpDB = {\\n Display: {\\n \\\"Open Logs\\\": \\\"Open tail windows for all running scripts.\\\",\\n \\\"Join Discord!!\\\": \\\"Attempts to open a link to the official Bitburner Discord server. Will also print the link to the terminal.\\\",\\n \\\"Create GitHub Issue\\\": \\\"Attempts to open a link to the official GitHub Issues page. Will also print the link to the terminal.\\\",\\n \\\"Clear Active\\\": \\\"Stop active OS scripts, clear their ports, and disable share mode if it is running.\\\",\\n \\\"Update\\\": \\\"Run the updater, relaunch the loader, and close the current tail.\\\",\\n \\\"Change Log\\\": \\\"Open the SphyxOS change log viewer.\\\",\\n \\\"REMOVE PROGRAM\\\": \\\"Remove SphyxOS files after confirmation, including optional local storage cleanup.\\\"\\n },\\n Batcher: {\\n \\\"Activate\\\": \\\"Start or stop the batcher controller script.\\\",\\n \\\"Auto-Buy Servers\\\": \\\"Let the batcher automatically purchase servers when enabled.\\\",\\n \\\"Use Hacknet\\\": \\\"Allow the batcher to use Hacknet resources when enabled.\\\",\\n \\\"Auto Hash\\\": \\\"Spend hashes automatically to support the batcher.\\\",\\n \\\"Money Mode\\\": \\\"Include money-focused batching in the active strategy.\\\",\\n \\\"XP Mode\\\": \\\"Include experience-focused batching in the active strategy.\\\",\\n \\\"Charge Stanek\\\": \\\"Charge Stanek fragments between batch cycles.\\\",\\n \\\"Pad Grows\\\": \\\"Add extra grow padding for safer batch timing. Good for rapid level ups.\\\",\\n \\\"LogErrors\\\": \\\"Enable additional batcher log/error output.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Hacknet: {\\n \\\"Buy Hacknet\\\": \\\"Run the Hacknet purchasing helper once.\\\",\\n \\\"Batcher: AutoBuy\\\": \\\"Let the batcher automatically buy Hacknet upgrades when available.\\\"\\n },\\n Hashing: {\\n \\\"No AutoHash\\\": \\\"Choose which hash spending option Auto Hash should use.\\\",\\n \\\"Money\\\": \\\"Spend hashes directly for money.\\\",\\n \\\"Reduce Min Sec\\\": \\\"Spend hashes to reduce minimum security on the current batch target.\\\",\\n \\\"Boost Max Money\\\": \\\"Spend hashes to raise max money on the current batch target.\\\",\\n \\\"Generate Contract\\\": \\\"Spend hashes to generate a coding contract.\\\",\\n \\\"Corp Money\\\": \\\"Spend hashes for corporation funds.\\\",\\n \\\"Corp Research\\\": \\\"Spend hashes for corporation research.\\\",\\n \\\"Boost BB Rank\\\": \\\"Spend hashes for Bladeburner rank.\\\",\\n \\\"Boost BB SP\\\": \\\"Spend hashes for Bladeburner skill points.\\\",\\n \\\"Boost Study\\\": \\\"Spend hashes to improve study gains.\\\",\\n \\\"Boost Train\\\": \\\"Spend hashes to improve gym training gains.\\\",\\n \\\"Boost Job Favor\\\": \\\"Spend hashes to improve company favor/job progression.\\\"\\n },\\n Stocks: {\\n \\\"Activate\\\": \\\"Start or stop the stock trader.\\\",\\n \\\"Buy\\\": \\\"Trigger an immediate stock buy pass.\\\",\\n \\\"Sell\\\": \\\"Trigger an immediate stock sell pass.\\\",\\n \\\"Toggle AutoBuy\\\": \\\"Enable or disable automatic stock buying.\\\",\\n \\\"Reset Stats\\\": \\\"Reset tracked stock stats/history.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Misc: {\\n \\\"Backdoor\\\": \\\"Run the basic backdoor helper for reachable servers.\\\",\\n \\\"Backdoor Basic\\\": \\\"Use singularity functions to backdoor the basic target set.\\\",\\n \\\"Backdoor All\\\": \\\"Use singularity functions to backdoor every eligible server.\\\",\\n \\\"Teleport\\\": \\\"Open the teleport/server movement helper.\\\",\\n \\\"Solve Contracts\\\": \\\"Run the coding contract solver.\\\",\\n \\\"Share Ram\\\": \\\"Start sharing free RAM across the network.\\\",\\n \\\"Keep Tab Alive\\\": \\\"Use a low-volume audio context trick to keep the tab active.\\\"\\n },\\n Singularity: {\\n \\\"Dump Money\\\": \\\"Spend money on augments and home upgrades.\\\",\\n \\\"AutoPilot\\\": \\\"Start or stop the autopilot controller.\\\",\\n \\\"Start On Next\\\": \\\"Tell autopilot whether to begin automatically on the next node.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n DarkNet: {\\n \\\"Activate\\\": \\\"Start or Stop the Darknet worm.\\\",\\n \\\"Phishing\\\": \\\"Enable or Disable Phishing attacks.\\\",\\n \\\"Inducing\\\": \\\"Enable or Disable Inducing nearby servers to move.\\\",\\n \\\"Sharing\\\": \\\"Enable or Disable Sharing of Darknet RAM.\\\",\\n \\\"WebStorm\\\": \\\"Try to start a WebStorm. Once started, this mode will automatically be disabled.\\\",\\n \\\"Stock\\\": \\\"Select which stock the DarkNet helper should promote. None disables stock promotion. All targets every stock. Owned stocks show in primary color while unowned stocks show in error color.\\\",\\n \\\"Show Lab Map\\\": \\\"Once the Lab has been discovered, show a map of the solvers progress.\\\"\\n },\\n IPvGo: {\\n \\\"Activate\\\": \\\"Start or stop the IPvGo bot.\\\",\\n \\\"Play White\\\": \\\"Play as white when the bot starts games.\\\",\\n \\\"Repeat\\\": \\\"Automatically continue into another game after a match ends.\\\",\\n \\\"Cheats\\\": \\\"Allow cheat-assisted behavior where supported.\\\",\\n \\\"Logging\\\": \\\"Enable extra logging for IPvGo decisions.\\\",\\n \\\"Netburners\\\": \\\"Allow Netburners as an IPvGo opponent.\\\",\\n \\\"Slum Snakes\\\": \\\"Allow Slum Snakes as an IPvGo opponent.\\\",\\n \\\"The Black Hand\\\": \\\"Allow The Black Hand as an IPvGo opponent.\\\",\\n \\\"Tetrads\\\": \\\"Allow Tetrads as an IPvGo opponent.\\\",\\n \\\"Daedalus\\\": \\\"Allow Daedalus as an IPvGo opponent.\\\",\\n \\\"Illuminati\\\": \\\"Allow Illuminati as an IPvGo opponent.\\\",\\n \\\"????????\\\": \\\"Allow the hidden post-fl1ght opponent.\\\",\\n \\\"No AI\\\": \\\"Restrict play to non-AI/practice style boards where supported.\\\",\\n \\\"SlowMode\\\": \\\"Add a delay before moves so games are easier to follow.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Gangs: {\\n \\\"Activate\\\": \\\"Start or stop the gang manager.\\\",\\n \\\"Auto-Ascend\\\": \\\"Automatically ascend gang members when thresholds are met.\\\",\\n \\\"Auto-EQ\\\": \\\"Automatically buy gang equipment.\\\",\\n \\\"Sleeves\\\": \\\"Assign sleeve support to gang-related work.\\\",\\n \\\"AutoMode\\\": \\\"Let the script choose between money and respect automatically.\\\",\\n \\\"Respect\\\": \\\"Force the gang to prioritize respect gain.\\\",\\n \\\"Money\\\": \\\"Force the gang to prioritize money gain.\\\",\\n \\\"Buy EQ All\\\": \\\"Buy equipment for all gang members.\\\",\\n \\\"Ascend All\\\": \\\"Ascend every gang member.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Corps: {\\n \\\"Activate\\\": \\\"Start or stop the corporation manager.\\\",\\n \\\"Reset TAII\\\": \\\"Clear/reset the TAII database used by the corp scripts.\\\",\\n \\\"Bribe\\\": \\\"Spend corporation funds to bribe eligible factions.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n BladeBurner: {\\n \\\"Activate\\\": \\\"Start or stop the Bladeburner manager.\\\",\\n \\\"Finisher\\\": \\\"Allow the manager to finish the node and move on when ready.\\\",\\n \\\"Int Mode\\\": \\\"Bias activity toward intelligence-related gains.\\\",\\n \\\"Sleeves\\\": \\\"Assign sleeve support to Bladeburner-related work.\\\",\\n \\\"Infil Only\\\": \\\"Limit sleeve support to infiltration-related behavior.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Stanek: {\\n \\\"Charge\\\": \\\"Start charging the current Stanek layout.\\\",\\n \\\"Save Config\\\": \\\"Save the current Stanek fragment layout.\\\",\\n \\\"Load Config\\\": \\\"Load a saved Stanek fragment layout.\\\",\\n \\\"Delete Config\\\": \\\"Delete a saved Stanek fragment layout.\\\",\\n \\\"Defaults\\\": \\\"Include default layouts as load options.\\\"\\n },\\n Sleeves: {\\n \\\"Activate\\\": \\\"Start or stop the sleeve manager.\\\",\\n \\\"Recovery\\\": \\\"Set sleeves to shock recovery mode.\\\",\\n \\\"Sync\\\": \\\"Set sleeves to synchronization mode.\\\",\\n \\\"Training\\\": \\\"Set sleeves to training mode.\\\",\\n \\\"Install Augments\\\": \\\"Allow the sleeve manager to install sleeve augments.\\\",\\n \\\"Cash\\\": \\\"Set sleeves to money-making work.\\\",\\n \\\"Karma\\\": \\\"Set sleeves to karma-reduction work.\\\",\\n \\\"Idle\\\": \\\"Set sleeves to idle.\\\",\\n \\\"Int\\\": \\\"Set sleeves to intelligence-focused work.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Grafting: {\\n \\\"Activate\\\": \\\"Start or Stop the auto-grafting helper.\\\",\\n \\\"Pop Out\\\": \\\"Open or close a dedicated tail window for this subsystem that can leave the game space.\\\"\\n },\\n Games: {\\n \\\"Minesweeper\\\": \\\"Classic Minesweeper with configurable difficulties and mouse support.\\\",\\n \\\"DOOM\\\": \\\"Classic DOOM 1, 2 and 3. Sound and Mouse support.\\\",\\n \\\"Timberman\\\": \\\"How long can you avoid the logs? Left/Right KB Arrows support.\\\"\\n },\\n Cheats: {\\n \\\"Dev Menu\\\": \\\"Open the Bitburner developer menu helper.\\\",\\n \\\"NOT the Dev Menu\\\": \\\"Opens the SphyxOS tail window dev menu. Does not give the dev menu achievement\\\",\\n \\\"Unlock All Achievements\\\": \\\"Unlock every achievement.\\\",\\n \\\"Casino\\\": \\\"Start or stop the Casino script.\\\",\\n \\\"Activate\\\": \\\"Start the AutoInfiltration manager. Waits for 80% Market rate before starting.\\\",\\n \\\"Auto\\\": \\\"Enable automatic infiltration handling.\\\",\\n \\\"Money\\\": \\\"Use auto infiltration for money rewards.\\\",\\n \\\"Faction\\\": \\\"Use auto infiltration for faction reputation rewards.\\\"\\n }\\n}\\nasync function proxyAuth(ns, server, password, func, ...argmnts) { return await runItHome(ns, \\\"SphyxOS/extras/nsProxyAuth.js\\\", [server, password, func, ...argmnts], ns.getFunctionRamCost(func) + 1.6 + 0.05) }\\nasync function runItHome(ns, script, argmts, scriptOverride) {\\n const thisPid = ns.exec(script, \\\"home\\\", { ramOverride: scriptOverride, temporary: true }, ...argmts)\\n if (thisPid === 0) throw new Error(\\\"Failed to run \\\" + script + \\\" on home.\\\")\\n await ns.nextPortWrite(thisPid)\\n return ns.readPort(thisPid)\\n}\\nfunction writeProxyAuth(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [server, password, func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n ns.dnet.connectToSession(server, password)\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxyAuth.js\\\", data, \\\"w\\\")\\n}\\nconst hashAutoTargetOptions = [\\n { label: \\\"None\\\", value: \\\"None\\\" },\\n { label: \\\"Money\\\", value: \\\"money\\\" },\\n { label: \\\"MinSec\\\", value: \\\"min\\\" },\\n { label: \\\"MaxMoney\\\", value: \\\"max\\\" },\\n { label: \\\".cct's\\\", value: \\\"coding\\\" },\\n { label: \\\"C-Money\\\", value: \\\"corp\\\" },\\n { label: \\\"C-Research\\\", value: \\\"research\\\" },\\n { label: \\\"BBRank\\\", value: \\\"bbrank\\\" },\\n { label: \\\"BBSp\\\", value: \\\"bbsp\\\" },\\n { label: \\\"Study\\\", value: \\\"study\\\" },\\n { label: \\\"Train\\\", value: \\\"train\\\" },\\n { label: \\\"Job Favor\\\", value: \\\"favor\\\" }\\n]\\nconst sleeveTrainingOptions = [\\n { label: \\\"None\\\", value: \\\"None\\\" },\\n { label: \\\"All\\\", value: \\\"All\\\" },\\n { label: \\\"Hack\\\", value: \\\"Hack\\\" },\\n { label: \\\"Str\\\", value: \\\"Str\\\" },\\n { label: \\\"Def\\\", value: \\\"Def\\\" },\\n { label: \\\"Dex\\\", value: \\\"Dex\\\" },\\n { label: \\\"Agi\\\", value: \\\"Agi\\\" },\\n { label: \\\"Cha\\\", value: \\\"Cha\\\" },\\n { label: \\\"Int\\\", value: \\\"Int\\\" }\\n]\\nconst sleeveLocalModes = [\\\"All\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Idle\\\", \\\"Recovery\\\", \\\"Sync\\\", \\\"Money\\\", \\\"Karma\\\", \\\"Int\\\"]\\n\""},{"filename":"SphyxOS/bins/autopilot.js","file":"\"import { proxy, proxyTry, runIt, hasBN, maxRun, getServerAvailRam, doGetScriptRam, upgHomeRam, destroyWD, getOwnedSF, getResetInf } from \\\"SphyxOS/util.js\\\"\\nimport { getReputationFromDonation, getPortOpeners, makeNewWindow, getWorth } from \\\"SphyxOS/util.js\\\"\\nlet HASBN14_3 = false\\nlet HASBN13 = false\\nlet HASBN10 = false\\nlet HASBN9 = false\\nlet HASBN7 = false\\nlet HASBN5 = false\\nlet HASBN3 = false\\nlet FAVOR = 150\\nlet GO_CHANGE = true\\nlet GANG_EQ_UPDATE = true\\nlet GANG_EQ_UPDATE2 = true\\nlet augments\\nlet FOCUS\\nlet currentNode\\nlet moneySwitch\\nconst WIDTH = 500\\nconst HEIGHT = 75\\nlet UPGRADED = false\\nlet MOVEON = false\\nlet win\\nconst CASINOMONEY = 10000000000\\nlet PRIMEMONEY\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n ns.clearPort(21)\\n ns.writePort(21, ns.pid)\\n ns.atExit(() => {\\n ns.clearPort(21)\\n if (win) win.close()\\n UPGRADED = false\\n })\\n win = false\\n getCommands(ns)\\n await ns.asleep(4)\\n ns.ui.setTailTitle(MOVEON ? \\\"AutoPilot - Will move on\\\" : \\\"AutoPilot - Will not move on\\\")\\n if (win) win.header(MOVEON ? \\\"AutoPilot - Will move on\\\" : \\\"AutoPilot - Will not move on\\\")\\n augments = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\")\\n moneySwitch = false\\n FOCUS = !augments.includes(\\\"Neuroreceptor Management Implant\\\")\\n HASBN14_3 = await hasBN(ns, 14, 3)\\n HASBN13 = await hasBN(ns, 13)\\n HASBN10 = await hasBN(ns, 10)\\n HASBN9 = await hasBN(ns, 9)\\n HASBN7 = await hasBN(ns, 7)\\n if (!HASBN7) HASBN7 = await hasBN(ns, 6)\\n HASBN5 = await hasBN(ns, 5)\\n HASBN3 = await hasBN(ns, 3, 3)\\n FAVOR = await proxy(ns, \\\"getFavorToDonate\\\")\\n GO_CHANGE = true\\n GANG_EQ_UPDATE = true\\n GANG_EQ_UPDATE2 = true\\n const resetInfo = await getResetInf(ns)\\n currentNode = resetInfo.currentNode\\n PRIMEMONEY = currentNode === 8 ? 249800000 : 0 //Need to travel\\n PRIMEMONEY += CASINOMONEY\\n\\n const neuroAmount = resetInfo.ownedAugs.get(\\\"NeuroFlux Governor\\\") ?? 0\\n //Startup\\n await ns.asleep(10) //Give the Loader script enough time to reach it's await\\n\\n let activeFrags;\\n if (HASBN13 && currentNode !== 8) {\\n activeFrags = await proxy(ns, \\\"stanek.activeFragments\\\")\\n if (activeFrags.length === 0)\\n await loadStanek(ns)\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"stanek\\\")\\n ns.writePort(1, \\\"puppet stanek on\\\")\\n }\\n //Currently supported BN's, 1, 2, 3, 4, 5, 6, 7, 9, 10, 14\\n //To do: 8, 11, 12, 13\\n //Specific startups\\n switch (currentNode) {\\n case 1:\\n case 4:\\n case 5:\\n case 9:\\n case 10:\\n default:\\n if (HASBN3 && ns.peek(9) === \\\"NULL PORT DATA\\\")\\n await runIt(ns, \\\"SphyxOS/bins/corp.js\\\", true, [\\\"quiet\\\"])\\n break\\n case 2:\\n if (ns.peek(6) === \\\"NULL PORT DATA\\\") {\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoAscend On\\\")\\n ns.writePort(1, \\\"gang autoascend on\\\")\\n ns.writePort(16, \\\"AutoEQ Off\\\")\\n ns.writePort(1, \\\"gang autoeq off\\\")\\n ns.writePort(16, \\\"AutoMode\\\")\\n ns.writePort(1, \\\"gang mode automode\\\")\\n ns.writePort(16, \\\"Sleeves Off\\\")\\n ns.writePort(16, \\\"NoTrain\\\")\\n ns.writePort(1, \\\"sleeves idle\\\") //Needed for now?\\n await runIt(ns, \\\"SphyxOS/bins/gang.js\\\", true, [])\\n }\\n if (HASBN3 && ns.peek(9) === \\\"NULL PORT DATA\\\")\\n await runIt(ns, \\\"SphyxOS/bins/corp.js\\\", true, [\\\"quiet\\\"])\\n break\\n case 3:\\n if (ns.peek(9) === \\\"NULL PORT DATA\\\")\\n await runIt(ns, \\\"SphyxOS/bins/corp.js\\\", true, [])\\n break\\n case 6:\\n case 7:\\n case 12:\\n break\\n case 8:\\n let hasWSE = false\\n let hasTIX = false\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) {\\n if (await proxy(ns, \\\"stock.hasWseAccount\\\")) hasWSE = true\\n if (await proxy(ns, \\\"stock.hasTixApiAccess\\\")) hasTIX = true\\n }\\n else {\\n if (await proxy(ns, \\\"stock.hasWSEAccount\\\")) hasWSE = true\\n if (await proxy(ns, \\\"stock.hasTIXAPIAccess\\\")) hasTIX = true\\n }\\n if (ns.peek(4) === \\\"NULL PORT DATA\\\" && hasWSE && hasTIX) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n await runIt(ns, \\\"SphyxOS/bins/tStocks.js\\\", true, [])\\n }\\n break\\n }\\n\\n //Always started up\\n if (ns.peek(5) === \\\"NULL PORT DATA\\\") {\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, \\\"No Logfile\\\")\\n ns.writePort(15, \\\"Repeat On\\\")\\n ns.writePort(1, \\\"ipvgo repeat on\\\")\\n ns.writePort(15, \\\"Play as White Off\\\")\\n ns.writePort(1, \\\"ipvgo playaswhite off\\\")\\n ns.writePort(15, HASBN14_3 ? \\\"Cheats On\\\" : \\\"Cheats Off\\\")\\n ns.writePort(1, HASBN14_3 ? \\\"ipvgo cheats on\\\" : \\\"ipvgo cheats off\\\")\\n ns.writePort(15, \\\"Logging Off\\\")\\n ns.writePort(1, \\\"ipvgo logging off\\\")\\n ns.writePort(15, \\\"Net Off\\\")\\n ns.writePort(1, \\\"ipvgo net off\\\")\\n ns.writePort(15, \\\"Slum Off\\\")\\n ns.writePort(1, \\\"ipvgo slum off\\\")\\n ns.writePort(15, \\\"BH Off\\\")\\n ns.writePort(1, \\\"ipvgo bh off\\\")\\n ns.writePort(15, \\\"Tetrad Off\\\")\\n ns.writePort(1, \\\"ipvgo tetrad off\\\")\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n ns.writePort(15, \\\"Illum Off\\\")\\n ns.writePort(1, \\\"ipvgo illum off\\\")\\n ns.writePort(15, \\\"???? Off\\\")\\n ns.writePort(1, \\\"ipvgo ???? off\\\")\\n ns.writePort(15, \\\"No AI Off\\\")\\n ns.writePort(1, \\\"ipvgo noai off\\\")\\n ns.writePort(15, \\\"SlowMode Off\\\")\\n ns.writePort(1, \\\"ipvgo slowmode off\\\")\\n await runIt(ns, \\\"SphyxOS/bins/go.js\\\", true, [])\\n }\\n if (ns.peek(2) === \\\"NULL PORT DATA\\\") {\\n await runIt(ns, \\\"SphyxOS/bins/puppetMini.js\\\", true, [])\\n }\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n ns.writePort(12, \\\"noautohash\\\")\\n ns.writePort(1, \\\"puppet autohash off\\\")\\n ns.writePort(12, \\\"xp\\\")\\n ns.writePort(1, \\\"puppet xp on\\\")\\n ns.writePort(12, \\\"nolog\\\")\\n ns.writePort(1, \\\"puppet log off\\\")\\n ns.writePort(12, \\\"nopad\\\")\\n ns.writePort(1, \\\"puppet pad off\\\")\\n\\n //Requires individualizing: 8, 11, 12\\n let MONEYCHANGE1 = true\\n let MONEYCHANGE2 = true\\n let MONEYCHANGE3 = true\\n let MONEYCHANGE4 = true\\n let MONEYCHANGE5 = true\\n let MONEYCHANGE6 = true\\n let hashMode = \\\"money\\\"\\n switch (currentNode) {\\n case 1:\\n case 3:\\n case 4:\\n case 5:\\n default:\\n while (true) {\\n //const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n //const neuroLevel = resetInfo.ownedAugs.get(\\\"NeuroFlux Governor\\\") ?? 0\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n if (HASBN9 && !await hasAllAugs(ns, \\\"Netburners\\\")) //Netburners\\n await factionWork(ns, \\\"1/8\\\", \\\"Netburners\\\", false, false, 80, true)\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) //Tian Di Hui\\n await factionWork(ns, \\\"2/8\\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\" })\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) //NiteSec\\n await factionWork(ns, \\\"3/8\\\", \\\"NiteSec\\\", false, true, false, false, { homeRam: 32 })\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) //CyberSec\\n await factionWork(ns, \\\"4/8\\\", \\\"CyberSec\\\", false, true, false, true)\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) //The Black Hand\\n await factionWork(ns, \\\"5/8\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64 })\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) //BitRunners\\n await factionWork(ns, \\\"6/8\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) //Daedalus\\n await factionWork(ns, \\\"7/8\\\", \\\"Daedalus\\\", true, false, false, true)\\n else //Daedalus after Red Pill\\n await farmFaction(ns, \\\"8/8\\\", \\\"Daedalus\\\", false, true)\\n }\\n case 2:\\n while (true) {\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n let gangCreation = false\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n if (!await proxy(ns, \\\"gang.inGang\\\")) {\\n gangCreation = true\\n await factionWork(ns, \\\"1/5\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"field\\\", cstats: 30, hashBuy: 50e12, karma: -9 })\\n }\\n else if (!await hasAllAugs(ns, \\\"Sector-12\\\")) {\\n if (moneySources?.sinceInstall.hacking < 10e9 && GANG_EQ_UPDATE) {\\n GANG_EQ_UPDATE = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ Off\\\")\\n ns.writePort(1, \\\"gang autoeq off\\\")\\n }\\n else if (GANG_EQ_UPDATE2 && moneySources?.sinceInstall.hacking > 10e9) {\\n GANG_EQ_UPDATE2 = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ On\\\")\\n ns.writePort(1, \\\"gang autoeq on\\\")\\n }\\n if (gangCreation) {\\n gangCreation = false\\n GO_CHANGE = true\\n }\\n await gangCheck(ns)\\n await factionWork(ns, \\\"2/5\\\", \\\"Sector-12\\\", true, false, false, false, { city: \\\"Sector-12\\\", hashBuy: await maxMoneyNeeded(ns, \\\"Slum Snakes\\\") / 2 })\\n }\\n else if (!await hasAllAugs(ns, \\\"Slum Snakes\\\")) {\\n if (moneySources?.sinceInstall.hacking < 10e9 && GANG_EQ_UPDATE) {\\n GANG_EQ_UPDATE = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ Off\\\")\\n ns.writePort(1, \\\"gang autoeq off\\\")\\n }\\n else if (GANG_EQ_UPDATE2 && moneySources?.sinceInstall.hacking > 10e9) {\\n GANG_EQ_UPDATE2 = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ On\\\")\\n ns.writePort(1, \\\"gang autoeq on\\\")\\n }\\n\\n await factionWork(ns, \\\"3/5\\\", \\\"Sector-12\\\", false, false, false, false, { city: \\\"Sector-12\\\" })\\n await gangCheck(ns)\\n if (await hasAllAugs(ns, \\\"Slum Snakes\\\")) {\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n }\\n else if (await proxy(ns, \\\"singularity.getFactionFavor\\\", \\\"Sector-12\\\") < FAVOR) {\\n if (moneySources?.sinceInstall.hacking < 10e9 && GANG_EQ_UPDATE) {\\n GANG_EQ_UPDATE = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ Off\\\")\\n ns.writePort(1, \\\"gang autoeq off\\\")\\n }\\n else if (GANG_EQ_UPDATE2 && moneySources?.sinceInstall.hacking > 10e9) {\\n GANG_EQ_UPDATE2 = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ On\\\")\\n ns.writePort(1, \\\"gang autoeq on\\\")\\n }\\n await gangCheck(ns)\\n await factionWork(ns, \\\"4/5\\\", \\\"Sector-12\\\", true, false, false, false, { city: \\\"Sector-12\\\", hashBuy: 1e18 })\\n }\\n else {\\n if (GANG_EQ_UPDATE) {\\n GANG_EQ_UPDATE = false\\n ns.writePort(16, \\\"Silent\\\")\\n ns.writePort(16, \\\"AutoEQ Off\\\")\\n ns.writePort(1, \\\"gang autoeq off\\\")\\n }\\n await farmFaction(ns, \\\"5/5\\\", \\\"Sector-12\\\", false, true, await maxMoneyNeeded(ns, \\\"Slum Snakes\\\"), \\\"hacking\\\", \\\"Sector-12\\\")\\n }\\n }\\n case 6:\\n case 7:\\n while (true) {\\n await casino(ns)\\n await prime(ns)\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n\\n if (moneySources?.sinceInstall.casino < 10000000000) {\\n await doCrime(ns, \\\"money\\\")\\n clearLogs(ns)\\n printLogs(ns, \\\"Crime for Money while we wait for Casino.\\\")\\n }\\n if (!await proxy(ns, \\\"bladeburner.inBladeburner\\\") && moneySources?.sinceInstall.casino >= 10000000000) {\\n clearLogs(ns)\\n printLogs(ns, \\\"Training for BB entrance.\\\")\\n }\\n if (ns.peek(8) === \\\"NULL PORT DATA\\\" && moneySources?.sinceInstall.casino >= 10000000000) {\\n ns.writePort(18, \\\"quiet\\\")\\n ns.writePort(18, \\\"finisher off\\\")\\n ns.writePort(1, \\\"bb finisher off\\\")\\n ns.writePort(18, \\\"int mode off\\\")\\n ns.writePort(1, \\\"bb int mode off\\\")\\n ns.writePort(18, HASBN10 ? \\\"sleeves on\\\" : \\\"sleeves off\\\")\\n ns.writePort(1, HASBN10 ? \\\"bb sleeves on\\\" : \\\"bb sleeves off\\\")\\n ns.writePort(18, \\\"sleeve infil off\\\")\\n ns.writePort(1, \\\"bb sleeve infil off\\\")\\n await runIt(ns, \\\"SphyxOS/bins/bb.js\\\", true, [])\\n clearLogs(ns)\\n printLogs(ns, \\\"Training for BB entrance.\\\")\\n }\\n if (HASBN9 && moneySources?.sinceInstall.casino >= 10000000000) {\\n await hashes(ns, 1000000, \\\"bbsp\\\")\\n await hashes(ns, 1000000, \\\"bbrank\\\")\\n }\\n if (await proxy(ns, \\\"bladeburner.inBladeburner\\\")) {\\n let count = 0\\n for (const bop of ns.bladeburner.getBlackOpNames()) {\\n count += await proxy(ns, \\\"bladeburner.getActionCountRemaining\\\", \\\"Black Operations\\\", bop)\\n }\\n clearLogs(ns)\\n printLogs(ns, \\\"Waiting for BladeBurner to finish. \\\" + (ns.bladeburner.getBlackOpNames().length - count) + \\\" / \\\" + ns.bladeburner.getBlackOpNames().length)\\n if (count === 0) {\\n UPGRADED = false\\n await endIt(ns)\\n }\\n }\\n await ns.asleep(1000)\\n }\\n case 8:\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n let data4SCost;\\n if (ns.ui.getGameInfo()?.versionNumber >= 44)\\n data4SCost = await proxy(ns, \\\"stock.has4SDataTixApi\\\") ? 0 : 25000000000\\n else\\n data4SCost = await proxy(ns, \\\"stock.has4SDataTIXAPI\\\") ? 0 : 25000000000\\n let buyAugsFlag = false\\n while (true) {\\n await casino(ns)\\n await prime(ns, false, true)\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (moneySources?.sinceInstall.casino >= 10000000000 && MONEYCHANGE1) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuy\\\")\\n ns.writePort(1, \\\"stocks autobuy on\\\")\\n MONEYCHANGE1 = false\\n }\\n if (data4SCost > 0 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > data4SCost) {\\n await proxy(ns, \\\"stock.purchase4SMarketDataTixApi\\\")\\n }\\n if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) { //14b for all augments and neuroflux. + 25b for 4s = 39b minimum to move on.\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000 + 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"1/8 - \\\" + formatNum(ns, 30000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\", buyRep: false, buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Tian Di Hui\\\") >= await maxRepNeeded(ns, \\\"Tian Di Hui\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 30000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 28000000000 + moneySources.sinceInstall?.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) {//CyberSec\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"CyberSec\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve.\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"2/8 - \\\" + formatNum(ns, 23000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"CyberSec\\\", false, true, false, true, { buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"CyberSec\\\") >= await maxRepNeeded(ns, \\\"CyberSec\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 23000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 21000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"NiteSec\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"3/8 - \\\" + formatNum(ns, 33000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"NiteSec\\\", false, true, false, true, { homeRam: 32, buyRep: false, buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"NiteSec\\\") >= await maxRepNeeded(ns, \\\"NiteSec\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 33000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 31000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"The Black Hand\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"4/8 - \\\" + formatNum(ns, 53000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64, buyRep: false, buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"The Black Hand\\\") >= await maxRepNeeded(ns, \\\"The Black Hand\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 53000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 51000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"BitRunners\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"5/8 - \\\" + formatNum(ns, 87000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128, buyRep: false, buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"BitRunners\\\") >= await maxRepNeeded(ns, \\\"BitRunners\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 87000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 85000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.skills.hacking >= 2500 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 102000000000) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE4 = false\\n }\\n await factionWork(ns, \\\"7/8 - \\\" + formatNum(ns, 178000000000 + data4SCost + moneySources?.sinceInstall.augmentations, 2) + \\\" - \\\", \\\"Daedalus\\\", true, false, false, true, { buyRep: false, buyAugs: buyAugsFlag })\\n if (MONEYCHANGE3 && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Daedalus\\\") >= await maxRepNeeded(ns, \\\"Daedalus\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") + await getWorth(ns) > 178000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuyoff\\\")\\n ns.writePort(1, \\\"stocks autobuy off\\\")\\n ns.writePort(13, \\\"sell\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE5 && !MONEYCHANGE3 && await getWorth(ns) <= 1 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 176000000000 + data4SCost + moneySources?.sinceInstall.augmentations) {\\n buyAugsFlag = true\\n MONEYCHANGE5 = false\\n }\\n if (MONEYCHANGE6 && player.factions.includes(\\\"Daedalus\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, \\\"autobuy\\\")\\n ns.writePort(1, \\\"stocks autobuy on\\\")\\n MONEYCHANGE6 = false\\n }\\n }\\n else {\\n if (MONEYCHANGE2) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 290000000) //Set reserve.\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE4 && player.factions.includes(\\\"Daedalus\\\")) {\\n ns.writePort(13, \\\"silent\\\")\\n ns.writePort(13, 1000000) //Set reserve. Need 1m to enter faction\\n MONEYCHANGE4 = false\\n }\\n await farmFaction(ns, \\\"8/8\\\", \\\"Daedalus\\\", false, true)\\n }\\n }\\n case 9:\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n while (true) {\\n await casino(ns) //Break the Casino\\n await prime(ns, false)\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n const cctCost = await proxy(ns, \\\"hacknet.hashCost\\\", \\\"Generate Coding Contract\\\")\\n const minHash = await proxy(ns, \\\"hacknet.hashCost\\\", \\\"Reduce Minimum Security\\\")\\n const maxHash = await proxy(ns, \\\"hacknet.hashCost\\\", \\\"Increase Maximum Money\\\")\\n const capacity = await proxy(ns, \\\"hacknet.hashCapacity\\\")\\n const maxHomeRam = await proxy(ns, \\\"getServerMaxRam\\\", \\\"home\\\")\\n\\n const myAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n if (moneySources?.sinceInstall.casino >= 10000000000 && moneySources?.sinceInstall.hacknet_expenses >= -10000000000) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/hacknetPurchaser.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n //Netburners has 5 augments. We want to buy 6 or more NFG. Means 11 min in float\\n if (!await hasAllAugs(ns, \\\"Netburners\\\") || neuroAmount < 6) {\\n\\n if (!await hasAllAugs(ns, \\\"Netburners\\\") && player.factions.includes(\\\"Netburners\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Netburners\\\") < await maxRepNeeded(ns, \\\"Netburners\\\"))\\n await factionWork(ns, \\\"01/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hackLvl: 80 })\\n else await factionWork(ns, \\\"01/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hashType: \\\"money\\\", hackLvl: 80 })\\n if (player.factions.includes(\\\"Netburners\\\") && await hasAllAugs(ns, \\\"Netburners\\\")) {\\n await dump(ns)\\n await restart(ns, 11)\\n }\\n }\\n //Tian has 8 unique augs to purchase here. We want at least 3 more NFG, bringing us up to 9 in total for NFG\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\") || neuroAmount < 9) {\\n\\n if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\") && player.factions.includes(\\\"Tian Di Hui\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Tian Di Hui\\\") < await maxRepNeeded(ns, \\\"Tian Di Hui\\\"))\\n await factionWork(ns, \\\"02/18\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\", hashBuy: 11e20, hackLvl: 50 })\\n else await factionWork(ns, \\\"02/18\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\", hashBuy: 11e20, hashType: \\\"money\\\", hackLvl: 50 })\\n if (player.factions.includes(\\\"Tian Di Hui\\\") && await hasAllAugs(ns, \\\"Tian Di Hui\\\")) {\\n await dump(ns)\\n await restart(ns, 8 + 9 - neuroAmount)\\n }\\n }\\n //CyberSec has 5 unitue augs to purchase. We want at least 6 more NFG, bringing us up to 15\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\") || neuroAmount < 15) {\\n if (!await hasAllAugs(ns, \\\"CyberSec\\\") && player.factions.includes(\\\"CyberSec\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"CyberSec\\\") < await maxRepNeeded(ns, \\\"CyberSec\\\"))\\n await factionWork(ns, \\\"03/18\\\", \\\"CyberSec\\\", false, true, false, false, { hashBuy: 1e20, homeRam: 32, hackLvl: 55 })\\n else await factionWork(ns, \\\"03/18\\\", \\\"CyberSec\\\", false, true, false, false, { hashBuy: 1e20, homeRam: 32, hashType: \\\"money\\\", hackLvl: 55 })\\n if (player.factions.includes(\\\"CyberSec\\\") && await hasAllAugs(ns, \\\"CyberSec\\\")) {\\n await dump(ns)\\n await restart(ns, 5 + 9 - neuroAmount + 6)\\n }\\n }\\n else if (neuroAmount < 40) {\\n if (await maxRepNeeded(ns, \\\"Netburners\\\", false) > await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Netburners\\\"))\\n await factionWork(ns, \\\"04/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hackLvl: 80 })\\n else await factionWork(ns, \\\"04/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hashType: \\\"money\\\", hackLvl: 80 })\\n if (player.factions.includes(\\\"Netburners\\\")) {\\n await dump(ns)\\n if (myAugs.length - augments.length >= 7 || myAugs.length - augments.length + neuroAmount >= 40) {//We want at least 50 when done.\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n }\\n }\\n //Chongqing has 3 unique augs, we have 40 NFG now, we want another 2 from here.\\n else if (!await hasAllAugs(ns, \\\"Chongqing\\\") || neuroAmount < 42) {\\n if (!await hasAllAugs(ns, \\\"Chongqing\\\") && player.factions.includes(\\\"Chongqing\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Chongqing\\\") < await maxRepNeeded(ns, \\\"Chongqing\\\"))\\n await factionWork(ns, \\\"05/18\\\", \\\"Chongqing\\\", false, false, false, false, { city: \\\"Chongqing\\\", hashBuy: 11e20 })\\n else await factionWork(ns, \\\"05/18\\\", \\\"Chongqing\\\", false, false, false, false, { city: \\\"Chongqing\\\", hashBuy: 11e20, hashType: \\\"money\\\" })\\n if (player.factions.includes(\\\"Chongqing\\\") && await hasAllAugs(ns, \\\"Chongqing\\\")) {\\n await dump(ns)\\n await restart(ns, 3 + 2 + 40 - neuroAmount)\\n }\\n }\\n //NiteSec has 6 unitue augs to purchase. We have 42NFG, We want at least 0 more NFG, bringing us up to 42\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) {\\n if (!await hasAllAugs(ns, \\\"NiteSec\\\") && player.factions.includes(\\\"NiteSec\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"NiteSec\\\") < await maxRepNeeded(ns, \\\"NiteSec\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"06/18\\\", \\\"NiteSec\\\", false, true, false, true, { hackLvl: 205, hashBuy: 1e20 })\\n }\\n else {\\n await factionWork(ns, \\\"06/18\\\", \\\"NiteSec\\\", false, true, false, true, { hackLvl: 205, hashBuy: 1e20, hashType: \\\"money\\\" })\\n }\\n if (player.factions.includes(\\\"NiteSec\\\") && await hasAllAugs(ns, \\\"NiteSec\\\")) {\\n await dump(ns)\\n await restart(ns, 6 + 42 - neuroAmount)\\n }\\n }\\n //Farm for a while\\n else if (neuroAmount < 51) {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (MONEYCHANGE2 && player.skills.hacking >= 230) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (maxHomeRam < 4096) {\\n while (await proxy(ns, \\\"singularity.upgradeHomeRam\\\")) { }\\n await factionWork(ns, \\\"07/18\\\", \\\"Netburners\\\", true, false, 80, false, { hashBuy: 11e20, hashType: \\\"money\\\", hackLvl: 80, buyRep: false })\\n }\\n else if (await proxy(ns, \\\"singularity.getFactionFavor\\\", \\\"Netburners\\\") < FAVOR && player.factions.includes(\\\"Netburners\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Netburners\\\") < await maxRepNeeded(ns, \\\"Netburners\\\", false))\\n await factionWork(ns, \\\"07/18\\\", \\\"Netburners\\\", true, false, 80, false, { hashBuy: 11e20, hackLvl: 80 })\\n else if (cctCost < 2400 && player.factions.includes(\\\"Netburners\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Netburners\\\") < await maxRepNeeded(ns, \\\"Netburners\\\", false))\\n await factionWork(ns, \\\"07/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hackLvl: 80 })\\n else await factionWork(ns, \\\"07/18\\\", \\\"Netburners\\\", false, false, 80, false, { hashBuy: 11e20, hashType: \\\"money\\\", hackLvl: 80 })\\n\\n if (maxHomeRam >= 4096) {\\n await dump(ns)\\n }\\n const numAugs = 51 - neuroAmount > 7 ? 7 : 51 - neuroAmount\\n await restart(ns, numAugs)\\n }\\n //The Black Hand has 4 augs \\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) {\\n if (cctCost < 4200 && !await hasAllAugs(ns, \\\"The Black Hand\\\") && player.factions.includes(\\\"The Black Hand\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"The Black Hand\\\") < await maxRepNeeded(ns, \\\"The Black Hand\\\"))\\n await factionWork(ns, \\\"08/18\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64, hackLvl: 345 })\\n else await factionWork(ns, \\\"08/18\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64, hashType: \\\"money\\\", hackLvl: 345 })\\n if (player.factions.includes(\\\"The Black Hand\\\") && await hasAllAugs(ns, \\\"The Black Hand\\\")) {\\n await dump(ns)\\n await restart(ns, 4)\\n }\\n }\\n else if (!await hasAllAugs(ns, \\\"Slum Snakes\\\")) {\\n if (cctCost < 5200 && player.factions.includes(\\\"Slum Snakes\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Slum Snakes\\\") < await maxRepNeeded(ns, \\\"Slum Snakes\\\"))\\n await factionWork(ns, \\\"09/18\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"security\\\", cstats: 30, karma: -9 })\\n else await factionWork(ns, \\\"09/18\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"security\\\", cstats: 30, karma: -9, hashType: \\\"money\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"Tetrads\\\")) {\\n if (cctCost < 5200 && player.factions.includes(\\\"Tetrads\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Tetrads\\\") < await maxRepNeeded(ns, \\\"Tetrads\\\"))\\n await factionWork(ns, \\\"10/18\\\", \\\"Tetrads\\\", false, false, false, true, { job: \\\"security\\\", cstats: 75, city: \\\"Chongqing\\\", karma: -18 })\\n else await factionWork(ns, \\\"10/18\\\", \\\"Tetrads\\\", false, false, false, true, { job: \\\"security\\\", cstats: 75, city: \\\"Chongqing\\\", karma: -18, hashType: \\\"money\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) {\\n if (cctCost < 5400 && player.factions.includes(\\\"BitRunners\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"BitRunners\\\") < await maxRepNeeded(ns, \\\"BitRunners\\\"))\\n await factionWork(ns, \\\"11/18\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128, hackLvl: 530 })\\n else await factionWork(ns, \\\"11/18\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128, hashType: \\\"money\\\", hackLvl: 530 })\\n }\\n //Farm for a while\\n else if (maxHomeRam < 32768 || neuroAmount < 100) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 1100) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (MONEYCHANGE3 && ns.peek(3) !== \\\"n00dles\\\") {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"autohash\\\")\\n ns.writePort(1, \\\"puppet autohash on\\\")\\n MONEYCHANGE3 = false\\n hashMode = \\\"None\\\"\\n }\\n if (MONEYCHANGE4 && minHash > capacity && maxHash > capacity) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"noautohash\\\")\\n ns.writePort(1, \\\"puppet autohash off\\\")\\n MONEYCHANGE4 = false\\n hashMode = \\\"money\\\"\\n }\\n if (maxHomeRam < 32768) {\\n while (await proxy(ns, \\\"singularity.upgradeHomeRam\\\")) { }\\n await factionWork(ns, \\\"12/18\\\", \\\"Netburners\\\", true, false, 80, false, { hashBuy: 11e20, hashType: hashMode, hackLvl: 80, buyRep: false })\\n }\\n else await factionWork(ns, \\\"12/18\\\", \\\"Netburners\\\", true, false, 80, false, { hashBuy: 11e20, hashType: hashMode, hackLvl: 80 })\\n\\n if (maxHomeRam >= 32768) {\\n await dump(ns)\\n }\\n await restart(ns, 6)\\n }\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 2500) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (cctCost < 5400 && player.factions.includes(\\\"Daedalus\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Daedalus\\\") < await maxRepNeeded(ns, \\\"Daedalus\\\"))\\n await factionWork(ns, \\\"13/18\\\", \\\"Daedalus\\\", true, false, false, true, { hashBuy: 1e21, augsAtOnce: 3, filterNFG: true })\\n else await factionWork(ns, \\\"13/18\\\", \\\"Daedalus\\\", true, false, false, true, { hashBuy: 1e21, hashType: \\\"money\\\", augsAtOnce: 3, filterNFG: true })\\n }\\n else if (!await hasAllAugs(ns, \\\"The Syndicate\\\")) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 2500) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (cctCost < 5400 && player.factions.includes(\\\"The Syndicate\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"The Syndicate\\\") < await maxRepNeeded(ns, \\\"The Syndicate\\\"))\\n await factionWork(ns, \\\"14/18\\\", \\\"The Syndicate\\\", false, false, false, true, { cstats: 200, city: \\\"Sector-12\\\", hashBuy: 1e21, karma: -90, buyRep: false })\\n else await factionWork(ns, \\\"14/18\\\", \\\"The Syndicate\\\", false, false, false, true, { cstats: 200, city: \\\"Sector-12\\\", hashBuy: 1e21, karma: -90, hashType: \\\"train\\\", buyRep: false })\\n }\\n else if (!await hasAllAugs(ns, \\\"Speakers for the Dead\\\")) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 2500) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (cctCost < 5400 && player.factions.includes(\\\"Speakers for the Dead\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Speakers for the Dead\\\") < await maxRepNeeded(ns, \\\"Speakers for the Dead\\\"))\\n await factionWork(ns, \\\"15/18\\\", \\\"Speakers for the Dead\\\", false, false, false, true, { cstats: 300, hashBuy: 50e21, karma: -45, killed: 30 })\\n else await factionWork(ns, \\\"15/18\\\", \\\"Speakers for the Dead\\\", false, false, false, true, { cstats: 300, hashBuy: 50e21, karma: -45, killed: 30, hashType: \\\"train\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"The Covenant\\\")) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 3000) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (cctCost < 5400 && player.factions.includes(\\\"The Covenant\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"The Covenant\\\") < await maxRepNeeded(ns, \\\"The Covenant\\\"))\\n await factionWork(ns, \\\"16/18\\\", \\\"The Covenant\\\", true, false, false, false, { cstats: 850, hashBuy: 1e21, augsAtOnce: 3, filterNFG: true })\\n else await factionWork(ns, \\\"16/18\\\", \\\"The Covenant\\\", true, false, false, false, { cstats: 850, hashBuy: 1e21, hashType: \\\"train\\\", augsAtOnce: 3, filterNFG: true })\\n }\\n else if (!await hasAllAugs(ns, \\\"Illuminati\\\")) {\\n if (MONEYCHANGE2 && player.skills.hacking >= 3000) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n if (cctCost < 5400 && player.factions.includes(\\\"Illuminati\\\") && await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"Illuminati\\\") < await maxRepNeeded(ns, \\\"Illuminati\\\"))\\n await factionWork(ns, \\\"17/18\\\", \\\"Illuminati\\\", true, false, false, false, { cstats: 1200, hashBuy: 1e21 })\\n else await factionWork(ns, \\\"17/18\\\", \\\"Illuminati\\\", true, false, false, false, { cstats: 1200, hashBuy: 1e21, hashType: \\\"train\\\" })\\n }\\n else if (!player.factions.includes(\\\"Netburners\\\")) {\\n await factionWork(ns, \\\"18/18\\\", \\\"Netburners\\\", true, false, 80, false, { hashbuy: 11e20, hashType: \\\"money\\\", hackLvl: 80, buyRep: false })\\n }\\n else {\\n if (MONEYCHANGE2 && player.skills.hacking >= 4000) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await farmFaction(ns, \\\"18/18\\\", \\\"Netburners\\\", false, true)\\n }\\n }\\n case 10:\\n while (true) {\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n const newestOwnedAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\")\\n if (HASBN9 && !await hasAllAugs(ns, \\\"Netburners\\\")) //Netburners\\n await factionWork(ns, \\\"01/15\\\", \\\"Netburners\\\", false, false, 80, true)\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) //Tian Di Hui\\n await factionWork(ns, \\\"02/15\\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\" })\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) //NiteSec\\n await factionWork(ns, \\\"03/15\\\", \\\"CyberSec\\\", false, true, false, true)\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) //CyberSec\\n await factionWork(ns, \\\"04/15\\\", \\\"NiteSec\\\", false, true, false, true, { homeRam: 32 })\\n else if (await proxy(ns, \\\"singularity.getFactionFavor\\\", \\\"The Black Hand\\\") < FAVOR) //The Black Hand\\n await factionWork(ns, \\\"05/15\\\", \\\"The Black Hand\\\", true, true, false, false, { homeRam: 64 })\\n else {\\n if (await maxSleeves(ns) === 8 && !await allSleevesUpgraded(ns)) { //\\n if (neuroAmount < 140)\\n await farmFaction(ns, \\\"06/15\\\", \\\"The Black Hand\\\", true, false, 0)\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) //BitRunners\\n await factionWork(ns, \\\"07/15\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else if (!await hasAllAugs(ns, \\\"Slum Snakes\\\"))\\n await factionWork(ns, \\\"08/15\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"security\\\", cstats: 30, karma: -9 })\\n else if (!await hasAllAugs(ns, \\\"Tetrads\\\"))\\n await factionWork(ns, \\\"09/15\\\", \\\"Tetrads\\\", false, false, false, true, { job: \\\"security\\\", cstats: 75, city: \\\"Chongqing\\\", karma: -18 })\\n else if (!await hasAllAugs(ns, \\\"The Syndicate\\\"))\\n await factionWork(ns, \\\"10/15\\\", \\\"The Syndicate\\\", false, false, false, true, { cstats: 200, city: \\\"Sector-12\\\", karma: -90 })\\n else if (!await hasAllAugs(ns, \\\"Speakers for the Dead\\\"))\\n await factionWork(ns, \\\"11/15\\\", \\\"Speakers for the Dead\\\", true, false, false, true, { cstats: 300, hashBuy: 50e12, karma: -45, killed: 30 })\\n else if (!await allSleevesUpgraded(ns)) {//Covenant until we get all sleeves\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.factions.includes(\\\"The Covenant\\\") && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 120e15) {\\n const pidof = await runIt(ns, \\\"SphyxOS/sleeves/buyUpgradeSleeves.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n await factionWork(ns, \\\"12/15\\\", \\\"The Covenant\\\", false, false, false, false, { cstats: 850, hashBuy: 1e21 })\\n if (await allSleevesUpgraded(ns)) {\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n }\\n }\\n else {\\n if (neuroAmount < 100)\\n await farmFaction(ns, \\\"06/15\\\", \\\"The Black Hand\\\", true, false, 0)\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) //BitRunners\\n await factionWork(ns, \\\"07->13/15\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) //Daedalus\\n await factionWork(ns, \\\"13/15\\\", \\\"Daedalus\\\", true, false, false, true)\\n else if (!newestOwnedAugs.includes(\\\"QLink\\\")) {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.city !== \\\"New Tokyo\\\") {\\n clearLogs(ns)\\n printLogs(ns, \\\"14/15 - Trying to travel to New Tokyo! In \\\" + player.city)\\n await proxy(ns, \\\"singularity.travelToCity\\\", \\\"New Tokyo\\\")\\n await ns.asleep(1000)\\n continue\\n }//Get to New Tokyo\\n let wrk = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (wrk === null || wrk.type !== \\\"GRAFTING\\\" && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > await proxy(ns, \\\"grafting.getAugmentationGraftPrice\\\", \\\"QLink\\\")) {\\n await proxy(ns, \\\"grafting.graftAugmentation\\\", \\\"QLink\\\", FOCUS)\\n }\\n clearLogs(ns)\\n printLogs(ns, \\\"14/15 - Grafting QLink. Please wait.\\\")\\n await ns.asleep(1000)\\n }\\n else\\n await farmFaction(ns, \\\"15/15\\\", \\\"Daedalus\\\", false, true, 0)\\n }\\n }\\n }\\n case 11:\\n while (true) {\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (!augments.includes(\\\"Neuroreceptor Management Implant\\\")) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 1)\\n await factionWork(ns, \\\"1/14\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n if (!augments.includes(\\\"Nanofiber Weave\\\")) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 1)\\n await factionWork(ns, \\\"2/14\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 3)\\n await factionWork(ns, \\\"3/14\\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\" })\\n }\\n else if (neuroAmount < 8) {\\n if (MONEYCHANGE1) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 8)\\n await factionWork(ns, \\\"4/14\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"CyberSec\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await factionWork(ns, \\\"5/14\\\", \\\"CyberSec\\\", false, true, false, true)\\n }\\n else if (neuroAmount < 14) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 6)\\n await factionWork(ns, \\\"6/14\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"NiteSec\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 2)\\n await factionWork(ns, \\\"7/14\\\", \\\"NiteSec\\\", false, true, false, true, { homeRam: 32 })\\n }\\n else if (neuroAmount < 17) {\\n if (MONEYCHANGE1 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 4)\\n await factionWork(ns, \\\"8/14\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) {\\n if (MONEYCHANGE3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE1 && player.factions.includes(\\\"The Black Hand\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 1)\\n if (await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"The Black Hand\\\") < await maxRepNeeded(ns, \\\"The Black Hand\\\"))\\n await factionWork(ns, \\\"9/14\\\", \\\"The Black Hand\\\", false, true, false, true, { hashBuy: 12e12, hashType: \\\"None\\\", buyRep: false })\\n else {\\n await factionWork(ns, \\\"9/14\\\", \\\"The Black Hand\\\", false, true, false, true, { job: \\\"none\\\", hashBuy: 12e12, hashType: \\\"None\\\", buyRep: false })\\n await doCrime(ns, \\\"money\\\")\\n }\\n }\\n else if (neuroAmount < 25) {\\n if (MONEYCHANGE2 && player.factions.includes(\\\"The Black Hand\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await dump(ns)\\n await restart(ns, 8)\\n await factionWork(ns, \\\"10/14\\\", \\\"The Black Hand\\\", false, true, false, false)//, 0, \\\"None\\\", 1e12, 64, 0, 0, \\\"none\\\", 0, false)\\n }\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) {\\n if (MONEYCHANGE3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE1 && player.factions.includes(\\\"BitRunners\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE1 = false\\n }\\n if (await proxy(ns, \\\"singularity.getFactionRep\\\", \\\"BitRunners\\\") < await maxRepNeeded(ns, \\\"BitRunners\\\", false))\\n await factionWork(ns, \\\"11/14\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else {\\n await doCrime(ns, \\\"money\\\")\\n await factionWork(ns, \\\"11/14\\\", \\\"BitRunners\\\", true, true, false, true, { job: \\\"none\\\", homeRam: 128 })\\n }\\n }\\n else if (neuroAmount < 90) {\\n if (MONEYCHANGE3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE1 && player.factions.includes(\\\"BitRunners\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE1 = false\\n }\\n const numAugs = 90 - neuroAmount > 8 ? 8 : 90 - neuroAmount\\n await restart(ns, numAugs)\\n await farmFaction(ns, \\\"12/14\\\", \\\"BitRunners\\\", true, false, 1000000)\\n }\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) {\\n if (MONEYCHANGE3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE1 && player.skills.hacking >= 2500) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE1 = false\\n }\\n await factionWork(ns, \\\"13/14\\\", \\\"Daedalus\\\", true, false, false, true)\\n }\\n else {\\n if (MONEYCHANGE3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE3 = false\\n }\\n if (MONEYCHANGE1 && player.skills.hacking >= 2500) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n ns.writePort(12, \\\"pad\\\")\\n ns.writePort(1, \\\"puppet pad on\\\")\\n MONEYCHANGE1 = false\\n }\\n await farmFaction(ns, \\\"14/14\\\", \\\"Daedalus\\\", false, true)\\n }\\n }\\n case 12:\\n while (true) {\\n //const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n //const neuroLevel = resetInfo.ownedAugs.get(\\\"NeuroFlux Governor\\\") ?? 0\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n if (!await hasAllAugs(ns, \\\"Netburners\\\")) //Netburners\\n await factionWork(ns, \\\"1/8\\\", \\\"Netburners\\\", false, false, 80, true)\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) //Tian Di Hui\\n await factionWork(ns, \\\"2/8\\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\" })\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) //NiteSec\\n await factionWork(ns, \\\"3/8\\\", \\\"NiteSec\\\", false, true, false, false, { homeRam: 32 })\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) //CyberSec\\n await factionWork(ns, \\\"4/8\\\", \\\"CyberSec\\\", false, true, false, true)\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) //The Black Hand\\n await factionWork(ns, \\\"5/8\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64 })\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) //BitRunners\\n await factionWork(ns, \\\"6/8\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) //Daedalus\\n await factionWork(ns, \\\"7/8\\\", \\\"Daedalus\\\", true, false, false, true)\\n else //Daedalus after Red Pill\\n await farmFaction(ns, \\\"8/8\\\", \\\"Daedalus\\\", false, true)\\n }\\n case 13:\\n while (true) {\\n const myAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (HASBN9 && !await hasAllAugs(ns, \\\"Netburners\\\")) //Netburners\\n await factionWork(ns, \\\"01/20\\\", \\\"Netburners\\\", false, false, 80, true)\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) //Tian Di Hui\\n await factionWork(ns, \\\"02/20\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n else if (neuroAmount < 5) {\\n if (MONEYCHANGE1) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 8 + 6)\\n await factionWork(ns, \\\"03/20\\\", \\\"Tian Di Hui\\\", false, false, false, false, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) //CyberSec\\n await factionWork(ns, \\\"04/20\\\", \\\"CyberSec\\\", false, true, false, false)\\n else if (neuroAmount < 11) {\\n if (MONEYCHANGE1 && myAugs.length - augments.length >= 10) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 5 + 6)\\n await factionWork(ns, \\\"05/20\\\", \\\"CyberSec\\\", false, true, false, false)\\n }\\n else if (neuroAmount < 42) { //CyberSec should be donatable after\\n if (MONEYCHANGE1 && myAugs.length - augments.length >= 6) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 8)\\n await factionWork(ns, \\\"06/20\\\", \\\"CyberSec\\\", false, true, false, false)\\n }\\n else if (neuroAmount < 47) {\\n if (MONEYCHANGE1 && myAugs.length - augments.length >= 3) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await dump(ns)\\n await restart(ns, 5)\\n await farmFaction(ns, \\\"07/20\\\", \\\"CyberSec\\\", true, false, 1000000000)\\n }\\n else if (!await hasAllAugs(ns, \\\"Slum Snakes\\\"))\\n await factionWork(ns, \\\"08/20\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"security\\\", cstats: 30, karma: -9 })\\n else if (!await hasAllAugs(ns, \\\"Tetrads\\\"))\\n await factionWork(ns, \\\"09/20\\\", \\\"Tetrads\\\", false, false, false, true, { job: \\\"security\\\", cstats: 75, city: \\\"Chongqing\\\", karma: -18 })\\n else if (!await hasAllAugs(ns, \\\"The Syndicate\\\")) {\\n if (MONEYCHANGE1 && player.skills.hacking > 160) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n MONEYCHANGE1 = false\\n }\\n if (MONEYCHANGE2 && player.factions.includes(\\\"The Syndicate\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"10/20\\\", \\\"The Syndicate\\\", true, false, false, true, { cstats: 200, city: \\\"Sector-12\\\", karma: -90 })\\n }\\n else if (neuroAmount < 55) {\\n if (MONEYCHANGE1 && myAugs.length - augments.length >= 2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n await restart(ns, 4)\\n await farmFaction(ns, \\\"11/20\\\", \\\"CyberSec\\\", true, false, 1000000000)\\n }\\n else if (neuroAmount < 80) {\\n if (MONEYCHANGE1 && myAugs.length - augments.length >= 4) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nopurchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers off\\\")\\n MONEYCHANGE1 = false\\n }\\n const amt = 80 - neuroAmount > 8 ? 8 : 80 - neuroAmount\\n await restart(ns, amt)\\n await farmFaction(ns, \\\"12/20\\\", \\\"CyberSec\\\", true, false, 1000000000)\\n }\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) //NiteSec\\n await factionWork(ns, \\\"13/20\\\", \\\"NiteSec\\\", false, true, false, true, { hashBuy: 1e9, homeRam: 32 })\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) //The Black Hand\\n await factionWork(ns, \\\"14/20\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64 })\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) //BitRunners\\n await factionWork(ns, \\\"15/20\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n else if (!await hasAllAugs(ns, \\\"Speakers for the Dead\\\"))\\n await factionWork(ns, \\\"16/20\\\", \\\"Speakers for the Dead\\\", true, false, false, true, { cstats: 300, karma: -45, killed: 30 })\\n else if (!await hasAllAugs(ns, \\\"The Covenant\\\"))\\n await factionWork(ns, \\\"17/20\\\", \\\"The Covenant\\\", true, false, false, false, { cstats: 850, augsAtOnce: 3, filterNFG: true })\\n else if (!await hasAllAugs(ns, \\\"Illuminati\\\"))\\n await factionWork(ns, \\\"18/20\\\", \\\"Illuminati\\\", true, false, false, false, { cstats: 1200 })\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) //Daedalus\\n await factionWork(ns, \\\"19/20\\\", \\\"Daedalus\\\", true, false, false, true)\\n else //Daedalus after Red Pill\\n await farmFaction(ns, \\\"20/20\\\", \\\"CyberSec\\\", true, true, 100000000000)\\n }\\n case 14:\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"nomoney\\\")\\n ns.writePort(1, \\\"puppet money off\\\")\\n while (true) {\\n //const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n //const neuroLevel = resetInfo.ownedAugs.get(\\\"NeuroFlux Governor\\\") ?? 0\\n await casino(ns) //Break the Casino\\n await prime(ns)\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n\\n if (HASBN9 && !await hasAllAugs(ns, \\\"Netburners\\\")) {//Netburners\\n if (MONEYCHANGE2 && player.skills.hacking >= 80) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"01/15\\\", \\\"Netburners\\\", false, false, 80, true)\\n }\\n else if (!await hasAllAugs(ns, \\\"Tian Di Hui\\\")) {//Tian Di Hui\\n if (MONEYCHANGE2 && player.factions.includes(\\\"Tian Di Hui\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"02/15\\\", \\\"Tian Di Hui\\\", false, false, false, true, { city: \\\"Chongqing\\\" })\\n }\\n else if (!await hasAllAugs(ns, \\\"NiteSec\\\")) {//NiteSec\\n if (MONEYCHANGE2 && player.factions.includes(\\\"NiteSec\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"03/15\\\", \\\"NiteSec\\\", false, true, false, false, { homeRam: 32 })\\n }\\n else if (!await hasAllAugs(ns, \\\"CyberSec\\\")) {//CyberSec\\n if (MONEYCHANGE2 && player.factions.includes(\\\"CyberSec\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"04/15\\\", \\\"CyberSec\\\", false, true, false, true)\\n }\\n //else if (neuroAmount < 30)\\n //await farmFaction(ns, \\\"xx/xx\\\", \\\"CyberSec\\\", true, false)\\n else if (!await hasAllAugs(ns, \\\"The Black Hand\\\")) {//The Black Hand\\n if (MONEYCHANGE2 && player.factions.includes(\\\"The Black Hand\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"05/15\\\", \\\"The Black Hand\\\", false, true, false, true, { homeRam: 64 })\\n }\\n else if (!await hasAllAugs(ns, \\\"BitRunners\\\")) {//BitRunners\\n if (MONEYCHANGE2 && player.factions.includes(\\\"BitRunners\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"06/15\\\", \\\"BitRunners\\\", true, true, false, true, { homeRam: 128 })\\n }\\n else if (neuroAmount < 100) {\\n if (MONEYCHANGE2 && player.factions.includes(\\\"BitRunners\\\")) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await farmFaction(ns, \\\"07/15\\\", \\\"BitRunners\\\", true, false)\\n }\\n else if (!await hasAllAugs(ns, \\\"Slum Snakes\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"08/15\\\", \\\"Slum Snakes\\\", false, false, false, true, { job: \\\"security\\\", cstats: 30, karma: -9 })\\n }\\n else if (!await hasAllAugs(ns, \\\"Tetrads\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"09/15\\\", \\\"Tetrads\\\", false, false, false, true, { job: \\\"security\\\", cstats: 75, city: \\\"Chongqing\\\", karma: -18 })\\n }\\n else if (!await hasAllAugs(ns, \\\"The Syndicate\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"10/15\\\", \\\"The Syndicate\\\", false, false, false, true, { cstats: 200, city: \\\"Sector-12\\\", hashBuy: 1e21, karma: -90 })\\n }\\n else if (!await hasAllAugs(ns, \\\"Speakers for the Dead\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"11/15\\\", \\\"Speakers for the Dead\\\", false, false, false, true, { cstats: 300, hashBuy: 50e21, karma: -45, killed: 30 })\\n }\\n else if (!await hasAllAugs(ns, \\\"The Covenant\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"12/15\\\", \\\"The Covenant\\\", true, false, false, false, { cstats: 850, hashBuy: 1e21, augsAtOnce: 3, filterNFG: true })\\n }\\n else if (!await hasAllAugs(ns, \\\"Illuminati\\\")) {\\n if (MONEYCHANGE2) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"13/15\\\", \\\"Illuminati\\\", true, false, false, false, { cstats: 1200, hashBuy: 1e21 })\\n }\\n else if (!await hasAllAugs(ns, \\\"Daedalus\\\")) {//Daedalus\\n if (MONEYCHANGE2 && player.skills.hacking >= 2000) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await factionWork(ns, \\\"14/15\\\", \\\"Daedalus\\\", true, false, false, true)\\n }\\n else {//Daedalus after Red Pill\\n if (MONEYCHANGE2 && player.skills.hacking >= 2000) {\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"money\\\")\\n ns.writePort(1, \\\"puppet money on\\\")\\n MONEYCHANGE2 = false\\n }\\n await farmFaction(ns, \\\"15/15\\\", \\\"Daedalus\\\", false, true)\\n }\\n }\\n }\\n}\\nfunction formatNum(ns, num, opt) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, opt)\\n else return ns.formatNumber(num, opt)\\n}\\n/** @param {NS} ns */\\nasync function restart(ns, augNum) {\\n const myAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n if (myAugs.length - augments.length >= augNum) {\\n UPGRADED = false\\n await dump(ns)\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n}\\nasync function dump(ns) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/dumpMoney.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n}\\n/** @param {NS} ns */\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction printLogs(ns, text) {\\n ns.printf(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"autopilot popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function prime(ns, purchaseServersOn = true, stocks = false) {\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n if (HASBN9 && moneySources?.sinceInstall[\\\"hacknet\\\"] < 1000000) await hashes(ns, 1e30, \\\"money\\\")\\n if (!UPGRADED && moneySources?.sinceInstall.casino >= 10000000000) {\\n if (await proxy(ns, \\\"singularity.getUpgradeHomeRamCost\\\") <= PRIMEMONEY)\\n while (await proxy(ns, \\\"singularity.upgradeHomeRam\\\")) { UPGRADED = true }\\n if (stocks) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) {\\n if (!await proxy(ns, \\\"stock.hasWseAccount\\\") && await proxy(ns, \\\"stock.purchaseWseAccount\\\")) UPGRADED = true\\n if (!await proxy(ns, \\\"stock.hasTixApiAccess\\\") && await proxy(ns, \\\"stock.purchaseTixApi\\\")) UPGRADED = true\\n }\\n else {\\n if (!await proxy(ns, \\\"stock.hasWSEAccount\\\") && await proxy(ns, \\\"stock.purchaseWseAccount\\\")) UPGRADED = true\\n if (!await proxy(ns, \\\"stock.hasTIXAPIAccess\\\") && await proxy(ns, \\\"stock.purchaseTixApi\\\")) UPGRADED = true\\n }\\n }\\n if (UPGRADED) {\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n else (UPGRADED = true)\\n }\\n if (purchaseServersOn && moneySources?.sinceInstall.casino >= 10000000000 && !moneySwitch) {\\n moneySwitch = true\\n ns.writePort(12, \\\"silent\\\")\\n ns.writePort(12, \\\"purchaseservers\\\")\\n ns.writePort(1, \\\"puppet autobuyservers on\\\")\\n }\\n}\\nasync function hashes(ns, moneyCeiling, type = \\\"coding\\\") {\\n if (HASBN9 && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") >= moneyCeiling) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/hacknetPurchaser.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n if (HASBN9)\\n await runIt(ns, \\\"SphyxOS/extras/hashIt.js\\\", false, [type])\\n}\\nasync function casino(ns) {\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n let CASINO = moneySources.sinceInstall?.casino >= 10e9 ? \\\"Done\\\" : \\\"Need\\\"\\n if (CASINO === \\\"Done\\\") return true\\n if (CASINO === \\\"Need\\\" && ns.peek(10) === \\\"NULL PORT DATA\\\") {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.city !== \\\"Aevum\\\" && await proxy(ns, \\\"singularity.travelToCity\\\", \\\"Aevum\\\")) {\\n if (await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") >= 10000) {\\n const pidof = await runIt(ns, \\\"SphyxOS/cheats/casino.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof) //We can do something else now\\n ns.clearPort(pidof)\\n }\\n }\\n }\\n else if (player.city === \\\"Aevum\\\" && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > 32000) {\\n const pidof = await runIt(ns, \\\"SphyxOS/cheats/casino.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof) //We can do something else now\\n ns.clearPort(pidof)\\n }\\n }\\n }\\n return false\\n}\\n/** @param {NS} ns */\\nasync function farmFaction(ns, step, faction, backdoor, end, moneyReserve = 25e12, job = \\\"hacking\\\", city = \\\"None\\\", augs = 11) {\\n let player = await proxy(ns, \\\"getPlayer\\\")\\n if (!player.factions.includes(faction)) {\\n let player = await proxy(ns, \\\"getPlayer\\\")\\n if (!player.factions.includes(faction)) {\\n if (backdoor) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/singularityBackdoor.js\\\", false, [\\\"quiet\\\", \\\"autopilot\\\"])\\n if (pidof) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Backdooring...\\\")\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n if (city !== \\\"None\\\") {\\n if (player.city !== city && !await proxy(ns, \\\"singularity.travelToCity\\\", city)) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Waiting to travel to \\\" + city)\\n await ns.asleep(1000)\\n return\\n }\\n }\\n await proxy(ns, \\\"singularity.checkFactionInvitations\\\")\\n await proxy(ns, \\\"singularity.joinFaction\\\", faction)\\n const currentWork = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (currentWork?.factionName !== faction) {\\n await proxy(ns, \\\"singularity.workForFaction\\\", faction, job, false)\\n }\\n clearLogs(ns)\\n player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.factions.includes(faction)) printLogs(ns, step + \\\" Working for \\\" + faction + \\\" for it's NeuroFlux\\\")\\n else {\\n printLogs(ns, step + \\\" Waiting to work for \\\" + faction)\\n await doCrime(ns, \\\"Money\\\")\\n }\\n }\\n }\\n else {\\n const currentWork = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (currentWork?.factionName !== faction) {\\n await proxy(ns, \\\"singularity.workForFaction\\\", faction, job, false)\\n }\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Working for \\\" + faction + \\\" for it's NeuroFlux\\\")\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/codingContracts.js\\\", false, [\\\"quiet\\\"])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n if (end) await endIt(ns)\\n if (await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > moneyReserve) {\\n await dump(ns)\\n }\\n await restart(ns, augs)\\n if (await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) < FAVOR * 3 / 4 && await proxy(ns, \\\"singularity.getFactionFavorGain\\\", faction) + await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) > FAVOR * 3 / 4) {\\n //Reset for favor\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n else if (await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) >= FAVOR * 3 / 4 && await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) < FAVOR && await proxy(ns, \\\"singularity.getFactionFavorGain\\\", faction) + await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) > FAVOR) {\\n //Reset for Max favor\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n const TRP = augments.includes(\\\"The Red Pill\\\")\\n if (GO_CHANGE && (ipvgoOpponents.includes(faction) || TRP)) {\\n GO_CHANGE = false\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, \\\"Net Off\\\")\\n ns.writePort(1, \\\"ipvgo net off\\\")\\n ns.writePort(15, \\\"Slum Off\\\")\\n ns.writePort(1, \\\"ipvgo slum off\\\")\\n ns.writePort(15, \\\"BH Off\\\")\\n ns.writePort(1, \\\"ipvgo bh off\\\")\\n ns.writePort(15, \\\"Tetrad Off\\\")\\n ns.writePort(1, \\\"ipvgo tetrad off\\\")\\n ns.writePort(15, \\\"Daed Off\\\")\\n ns.writePort(1, \\\"ipvgo daed off\\\")\\n ns.writePort(15, \\\"Illum Off\\\")\\n ns.writePort(1, \\\"ipvgo illum off\\\")\\n ns.writePort(15, \\\"???? Off\\\")\\n ns.writePort(1, \\\"ipvgo ???? off\\\")\\n if (TRP) {\\n ns.writePort(15, \\\"???? On\\\")\\n ns.writePort(1, \\\"ipvgo ???? on\\\")\\n }\\n else {\\n if (currentNode === 9) {\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n }\\n else {\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n }\\n switch (faction) {\\n case \\\"Netburners\\\":\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n break\\n case \\\"Slum Snakes\\\":\\n ns.writePort(15, \\\"Slum On\\\")\\n ns.writePort(1, \\\"ipvgo slum on\\\")\\n break\\n case \\\"The Black Hand\\\":\\n ns.writePort(15, \\\"BH On\\\")\\n ns.writePort(1, \\\"ipvgo bh on\\\")\\n break\\n case \\\"Tetrads\\\":\\n ns.writePort(15, \\\"Tetrad On\\\")\\n ns.writePort(1, \\\"ipvgo tetrad on\\\")\\n break\\n case \\\"Daedalus\\\":\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n break\\n case \\\"Illuminati\\\":\\n ns.writePort(15, \\\"Illum On\\\")\\n ns.writePort(1, \\\"ipvgo illum on\\\")\\n break\\n }\\n }\\n }\\n else if (GO_CHANGE) {\\n GO_CHANGE = false\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, \\\"Net Off\\\")\\n ns.writePort(1, \\\"ipvgo net off\\\")\\n ns.writePort(15, \\\"Slum Off\\\")\\n ns.writePort(1, \\\"ipvgo slum off\\\")\\n ns.writePort(15, \\\"BH Off\\\")\\n ns.writePort(1, \\\"ipvgo bh off\\\")\\n ns.writePort(15, \\\"Tetrad Off\\\")\\n ns.writePort(1, \\\"ipvgo tetrad off\\\")\\n ns.writePort(15, \\\"Daed Off\\\")\\n ns.writePort(1, \\\"ipvgo daed off\\\")\\n ns.writePort(15, \\\"Illum Off\\\")\\n ns.writePort(1, \\\"ipvgo illum off\\\")\\n ns.writePort(15, \\\"???? Off\\\")\\n ns.writePort(1, \\\"ipvgo ???? off\\\")\\n if (currentNode === 9) {\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n }\\n else {\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n }\\n }\\n await ns.asleep(1000)\\n}\\n/** @param {NS} ns */\\nasync function factionWork(ns, step, faction, breakToMaxFavor, backdoor, hacknetPurchase, restart, settings) {\\n const job = settings?.job ?? \\\"hacking\\\"\\n const cstats = settings?.cstats ?? 0\\n const city = settings?.city ?? \\\"None\\\"\\n const hashBuy = settings?.hashBuy ?? 1e12\\n const homeRam = settings?.homeRam ?? 0\\n const karma = settings?.karma ?? 0\\n const killed = settings?.killed ?? 0\\n const hashType = settings?.hashType ?? \\\"coding\\\"\\n const hackLvl = settings?.hackLvl ?? 0\\n const buyRep = settings?.buyRep ?? true\\n const augsAtOnce = settings?.augsAtOnce ?? 11\\n const filterNFG = settings?.filterNFG ?? false\\n const moneySaved = settings?.moneySaved ?? 1000000\\n const buyAugs = settings?.buyAugs ?? true\\n\\n let player = await proxy(ns, \\\"getPlayer\\\")\\n if (!player.factions.includes(faction)) {\\n await proxy(ns, \\\"singularity.checkFactionInvitations\\\")\\n await ns.asleep(4)\\n await proxy(ns, \\\"singularity.joinFaction\\\", faction)\\n const player2 = await proxy(ns, \\\"getPlayer\\\")\\n if (player2.factions.includes(faction)) return\\n if (backdoor) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/singularityBackdoor.js\\\", false, [\\\"quiet\\\", \\\"autopilot\\\"])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n const moneySources = await proxy(ns, \\\"getMoneySources\\\")\\n if (moneySources?.sinceInstall.casino >= 10000000000) {\\n if (homeRam > await proxy(ns, \\\"getServerMaxRam\\\", \\\"home\\\"))\\n await proxy(ns, \\\"singularity.upgradeHomeRam\\\")\\n if (hacknetPurchase && player.skills.hacking >= hacknetPurchase) {\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/hacknetPurchaser.js\\\", false, [])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n if (HASBN9 && hashType !== \\\"None\\\") {\\n const ports = await getPortOpeners(ns)\\n if (ports < 5) await hashes(ns, hashBuy, \\\"money\\\")\\n await hashes(ns, hashBuy, hashType)\\n }\\n const skills = player.skills\\n const wrk = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (skills.hacking < hacknetPurchase || skills.hacking < hackLvl) {\\n if (player.city !== \\\"Sector-12\\\" && !await proxy(ns, \\\"singularity.travelToCity\\\", \\\"Sector-12\\\")) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Waiting to travel to Sector-12\\\")\\n await doCrime(ns, \\\"Money\\\")\\n await ns.asleep(1000)\\n return\\n }\\n clearLogs(ns)\\n const highest = hacknetPurchase > hackLvl ? hacknetPurchase : hackLvl\\n printLogs(ns, step + \\\" Train Hack to \\\" + highest)\\n if (wrk === null || wrk.classType !== \\\"Computer Science\\\")\\n await proxy(ns, \\\"singularity.universityCourse\\\", \\\"Rothman University\\\", \\\"Computer Science\\\", FOCUS)\\n await ns.asleep(1000)\\n return\\n }\\n\\n if (cstats > 0 && (skills.agility < cstats || skills.strength < cstats || skills.defense < cstats || skills.dexterity < cstats)) {\\n if (player.city !== \\\"Sector-12\\\" && !await proxy(ns, \\\"singularity.travelToCity\\\", \\\"Sector-12\\\")) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Waiting to travel to Sector-12\\\")\\n await doCrime(ns, \\\"Money\\\")\\n await ns.asleep(1000)\\n return\\n }\\n if (skills.strength < cstats) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Train Str to \\\" + cstats)\\n if (wrk === null || wrk.classType !== \\\"str\\\")\\n await proxy(ns, \\\"singularity.gymWorkout\\\", \\\"Powerhouse Gym\\\", \\\"str\\\", FOCUS)\\n }\\n else if (skills.agility < cstats) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Train Agi to \\\" + cstats)\\n if (wrk === null || wrk.classType !== \\\"agi\\\")\\n await proxy(ns, \\\"singularity.gymWorkout\\\", \\\"Powerhouse Gym\\\", \\\"agi\\\", FOCUS)\\n }\\n else if (skills.defense < cstats) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Train Def to \\\" + cstats)\\n if (wrk === null || wrk.classType !== \\\"def\\\")\\n await proxy(ns, \\\"singularity.gymWorkout\\\", \\\"Powerhouse Gym\\\", \\\"def\\\", FOCUS)\\n }\\n else {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Train Dex to \\\" + cstats)\\n if (wrk === null || wrk.classType !== \\\"dex\\\")\\n await proxy(ns, \\\"singularity.gymWorkout\\\", \\\"Powerhouse Gym\\\", \\\"dex\\\", FOCUS)\\n }\\n await ns.asleep(1000)\\n return\\n }\\n if (karma !== 0 && karma < 0 && ns.heart.break() > karma) { //One day there may be positive karma. I know I tried once.\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Need Karma\\\")\\n await doCrime(ns, \\\"Karma\\\")\\n await ns.asleep(1000)\\n return\\n }\\n if (player.numPeopleKilled < killed) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Need Kills\\\")\\n await doCrime(ns, \\\"Killed\\\")\\n await ns.asleep(1000)\\n return\\n }\\n if (city !== \\\"None\\\") {\\n if (player.city !== city && !await proxy(ns, \\\"singularity.travelToCity\\\", city)) {\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Waiting to travel to \\\" + city)\\n await doCrime(ns, \\\"Money\\\")\\n await ns.asleep(1000)\\n return\\n }\\n }\\n }\\n await proxy(ns, \\\"singularity.checkFactionInvitations\\\")\\n await ns.asleep(4)\\n await proxy(ns, \\\"singularity.joinFaction\\\", faction)\\n const currentWork = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (job !== \\\"none\\\" && currentWork?.factionName !== faction)\\n await proxy(ns, \\\"singularity.workForFaction\\\", faction, job, FOCUS)\\n clearLogs(ns)\\n player = await proxy(ns, \\\"getPlayer\\\")\\n if (player.factions.includes(faction)) printLogs(ns, step + \\\" Working for \\\" + faction)\\n else {\\n printLogs(ns, step + \\\" Waiting to work for \\\" + faction)\\n await doCrime(ns, \\\"Money\\\")\\n }\\n }\\n else {\\n const currentWork = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (job !== \\\"none\\\" && currentWork?.factionName !== faction)\\n await proxy(ns, \\\"singularity.workForFaction\\\", faction, job, FOCUS)\\n if (HASBN3 && await proxy(ns, \\\"singularity.getFactionRep\\\", faction) < await maxRepNeeded(ns, faction)) {\\n const corp = await proxyTry(ns, \\\"corporation.getCorporation\\\")\\n if (corp && corp.valuation >= 100000000000000) {\\n await proxyTry(ns, \\\"corporation.bribe\\\", faction, corp.funds / 100)\\n }\\n }\\n if (buyAugs && !await hasAllAugs(ns, faction) && await proxy(ns, \\\"singularity.getFactionRep\\\", faction) >= await maxRepNeeded(ns, faction) && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > await maxMoneyNeeded(ns, faction)) {\\n let augsFromFaction = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n augsFromFaction = augsFromFaction.filter(f => f !== \\\"NeuroFlux Governor\\\")\\n\\n let augs = []\\n for (const aug of augsFromFaction) {\\n const record = {\\n \\\"Name\\\": aug,\\n \\\"Price\\\": await proxy(ns, \\\"singularity.getAugmentationPrice\\\", aug)\\n }\\n augs.push(record)\\n }\\n augs = augs.toSorted((a, b) => b.Price - a.Price)\\n let augCheck = true\\n while (augCheck && await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\") > await maxMoneyNeeded(ns, faction)) {\\n augCheck = false\\n for (const aug of augs)\\n if (await proxy(ns, \\\"singularity.purchaseAugmentation\\\", faction, aug.Name)) {\\n augCheck = true\\n break\\n }\\n }\\n }\\n else if (HASBN9 && hashType !== \\\"None\\\") {\\n const ports = await getPortOpeners(ns)\\n if (ports < 5) await hashes(ns, hashBuy, \\\"money\\\")\\n await hashes(ns, hashBuy, hashType)\\n }\\n clearLogs(ns)\\n printLogs(ns, step + \\\" Working for \\\" + faction)\\n const pidof = await runIt(ns, \\\"SphyxOS/bins/codingContracts.js\\\", false, [\\\"quiet\\\"])\\n if (pidof) {\\n await ns.nextPortWrite(pidof)\\n ns.clearPort(pidof)\\n }\\n }\\n const myAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const augments = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\")\\n if (restart && myAugs.length - augments.length >= augsAtOnce) {\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n const augs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\")\\n const TRP = augs.includes(\\\"The Red Pill\\\")\\n if (GO_CHANGE && (ipvgoOpponents.includes(faction) || TRP)) {\\n GO_CHANGE = false\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, \\\"Net Off\\\")\\n ns.writePort(1, \\\"ipvgo net off\\\")\\n ns.writePort(15, \\\"Slum Off\\\")\\n ns.writePort(1, \\\"ipvgo slum off\\\")\\n ns.writePort(15, \\\"BH Off\\\")\\n ns.writePort(1, \\\"ipvgo bh off\\\")\\n ns.writePort(15, \\\"Tetrad Off\\\")\\n ns.writePort(1, \\\"ipvgo tetrad off\\\")\\n ns.writePort(15, \\\"Daed Off\\\")\\n ns.writePort(1, \\\"ipvgo daed off\\\")\\n ns.writePort(15, \\\"Illum Off\\\")\\n ns.writePort(1, \\\"ipvgo illum off\\\")\\n ns.writePort(15, \\\"???? Off\\\")\\n ns.writePort(1, \\\"ipvgo ???? off\\\")\\n if (TRP) {\\n ns.writePort(15, \\\"???? On\\\")\\n ns.writePort(1, \\\"ipvgo ???? on\\\")\\n }\\n else {\\n if (currentNode === 9) {\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n }\\n else {\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n }\\n switch (faction) {\\n case \\\"Netburners\\\":\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n break\\n case \\\"Slum Snakes\\\":\\n ns.writePort(15, \\\"Slum On\\\")\\n ns.writePort(1, \\\"ipvgo slum on\\\")\\n break\\n case \\\"The Black Hand\\\":\\n ns.writePort(15, \\\"BH On\\\")\\n ns.writePort(1, \\\"ipvgo bh on\\\")\\n break\\n case \\\"Tetrads\\\":\\n ns.writePort(15, \\\"Tetrad On\\\")\\n ns.writePort(1, \\\"ipvgo tetrad on\\\")\\n break\\n case \\\"Daedalus\\\":\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n break\\n case \\\"Illuminati\\\":\\n ns.writePort(15, \\\"Illum On\\\")\\n ns.writePort(1, \\\"ipvgo illum on\\\")\\n break\\n }\\n }\\n }\\n else if (GO_CHANGE) {\\n GO_CHANGE = false\\n ns.writePort(15, \\\"Silent\\\")\\n ns.writePort(15, \\\"Net Off\\\")\\n ns.writePort(1, \\\"ipvgo net off\\\")\\n ns.writePort(15, \\\"Slum Off\\\")\\n ns.writePort(1, \\\"ipvgo slum off\\\")\\n ns.writePort(15, \\\"BH Off\\\")\\n ns.writePort(1, \\\"ipvgo bh off\\\")\\n ns.writePort(15, \\\"Tetrad Off\\\")\\n ns.writePort(1, \\\"ipvgo tetrad off\\\")\\n ns.writePort(15, \\\"Daed Off\\\")\\n ns.writePort(1, \\\"ipvgo daed off\\\")\\n ns.writePort(15, \\\"Illum Off\\\")\\n ns.writePort(1, \\\"ipvgo illum off\\\")\\n ns.writePort(15, \\\"???? Off\\\")\\n ns.writePort(1, \\\"ipvgo ???? off\\\")\\n if (currentNode === 9) {\\n ns.writePort(15, \\\"Net On\\\")\\n ns.writePort(1, \\\"ipvgo net on\\\")\\n }\\n else {\\n ns.writePort(15, \\\"Daed On\\\")\\n ns.writePort(1, \\\"ipvgo daed on\\\")\\n }\\n }\\n if (breakToMaxFavor) {\\n if (await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) < FAVOR * 3 / 4 && await proxy(ns, \\\"singularity.getFactionFavorGain\\\", faction) + await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) > FAVOR * 3 / 4) {\\n //Reset for favor\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n else if (await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) >= FAVOR * 3 / 4 && await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) < FAVOR && await proxy(ns, \\\"singularity.getFactionFavorGain\\\", faction) + await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) > FAVOR) {\\n //Reset for Max favor\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n await proxy(ns, \\\"singularity.softReset\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n }\\n if (buyRep && await proxy(ns, \\\"singularity.getFactionFavor\\\", faction) >= FAVOR) {\\n const maxRep = await maxRepNeeded(ns, faction, filterNFG)\\n if (await proxy(ns, \\\"singularity.getFactionRep\\\", faction) < maxRep) {\\n const donate = await getReputationFromDonation(ns, 1e6) //Rep for donating 1e6 dollars\\n const rep = await proxy(ns, \\\"singularity.getFactionRep\\\", faction)\\n const targetrep = maxRep\\n const maxDonate = ((targetrep - rep) / donate * 1e6) + 1\\n const moneyAvailable = await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\")\\n await proxy(ns, \\\"singularity.donateToFaction\\\", faction, Math.min(moneyAvailable - moneySaved, maxDonate))\\n }\\n }\\n if (restart && await hasAllAugs(ns, faction)) {\\n await dump(ns)\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n await ns.asleep(1000)\\n}\\n/** @param {NS} ns */\\nasync function gangCheck(ns) {\\n const player = await proxy(ns, \\\"getPlayer\\\")\\n const total = await totalAugs(ns, \\\"Slum Snakes\\\", true)\\n const myMoney = await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\")\\n const maxMoney = Math.min(await currentMaxUnlockCost(ns, \\\"Slum Snakes\\\"), 8e9)\\n const hasMoney = myMoney >= maxMoney\\n const waiting = await augsWaiting(ns)\\n if ((await totalAugs(ns, \\\"Slum Snakes\\\") === total && total !== 0 && hasMoney) || (total + waiting > 11 && waiting === 0 && hasMoney) || (total + waiting > 11 && waiting > 0)) {\\n await dump(ns)\\n }\\n if (await augsWaiting(ns) >= 8) {\\n UPGRADED = false\\n await proxy(ns, \\\"singularity.installAugmentations\\\", \\\"SphyxOS/singularity/restart.js\\\")\\n }\\n if (player.skills.hacking >= 15000) await endIt(ns)\\n}\\n/** @param {NS} ns */\\nasync function augsWaiting(ns) {\\n const augs1 = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const augs2 = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", false)\\n return augs1.length - augs2.length\\n}\\n/** @param {NS} ns */\\nasync function totalAugs(ns, faction, onlyUnlocked = false) {\\n const allFacAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const allAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const factionAugs = allFacAugs.filter(f => f !== \\\"NeuroFlux Governor\\\" && !allAugs.includes(f))\\n let count = 0\\n const rep = await proxy(ns, \\\"singularity.getFactionRep\\\", faction)\\n for (const aug of factionAugs) {\\n if (onlyUnlocked) {\\n if (rep >= await proxy(ns, \\\"singularity.getAugmentationRepReq\\\", aug)) count++\\n }\\n else count++\\n }\\n return count\\n}\\n/** @param {NS} ns */\\nasync function hasAllAugs(ns, faction) {\\n const allAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const factionAugs = allAugs.filter(f => f !== \\\"NeuroFlux Governor\\\")\\n const ownedAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n for (const aug of factionAugs) {\\n if (!ownedAugs.includes(aug)) return false\\n }\\n return true\\n}\\n/** @param {NS} ns */\\nasync function maxRepNeeded(ns, faction, filterNFG = true) {\\n const allFacAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const allAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n let factionAugs\\n if (filterNFG) factionAugs = allFacAugs.filter(f => f !== \\\"NeuroFlux Governor\\\" && !allAugs.includes(f))\\n else factionAugs = allFacAugs.filter(aug => !allAugs.includes(aug))\\n let repNeeded = 0\\n for (const aug of factionAugs) {\\n const rep = await proxy(ns, \\\"singularity.getAugmentationRepReq\\\", aug)\\n if (rep > repNeeded) repNeeded = rep\\n }\\n return repNeeded\\n}\\n/** @param {NS} ns */\\nasync function maxMoneyNeeded(ns, faction) {\\n const allFacAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const allAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const factionAugs = allFacAugs.filter(f => f !== \\\"NeuroFlux Governor\\\" && !allAugs.includes(f))\\n let moneyNeeded = 0\\n for (const aug of factionAugs) {\\n const money = await proxy(ns, \\\"singularity.getAugmentationPrice\\\", aug)\\n if (money > moneyNeeded) moneyNeeded = money\\n }\\n return moneyNeeded\\n}\\n/** @param {NS} ns */\\nasync function currentMaxUnlockCost(ns, faction) {\\n const allFacAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const allAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const tmp = allFacAugs.filter(f => f !== \\\"NeuroFlux Governor\\\" && !allAugs.includes(f))\\n const factionAugs = []\\n const myRep = await proxy(ns, \\\"singularity.getFactionRep\\\", faction)\\n for (const aug of tmp) {\\n const rep = await proxy(ns, \\\"singularity.getAugmentationRepReq\\\", aug)\\n if (myRep >= rep) factionAugs.push(aug)\\n }\\n let moneyNeeded = 0\\n for (const aug of factionAugs) {\\n const money = await proxy(ns, \\\"singularity.getAugmentationPrice\\\", aug)\\n if (money > moneyNeeded) moneyNeeded = money\\n }\\n return moneyNeeded\\n}\\n/** @param {NS} ns */\\nasync function endIt(ns) {\\n //We need to upgrade ram to a certain minimum.\\n const maxRam = await maxRun(ns, false)\\n if (maxRam < 256 && await getServerAvailRam(ns, \\\"home\\\") < 256) {\\n const upgCost = await doGetScriptRam(ns, \\\"SphyxOS/singularity/upgradeHomeRam.js\\\")\\n if (maxRam >= upgCost) await upgHomeRam(ns)\\n }\\n else if (maxRam >= 256) {\\n const nextBN = await getNextBN(ns)\\n if (MOVEON) await destroyWD(ns, nextBN, \\\"SphyxOS/singularity/restart.js\\\")\\n else {\\n if (!ns.fileExists(\\\"b1t_flum3.exe\\\")) {\\n while (!ns.fileExists(\\\"b1t_flum3.exe\\\", \\\"home\\\")) {\\n clearLogs(ns)\\n printLogs(ns, \\\"Creating b1t_flum3.exe. Please wait\\\")\\n await proxy(ns, \\\"singularity.createProgram\\\", \\\"b1t_flum3.exe\\\")\\n await ns.asleep(5000)\\n }\\n }\\n UPGRADED = false\\n await destroyWD(ns, 1, \\\"SphyxOS/singularity/flume.js\\\")\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function getNextBN(ns) {\\n let nextbn = 0\\n let nextbnlvl = 0\\n for (let check of bnorder) {\\n let isthere = false\\n const sourceFiles = await getOwnedSF(ns)\\n for (const bn of sourceFiles) {\\n let bonus = 0\\n const resetInfo = await getResetInf(ns)\\n if (resetInfo.currentNode == check[0]) bonus = 1\\n if (bn.n == check[0] && bn.lvl + bonus >= check[1]) isthere = true\\n if (bn.n == resetInfo.currentNode && 1 >= check[1]) isthere = true\\n if (currentNode === check[0] && 1 >= check[1]) isthere = true\\n }\\n if (isthere == false) {\\n nextbn = check[0]\\n nextbnlvl = check[1]\\n break\\n }\\n }\\n let value = ns.sprintf(\\\"%s\\\" + \\\".\\\" + \\\"%s\\\", nextbn, nextbnlvl)\\n return Number.parseInt(value)\\n}\\n/** @param {NS} ns */\\nasync function loadStanek(ns) {\\n let defaultFileLocation = \\\"/SphyxOS/stanek/loadouts/\\\"\\n await proxy(ns, \\\"stanek.acceptGift\\\")\\n const homeFiles = await proxy(ns, \\\"ls\\\", \\\"home\\\", defaultFileLocation)\\n const files = homeFiles.map(m => [m.substring(defaultFileLocation.length - 1), defaultFileLocation])\\n\\n let usableFiles = []\\n for (const testFile of files) {\\n //const testFile = file.substring(12)\\n const [width, hight, ...fileName] = testFile[0].substring(0, testFile[0].length - 4).split(\\\"x\\\")\\n if (width <= await proxy(ns, \\\"stanek.giftWidth\\\") && hight <= await proxy(ns, \\\"stanek.giftHeight\\\") && fileName.includes(\\\"autoPilot\\\"))\\n usableFiles.push([width + \\\"x\\\" + hight + \\\"x\\\" + fileName.join(\\\"x\\\"), testFile[1]])\\n }\\n usableFiles = usableFiles.sort((a, b) => {\\n const [width, height] = a[0].split(\\\"x\\\")\\n const [width2, height2] = b[0].split(\\\"x\\\")\\n return (width2 + height2) - (width + height)\\n })\\n const selectable = []\\n for (const usableFile of usableFiles) {\\n selectable.push(usableFile[0])\\n }\\n const chosen = selectable.shift()\\n if (chosen === \\\"\\\") {\\n ns.toast(\\\"No loadout for Stanek found!\\\", \\\"error\\\", 3000)\\n ns.exit()\\n }\\n else {\\n ns.stanek.clearGift()\\n for (const file of usableFiles) {\\n if (chosen === file[0]) {\\n defaultFileLocation = file[1]\\n break\\n }\\n }\\n await proxy(ns, \\\"scp\\\", defaultFileLocation + chosen + \\\".txt\\\", ns.self().server, \\\"home\\\")\\n const file = JSON.parse(ns.read(defaultFileLocation + chosen + \\\".txt\\\"))\\n for (const frag of file) {\\n //.x, .y, .rotation, .id\\n await proxy(ns, \\\"stanek.placeFragment\\\", frag.x, frag.y, frag.rotation, frag.id)\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function allSleevesUpgraded(ns) {\\n const numSleeves = await proxy(ns, \\\"sleeve.getNumSleeves\\\")\\n if (await maxSleeves(ns) > numSleeves) return false\\n for (let slv = 0; slv < numSleeves; slv++) {\\n const mrBean = await proxy(ns, \\\"sleeve.getSleeve\\\", slv)\\n if (mrBean.memory < 100) return false\\n }\\n return true\\n}\\nasync function maxSleeves(ns) {\\n const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n const sourceFiles = []\\n for (const item of resetInfo.ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let added = currentNode === 10 ? 1 : 0\\n for (const sf of sourceFiles) if (sf.n === 10) {\\n added += sf.lvl === 3 ? 2 : sf.lvl\\n }\\n return 5 + added\\n}\\n\\n\\n/** @param {NS} ns */\\nasync function doCrime(ns, type, slv = null) {\\n //Cycle our crimes and find the best for our mode.\\n const me = slv === null ? await proxy(ns, \\\"getPlayer\\\") : await proxy(ns, \\\"sleeve.getSleeve\\\", slv)\\n let bestRatio = 0\\n let bestCrime = \\\"Mug\\\"\\n for (const crime of crimes) {\\n const chance = getChance(crime, me)\\n const gain = type === \\\"Money\\\" ? crime.money : type === \\\"Karma\\\" ? crime.karma : type === \\\"Killed\\\" ? crime.kills : crime.intelligence_exp\\n const ratio = gain * chance / crime.time\\n if (ratio > bestRatio) {\\n bestRatio = ratio\\n bestCrime = crime.name\\n }\\n }\\n if (slv === null) {\\n const maxRam = await maxRun(ns, false, false)\\n if (maxRam < ns.getFunctionRamCost(\\\"singularity.commitCrime\\\") + 1.6)\\n return\\n const task = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (task?.crimeType !== bestCrime) {\\n await proxyTry(ns, \\\"singularity.commitCrime\\\", bestCrime, FOCUS)\\n if (maxRam < ns.getFunctionRamCost(\\\"singularity.commitCrime\\\") + 1.6) {\\n ns.toast(\\\"Please commit \\\" + bestCrime, \\\"info\\\", 10000)\\n await ns.asleep(10000)\\n }\\n }\\n }\\n else {\\n const task = await proxy(ns, \\\"sleeve.getTask\\\", slv)\\n if (task?.crimeType !== bestCrime)\\n await proxyTry(ns, \\\"sleeve.setToCommitCrime\\\", slv, bestCrime)\\n }\\n}\\n\\nfunction getChance(crimestats, person) {\\n let hackweight = crimestats.hacking_success_weight * person.skills.hacking\\n let strweight = crimestats.strength_success_weight * person.skills.strength\\n let defweight = crimestats.defense_success_weight * person.skills.defense\\n let dexweight = crimestats.dexterity_success_weight * person.skills.dexterity\\n let agiweight = crimestats.agility_success_weight * person.skills.agility\\n let chaweight = crimestats.charisma_success_weight * person.skills.charisma\\n let intweight = HASBN5 ? 0.025 * person.skills.intelligence : 0\\n let chance = hackweight + strweight + defweight + dexweight + agiweight + chaweight + intweight\\n chance /= 975\\n chance /= crimestats.difficulty\\n chance *= person.mults.crime_success\\n if (HASBN5) chance *= 1 + (1 * Math.pow(person.skills.intelligence, 0.8)) / 600\\n chance *= 100\\n return Math.min(chance, 100)\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(22) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(22)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"AutoPilot\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Autopilot will use a popout\\\")\\n if (win) win.header(MOVEON ? \\\"AutoPilot - Will move on\\\" : \\\"AutoPilot - Will not move on\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n win = false\\n if (!silent) ns.tprintf(\\\"Autopilot will not use a popout\\\")\\n break\\n case \\\"moveon\\\":\\n MOVEON = true\\n if (!silent) ns.tprintf(\\\"Autopilot will move on when done\\\")\\n ns.ui.setTailTitle(\\\"AutoPilot - Will move on\\\")\\n if (win) win.header(\\\"AutoPilot - Will move on\\\")\\n break;\\n case \\\"nomoveon\\\":\\n MOVEON = false\\n if (!silent) ns.tprintf(\\\"Autopilot will not move on when done\\\")\\n ns.ui.setTailTitle(\\\"AutoPilot - Will not move on\\\")\\n if (win) win.header(\\\"AutoPilot - Will not move on\\\")\\n break;\\n case \\\"silent\\\":\\n silent = true\\n break;\\n default:\\n ns.tprintf(\\\"Invalid command received in Autopilot: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nconst crimes = [\\n {\\n \\\"name\\\": \\\"Shoplift\\\",\\n \\\"time\\\": 2e3,\\n \\\"money\\\": 15e3,\\n \\\"difficulty\\\": 1 / 20,\\n \\\"karma\\\": 0.1,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },/*\\n {\\n \\\"name\\\": \\\"Rob Store\\\",\\n \\\"time\\\": 60e3,\\n \\\"money\\\": 400e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.5,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 7.5 * 0.05\\n },*/\\n {\\n \\\"name\\\": \\\"Mug\\\",\\n \\\"time\\\": 4e3,\\n \\\"money\\\": 36e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.25,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1.5,\\n \\\"defense_success_weight\\\": 0.5,\\n \\\"dexterity_success_weight\\\": 1.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },/*\\n {\\n \\\"name\\\": \\\"Larceny\\\",\\n \\\"time\\\": 90e3,\\n \\\"money\\\": 800e3,\\n \\\"difficulty\\\": 1 / 3,\\n \\\"karma\\\": 1.5,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 15 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Deal Drugs\\\",\\n \\\"time\\\": 10e3,\\n \\\"money\\\": 120e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 0.5,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 3,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Bond Forgery\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 4.5e6,\\n \\\"difficulty\\\": 1 / 2,\\n \\\"karma\\\": 0.1,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0.05,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1.25,\\n \\\"agility_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 60 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Traffick Arms\\\",\\n \\\"time\\\": 40e3,\\n \\\"money\\\": 600e3,\\n \\\"difficulty\\\": 2,\\n \\\"karma\\\": 1,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },*/\\n {\\n \\\"name\\\": \\\"Homicide\\\",\\n \\\"time\\\": 3e3,\\n \\\"money\\\": 45e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 3,\\n \\\"kills\\\": 1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 2,\\n \\\"defense_success_weight\\\": 2,\\n \\\"dexterity_success_weight\\\": 0.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n }/*,\\n {\\n \\\"name\\\": \\\"Grand Theft Auto\\\",\\n \\\"time\\\": 80e3,\\n \\\"money\\\": 1.6e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 5,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 4,\\n \\\"agility_success_weight\\\": 2,\\n \\\"charisma_success_weight\\\": 2,\\n \\\"intelligence_exp\\\": 16 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Kidnap\\\",\\n \\\"time\\\": 120e3,\\n \\\"money\\\": 3.6e6,\\n \\\"difficulty\\\": 5,\\n \\\"karma\\\": 6,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 26 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Assassination\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 12e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 10,\\n \\\"kills\\\": 1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 65 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Heist\\\",\\n \\\"time\\\": 600e3,\\n \\\"money\\\": 120e6,\\n \\\"difficulty\\\": 18,\\n \\\"karma\\\": 15,\\n \\\"kills\\\": 0,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 130 * 0.05\\n }*/\\n]\\n//[[0, 1]] [0] is Node, [1] is lvl\\nconst bnorder = [[4, 3], [5, 1], [3, 3], [10, 3], [7, 1], [9, 3], [14, 3], [13, 3], [1, 3], [2, 3], [7, 3], [6, 3], [8, 3], [5, 3], [11, 3], [12, 99999]]\\nconst ipvgoOpponents = [\\\"Tetrads\\\", \\\"The Black Hand\\\", \\\"Daedalus\\\", \\\"Illuminati\\\", \\\"????????????\\\"]\\n//const ipvgoOpponents = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\", \\\"????????????\\\"]\""},{"filename":"SphyxOS/bins/bb.js","file":"\"import { hasBN, getPlay, getBNMults, getResetInf, doGetScriptRam, getServerAvailRam, maxRun } from \\\"SphyxOS/util.js\\\"\\nimport { doCrime, travelCity, setGym, getOwnedSF, destroyWD, upgHomeRam } from \\\"SphyxOS/util.js\\\"\\nimport { sleeveGetNum, sleeveGet, sleeveShockRecovery, sleeveIdle, sleeveSetToBBAction, sleeveGetAugs } from \\\"SphyxOS/util.js\\\"\\nimport { bbJoinBBDiv, bbJoinBBFac, bbGetStam, bbGetCity, bbGetCityChaos, bbGetActionEstSuccessChance, bbGetSkillPoints } from \\\"SphyxOS/util.js\\\"\\nimport { bbSetActionAutoLvl, bbGetSkillLevel, bbGetActionMaxLvl, bbGetActionCountRemain, bbGetCurrentAction, bbUpgradeSkill } from \\\"SphyxOS/util.js\\\"\\nimport { bbGetSkillUpgradeCost, bbSwitchCity, bbSetActionLevel, bbGetActionTime, bbStartAction, bbGetActionCurTime, bbGetRank } from \\\"SphyxOS/util.js\\\"\\nimport { bbGetCityEstPop, bbGetCityComms, bbGetActionRepGain, bbGetBlackOpRank, bbGetActionCurLvl, makeNewWindow, proxy, proxyTry } from \\\"SphyxOS/util.js\\\"\\nimport { reservedRam } from \\\"SphyxOS/util.js\\\"\\n\\nconst STARTUP_SCRIPT = \\\"SphyxOS/bladeBurner/restart.js\\\"\\nlet FINISHER = false\\nlet INTMODE = false\\nlet LVLUP = 1\\nlet SLEEVEINFILSTATUS = false\\nlet SLEEVES_ENABLED = false\\nlet HASBN4 = false\\nconst HEIGHT = 710\\nconst WIDTH = 760\\nconst CSTATS = 100\\nconst TRAIN_STATS = 110\\nconst SLEEVE_STATS = 5\\nconst TRAIN_STAMINA = 50\\nconst CHAOS_TOP = 60\\nconst CHAOS_FLOOR = 55\\nconst BOPS_SUCCESS_TRY = .8\\nconst MIN_CHANCE_SUCCESS = .85\\nconst SLEEVE_SHOCK = 98\\nconst SLEEVE_CHANCE = .85\\nlet PRIORITY_CITY = false\\nlet sleeve_infil = false\\nlet sleeve_analyze = false\\nlet sleeve_bounty = false\\nlet sleeve_retire = false\\nlet sleeve_tracking = false\\nlet sleeve_diplomacy = false\\nlet sleeve_working = 0\\nconst queues = []\\nlet queuestask = [null, null, null, null]\\nlet queueswait = 0\\nlet endItCost;\\nlet win\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n win = false\\n ns.atExit(() => {\\n if (win) win.close()\\n })\\n ns.clearPort(8)\\n ns.writePort(8, ns.pid)\\n getCommands(ns)\\n await init(ns)\\n //Are we already in or do we have the stats for it?\\n let joined = await bbJoinBBDiv(ns)\\n while (!joined) {\\n joined = await bbJoinBBDiv(ns)\\n await trainUp(ns)\\n await ns.asleep(1000)\\n }\\n if (HASBN4 && await hasBN(ns, 7, 3) && await maxRun(ns, false) >= await doGetScriptRam(ns, \\\"SphyxOS/singularity/commitCrime.js\\\"))\\n await doCrime(ns, \\\"Mug\\\")\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n for (const contract of ns.bladeburner.getContractNames())\\n await bbSetActionAutoLvl(ns, \\\"Contracts\\\", contract, false)\\n for (const op of ns.bladeburner.getOperationNames())\\n await bbSetActionAutoLvl(ns, \\\"Operations\\\", op, false)\\n const joinBBFacCost = await doGetScriptRam(ns, \\\"SphyxOS/bladeBurner/joinBBFac.js\\\")\\n\\n while (true) { //Main loop\\n const maxRam = await maxRun(ns, false)\\n if (HASBN4) await endIt(ns)\\n if (maxRam >= joinBBFacCost) await bbJoinBBFac(ns)\\n await ns.asleep(0)\\n await updatedisplay(ns)\\n ns.ui.renderTail()\\n await ns.bladeburner.nextUpdate()\\n await updateskills(ns)\\n await ns.asleep(0)\\n if (SLEEVES_ENABLED) await updatesleeves(ns)\\n await ns.asleep(0)\\n if (queueswait > performance.now()) continue //Trap inside the start of the loop until our job is done\\n if (queues.length > 0) { //We have a queued command\\n await runmission(ns, queues.shift())\\n continue\\n }\\n const chaos = await checkChaos(ns)\\n if (chaos) {\\n queue(\\\"General\\\", \\\"Diplomacy\\\", chaos, 1)\\n continue\\n }\\n const stamina = await bbGetStam(ns)\\n const city = await bbGetCity(ns)\\n const trainStats = await getTrainStats(ns)\\n if (trainStats < TRAIN_STATS || stamina[1] < TRAIN_STAMINA) {\\n queue(\\\"General\\\", \\\"Training\\\", city, 1)\\n continue\\n }\\n if (stamina[0] / stamina[1] < .55) {\\n queue(\\\"General\\\", \\\"Hyperbolic Regeneration Chamber\\\", city, 1)\\n queue(\\\"General\\\", \\\"Training\\\", city, 1)\\n continue\\n }\\n let diff = .15\\n if (SLEEVES_ENABLED)\\n diff = 0\\n const tracking = await checkTracking(ns, diff)\\n if (tracking) {\\n const bestAna = await getBestAnalysisMission(ns, tracking)\\n queue(bestAna[0], bestAna[1], bestAna[2], bestAna[3])\\n continue\\n }\\n const best = await getBestMission(ns) // Get the best mission. null means there are none\\n if (best === null) {\\n queue(\\\"General\\\", \\\"Training\\\", city, 1)\\n continue\\n }\\n else {\\n queue(best[0], best[1], best[2], best[3])\\n continue\\n }\\n }\\n} //End of main\\n/** @param {NS} ns */\\nasync function updatesleeves(ns) {\\n let s = ns.sleeve\\n\\n // get our sleeve ratings\\n const isleeves = []\\n const slvnum = await sleeveGetNum(ns)\\n for (let islv = 0; islv < slvnum; islv++) {\\n const slv = await sleeveGet(ns, islv)\\n let record = {\\n \\\"Sleeve\\\": islv,\\n \\\"Power\\\": getslvpower(slv),\\n \\\"Cycles\\\": slv.storedCycles,\\n \\\"Person\\\": slv\\n }\\n isleeves.push(record)\\n if (slv.shock > SLEEVE_SHOCK) {\\n await sleeveShockRecovery(ns, islv)\\n }\\n else if (ns.sleeve.getTask(islv)?.type === \\\"RECOVERY\\\") {\\n await sleeveIdle(ns, islv)\\n }\\n }\\n isleeves.sort((a, b) => { return b.Cycles - a.Cycles }) //Lowest first so we cycle\\n\\n if (SLEEVEINFILSTATUS) {\\n const bestslv = isleeves.shift()\\n if (!sleeve_infil && s.getTask(bestslv.Sleeve) === null) {\\n await sleeveSetToBBAction(ns, bestslv.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (bestslv.Cycles > s.getTask(bestslv.Sleeve).cyclesNeeded) {\\n sleeve_infil = true\\n s.getTask(bestslv.Sleeve).nextCompletion.then(() => {\\n sleeve_infil = false\\n sleeveIdle(ns, bestslv.Sleeve).then()\\n })\\n }\\n else await sleeveIdle(ns, bestslv.Sleeve)\\n }\\n }\\n else { //We are assigning all sleeves to their respective tasks\\n const city = await bbGetCity(ns)\\n const cityChaos = await bbGetCityChaos(ns, city)\\n let diff = .15\\n if (SLEEVES_ENABLED)\\n diff = 0\\n const analyze = await cityneedsanalysis(ns, city, diff)\\n const stamina = await bbGetStam(ns)\\n const stamPerc = stamina[0] / stamina[1]\\n const maxHome = await getServerAvailRam(ns, \\\"home\\\")\\n const maxRam = maxHome <= 16 ? await maxRun(ns, false, true) : maxHome\\n const idleCost = await doGetScriptRam(ns, \\\"SphyxOS/sleeves/setToIdle.js\\\")\\n const maxWork = Math.min(Math.max(1, Math.floor(maxRam / (idleCost * 3))), slvnum)\\n for (const me of isleeves) {\\n let trainSlv = false\\n if (s.getTask(me.Sleeve) !== null) {\\n continue //Our sleeve is working...\\n }\\n if (me.Power < SLEEVE_STATS && stamPerc > .55 && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Training\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeveIdle(ns, me.Sleeve).then()\\n sleeve_working--\\n })\\n continue\\n }\\n else {\\n await sleeveIdle(ns, me.Sleeve)\\n continue // Save up for training. Move on to the next\\n }\\n }\\n if (me.Person.hp.current + 2 <= me.Person.hp.max && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Hyperbolic Regeneration Chamber\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeveIdle(ns, me.Sleeve).then()\\n sleeve_working--\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n continue\\n }\\n if (!sleeve_analyze && analyze && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Field Analysis\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_analyze = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_analyze = false\\n sleeve_working--\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n }\\n const countTracking = await bbGetActionCountRemain(ns, \\\"Contracts\\\", \\\"Tracking\\\")\\n const currentAction = await bbGetCurrentAction(ns)\\n if (!analyze && sleeve_working < maxWork && cityChaos <= CHAOS_FLOOR && !sleeve_tracking && currentAction?.name !== \\\"Tracking\\\" && countTracking >= 1) {\\n const maxTrack = await bbGetActionMaxLvl(ns, \\\"Contracts\\\", \\\"Tracking\\\")\\n for (let i = maxTrack; i > 0; i--) {\\n await bbSetActionLevel(ns, \\\"Contracts\\\", \\\"Tracking\\\", i)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)\\n if (chance[0] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)\\n //ns.tprintf(\\\"Contracts-Sleeve:%s %s\\\", me.Sleeve, chance[0])\\n if (chance[0] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Take on contracts\\\", \\\"Tracking\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_tracking = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_tracking = false\\n sleeve_working--\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n }\\n }\\n await ns.asleep(0)\\n const countBounty = await bbGetActionCountRemain(ns, \\\"Contracts\\\", \\\"Bounty Hunter\\\")\\n if (!analyze && sleeve_working < maxWork && cityChaos <= CHAOS_FLOOR && currentAction?.name !== \\\"Bounty Hunter\\\" && !sleeve_bounty && countBounty >= 1) {\\n const maxBounty = await bbGetActionMaxLvl(ns, \\\"Contracts\\\", \\\"Bounty Hunter\\\")\\n for (let i = maxBounty; i > 0; i--) {\\n await bbSetActionLevel(ns, \\\"Contracts\\\", \\\"Bounty Hunter\\\", i)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)\\n if (chance[0] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)\\n //ns.tprintf(\\\"BHunter-Sleeve:%s %s\\\", me.Sleeve, chance[0]) \\n if (chance[0] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Take on contracts\\\", \\\"Bounty Hunter\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_bounty = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_working--\\n sleeve_bounty = false\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n }\\n }\\n await ns.asleep(0)\\n const countRetire = await bbGetActionCountRemain(ns, \\\"Contracts\\\", \\\"Retirement\\\")\\n if (!analyze && sleeve_working < maxWork && cityChaos <= CHAOS_FLOOR && currentAction?.name !== \\\"Retirement\\\" && !sleeve_retire && countRetire >= 1) {\\n const maxRet = await bbGetActionMaxLvl(ns, \\\"Contracts\\\", \\\"Retirement\\\")\\n for (let i = maxRet; i > 0; i--) {\\n await bbSetActionLevel(ns, \\\"Contracts\\\", \\\"Retirement\\\", i)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)\\n if (chance[0] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)\\n //ns.tprintf(\\\"Retirement-Sleeve:%s %s\\\", me.Sleeve, chance[0]) \\n if (chance[0] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Take on contracts\\\", \\\"Retirement\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_retire = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_retire = false\\n sleeve_working--\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n await sleeveIdle(ns, me.Sleeve)\\n }\\n }\\n await ns.asleep(0)\\n if (cityChaos > CHAOS_FLOOR && !sleeve_diplomacy && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Diplomacy\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_diplomacy = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_diplomacy = false\\n sleeve_working--\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n }\\n if (trainSlv && stamPerc > .55 && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Training\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeveIdle(ns, me.Sleeve).then()\\n sleeve_working--\\n })\\n continue\\n }\\n else {\\n await sleeveIdle(ns, me.Sleeve)\\n continue\\n }\\n }\\n if (!sleeve_infil && sleeve_working < maxWork) {\\n await sleeveSetToBBAction(ns, me.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_working++\\n sleeve_infil = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_working--\\n sleeve_infil = false\\n sleeveIdle(ns, me.Sleeve).then()\\n })\\n continue\\n }\\n else await sleeveIdle(ns, me.Sleeve)\\n }\\n }\\n }\\n} // Updatesleeves function\\n/** @param {NS} ns */\\nasync function updateskills(ns) {\\n let b = ns.bladeburner\\n let count = 0\\n while (true) {\\n count++\\n if (count > 2000) {\\n await ns.asleep(4)\\n count = 0\\n }\\n if (INTMODE) {\\n const maxUpgrade = await calcMaxUpgradeCount(ns, \\\"Hyperdrive\\\", await bbGetSkillPoints(ns))\\n if (!maxUpgrade) break\\n const hyperSkill = await bbGetSkillLevel(ns, \\\"Hyperdrive\\\")\\n if (hyperSkill <= Number.MAX_SAFE_INTEGER - 1) {\\n await bbUpgradeSkill(ns, \\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else if (maxUpgrade >= hyperSkill / 1e8) {\\n await bbUpgradeSkill(ns, \\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else break\\n }\\n else {\\n let bestcost = Number.POSITIVE_INFINITY\\n let bestskill = \\\"Hyperdrive\\\"\\n for (const skl of b.getSkillNames()) {\\n const skillRate = await skillrating(ns, skl)\\n if (skillRate < bestcost) {\\n bestcost = skillRate\\n bestskill = skl\\n }\\n }\\n if (LVLUP > 0) {\\n const update = await bbUpgradeSkill(ns, bestskill, LVLUP)\\n if (!update) break\\n }\\n\\n if (LVLUP <= 0) {\\n const maxUpgrade = await calcMaxUpgradeCount(ns, bestskill, await bbGetSkillPoints(ns))\\n const update = await bbUpgradeSkill(bestskill, maxUpgrade)\\n if (!update) break\\n }\\n }\\n }\\n}\\nasync function skillrating(ns, skill) {\\n let mod = 0\\n skillmods.map(x => { x[0] === skill ? mod = x[1] : null })\\n let cost = await bbGetSkillUpgradeCost(ns, skill)\\n return cost / mod === 0 ? Number.POSITIVE_INFINITY : cost / mod\\n}\\n/** @param {NS} ns */\\nasync function cityneedsanalysis(ns, city, diff = 0) {\\n const b = ns.bladeburner\\n const startcity = await bbGetCity(ns)\\n await bbSwitchCity(ns, city)\\n for (const bop of b.getBlackOpNames()) {\\n if (await proxy(ns, \\\"bladeburner.getActionCountRemaining\\\", \\\"Black Operations\\\", bop) >= 1) {\\n let chance = await bbGetActionEstSuccessChance(ns, \\\"Black Operations\\\", bop)\\n if (chance[1] - chance[0] > diff) {\\n await bbSwitchCity(ns, startcity)\\n return true\\n }\\n break\\n }\\n }\\n for (const contract of b.getContractNames()) {\\n const max = await proxy(ns, \\\"bladeburner.getActionMaxLevel\\\", \\\"Contracts\\\", contract)\\n await proxy(ns, \\\"bladeburner.setActionLevel\\\", \\\"Contracts\\\", contract, max)\\n let chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", contract)\\n if (chance[1] - chance[0] > diff) {\\n await bbSwitchCity(ns, startcity)\\n return true\\n }\\n }\\n for (const op of b.getOperationNames()) {\\n const max = await proxy(ns, \\\"bladeburner.getActionMaxLevel\\\", \\\"Operations\\\", op)\\n await proxy(ns, \\\"bladeburner.setActionLevel\\\", \\\"Operations\\\", op, max)\\n let chance = await bbGetActionEstSuccessChance(ns, \\\"Operations\\\", op)\\n if (chance[1] - chance[0] > diff) {\\n await bbSwitchCity(ns, startcity)\\n return true\\n }\\n }\\n await bbSwitchCity(ns, startcity)\\n return false\\n}\\nasync function checkTracking(ns, diff) {\\n for (const city of cities) {\\n const analyze = await cityneedsanalysis(ns, city, diff)\\n if (analyze)\\n return city\\n }\\n return false\\n}\\n//Returns an array. [0] is missions name, [1] is missions type, [2] is the city\\n/** @param {NS} ns */\\nasync function getBestMission(ns) {\\n let b = ns.bladeburner\\n\\n const startcity = await bbGetCity(ns)\\n let bestresult = 0\\n let bestoperation = null\\n let bestoperationtype = null\\n let bestoperationcity = null\\n let bestoperationlevel = 1\\n\\n let blackops = []\\n for (const bop of b.getBlackOpNames()) {\\n const count = await bbGetActionCountRemain(ns, \\\"Black Operations\\\", bop)\\n if (count > 0) {\\n let record = {\\n \\\"BOP\\\": bop,\\n \\\"Rank\\\": await bbGetBlackOpRank(ns, bop)\\n }\\n blackops.push(record)\\n }\\n }\\n blackops = blackops.sort((x, y) => { return y.Rank - x.Rank })\\n const next = blackops.pop()\\n let bopchance;\\n if (next !== undefined) bopchance = await bbGetActionEstSuccessChance(ns, \\\"Black Operations\\\", next.BOP)\\n const rank = await bbGetRank(ns)\\n if (next !== undefined && (bopchance[0] + bopchance[1]) / 2 >= BOPS_SUCCESS_TRY && next.Rank <= rank) return [\\\"Black Operations\\\", next.BOP, startcity, 1]\\n\\n for (const city of cities) {\\n await bbSwitchCity(ns, city)\\n for (const contract of b.getContractNames()) {\\n if (contract === \\\"Tracking\\\" && sleeve_tracking) continue // If a sleeve is doing something, move on.\\n if (contract === \\\"Bounty Hunter\\\" && sleeve_bounty) continue // Not because it causes a conflict\\n if (contract === \\\"Retirement\\\" && sleeve_retire) continue // But so we can focus on getting to Operations\\n const count = await bbGetActionCountRemain(ns, \\\"Contracts\\\", contract)\\n if (count < 1) continue\\n const maxCLvl = await bbGetActionMaxLvl(ns, \\\"Contracts\\\", contract)\\n for (let level = maxCLvl; level > 0; level--) {\\n await bbSetActionLevel(ns, \\\"Contracts\\\", contract, level)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Contracts\\\", contract)\\n if ((chance[0] + chance[1]) / 2 >= MIN_CHANCE_SUCCESS) {\\n const result = (chance[0] + chance[1]) / 2 * await bbGetActionRepGain(ns, \\\"Contracts\\\", contract) / await bbGetActionTime(ns, \\\"Contracts\\\", contract)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = contract\\n bestoperationtype = \\\"Contracts\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n const ops = [\\\"Undercover Operation\\\", \\\"Sting Operation\\\", \\\"Assassination\\\"]\\n for (const o of ops) {\\n const count = await bbGetActionCountRemain(ns, \\\"Operations\\\", o)\\n if (count < 1) continue\\n const maxOLvl = await bbGetActionMaxLvl(ns, \\\"Operations\\\", o)\\n for (let level = maxOLvl; level > 0; level--) {\\n await bbSetActionLevel(ns, \\\"Operations\\\", o, level)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Operations\\\", o)\\n if ((chance[0] + chance[1]) / 2 >= MIN_CHANCE_SUCCESS) {\\n const bonus = o === \\\"Assassination\\\" ? 10 : 1\\n const result = (chance[0] + chance[1]) / 2 * await bbGetActionRepGain(ns, \\\"Operations\\\", o) * bonus / await bbGetActionTime(ns, \\\"Operations\\\", o)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = o\\n bestoperationtype = \\\"Operations\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n }\\n await bbSwitchCity(ns, startcity)\\n return bestoperation !== null ? [bestoperationtype, bestoperation, bestoperationcity, bestoperationlevel] : null\\n}\\n/** @param {NS} ns */\\nasync function getBestAnalysisMission(ns, city) {\\n const startcity = await bbGetCity(ns)\\n let bestresult = 0\\n let bestoperation = null\\n let bestoperationtype = null\\n let bestoperationlevel = 1\\n\\n for (const operation of [\\\"Undercover Operation\\\", \\\"Investigation\\\"]) {\\n const count = await bbGetActionCountRemain(ns, \\\"Operations\\\", operation)\\n if (count >= 1) {\\n const maxOLvl = await bbGetActionMaxLvl(ns, \\\"Operations\\\", operation)\\n for (let level = maxOLvl; level > 0; level--) {\\n await bbSetActionLevel(ns, \\\"Operations\\\", operation, level)\\n const chance = await bbGetActionEstSuccessChance(ns, \\\"Operations\\\", operation)\\n if ((chance[0] + chance[1]) / 2 >= MIN_CHANCE_SUCCESS) {\\n const result = (chance[0] + chance[1]) / 2 * await bbGetActionRepGain(ns, \\\"Operations\\\", operation) / await bbGetActionTime(ns, \\\"Operations\\\", \\\"Undercover Operation\\\")\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = operation\\n bestoperationtype = \\\"Operations\\\"\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n }\\n await bbSwitchCity(ns, startcity)\\n return bestoperation !== null ? [bestoperationtype, bestoperation, city, bestoperationlevel] : [\\\"General\\\", \\\"Field Analysis\\\", city, 1]\\n}\\n/** @param {NS} ns */\\nasync function checkChaos(ns) {\\n const priorityCityChaos = PRIORITY_CITY ? await bbGetCityChaos(ns, PRIORITY_CITY) : 0\\n if (PRIORITY_CITY && priorityCityChaos <= CHAOS_FLOOR) PRIORITY_CITY = false\\n if (!PRIORITY_CITY) {\\n for (const city of cities) { //New emergency?\\n const cityChaos = await bbGetCityChaos(ns, city)\\n if (cityChaos >= CHAOS_TOP) {\\n PRIORITY_CITY = city\\n return PRIORITY_CITY\\n }\\n }\\n }\\n return PRIORITY_CITY\\n}\\n/** @param {NS} ns */\\nasync function updatedisplay(ns) {\\n clearLogs(ns)\\n const b = ns.bladeburner\\n const s = ns.sleeve\\n const city = await bbGetCity(ns)\\n const stamina = await bbGetStam(ns)\\n update(ns, ns.sprintf(\\\"Rank: %s Operations Queued: %s\\\", fNumber(ns, await bbGetRank(ns)), queues.length))\\n update(ns, ns.sprintf(\\\"Stamina: %s/%s(%s%s)\\\", fNumber(ns, stamina[0]), fNumber(ns, stamina[1]), fNumber(ns, stamina[0] / stamina[1] * 100, 2), \\\"%\\\"))\\n update(ns, ns.sprintf(\\\"Current City: %s\\\", city))\\n update(ns, ns.sprintf(\\\"Est. Population: %s\\\", fNumber(ns, await bbGetCityEstPop(ns, city))))\\n update(ns, ns.sprintf(\\\"Synth Comms: %s\\\", fNumber(ns, await bbGetCityComms(ns, city), 0)))\\n update(ns, ns.sprintf(\\\"Chaos: %s\\\", fNumber(ns, await bbGetCityChaos(ns, city))))\\n const skillPoints = await bbGetSkillPoints(ns)\\n update(ns, ns.sprintf(\\\"Skill Points: %s\\\", skillPoints > 1000 ? fNumber(ns, skillPoints) : skillPoints))\\n update(ns, ns.sprintf(\\\"Bonus Time: %s\\\", b.getBonusTime() / 1000 >= 1000 ? fNumber(ns, b.getBonusTime() / 1000) : b.getBonusTime() / 1000))\\n await updatemissions(ns)\\n if (queuestask.Type === undefined) update(ns, \\\"Current Task: None(0/0)\\\")\\n else update(ns, ns.sprintf(\\\"Current Task: %s(%s/%s) %s\\\", queuestask.Type, queuestask.Level, queuestask.Type === \\\"Black Operations\\\" || queuestask.Type === \\\"General\\\" ? 1 : await bbGetActionMaxLvl(ns, queuestask.Type, queuestask.Name), queuestask.Name))\\n const actionCurTime = await bbGetActionCurTime(ns)\\n if (queuestask.Type !== undefined) {\\n const actionTime = await bbGetActionTime(ns, queuestask.Type, queuestask.Name)\\n update(ns, ns.sprintf(\\\"Progress: %s Time: %s\\\", updateprogress(actionTime, actionCurTime), fTime(ns, actionTime - actionCurTime)))\\n }\\n else\\n update(ns, ns.sprintf(\\\"Progress: %s Time: n/a\\\", updateprogress(10, 0)))\\n update(ns, \\\"------------------------------------------------------------------------------\\\")\\n if (!SLEEVES_ENABLED) update(ns, \\\"SLEEVE SUPPORT DISABLED\\\")\\n else {\\n const numSleeves = await sleeveGetNum(ns)\\n for (let slv = 0; slv < numSleeves; slv++) {\\n let task = s.getTask(slv)\\n const currentSlv = await sleeveGet(ns, slv)\\n let cycles\\n cycles = currentSlv.storedCycles > 1000 ? fNumber(ns, currentSlv.storedCycles, 2) : currentSlv.storedCycles\\n let buf = ns.sprintf(\\\"Sleeve: %s Cycles: %-7s \\\", slv, cycles)\\n if (task !== null) {\\n if (task.type === \\\"INFILTRATE\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: Infiltration\\\")\\n else if (task.type === \\\"CRIME\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Crime: \\\" + task.crimeType)\\n else if (task.type === \\\"BLADEBURNER\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: \\\" + task.actionName.substring(0, 14))\\n else if (task.type === \\\"RECOVERY\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Shock Recovery\\\")\\n\\n\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"?\\\" + task.type)\\n }\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"Idle: ------------\\\")\\n if (task !== null) buf += ns.sprintf(updateprogress(task.cyclesNeeded, task.cyclesWorked))\\n else buf += ns.sprintf(updateprogress(10, 0))\\n const slvAugs = await sleeveGetAugs(ns, slv)\\n buf += ns.sprintf(\\\" Augs: %2s%s\\\", slvAugs, \\\"\\\\n\\\")\\n update(ns, buf)\\n }\\n }\\n ns.ui.renderTail()\\n}\\n/** @param {NS} ns */\\nasync function updatemissions(ns) {\\n //Cycle through all the mission types and show how many we currently have in our city and how many we have overall\\n let b = ns.bladeburner\\n for (const contract of b.getContractNames()) {\\n const count = await bbGetActionCountRemain(ns, \\\"Contracts\\\", contract)\\n count >= 1000 ? update(ns, ns.sprintf(\\\"Contracts: \\\" + fNumber(ns, count) + \\\" \\\" + contract)) : update(ns, ns.sprintf(\\\"Contracts: \\\" + fNumber(ns, count, 2) + \\\" \\\" + contract))\\n }\\n for (const operation of b.getOperationNames()) {\\n const count = await bbGetActionCountRemain(ns, \\\"Operations\\\", operation)\\n count >= 1000 ? update(ns, ns.sprintf(\\\"Operation: \\\" + fNumber(ns, count) + \\\" \\\" + operation)) : update(ns, ns.sprintf(\\\"Operation: \\\" + fNumber(ns, count, 2) + \\\" \\\" + operation))\\n }\\n}\\n/** @param {NS} ns */\\nfunction updateprogress(max_time, run_time, bar_length = 20) {\\n let done = run_time > 0 ? Math.max(max_time / run_time, 1) : 0\\n let buffer = \\\"[\\\"\\n if (done > 0) {\\n buffer = buffer.padEnd(Math.round((bar_length - 2) / done), \\\"|\\\") // open square bracket + asterisk\\n buffer += \\\"*\\\"\\n }\\n buffer = buffer.padEnd(bar_length - 1, \\\"-\\\")\\n buffer += \\\"]\\\"\\n\\n return buffer\\n}\\n/** @param {NS} ns */\\nasync function runmission(ns, best) {\\n //best.Type, best.Name, best.City, best.Level\\n let b = ns.bladeburner\\n queuestask = best\\n const action = await bbGetCurrentAction(ns)\\n //Resuming?\\n const myCity = await bbGetCity(ns)\\n const actionCurrentLvl = await bbGetActionCurLvl(ns, best.Type, best.Name)\\n const blackOpTimeAddition = best.Type === \\\"BlackOp\\\" ? 2000 : 0 //BOPs seem to lag a few seconds\\n if (action !== null && best.City === myCity && best.Type === action.type && best.Name === action.name && (best.Type === \\\"General\\\" || best.Type === \\\"BlackOp\\\" || best.Level === actionCurrentLvl)) {\\n const actionTime = await bbGetActionTime(ns, best.Type, best.Name)\\n const actionCurTime = await bbGetActionCurTime(ns)\\n if ((b.getBonusTime() - 1000) > actionTime) { //All under bonus time\\n queueswait = performance.now() + Math.max((actionTime / 5) - actionCurTime + blackOpTimeAddition, 500)\\n }\\n else queueswait = performance.now() + Math.max(actionTime - b.getBonusTime() - actionCurTime + (blackOpTimeAddition / 2), 500)\\n }\\n else {\\n //New action\\n if (best.City !== myCity) await bbSwitchCity(ns, best.City)\\n await proxyTry(ns, \\\"bladeburner.setActionLevel\\\", best.Type, best.Name, best.Level)\\n await bbStartAction(ns, best.Type, best.Name)\\n const actionTime = await bbGetActionTime(ns, best.Type, best.Name)\\n if (b.getBonusTime() - 1000 > actionTime) { //All under bonus time\\n queueswait = performance.now() + Math.max((actionTime / 5) + blackOpTimeAddition, 500)\\n }\\n else queueswait = performance.now() + Math.max(actionTime - b.getBonusTime() + (blackOpTimeAddition / 2), 500)\\n }\\n}\\nasync function getTrainStats(ns) {\\n const me = await getPlay(ns)\\n return (me.skills.agility + me.skills.defense + me.skills.dexterity + me.skills.strength) / 4\\n}\\nfunction queue(type, name, city, level) {\\n let mission = {\\n \\\"Type\\\": type,\\n \\\"Name\\\": name,\\n \\\"City\\\": city,\\n \\\"Level\\\": level\\n }\\n queues.push(mission)\\n}\\n/** @param {NS} ns */\\nasync function init(ns) {\\n sleeve_infil = false\\n sleeve_analyze = false\\n sleeve_tracking = false\\n sleeve_bounty = false\\n sleeve_retire = false\\n sleeve_diplomacy = false\\n sleeve_working = 0\\n queues.length = 0\\n if (SLEEVES_ENABLED) {\\n const sleeves = await sleeveGetNum(ns)\\n for (let slv = 0; slv < sleeves; slv++)\\n await sleeveIdle(ns, slv)\\n }\\n HASBN4 = await hasBN(ns, 4, 2)\\n queuestask = [null, null, null, null]\\n queueswait = 0\\n PRIORITY_CITY = false\\n LVLUP = 1\\n endItCost = await doGetScriptRam(ns, \\\"SphyxOS/singularity/destroyWD.js\\\")\\n}\\n/** @param {NS} ns */\\nasync function trainUp(ns) {\\n const me = await getPlay(ns)\\n const skls = me.skills\\n const wrk = HASBN4 ? await proxy(ns, \\\"singularity.getCurrentWork\\\") : false\\n if (me.city !== \\\"Sector-12\\\") {\\n clearLogs(ns)\\n update(ns, \\\"Please go to Sector-12\\\")\\n //Travel to our Gym \\n if (HASBN4) await travelCity(ns, \\\"Sector-12\\\")\\n }\\n else if (skls.charisma < CSTATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Cha to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"Leadership\\\"))\\n await proxy(ns, \\\"singularity.universityCourse\\\", \\\"Rothman University\\\", \\\"Leadership\\\", false)\\n }\\n else if (skls.strength < CSTATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Str to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"str\\\"))\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"str\\\", false)\\n }\\n else if (skls.defense < CSTATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Def to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"def\\\"))\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"def\\\", false)\\n }\\n else if (skls.dexterity < CSTATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Dex to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"dex\\\"))\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"dex\\\", false)\\n }\\n else if (skls.agility < CSTATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Agi to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"agi\\\"))\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"agi\\\", false)\\n }\\n}\\n/** @param {NS} ns */\\nfunction getslvpower(slv) {\\n let skill = slv.skills\\n return ((skill.agility + skill.defense + skill.dexterity + skill.strength) / 4)\\n}\\n/** @param {NS} ns */\\nasync function calcMaxUpgradeCount(ns, skill, cost) {\\n let baseCost;\\n let costInc;\\n const currentLevel = await bbGetSkillLevel(ns, skill)\\n const currentNodeMults = await getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n const m = -baseCost - costInc * currentLevel + costInc / 2\\n const delta = Math.sqrt(m * m + (2 * costInc * cost) / currentNodeMults.BladeburnerSkillCost)\\n const result = Math.round((m + delta) / costInc)\\n const costOfResultPlus1 = await calculateCost(ns, skill, result + 1)\\n if (costOfResultPlus1 <= cost) {\\n return result + 1\\n }\\n const costOfResult = await calculateCost(ns, skill, result)\\n if (costOfResult <= cost) {\\n return result\\n }\\n return result - 1\\n}\\nasync function calculateCost(ns, skill, count = 1) {\\n const currentLevel = await bbGetSkillLevel(ns, skill)\\n const actualCount = currentLevel + count - currentLevel\\n let baseCost;\\n let costInc;\\n const currentNodeMults = await getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n return Math.round(\\n actualCount *\\n currentNodeMults.BladeburnerSkillCost *\\n (baseCost + costInc * (currentLevel + (actualCount - 1) / 2)))\\n}\\n/** @param {NS} ns */\\nasync function endIt(ns) {\\n //We need to upgrade ram to a certain minimum.\\n const maxRam = await maxRun(ns, false)\\n if (await getServerAvailRam(ns, \\\"home\\\") < reservedRam) {\\n const upgCost = await doGetScriptRam(ns, \\\"SphyxOS/singularity/upgradeHomeRam.js\\\")\\n if (maxRam >= upgCost) await upgHomeRam(ns)\\n }\\n else if (FINISHER && maxRam >= endItCost) {\\n const nextBN = await getNextBN(ns)\\n await destroyWD(ns, nextBN, STARTUP_SCRIPT)\\n }\\n}\\n/** @param {NS} ns */\\nasync function getNextBN(ns) {\\n let nextbn = 0\\n let nextbnlvl = 0\\n for (let check of bnorder) {\\n let isthere = false\\n const sourceFiles = await getOwnedSF(ns)\\n for (const bn of sourceFiles) {\\n let bonus = 0\\n const resetInfo = await getResetInf(ns)\\n if (resetInfo.currentNode == check[0]) bonus = 1\\n if (bn.n == check[0] && bn.lvl + bonus >= check[1]) isthere = true\\n if (bn.n == resetInfo.currentNode && 1 >= check[1]) isthere = true\\n if (resetInfo.currentNode === check[0] && 1 >= check[1]) isthere = true\\n }\\n if (isthere == false) {\\n nextbn = check[0]\\n nextbnlvl = check[1]\\n break\\n }\\n }\\n let value = ns.sprintf(\\\"%s\\\" + \\\".\\\" + \\\"%s\\\", nextbn, nextbnlvl)\\n return Number.parseInt(value)\\n}\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win && win.closed) {\\n win.close()\\n win = false\\n ns.writePort(1, \\\"bb popout off\\\")\\n }\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printRaw(text)\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let quiet = false\\n while (ns.peek(18) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(18)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"BladeBurner\\\", ns.ui.getTheme())\\n if (!quiet) ns.tprintf(\\\"BB: Will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n if (!quiet) ns.tprintf(\\\"BB: Will not use a popout\\\")\\n break\\n case \\\"sleeve infil on\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Sleeves set to infil only\\\")\\n SLEEVEINFILSTATUS = true\\n break;\\n case \\\"sleeve infil off\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Sleeves will not focus on infil\\\")\\n SLEEVEINFILSTATUS = false\\n break;\\n case \\\"int mode on\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Int mode ON\\\")\\n INTMODE = true\\n break;\\n case \\\"int mode off\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Int mode OFF\\\")\\n INTMODE = false\\n break;\\n case \\\"sleeves on\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Sleeves activated\\\")\\n SLEEVES_ENABLED = true\\n const slvNum = await sleeveGetNum(ns)\\n for (let slv = 0; slv < slvNum; slv++)\\n await sleeveIdle(ns, slv)\\n break;\\n case \\\"sleeves off\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Sleeves deactivated\\\")\\n SLEEVES_ENABLED = false\\n break;\\n case \\\"finisher on\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Finisher activated\\\")\\n FINISHER = true\\n break;\\n case \\\"finisher off\\\":\\n if (!quiet) ns.tprintf(\\\"BB: Finisher deactivated\\\")\\n FINISHER = false\\n break;\\n case \\\"quiet\\\":\\n quiet = true\\n break;\\n default:\\n ns.tprintf(\\\"Invalid command received in BB: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\\n//[0] is Node, [1] is lvl\\nconst bnorder = [[1, 3], [2, 3], [5, 1], [4, 3], [7, 3], [6, 3], [3, 3], [13, 3], [5, 3], [9, 3], [10, 3], [11, 3], [14, 3], [8, 3], [12, 36000]]\\nconst cities = [\\\"Sector-12\\\", \\\"Aevum\\\", \\\"Volhaven\\\", \\\"Chongqing\\\", \\\"New Tokyo\\\", \\\"Ishima\\\"]\\n//skillmods [0] name, [1] My rating, [2] baseCost, [3] costInc\\nconst skillmods = [\\n [\\\"Blade\\\\'s Intuition\\\", 2.0, 3, 2.1],\\n [\\\"Cloak\\\", 0.8, 1, 1.1],\\n [\\\"Short-Circuit\\\", 1.0, 2, 2.1],\\n [\\\"Digital Observer\\\", 1.6, 2, 2.1],\\n [\\\"Tracer\\\", 1.0, 2, 2.1],\\n [\\\"Overclock\\\", 2.2, 3, 1.4],\\n [\\\"Reaper\\\", 1.0, 2, 2.1],\\n [\\\"Evasive System\\\", 2.0, 2, 2.1],\\n [\\\"Datamancer\\\", 1.0, 3, 1],\\n [\\\"Cyber\\\\'s Edge\\\", 1.0, 1, 3],\\n [\\\"Hands of Midas\\\", 0.1, 2, 2.5],\\n [\\\"Hyperdrive\\\", 2.5, 1, 2.5],\\n]\""},{"filename":"SphyxOS/bins/changeLog.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const log = \\\"SphyxOS/changeLog.txt\\\"\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n const file = ns.read(log)\\n ns.printf(\\\"%s\\\", file)\\n}\""},{"filename":"SphyxOS/bins/codingContracts.js","file":"\"import { getCType, getCData, getServersLight, cctAttempt } from \\\"SphyxOS/util.js\\\"\\n\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n const workers = []\\n const working = []\\n await ns.sleep(100)\\n ns.atExit(() => {\\n while (workers.length > 0) {\\n let worker = workers.pop()\\n worker.terminate()\\n worker = null\\n }\\n while (working.length > 0) {\\n let worker = working.pop()\\n worker.terminate()\\n worker = null\\n }\\n if (ns.args.includes(\\\"darknet\\\")) ns.writePort(ns.pid, true)\\n else ns.writePort(ns.pid, true)\\n })\\n //ns.args: 0 is server 1 is script name\\n const servers = ns.args.includes(\\\"darknet\\\") ? [ns.args[0]] : await getServersLight(ns)\\n //[server, file, type] entries\\n const contracts = []\\n const ready = []\\n workers.length = 0\\n let inFlight = 0\\n let count = 0\\n let failed = 0\\n let unsolved = 0\\n\\n for (const server of servers) {\\n for (const file of ns.ls(server).filter(f => f.includes(\\\".cct\\\"))) {\\n const type = await getCType(ns, file, server)\\n contracts.push([server, file, type])\\n if (contracts.length % 1000 === 0) await ns.sleep(0)\\n }\\n }\\n for (const contract of contracts) {\\n let found = false\\n for (const type of types) {\\n if (contract[2] === type[0]) {\\n found = true\\n const worker = getWorker(workers)\\n inFlight++\\n worker.onmessage = (msg) => {\\n ready.push(msg)\\n workers.push(worker)\\n }\\n const data = await getCData(ns, contract[1], contract[0])\\n worker.postMessage([type[1], data, contract[1], contract[0]])\\n working.push(worker)\\n if (inFlight - count > 50) await ns.asleep(100)\\n break\\n }\\n }\\n if (!found) {\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Unknown type: %s\\\", contract[2])\\n unsolved++\\n }\\n }\\n while (inFlight > count) {\\n while (ready.length > 0) {\\n const msg = ready.pop()\\n try { ns.ls(msg.data[2]) } //Is the server still there?\\n catch {\\n failed++\\n count++\\n continue\\n }\\n const reward = await cctAttempt(ns, msg.data[0], msg.data[1], msg.data[2])\\n if (reward && !ns.args.includes(\\\"quiet\\\")) ns.tprintf(reward)\\n else {\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Failed: %s\\\", msg.data[3])\\n failed++\\n }\\n count++\\n }\\n await ns.asleep(100)\\n }\\n while (workers.length > 0) {\\n let worker = workers.pop()\\n worker.terminate()\\n worker = null\\n }\\n while (working.length > 0) {\\n let worker = working.pop()\\n worker.terminate()\\n worker = null\\n }\\n if (!ns.args.includes(\\\"quiet\\\")) {\\n ns.tprintf(\\\"Solved: %s\\\", count - failed)\\n ns.tprintf(\\\"Failed: %s\\\", failed)\\n ns.tprintf(\\\"Unsolved: %s\\\", unsolved)\\n ns.tprintf(\\\"Workers Used: %s\\\", workers.length)\\n }\\n}\\nfunction getWorker(workers) {\\n if (workers.length) return workers.pop()\\n else {\\n const blob = new Blob([workerCode], { type: \\\"application/javascript\\\" })\\n const worker = new Worker(URL.createObjectURL(blob))\\n return worker\\n }\\n}\\nconst types = [\\n [\\\"Algorithmic Stock Trader I\\\", \\\"stonks1\\\"],\\n [\\\"Algorithmic Stock Trader II\\\", \\\"stonks2\\\"],\\n [\\\"Algorithmic Stock Trader III\\\", \\\"stonks3\\\"],\\n [\\\"Algorithmic Stock Trader IV\\\", \\\"stonks4\\\"],\\n [\\\"Array Jumping Game\\\", \\\"arrayjumpinggame\\\"],\\n [\\\"Array Jumping Game II\\\", \\\"arrayjumpinggameII\\\"],\\n [\\\"Square Root\\\", \\\"bigIntSquareRoot\\\"],\\n [\\\"Compression I: RLE Compression\\\", \\\"rlecompression\\\"],\\n [\\\"Compression II: LZ Decompression\\\", \\\"lzdecompression\\\"],\\n [\\\"Compression III: LZ Compression\\\", \\\"lzcompression\\\"],\\n [\\\"Encryption I: Caesar Cipher\\\", \\\"caesarcipher\\\"],\\n [\\\"Encryption II: Vigenère Cipher\\\", \\\"vigenere\\\"],\\n [\\\"Find All Valid Math Expressions\\\", \\\"fcnFindAllValidMathExpressions\\\"],\\n [\\\"Find Largest Prime Factor\\\", \\\"largestprimefactor\\\"],\\n [\\\"Generate IP Addresses\\\", \\\"generateips\\\"],\\n [\\\"HammingCodes: Encoded Binary to Integer\\\", \\\"hammingdecode\\\"],\\n [\\\"HammingCodes: Integer to Encoded Binary\\\", \\\"hammingencode\\\"],\\n [\\\"Largest Rectangle in a Matrix\\\", \\\"largestrectangleinmatrix\\\"],\\n [\\\"Merge Overlapping Intervals\\\", \\\"mergeoverlappingintervals\\\"],\\n [\\\"Minimum Path Sum in a Triangle\\\", \\\"minpathsum\\\"],\\n [\\\"Proper 2-Coloring of a Graph\\\", \\\"twocolor\\\"],\\n [\\\"Sanitize Parentheses in Expression\\\", \\\"sanitizeparentheses\\\"],\\n [\\\"Shortest Path in a Grid\\\", \\\"shortestpathinagrid\\\"],\\n [\\\"Spiralize Matrix\\\", \\\"spiralizematrix\\\"],\\n [\\\"Subarray with Maximum Sum\\\", \\\"subarraywithmaximumsum\\\"],\\n [\\\"Total Ways to Sum\\\", \\\"totalwaystosum\\\"],\\n [\\\"Total Ways to Sum II\\\", \\\"totalwaystosumII\\\"],\\n [\\\"Unique Paths in a Grid I\\\", \\\"uniquepathsI\\\"],\\n [\\\"Unique Paths in a Grid II\\\", \\\"uniquepathsII\\\"],\\n [\\\"Total Number of Primes\\\", \\\"totalPrimes\\\"]\\n];\\n\\nconst workerCode = `\\nfunction minpathsum(data) {\\n\\twhile (data.length > 1) {\\n\\t\\tfor (let i = 0; i < (data[data.length - 2]).length; i++) {\\n\\t\\t\\tdata[data.length - 2][i] += Math.min(data[data.length - 1][i], Math.min(data[data.length - 1][i + 1]));\\n\\t\\t}\\n\\t\\tdata.pop();\\n\\t}\\n\\treturn data[0][0];\\n}\\nfunction uniquepathsI(data) {\\n\\tlet numbers = []\\n\\tfor (let i = 0; i < data[0]; i++) {\\n\\t\\tnumbers.push([]);\\n\\t\\tfor (let j = 0; j < data[1]; j++) {\\n\\t\\t\\tnumbers[numbers.length - 1].push(1);\\n\\t\\t\\tif (i > 0 && j != 0) {\\n\\t\\t\\t\\tnumbers[i][j] = numbers[i - 1][j] + numbers[i][j - 1];\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn numbers[data[0] - 1][data[1] - 1];\\n}\\nfunction uniquepathsII(data) {\\n\\tlet answer = [];\\n\\tfor (let i = 0; i < data.length; i++) {\\n\\t\\tanswer.push(new Array(data[0].length).fill(0));\\n\\t}\\n\\tfor (let i = data.length - 1; i >= 0; i--) {\\n\\t\\tfor (let j = data[0].length - 1; j >= 0; j--) {\\n\\t\\t\\tif (data[i][j] == 0) {\\n\\t\\t\\t\\tanswer[i][j] = (i + 1 < data.length ? answer[i + 1][j] : 0) + (j + 1 < data[0].length ? answer[i][j + 1] : 0);\\n\\t\\t\\t\\tanswer[data.length - 1][data[0].length - 1] = 1;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn answer[0][0];\\n}\\nfunction largestprimefactor(data) {\\n\\tlet i = 2;\\n\\twhile (data > 1) {\\n\\t\\twhile (data % i == 0) {\\n\\t\\t\\tdata /= i;\\n\\t\\t}\\n\\t\\ti += 1;\\n\\t}\\n\\treturn i - 1;\\n}\\nfunction mergeoverlappingintervals(data) {\\n\\tlet intervals = (new Array(data.map(x => x[1]).reduce((a, b) => { return Math.max(a, b) }))).fill(0);\\n\\tfor (let interval of data) {\\n\\t\\tfor (let i = interval[0]; i < interval[1]; i++) {\\n\\t\\t\\tintervals[i] = 1;\\n\\t\\t}\\n\\t}\\n\\tif (intervals.indexOf(1) == -1) {\\n\\t\\treturn [];\\n\\t}\\n\\tlet answer = [[intervals.indexOf(1), intervals.indexOf(0, intervals.indexOf(1))]];\\n\\twhile ((answer[answer.length - 1][0] != -1) && (answer[answer.length - 1][1] != -1)) {\\n\\t\\tlet a = intervals.indexOf(1, 1 + answer[answer.length - 1][1]);\\n\\t\\tanswer.push([a, intervals.indexOf(0, a)]);\\n\\t}\\n\\tif (answer[answer.length - 1][1] == -1) {\\n\\t\\tanswer[answer.length - 1][1] = intervals.length;\\n\\t}\\n\\tif (answer[answer.length - 1][0] == -1) {\\n\\t\\tanswer.pop();\\n\\t}\\n\\treturn answer;\\n}\\nfunction caesarcipher(data) {\\n\\treturn data[0].split(\\\"\\\").map(x => { return x === \\\" \\\" ? \\\" \\\" : \\\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\\\"[((\\\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\\\".indexOf(x) + 26 - data[1]) % 26)] }).join(\\\"\\\");\\n\\t// return data[0].split(\\\"\\\").map(x => x.charCodeAt(0)).map(x => x == 32 ? 32 : (x + 65 - data[1])%26 + 65).map(x => String.fromCharCode(x)).join(\\\"\\\");\\n}\\nfunction vigenere(data) {\\n\\treturn data[0].split(\\\"\\\").map((x, i) => { return \\\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\\\"[((\\\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\\\".indexOf(x) + 13 + data[1].charCodeAt(i % data[1].length))) % 26] }).join(\\\"\\\");\\n}\\nfunction totalwaystosum(data) {\\n\\tlet answer = [1].concat((new Array(data + 1)).fill(0));\\n\\tfor (let i = 1; i < data; i++) {\\n\\t\\tfor (let j = i; j <= data; j++) {\\n\\t\\t\\tanswer[j] += answer[j - i];\\n\\t\\t}\\n\\t}\\n\\treturn answer[data];\\n}\\nfunction totalwaystosumII(data) {\\n\\tlet answer = [1].concat((new Array(data[0])).fill(0));\\n\\tfor (let i of data[1]) {\\n\\t\\tfor (let j = i; j <= data[0]; j++) {\\n\\t\\t\\tanswer[j] += answer[j - i];\\n\\t\\t}\\n\\t}\\n\\treturn answer[data[0]];\\n}\\nfunction spiralizematrix(data) {\\n\\tlet answer = [];\\n\\twhile (data.length > 0 && data[0].length > 0) {\\n\\t\\tanswer = answer.concat(data.shift());\\n\\t\\tif (data.length > 0 && data[0].length > 0) {\\n\\t\\t\\tanswer = answer.concat(data.map(x => x.pop()));\\n\\t\\t\\tif (data.length > 0 && data[0].length > 0) {\\n\\t\\t\\t\\tanswer = answer.concat(data.pop().reverse());\\n\\t\\t\\t\\tif (data.length > 0 && data[0].length > 0) {\\n\\t\\t\\t\\t\\tanswer = answer.concat(data.map(x => x.shift()).reverse());\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn answer;\\n}\\nfunction subarraywithmaximumsum(data) {\\n\\tlet answer = -1e308;\\n\\tfor (let i = 0; i < data.length; i++) {\\n\\t\\tfor (let j = i; j < data.length; j++) {\\n\\t\\t\\tanswer = Math.max(answer, data.slice(i, j + 1).reduce((a, b) => { return a + b }));\\n\\t\\t}\\n\\t}\\n\\treturn answer;\\n}\\nfunction twocolor(data) {\\n\\tfor (let i = 0; i < 2 ** data[0]; i++) {\\n\\t\\tlet answer = [];\\n\\t\\tfor (let j = 0; j < data[0]; j++) {\\n\\t\\t\\tanswer[j] = (2 ** j & i) > 0 ? 1 : 0;\\n\\t\\t}\\n\\t\\tif (data[1].map(x => answer[x[0]] != answer[x[1]]).reduce((a, b) => { return a + b }) == data[1].length) {\\n\\t\\t\\treturn answer;\\n\\t\\t}\\n\\t}\\n\\treturn [];\\n}\\nfunction rlecompression(data) {\\n\\tlet answer = \\\"\\\";\\n\\tdata = data.split(\\\"\\\");\\n\\twhile (data.length > 0) {\\n\\t\\tlet z = data.splice(0, 1);\\n\\t\\tlet i = 1;\\n\\t\\twhile (i < 9 && data[0] == z & data.length > 0) {\\n\\t\\t\\ti += 1;\\n\\t\\t\\tdata.splice(0, 1);\\n\\t\\t}\\n\\t\\tanswer = answer.concat(i.toString()).concat(z);\\n\\t}\\n\\treturn answer;\\n}\\nfunction lzdecompression(data) {\\n\\tif (data.length == 0) {\\n\\t\\treturn \\\"\\\";\\n\\t}\\n\\tdata = data.split(\\\"\\\");\\n\\tlet answer = \\\"\\\";\\n\\twhile (data.length > 0) {\\n\\t\\tlet chunklength = parseInt(data.shift());\\n\\t\\tif (chunklength > 0) {\\n\\t\\t\\tanswer = answer.concat(data.splice(0, chunklength).join(\\\"\\\"));\\n\\t\\t}\\n\\t\\tif (data.length > 0) {\\n\\t\\t\\tchunklength = parseInt(data.shift());\\n\\t\\t\\tif (chunklength != 0) {\\n\\t\\t\\t\\tlet rewind = parseInt(data.shift());\\n\\t\\t\\t\\tfor (let i = 0; i < chunklength; i++) {\\n\\t\\t\\t\\t\\tanswer = answer.concat(answer[answer.length - rewind]);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn answer;\\n}\\nfunction lzcompression(str) {\\n\\t// state [i][j] contains a backreference of offset i and length j\\n\\tlet cur_state = Array.from(Array(10), _ => Array(10)), new_state, tmp_state, result;\\n\\tcur_state[0][1] = ''; // initial state is a literal of length 1\\n\\tfor (let i = 1; i < str.length; i++) {\\n\\t\\tnew_state = Array.from(Array(10), _ => Array(10));\\n\\t\\tconst c = str[i];\\n\\t\\t// handle literals\\n\\t\\tfor (let len = 1; len <= 9; len++) {\\n\\t\\t\\tconst input = cur_state[0][len];\\n\\t\\t\\tif (input === undefined) continue;\\n\\t\\t\\tif (len < 9) set(new_state, 0, len + 1, input); // extend current literal\\n\\t\\t\\telse set(new_state, 0, 1, input + '9' + str.substring(i - 9, i) + '0'); // start new literal\\n\\t\\t\\tfor (let offset = 1; offset <= Math.min(9, i); offset++) { // start new backreference\\n\\t\\t\\t\\tif (str[i - offset] === c) set(new_state, offset, 1, input + len + str.substring(i - len, i));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\t// handle backreferences\\n\\t\\tfor (let offset = 1; offset <= 9; offset++) {\\n\\t\\t\\tfor (let len = 1; len <= 9; len++) {\\n\\t\\t\\t\\tconst input = cur_state[offset][len];\\n\\t\\t\\t\\tif (input === undefined) continue;\\n\\t\\t\\t\\tif (str[i - offset] === c) {\\n\\t\\t\\t\\t\\tif (len < 9) set(new_state, offset, len + 1, input); // extend current backreference\\n\\t\\t\\t\\t\\telse set(new_state, offset, 1, input + '9' + offset + '0'); // start new backreference\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tset(new_state, 0, 1, input + len + offset); // start new literal\\n\\t\\t\\t\\t// end current backreference and start new backreference\\n\\t\\t\\t\\tfor (let new_offset = 1; new_offset <= Math.min(9, i); new_offset++) {\\n\\t\\t\\t\\t\\tif (str[i - new_offset] === c) set(new_state, new_offset, 1, input + len + offset + '0');\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\ttmp_state = new_state;\\n\\t\\tnew_state = cur_state;\\n\\t\\tcur_state = tmp_state;\\n\\t}\\n\\tfor (let len = 1; len <= 9; len++) {\\n\\t\\tlet input = cur_state[0][len];\\n\\t\\tif (input === undefined) continue;\\n\\t\\tinput += len + str.substring(str.length - len, str.length);\\n\\t\\t// noinspection JSUnusedAssignment\\n\\t\\tif (result === undefined || input.length < result.length) result = input;\\n\\t}\\n\\tfor (let offset = 1; offset <= 9; offset++) {\\n\\t\\tfor (let len = 1; len <= 9; len++) {\\n\\t\\t\\tlet input = cur_state[offset][len];\\n\\t\\t\\tif (input === undefined) continue;\\n\\t\\t\\tinput += len + '' + offset;\\n\\t\\t\\tif (result === undefined || input.length < result.length) result = input;\\n\\t\\t}\\n\\t}\\n\\treturn result ?? '';\\n}\\nfunction stonks1(data) {\\n\\tlet best = 0;\\n\\tfor (let i = 0; i < data.length; i++) {\\n\\t\\tfor (let j = i + 1; j < data.length; j++) {\\n\\t\\t\\tbest = Math.max(best, data[j] - data[i]);\\n\\t\\t}\\n\\t}\\n\\treturn best;\\n}\\nfunction set(state, i, j, str) {\\n\\tif (state[i][j] === undefined || str.length < state[i][j].length) state[i][j] = str;\\n}\\nfunction stonks2(data) {\\n\\tlet best = 0;\\n\\tlet queue = {};\\n\\tqueue[JSON.stringify(data)] = 0;\\n\\twhile (Object.keys(queue).length > 0) {\\n\\t\\tlet current = Object.keys(queue)[0];\\n\\t\\tlet value = queue[current];\\n\\t\\tdelete queue[current];\\n\\t\\tlet stonks = JSON.parse(current);\\n\\t\\tfor (let i = 0; i < stonks.length; i++) {\\n\\t\\t\\tfor (let j = i + 1; j < stonks.length; j++) {\\n\\t\\t\\t\\tbest = Math.max(best, value + stonks[j] - stonks[i]);\\n\\t\\t\\t\\tlet remaining = stonks.slice(j + 1);\\n\\t\\t\\t\\tif (remaining.length > 0) {\\n\\t\\t\\t\\t\\tif (!Object.keys(queue).includes(JSON.stringify(remaining))) {\\n\\t\\t\\t\\t\\t\\tqueue[JSON.stringify(remaining)] = -1e308;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tqueue[JSON.stringify(remaining)] = Math.max(queue[JSON.stringify(remaining)], value + stonks[j] - stonks[i]);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn best;\\n}\\nfunction stonks3(data) {\\n\\tlet best = 0;\\n\\tfor (let i = 0; i < data.length; i++) {\\n\\t\\tfor (let j = i + 1; j < data.length; j++) {\\n\\t\\t\\tbest = Math.max(best, data[j] - data[i]);\\n\\t\\t\\tfor (let k = j + 1; k < data.length; k++) {\\n\\t\\t\\t\\tfor (let l = k + 1; l < data.length; l++) {\\n\\t\\t\\t\\t\\tbest = Math.max(best, data[j] - data[i] + data[l] - data[k]);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn best;\\n}\\nfunction stonks4(data) {\\n\\tlet best = 0;\\n\\tlet queue = {};\\n\\tqueue[0] = {};\\n\\tqueue[0][JSON.stringify(data[1])] = 0;\\n\\tfor (let ii = 0; ii < data[0]; ii++) {\\n\\t\\tqueue[ii + 1] = {};\\n\\t\\twhile (Object.keys(queue[ii]).length > 0) {\\n\\t\\t\\tlet current = Object.keys(queue[ii])[0];\\n\\t\\t\\tlet value = queue[ii][current];\\n\\t\\t\\tdelete queue[ii][current];\\n\\t\\t\\tlet stonks = JSON.parse(current);\\n\\t\\t\\tfor (let i = 0; i < stonks.length; i++) {\\n\\t\\t\\t\\tfor (let j = i + 1; j < stonks.length; j++) {\\n\\t\\t\\t\\t\\tbest = Math.max(best, value + stonks[j] - stonks[i]);\\n\\t\\t\\t\\t\\tlet remaining = stonks.slice(j + 1);\\n\\t\\t\\t\\t\\tif (remaining.length > 0) {\\n\\t\\t\\t\\t\\t\\tif (!Object.keys(queue[ii + 1]).includes(JSON.stringify(remaining))) {\\n\\t\\t\\t\\t\\t\\t\\tqueue[ii + 1][JSON.stringify(remaining)] = -1e308;\\n\\t\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t\\tqueue[ii + 1][JSON.stringify(remaining)] = Math.max(queue[ii + 1][JSON.stringify(remaining)], value + stonks[j] - stonks[i]);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn best;\\n}\\nfunction generateips(data) {\\n\\tlet answer = [];\\n\\tfor (let i = 1; i + 1 < data.length; i++) {\\n\\t\\tfor (let j = i + 1; j + 1 < data.length; j++) {\\n\\t\\t\\tfor (let k = j + 1; k < data.length; k++) {\\n\\t\\t\\t\\tanswer.push([data.substring(0, i), data.substring(i, j), data.substring(j, k), data.substring(k)]);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\tfor (let i = 0; i < 4; i++) {\\n\\t\\tanswer = answer.filter(x => 0 <= parseInt(x[i]) && parseInt(x[i]) <= 255 && (x[i] == \\\"0\\\" || x[i].substring(0, 1) != \\\"0\\\"));\\n\\t}\\n\\treturn answer.map(x => x.join(\\\".\\\"));\\n}\\nfunction arrayjumpinggame(data) {\\n\\tlet queue = new Set();\\n\\tif (data[0] == 0) {\\n\\t\\treturn 0;\\n\\t}\\n\\tqueue.add(\\\"[\\\" + data.toString() + \\\"]\\\");\\n\\twhile (queue.size > 0) {\\n\\t\\tlet current = Array.from(queue)[0];\\n\\t\\tqueue.delete(current);\\n\\t\\tcurrent = JSON.parse(current);\\n\\t\\tif (current[0] != 0) {\\n\\t\\t\\tif (current[0] + 1 > current.length) {\\n\\t\\t\\t\\treturn 1;\\n\\t\\t\\t}\\n\\t\\t\\tfor (let i = 1; i <= current[0] && i < current.length; i++) {\\n\\t\\t\\t\\tqueue.add((\\\"[\\\".concat(current.slice(i)).toString()).concat(\\\"]\\\"));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn 0;\\n}\\nfunction arrayjumpinggameII(data) {\\n\\tlet queue = {};\\n\\tlet best = 1e308;\\n\\tqueue[data.toString()] = 0;\\n\\twhile (Object.keys(queue).length > 0) {\\n\\t\\tlet current = Object.keys(queue)[0];\\n\\t\\tlet value = queue[current];\\n\\t\\tdelete queue[current];\\n\\t\\tcurrent = current.split(\\\",\\\").map(i => parseInt(i));\\n\\t\\tif (current[0] + 1 >= current.length) {\\n\\t\\t\\tbest = Math.min(best, value + 1);\\n\\t\\t} else {\\n\\t\\t\\tfor (let i = 1; i <= current[0]; i++) {\\n\\t\\t\\t\\tlet newIndex = current.slice(i).toString();\\n\\t\\t\\t\\tif (!Object.keys(queue).includes(newIndex)) queue[newIndex] = 1e308;\\n\\t\\t\\t\\tqueue[newIndex] = Math.min(queue[newIndex], value + 1);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\treturn best == 1e308 ? 0 : best;\\n}\\nfunction hammingencode(data) {\\n const enc = [0];\\n const data_bits = data.toString(2).split(\\\"\\\").reverse();\\n\\n data_bits.forEach((e, i, a) => {\\n a[i] = parseInt(e);\\n });\\n\\n let k = data_bits.length;\\n\\n for (let i = 1; k > 0; i++) {\\n if ((i & (i - 1)) !== 0) {\\n enc[i] = data_bits[--k];\\n } else {\\n enc[i] = 0;\\n }\\n }\\n\\n let parity = 0;\\n\\n /* Figure out the subsection parities */\\n for (let i = 0; i < enc.length; i++) {\\n if (enc[i]) {\\n parity ^= i;\\n }\\n }\\n\\n parity = parity.toString(2).split(\\\"\\\").reverse();\\n parity.forEach((e, i, a) => {\\n a[i] = parseInt(e);\\n });\\n\\n /* Set the parity bits accordingly */\\n for (let i = 0; i < parity.length; i++) {\\n enc[2 ** i] = parity[i] ? 1 : 0;\\n }\\n\\n parity = 0;\\n /* Figure out the overall parity for the entire block */\\n for (let i = 0; i < enc.length; i++) {\\n if (enc[i]) {\\n parity++;\\n }\\n }\\n\\n /* Finally set the overall parity bit */\\n enc[0] = parity % 2 === 0 ? 0 : 1;\\n\\n return enc.join(\\\"\\\");\\n}\\nfunction hammingdecode(data) {\\n\\tlet powersoftwo = (new Array(Math.ceil(Math.log2(data)))).fill(0).map((_, i) => 2 ** i);\\n\\tlet badbits = [];\\n\\tfor (let i of powersoftwo.filter(x => x < data.length)) {\\n\\t\\tlet checksum = (new Array(data.length)).fill(0).map((_, i) => i).filter(x => x > i && (i & x)).map(x => parseInt(data.substring(x, x + 1))).reduce((a, b) => a ^ b);\\n\\t\\tif (parseInt(data.substring(i, i + 1)) != checksum) {\\n\\t\\t\\tbadbits.push(i);\\n\\t\\t}\\n\\t}\\n\\tif (badbits.length == 0) { // No error in the data\\n\\t\\tlet checksum = data.substring(1).split(\\\"\\\").map(x => parseInt(x)).reduce((a, b) => a ^ b);\\n\\t\\tif (checksum == parseInt(data.substring(0, 1))) {\\n\\t\\t\\tlet number = data.split(\\\"\\\").map(x => parseInt(x));\\n\\t\\t\\tfor (let i of powersoftwo.filter(x => x < data.length).reverse()) {\\n\\t\\t\\t\\tnumber.splice(i, 1);\\n\\t\\t\\t}\\n\\t\\t\\tnumber.splice(0, 1);\\n\\t\\t\\treturn number.reduce((a, b) => a * 2 + b);\\n\\t\\t}\\n\\t}\\n\\tlet badindex = badbits.reduce((a, b) => a | b, 0);\\n\\treturn hammingdecode(data.substring(0, badindex).concat(data.substring(badindex, badindex + 1) == \\\"0\\\" ? \\\"1\\\" : \\\"0\\\").concat(data.substring(badindex + 1)));\\n}\\nfunction findallvalidmathexpressions(data) {\\n\\tlet queue = new Set();\\n\\tqueue.add(data[0]);\\n\\tfor (let current of queue) {\\n\\t\\tlet splitted = current.split(\\\"\\\");\\n\\t\\tfor (let i = 1; i < splitted.length; i++) {\\n\\t\\t\\tif (!(\\\"+-*\\\".includes(splitted[i - 1])) && !(\\\"+-*\\\".includes(splitted[i]))) {\\n\\t\\t\\t\\tqueue.add((splitted.slice(0, i).concat(\\\"+\\\").concat(splitted.slice(i))).join(\\\"\\\"));\\n\\t\\t\\t\\tqueue.add((splitted.slice(0, i).concat(\\\"-\\\").concat(splitted.slice(i))).join(\\\"\\\"));\\n\\t\\t\\t\\tqueue.add((splitted.slice(0, i).concat(\\\"*\\\").concat(splitted.slice(i))).join(\\\"\\\"));\\n\\t\\t\\t\\t//\\t\\t\\t\\tqueue.add((splitted.slice(0, i).concat(\\\"*-\\\").concat(splitted.slice(i))).join(\\\"\\\"));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\tlet zeroes = Array.from(queue) //.concat(Array.from(queue).map(x => \\\"-\\\".concat(x)));\\n\\tfor (let i = 0; i < 10; i++) {\\n\\t\\tzeroes = zeroes.filter(x => !x.includes(\\\"+0\\\".concat(i.toString())));\\n\\t\\tzeroes = zeroes.filter(x => !x.includes(\\\"-0\\\".concat(i.toString())));\\n\\t\\tzeroes = zeroes.filter(x => !x.includes(\\\"*0\\\".concat(i.toString())));\\n\\t\\tzeroes = zeroes.filter(x => x.substring(0, 1) != \\\"0\\\" || \\\"+-*\\\".includes(x.substring(1, 2)));\\n\\t}\\n\\treturn zeroes.filter(x => eval(x) == data[1]);\\n}\\nfunction fcnFindAllValidMathExpressions(data)\\n{\\n const digitsStr = data[0];\\n const target = data[1];\\n\\n const digits = [];\\n for (const digit of digitsStr)\\n {\\n digits.push(Number(digit));\\n }\\n\\n return calcResults(digits, target);\\n}\\nfunction calcResults(digits, target, multiplier = 1, digitsLength = digits.length)\\n{\\n const results = [];\\n \\n let numberSplit = 0;\\n let numberSplitMultiplied = 0;\\n let factorDigit = 1;\\n let i = digitsLength - 1;\\n while (i >= 0)\\n {\\n const newDigit = digits[i];\\n if (newDigit != 0 || i == digitsLength - 1)\\n {\\n numberSplit = numberSplit + newDigit*factorDigit;\\n numberSplitMultiplied = numberSplit*multiplier;\\n\\n if (i == 0 && numberSplitMultiplied == target)\\n {\\n results.push(numberSplit.toString());\\n break;\\n }\\n\\n let resultsSub = calcResults(digits, target - numberSplitMultiplied, 1, i);\\n if (resultsSub.length != 0)\\n {\\n const endString = \\\"+\\\" + numberSplit.toString();\\n resultsSub.forEach(resultSub => results.push(resultSub + endString));\\n }\\n\\n if (numberSplitMultiplied != 0) resultsSub = calcResults(digits, target + numberSplitMultiplied, 1, i);\\n if (resultsSub.length != 0)\\n {\\n const endString = \\\"-\\\" + numberSplit.toString();\\n resultsSub.forEach(resultSub => results.push(resultSub + endString));\\n }\\n\\n resultsSub = calcResults(digits, target, numberSplitMultiplied, i);\\n if (resultsSub.length != 0)\\n {\\n const endString = \\\"*\\\" + numberSplit.toString();\\n resultsSub.forEach(resultSub => results.push(resultSub + endString));\\n }\\n }\\n\\n factorDigit *= 10;\\n --i;\\n }\\n return results;\\n}\\nfunction sanitizeparentheses(data) {\\n\\tlet queue = new Set();\\n\\tqueue.add(data);\\n\\twhile (Array.from(queue).length > 0 && (Array.from(queue)[0].split(\\\"\\\").includes(\\\"(\\\") || Array.from(queue)[0].split(\\\"\\\").includes(\\\")\\\"))) {\\n\\t\\tlet answer = [];\\n\\t\\tlet nextqueue = new Set();\\n\\t\\tfor (let current of Array.from(queue)) {\\n\\t\\t\\tlet good = true;\\n\\t\\t\\tlet goodsofar = 0;\\n\\t\\t\\tfor (let i = 0; i < current.length; i++) {\\n\\t\\t\\t\\tif (current.substring(i, i + 1) == \\\"(\\\") {\\n\\t\\t\\t\\t\\tgoodsofar += 1;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (current.substring(i, i + 1) == \\\")\\\") {\\n\\t\\t\\t\\t\\tgoodsofar -= 1;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (goodsofar < 0) {\\n\\t\\t\\t\\t\\tgood = false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tif (goodsofar != 0) {\\n\\t\\t\\t\\tgood = false;\\n\\t\\t\\t}\\n\\t\\t\\tif (good) {\\n\\t\\t\\t\\tanswer.push(current);\\n\\t\\t\\t}\\n\\t\\t\\tfor (let i = 0; i < current.length; i++) {\\n\\t\\t\\t\\tif (\\\"()\\\".includes(current.substring(i, i + 1))) {\\n\\t\\t\\t\\t\\tnextqueue.add(current.substring(0, i).concat(current.substring(i + 1)));\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (answer.length > 0) {\\n\\t\\t\\treturn answer;\\n\\t\\t}\\n\\t\\tqueue = JSON.parse(JSON.stringify(Array.from(nextqueue)));\\n\\t}\\n\\treturn [Array.from(queue)[0]];\\n}\\nfunction bigIntSquareRoot(input) {\\n /* Sample description:\\n You are given a ~200 digit BigInt. Find the square root of this number, to the nearest integer.\\nHint: If you are having trouble, you might consult https://en.wikipedia.org/wiki/Methods_of_computing_square_roots\\n\\nInput number:\\n155749932796205787079025839946442092616646565216212968193628150507722784379219739882976855229303236383313179875170603194170831690566247341307989070313945888007061855549721919178598301718356612610671431\\n */\\n\\n // Yes, this could be inlined, but I was testing different algorithms, and it seems to work, so...\\n return squareRootHeronsMethod(input).toString();\\n}\\nfunction squareRootHeronsMethod(input) {\\n // Shouldn't be necessary; added during testing due to infinite loops with earlier designs\\n const maxPasses = 400;\\n let passes = 0;\\n let x = 1n;\\n\\n // This SHOULD provide us with bounds if the root would be a decimal value\\n while (!(x ** 2n <= input && (x + 1n) ** 2n > input)) {\\n x = (x + (input / x)) / 2n;\\n if (passes > maxPasses) {\\n return -1n;\\n }\\n passes++;\\n }\\n\\n // If it isn't a perfect square, check which value is closer\\n if (absoluteValue(input - (x ** 2n)) > absoluteValue(input - ((x + 1n) ** 2n))) {\\n x += 1n;\\n }\\n\\n return x;\\n}\\nfunction absoluteValue(n) {\\n if (n > 0n) {return n;}\\n\\n return 0n - n;\\n}\\nfunction shortestpathinagrid(data) {\\n\\tlet solutions = { \\\"0,0\\\": \\\"\\\" };\\n\\tlet queue = new Set();\\n\\tqueue.add(\\\"0,0\\\");\\n\\tfor (let current of queue) {\\n\\t\\tlet x = parseInt(current.split(\\\",\\\")[0]);\\n\\t\\tlet y = parseInt(current.split(\\\",\\\")[1]);\\n\\t\\tif (x > 0) {\\n\\t\\t\\tif (data[x - 1][y] == 0) {\\n\\t\\t\\t\\tlet key = (x - 1).toString().concat(\\\",\\\").concat(y.toString());\\n\\t\\t\\t\\tif (!Array.from(queue).includes(key)) {\\n\\t\\t\\t\\t\\tsolutions[key] = solutions[current] + \\\"U\\\";\\n\\t\\t\\t\\t\\tqueue.add(key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (x + 1 < data.length) {\\n\\t\\t\\tif (data[x + 1][y] == 0) {\\n\\t\\t\\t\\tlet key = (x + 1).toString().concat(\\\",\\\").concat(y.toString());\\n\\t\\t\\t\\tif (!Array.from(queue).includes(key)) {\\n\\t\\t\\t\\t\\tsolutions[key] = solutions[current] + \\\"D\\\";\\n\\t\\t\\t\\t\\tqueue.add(key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (y > 0) {\\n\\t\\t\\tif (data[x][y - 1] == 0) {\\n\\t\\t\\t\\tlet key = x.toString().concat(\\\",\\\").concat((y - 1).toString());\\n\\t\\t\\t\\tif (!Array.from(queue).includes(key)) {\\n\\t\\t\\t\\t\\tsolutions[key] = solutions[current] + \\\"L\\\";\\n\\t\\t\\t\\t\\tqueue.add(key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (y + 1 < data[0].length) {\\n\\t\\t\\tif (data[x][y + 1] == 0) {\\n\\t\\t\\t\\tlet key = x.toString().concat(\\\",\\\").concat((y + 1).toString());\\n\\t\\t\\t\\tif (!Array.from(queue).includes(key)) {\\n\\t\\t\\t\\t\\tsolutions[key] = solutions[current] + \\\"R\\\";\\n\\t\\t\\t\\t\\tqueue.add(key);\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\tlet finalkey = (data.length - 1).toString().concat(\\\",\\\").concat((data[0].length - 1).toString());\\n\\tif (Object.keys(solutions).includes(finalkey)) {\\n\\t\\treturn solutions[finalkey];\\n\\t}\\n\\treturn \\\"\\\";\\n}\\nfunction totalPrimes(n) {\\n let low = n[0]\\n let high = n[1]\\n /** Modified Sieve of Eratosthenes to find primes across a range, rather than all primes below a value.*/\\n //0 and 1 are not checked, so are removed here.\\n if (low < 2) {\\n low = 2;\\n }\\n let primes = 0;\\n //Only store the potential primes in the low to high range instead of 0 to high.\\n const arr = Array(high - low + 1);\\n //In order to mark off all composite numbers, we need to run up through sqrt(high), since primes squares are the worst case.\\n const checks = simpleSieve(Math.ceil(Math.sqrt(high)));\\n for (const i of checks) {\\n //same logic as for the simple sieve to mark off multiples of identified primes, but we only start checking at the first multiple>=low.\\n const lim = Math.max(i, Math.ceil(low / i)) * i;\\n for (let j = lim; j <= high; j += i) {\\n arr[j - low] = 1;\\n }\\n }\\n for (let a = 0; a <= high - low; a++) {\\n if (!arr[a]) {\\n //We don't really care what the value of the prime is, just how many we find.\\n ++primes;\\n }\\n }\\n return primes;\\n}\\nfunction simpleSieve(max) {\\n const primes = [];\\n //The array of numbers to check if they're prime is left blank. Blank and resulting prime values are falsey, non-primes are marked truthy.\\n const arr = Array(max);\\n //We only need to check factors up to the square root of max\\n for (let i = 2; i * i <= max; i++) {\\n //and only the prime factors\\n if (!arr[i]) {\\n //and we can then mark off all subsequent multiples of that prime\\n for (let p = i * i; p <= max; p += i) {\\n arr[p] = 1;\\n }\\n }\\n }\\n //It should be faster to loop over the array again than to check factors all the way to max and mark primes at the same time.\\n for (let i = 2; i <= max; i++) {\\n if (!arr[i]) {\\n primes.push(i);\\n }\\n }\\n return primes;\\n}\\nfunction largestrectangleinmatrix(data) {\\n const histograms = Array.from({ length: data.length }, () => Array(data[0].length).fill(0));\\n for (let i = 0; i < data[0].length; i++) {\\n let count = 0;\\n for (let j = 0; j < data.length; j++) {\\n if (data[j][i] == 0) {\\n count++;\\n } else {\\n count = 0;\\n }\\n histograms[j][i] = count;\\n }\\n }\\n let maxArea = 0;\\n let maxL = 0;\\n let maxR = 0;\\n let maxU = 0;\\n let maxD = 0;\\n for (let i = 0; i < histograms.length; i++) {\\n const row = histograms[i];\\n for (let j = 0; j < row.length; j++) {\\n if (row[j] == 0) continue;\\n let left = j;\\n let right = j;\\n // If the index is -1/row.length (out of bounds), it will return undefined. That's when comparing to a number\\n // also returns false.\\n while (row[left - 1] >= row[j]) {\\n left--;\\n }\\n while (row[right + 1] >= row[j]) {\\n right++;\\n }\\n if ((right - left + 1) * row[j] > maxArea) {\\n maxArea = (right - left + 1) * row[j];\\n maxL = left;\\n maxR = right;\\n maxU = i - row[j] + 1;\\n maxD = i;\\n }\\n }\\n }\\n return [\\n [maxU, maxL],\\n [maxD, maxR],\\n ];\\n}\\n\\nonmessage = (event) => {postMessage([eval(event.data[0])(event.data[1]), event.data[2], event.data[3], event.data[0]]);}\\n`;\""},{"filename":"SphyxOS/bins/corp.js","file":"\"/* Author: Sphyxis */\\nconst corpName = \\\"Sphyx-Corp\\\"\\nconst div1 = \\\"Family Farm\\\" //Agriculture\\nconst div2 = \\\"The Bog Pit\\\" //Chemical\\nconst div3 = \\\"Ciggy\\\\'s r Us\\\" //Tobacco\\nconst div4 = \\\"Bob\\\\'s Burgers\\\" //Restaurant\\nconst div5 = \\\"Brawndo\\\" //Water Utilities\\nconst div6 = \\\"Fabrikator\\\" //Computer Hardware\\nconst div7 = \\\"The Furnace\\\" //Refinery\\nconst div8 = \\\"Diggers Inc.\\\" //Mining\\nlet win\\nconst workers = []\\nlet workersWIP = []\\nconst round1Money = 440e9 //b\\nconst round2Money = 8.8e12 //t\\nconst round3Money = 12e15 //q\\nconst round4Money = 500e18 //Q\\nlet tobaccoBooster = false\\nlet ta2DB = [] //TA2 DB\\nconst indDataDB = []\\nconst matDataDB = []\\nlet researchedDB = []\\nlet hasDivDB = []\\nlet hasOfficeDB = []\\nlet hasWarehouseDB = []\\nlet roundTrigger = false\\nlet bnMults\\nlet oldRound\\nlet teaNeeded\\nlet investOffer\\nconst HEIGHT = 780\\nconst WIDTH = 900\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n if (!ns.args.includes(\\\"quiet\\\")) ns.ui.openTail()\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n ns.clearLog()\\n ns.clearPort(9)\\n ns.writePort(9, ns.pid)\\n ns.atExit(() => {\\n ns.clearPort(9)\\n })\\n hasDivDB = []\\n researchedDB = []\\n hasOfficeDB = []\\n hasWarehouseDB = []\\n win = false\\n ns.atExit(() => {\\n for (const worker of workers)\\n worker.terminate()\\n for (const worker of workersWIP)\\n worker.terminate()\\n workers.length = 0\\n workersWIP = []\\n ns.clearPort(9)\\n if (win) win.close()\\n })\\n //Create our proxy files\\n writeProxy(ns)\\n writeProxyTry(ns)\\n writeBNMults(ns)\\n const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n const myBN = resetInfo.currentNode\\n const sfLevel = resetInfo.ownedSF.has(3) ? resetInfo.ownedSF.get(3) : 0\\n if (myBN !== 3 && sfLevel !== 3) {\\n update(ns, \\\"You cannot start a corp yet. Be in BN 3 or have SF 3.3 to start.\\\")\\n ns.exit()\\n }\\n\\n bnMults = await getBNMults(ns)\\n const selfFund = myBN === 3 ? false : true\\n if (!await proxy(ns, \\\"corporation.canCreateCorporation\\\", selfFund)) {\\n ns.clearLog()\\n ns.print(\\\"Cannot create a corporation\\\")\\n ns.exit()\\n }\\n getCommands(ns)\\n await ns.asleep(4)\\n while (!await proxy(ns, \\\"corporation.hasCorporation\\\")) {\\n await proxy(ns, \\\"corporation.createCorporation\\\", corpName, selfFund)\\n await ns.asleep(1000)\\n clearLogs(ns)\\n update(ns, \\\"Cannot create corporation yet\\\")\\n }\\n const invest = await proxy(ns, \\\"corporation.getInvestmentOffer\\\")\\n let round = invest.round\\n teaNeeded = true\\n oldRound = 0\\n tobaccoBooster = false\\n while (round === 1) {\\n await prep(ns)\\n await updateHud(ns)\\n let division1 = await proxy(ns, \\\"corporation.getDivision\\\", div1)\\n if (division1.numAdVerts < 2)\\n while (division1.numAdVerts < 2) {\\n await proxy(ns, \\\"corporation.hireAdVert\\\", div1)\\n division1 = await proxy(ns, \\\"corporation.getDivision\\\", div1)\\n }\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const nState = corp.nextState\\n if (nState === \\\"SALE\\\")\\n await sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div1, \\\"Sector-12\\\")\\n if (!teaNeeded && office.employeeJobs.Business > 0) {\\n await optimizeMats(ns)\\n }\\n await purchase(ns)\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = await teaParty(ns)\\n round = await checkInvest(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n await manageOffice(ns)\\n await warehouseUpgrade(ns)\\n }\\n await proxyTry(ns, \\\"corporation.levelUpgrade\\\", \\\"ABC SalesBots\\\")\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 2) {\\n await prep(ns)\\n await updateHud(ns)\\n let hasDiv2 = false\\n //Set up Tobacco \\n let count = 0\\n if (researchedDB[\\\"Export\\\"])\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n while (hasDiv2 && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Factories\\\") < 16 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Smart Factories\\\") <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Smart Factories\\\")\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const nState = corp.nextState\\n if (nState === \\\"SALE\\\")\\n await sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n await importExport(ns)\\n await purchase(ns)\\n const materials = await proxy(ns, \\\"corporation.getMaterial\\\", div1, \\\"Sector-12\\\", \\\"Plants\\\")\\n while (await corpFunds(ns) > await proxy(ns, \\\"corporation.getHireAdVertCost\\\", div1) && await proxy(ns, \\\"corporation.getHireAdVertCount\\\", div1) < 12 && hasDiv2)\\n await proxyTry(ns, \\\"corporation.hireAdVert\\\", div1)\\n if (await proxy(ns, \\\"corporation.getHireAdVertCount\\\", div1) < 11 && materials.stored > 200)\\n await proxyTry(ns, \\\"corporation.hireAdVert\\\", div1)\\n else if (hasDiv2 && materials.stored > 200)\\n await proxyTry(ns, \\\"corporation.hireAdVert\\\", div1)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div1, \\\"Sector-12\\\")\\n if (ns.ui.getGameInfo()?.versionNumber === undefined) {\\n if (!teaNeeded && office.employeeJobs.Business > 0 && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"DreamSense\\\") === 0)\\n await proxyTry(ns, \\\"corporation.levelUpgrade\\\", \\\"DreamSense\\\")\\n }\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = await teaParty(ns)\\n round = await checkInvest(ns)\\n await warehouseUpgrade(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n await manageOffice(ns)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div1, \\\"Sector-12\\\")\\n if (!teaNeeded && office.employeeJobs.Business > 0) {\\n\\n while (hasDiv2 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"ABC SalesBots\\\") && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"ABC SalesBots\\\") < 30)\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"ABC SalesBots\\\")\\n await optimizeMats(ns)\\n }\\n while (await corpFunds(ns) >= await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"ABC SalesBots\\\") && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"ABC SalesBots\\\") < 10)\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"ABC SalesBots\\\")\\n }\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 3 || round === 4) {\\n await prep(ns)\\n await updateHud(ns)\\n while (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Factories\\\") < 20 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Smart Factories\\\") <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Smart Factories\\\")\\n\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const nState = corp.nextState\\n if (nState === \\\"SALE\\\") {\\n await sell(ns)\\n }\\n if (nState === \\\"PURCHASE\\\") {\\n await importExport(ns)\\n await purchase(ns)\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div1, \\\"Sector-12\\\", \\\"Plants\\\")\\n if (material.stored > 200)\\n await proxyTry(ns, \\\"corporation.hireAdVert\\\", div1)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div1, \\\"Sector-12\\\")\\n if (ns.ui.getGameInfo()?.versionNumber === undefined) {\\n if (!teaNeeded && office.employeeJobs.Business > 0 && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"DreamSense\\\") === 0)\\n await proxyTry(ns, \\\"corporation.levelUpgrade\\\", \\\"DreamSense\\\")\\n }\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = await teaParty(ns)\\n round = await checkInvest(ns)\\n await manageProducts(ns)\\n await spendRP(ns)\\n await warehouseUpgrade(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n await updateMisc(ns)\\n await manageOffice(ns)\\n await optimizeMats(ns)\\n }\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 5) {\\n await prep(ns)\\n await updateHud(ns)\\n\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const nState = corp.nextState\\n if (nState === \\\"SALE\\\") {\\n await sell(ns)\\n }\\n if (nState === \\\"PURCHASE\\\") {\\n await updateMisc(ns)\\n await importExport(ns)\\n await purchase(ns)\\n }\\n\\n if (nState === \\\"START\\\") {\\n teaNeeded = await teaParty(ns)\\n await manageProducts(ns)\\n await spendRP(ns)\\n await warehouseUpgrade(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n await optimizeMats(ns)\\n await manageOffice(ns)\\n }\\n await ns.corporation.nextUpdate()\\n }\\n}\\n/** @param {NS} ns */\\nasync function checkInvest(ns) {\\n const round = investOffer.round\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n if (round === 1) {\\n if (round1Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n await proxy(ns, \\\"corporation.acceptInvestmentOffer\\\")\\n teaNeeded = true\\n roundTrigger = false\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Off to round 2!\\\")\\n return 2\\n }\\n }\\n return 1\\n }\\n if (round === 2) {\\n let hasDiv2 = false\\n //Set up Tobacco \\n let count = 0\\n if (researchedDB[\\\"Export\\\"])\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n if ((hasDiv2 && investOffer.funds + corp.funds > 30e9 && round2Money * bnMults.CorporationValuation < investOffer.funds + corp.funds) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + Math.min(30e9, corp.funds)) {\\n oldRound = investOffer.funds + Math.min(30e9, corp.funds)\\n }\\n else if (investOffer.funds + Math.min(30e9, corp.funds) > 30e9) {\\n await proxy(ns, \\\"corporation.acceptInvestmentOffer\\\")\\n teaNeeded = true\\n roundTrigger = false\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Off to round 3!\\\")\\n return 3\\n }\\n }\\n return 2\\n }\\n if (round === 3) {\\n if (round3Money * bnMults.CorporationValuation < (investOffer.funds * 4) + (corp.funds * bnMults.CorporationValuation)) {\\n tobaccoBooster = true\\n }\\n if ((round3Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation)) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n await proxy(ns, \\\"corporation.acceptInvestmentOffer\\\")\\n teaNeeded = true\\n roundTrigger = false\\n tobaccoBooster = false\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Off to round 4!\\\")\\n return 4\\n }\\n }\\n return 3\\n }\\n if (round === 4) {\\n if (round4Money * bnMults.CorporationValuation < (investOffer.funds * 4) + (corp.funds * bnMults.CorporationValuation)) {\\n tobaccoBooster = true\\n }\\n if ((round4Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation)) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n await proxy(ns, \\\"corporation.acceptInvestmentOffer\\\")\\n teaNeeded = true\\n roundTrigger = false\\n if (!ns.args.includes(\\\"quiet\\\")) ns.tprintf(\\\"Off to round 5!\\\")\\n return 5\\n }\\n }\\n return 4\\n }\\n}\\n/** @param {NS} ns */\\nasync function corpFunds(ns) {\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n return corp.funds\\n}\\n/** @param {NS} ns */\\nasync function prep(ns) {\\n investOffer = await proxy(ns, \\\"corporation.getInvestmentOffer\\\")\\n const round = investOffer.round\\n if (round >= 1) {\\n if (!hasDivDB[div1]) {\\n let division1 = await proxyTry(ns, \\\"corporation.getDivision\\\", div1)\\n if (division1)\\n hasDivDB[div1] = division1\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Agriculture\\\", div1)\\n division1 = await proxyTry(ns, \\\"corporation.getDivision\\\", div1)\\n if (division1)\\n hasDivDB[div1] = division1\\n }\\n }\\n for (const city of cities) {\\n if (!hasOfficeDB[div1 + city]) {\\n await proxyTry(ns, \\\"corporation.expandCity\\\", div1, city)\\n if (await proxyTry(ns, \\\"corporation.getOffice\\\", div1, city))\\n hasOfficeDB[div1 + city] = true\\n }\\n if (!hasWarehouseDB[div1 + city]) {\\n await proxyTry(ns, \\\"corporation.purchaseWarehouse\\\", div1, city)\\n const warehouse = await proxy(ns, \\\"corporation.hasWarehouse\\\", div1, city)\\n if (warehouse)\\n hasWarehouseDB[div1 + city] = warehouse\\n }\\n }\\n }\\n if (round >= 2) {\\n if (!researchedDB[\\\"Export\\\"]) {\\n await proxyTry(ns, \\\"corporation.purchaseUnlock\\\", \\\"Export\\\")\\n if (await proxy(ns, \\\"corporation.hasUnlock\\\", \\\"Export\\\"))\\n researchedDB[\\\"Export\\\"] = true\\n }\\n if (researchedDB[\\\"Export\\\"]) {\\n if (!hasDivDB[div2]) {\\n let division2 = await proxyTry(ns, \\\"corporation.getDivision\\\", div2)\\n if (division2)\\n hasDivDB[div2] = division2\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Chemical\\\", div2)\\n division2 = await proxyTry(ns, \\\"corporation.getDivision\\\", div2)\\n if (division2)\\n hasDivDB[div2] = division2\\n }\\n }\\n if (hasDivDB[div2]) {\\n for (const city of cities) {\\n if (!hasOfficeDB[div2 + city]) {\\n await proxyTry(ns, \\\"corporation.expandCity\\\", div2, city)\\n if (await proxyTry(ns, \\\"corporation.getOffice\\\", div2, city))\\n hasOfficeDB[div2 + city] = true\\n }\\n if (!hasWarehouseDB[div2 + city]) {\\n await proxyTry(ns, \\\"corporation.purchaseWarehouse\\\", div2, city)\\n if (await proxy(ns, \\\"corporation.hasWarehouse\\\", div2, city))\\n hasWarehouseDB[div2 + city] = true\\n }\\n }\\n }\\n }\\n }\\n if (round >= 3) {\\n if (!researchedDB[\\\"Market Research - Demand\\\"]) {\\n await proxyTry(ns, \\\"corporation.purchaseUnlock\\\", \\\"Market Research - Demand\\\")\\n if (await proxy(ns, \\\"corporation.hasUnlock\\\", \\\"Market Research - Demand\\\"))\\n researchedDB[\\\"Market Research - Demand\\\"] = true\\n }\\n if (!researchedDB[\\\"Market Data - Competition\\\"]) {\\n await proxyTry(ns, \\\"corporation.purchaseUnlock\\\", \\\"Market Data - Competition\\\")\\n if (await proxy(ns, \\\"corporation.hasUnlock\\\", \\\"Market Data - Competition\\\"))\\n researchedDB[\\\"Market Data - Competition\\\"] = true\\n }\\n if (!hasDivDB[div3] && researchedDB[\\\"Market Research - Demand\\\"] && researchedDB[\\\"Market Data - Competition\\\"]) {\\n let division3 = await proxyTry(ns, \\\"corporation.getDivision\\\", div3)\\n if (division3)\\n hasDivDB[div3] = division3\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Tobacco\\\", div3)\\n division3 = await proxyTry(ns, \\\"corporation.getDivision\\\", div3)\\n if (division3)\\n hasDivDB[div3] = division3\\n }\\n }\\n if (hasDivDB[div3]) {\\n for (const city of cities) {\\n if (!hasOfficeDB[div3 + city]) {\\n await proxyTry(ns, \\\"corporation.expandCity\\\", div3, city)\\n if (await proxyTry(ns, \\\"corporation.getOffice\\\", div3, city))\\n hasOfficeDB[div3 + city] = true\\n }\\n if (!hasWarehouseDB[div3 + city]) {\\n await proxyTry(ns, \\\"corporation.purchaseWarehouse\\\", div3, city)\\n if (await proxy(ns, \\\"corporation.hasWarehouse\\\", div3, city))\\n hasWarehouseDB[div3 + city] = true\\n }\\n }\\n }\\n }\\n if (round >= 5) {\\n let division4 = await proxyTry(ns, \\\"corporation.getDivision\\\", div4)\\n if (division4)\\n hasDivDB[div4] = division4\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Restaurant\\\", div4)\\n division4 = await proxyTry(ns, \\\"corporation.getDivision\\\", div4)\\n if (division4)\\n hasDivDB[div4] = division4\\n }\\n for (const city of cities) {\\n if (!hasOfficeDB[div4 + city]) {\\n await proxyTry(ns, \\\"corporation.expandCity\\\", div4, city)\\n if (await proxyTry(ns, \\\"corporation.getOffice\\\", div4, city))\\n hasOfficeDB[div4 + city] = true\\n }\\n if (!hasWarehouseDB[div4 + city]) {\\n await proxy(ns, \\\"corporation.purchaseWarehouse\\\", div4, city)\\n if (await proxy(ns, \\\"corporation.hasWarehouse\\\", div4, city))\\n hasWarehouseDB[div4 + city] = true\\n }\\n }\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n if (corp.valuation >= 100e12) {\\n if (!researchedDB[\\\"Government Partnership\\\"]) {\\n await proxyTry(ns, \\\"corporation.purchaseUnlock\\\", \\\"Government Partnership\\\")\\n if (await proxy(ns, \\\"corporation.hasUnlock\\\", \\\"Government Partnership\\\"))\\n researchedDB[\\\"Government Partnership\\\"] = true\\n }\\n if (!researchedDB[\\\"Shady Accounting\\\"]) {\\n await proxyTry(ns, \\\"corporation.purchaseUnlock\\\", \\\"Shady Accounting\\\")\\n if (await proxy(ns, \\\"corporation.hasUnlock\\\", \\\"Shady Accounting\\\"))\\n researchedDB[\\\"Shady Accounting\\\"] = true\\n }\\n if (!corp.public) {\\n await proxy(ns, \\\"corporation.goPublic\\\", 0)\\n await proxy(ns, \\\"corporation.issueDividends\\\", 0.1)\\n }\\n }\\n if (corp.revenue >= 1e24) {\\n let division5 = await proxyTry(ns, \\\"corporation.getDivision\\\", div5)\\n if (division5)\\n hasDivDB[div5] = await proxy(ns, \\\"corporation.getDivision\\\", div5)\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Water Utilities\\\", div5)\\n division5 = await proxyTry(ns, \\\"corporation.getDivision\\\", div5)\\n if (division5)\\n hasDivDB[div5] = await proxy(ns, \\\"corporation.getDivision\\\", div5)\\n }\\n let division6 = await proxyTry(ns, \\\"corporation.getDivision\\\", div6)\\n if (division6)\\n hasDivDB[div6] = await proxy(ns, \\\"corporation.getDivision\\\", div6)\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Computer Hardware\\\", div6)\\n division6 = await proxyTry(ns, \\\"corporation.getDivision\\\", div6)\\n if (division6)\\n hasDivDB[div6] = await proxy(ns, \\\"corporation.getDivision\\\", div6)\\n }\\n let division7 = await proxyTry(ns, \\\"corporation.getDivision\\\", div7)\\n if (division7)\\n hasDivDB[div7] = await proxy(ns, \\\"corporation.getDivision\\\", div7)\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Refinery\\\", div7)\\n division7 = await proxyTry(ns, \\\"corporation.getDivision\\\", div7)\\n if (division7)\\n hasDivDB[div7] = await proxy(ns, \\\"corporation.getDivision\\\", div7)\\n }\\n let division8 = await proxyTry(ns, \\\"corporation.getDivision\\\", div8)\\n if (division8)\\n hasDivDB[div8] = await proxy(ns, \\\"corporation.getDivision\\\", div8)\\n else {\\n await proxyTry(ns, \\\"corporation.expandIndustry\\\", \\\"Mining\\\", div8)\\n division8 = await proxyTry(ns, \\\"corporation.getDivision\\\", div8)\\n if (division8)\\n hasDivDB[div8] = await proxy(ns, \\\"corporation.getDivision\\\", div8)\\n }\\n for (const city of cities) {\\n //Set up divs\\n const divs = [div5, div6, div7, div8]\\n for (const div of divs) {\\n if (!hasOfficeDB[div + city]) {\\n await proxyTry(ns, \\\"corporation.expandCity\\\", div, city)\\n if (await proxyTry(ns, \\\"corporation.getOffice\\\", div, city))\\n hasOfficeDB[div + city] = true\\n }\\n if (!hasWarehouseDB[div + city]) {\\n await proxyTry(ns, \\\"corporation.purchaseWarehouse\\\", div, city)\\n if (await proxy(ns, \\\"corporation.hasWarehouse\\\", div, city))\\n hasWarehouseDB[div + city] = true\\n }\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function updateMisc(ns) {\\n const round = investOffer.round\\n let corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const mult = round === 3 ? 3 : 2.5\\n let hasDiv4 = false\\n let hasDiv3 = false\\n let div3Count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div3 + city])\\n div3Count++\\n if (div3Count === 6) hasDiv3 = true\\n\\n\\n let div4Count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div4 + city])\\n div4Count++\\n if (div4Count === 6) hasDiv4 = true\\n\\n if (round === 3 && !hasDiv3) return\\n const division3 = await proxy(ns, \\\"corporation.getDivision\\\", div3)\\n const division4 = await proxyTry(ns, \\\"corporation.getDivision\\\", div4)\\n if (round >= 3\\n && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Wilson Analytics\\\") < corp.funds\\n && (((round >= 5)\\n && (hasDiv4\\n && (division4.awareness < Number.MAX_VALUE\\n || division4.popularity < Number.MAX_VALUE)))\\n || (hasDiv3\\n && (division3.awareness < Number.MAX_VALUE\\n || division3.popularity < Number.MAX_VALUE)))) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Wilson Analytics\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n while ((round === 3)\\n && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Wilson Analytics\\\") < await corpFunds(ns)\\n && await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Wilson Analytics\\\") < 2) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Wilson Analytics\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n if (round < 5 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"ABC SalesBots\\\") * mult / 2 < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"ABC SalesBots\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n while (round >= 5 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"ABC SalesBots\\\") * mult / 2 < await corpFunds(ns))\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"ABC SalesBots\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n if ((round === 3 && corp.revenue >= 8e7) || round >= 4) {\\n if (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Neural Accelerators\\\") < 500 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Neural Accelerators\\\") * mult < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Neural Accelerators\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n if (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Project Insight\\\") < 500 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Project Insight\\\") * mult < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Project Insight\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n if (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Nuoptimal Nootropic Injector Implants\\\") < 500 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Nuoptimal Nootropic Injector Implants\\\") * mult < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Nuoptimal Nootropic Injector Implants\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n if (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"FocusWires\\\") < 500 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"FocusWires\\\") * mult < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"FocusWires\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n if (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Speech Processor Implants\\\") < 500 && await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Speech Processor Implants\\\") * mult < corp.funds) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Speech Processor Implants\\\")\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n }\\n\\n if (round >= 3 && round <= 4) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (![\\\"Tobacco\\\", \\\"Restaurant\\\"].includes(hasDivDB[div].type)) continue\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n if (corp.funds >= await proxy(ns, \\\"corporation.getHireAdVertCost\\\", div) * mult / 2\\n && (division.awareness < Number.MAX_VALUE || division.popularity < Number.MAX_VALUE)) {\\n await proxy(ns, \\\"corporation.hireAdVert\\\", div)\\n corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n }\\n }\\n }\\n if (round === 5) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (![\\\"Tobacco\\\", \\\"Restaurant\\\", \\\"Computer Hardware\\\"].includes(hasDivDB[div].type)) continue\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n while (await corpFunds(ns) >= await proxy(ns, \\\"corporation.getHireAdVertCost\\\", div) * mult / 2\\n && (division.awareness < Number.MAX_VALUE || division.popularity < Number.MAX_VALUE))\\n await proxy(ns, \\\"corporation.hireAdVert\\\", div)\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function getRP(ns, div) {\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n return division.researchPoints\\n}\\n/** @param {NS} ns */\\nasync function spendRP(ns) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n switch (hasDivDB[div].type) {\\n case \\\"Mining\\\":\\n case \\\"Refinery\\\":\\n case \\\"Computer Hardware\\\":\\n case \\\"Water Utilities\\\":\\n case \\\"Chemical\\\":\\n case \\\"Agriculture\\\": {\\n if (!researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"]) {\\n if (await getRP(ns, div) / 2 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Hi-Tech R&D Laboratory\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Hi-Tech R&D Laboratory\\\")\\n researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Overclock\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Overclock\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Overclock\\\")\\n researchedDB[div + \\\"Overclock\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Sti.mu\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Sti.mu\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Sti.mu\\\")\\n researchedDB[div + \\\"Sti.mu\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Automatic Drug Administration\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Automatic Drug Administration\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Automatic Drug Administration\\\")\\n researchedDB[div + \\\"Automatic Drug Administration\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Go-Juice\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Go-Juice\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Go-Juice\\\")\\n researchedDB[div + \\\"Go-Juice\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"CPH4 Injections\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"CPH4 Injections\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"CPH4 Injections\\\")\\n researchedDB[div + \\\"CPH4 Injections\\\"] = true\\n }\\n else break\\n }\\n }\\n break\\n case \\\"Restaurant\\\":\\n case \\\"Tobacco\\\": {\\n if (!researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"]) {\\n if (await getRP(ns, div) / 2 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Hi-Tech R&D Laboratory\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Hi-Tech R&D Laboratory\\\")\\n researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"uPgrade: Fulcrum\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"uPgrade: Fulcrum\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"uPgrade: Fulcrum\\\")\\n researchedDB[div + \\\"uPgrade: Fulcrum\\\"] = true\\n }\\n else break\\n break\\n }\\n /*if (!researchedDB[div + \\\"uPgrade: Capacity.I\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"uPgrade: Capacity.I\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"uPgrade: Capacity.I\\\")\\n researchedDB[div + \\\"uPgrade: Capacity.I\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"uPgrade: Capacity.II\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"uPgrade: Capacity.II\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"uPgrade: Capacity.II\\\")\\n researchedDB[div + \\\"uPgrade: Capacity.II\\\"] = true\\n }\\n else break\\n break\\n }\\n */\\n if (!researchedDB[div + \\\"Self-Correcting Assemblers\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Self-Correcting Assemblers\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Self-Correcting Assemblers\\\")\\n researchedDB[div + \\\"Self-Correcting Assemblers\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Drones\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Drones\\\")\\n researchedDB[div + \\\"Drones\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones - Assembly\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Drones - Assembly\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Drones - Assembly\\\")\\n researchedDB[div + \\\"Drones - Assembly\\\"] = false\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones - Transport\\\"]) {\\n if (await getRP(ns, div) / 10 > await proxy(ns, \\\"corporation.getResearchCost\\\", div, \\\"Drones - Transport\\\")) {\\n await proxy(ns, \\\"corporation.research\\\", div, \\\"Drones - Transport\\\")\\n researchedDB[div + \\\"Drones - Transport\\\"] = true\\n }\\n else break\\n break\\n }\\n }\\n break\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function manageProducts(ns) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (!hasDivDB[div].makesProducts) continue\\n let active = 0\\n let calculating = 0\\n let division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress === 100) {\\n const ta2 = ta2DB[div + \\\"Sector-12\\\" + prod]\\n if (ta2 !== undefined && ta2.markupLimit !== 0)\\n active++\\n else\\n calculating++\\n }\\n }\\n //Discontinue?\\n if (active + calculating === division.maxProducts && calculating <= 1) {\\n let worstProd = \\\"none\\\"\\n let worstRating = Infinity\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress != 100 || await getSellPrice(ns, div, \\\"Sector-12\\\", prod) === 0) continue\\n if (await getSellPrice(ns, div, \\\"Sector-12\\\", prod) < worstRating) {\\n worstProd = prod\\n worstRating = await getSellPrice(ns, div, \\\"Sector-12\\\", prod)\\n }\\n }\\n for (const city of cities)\\n delete ta2DB[div + city + worstProd]\\n await proxy(ns, \\\"corporation.discontinueProduct\\\", div, worstProd)\\n division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n }\\n //Discontinue?\\n else if (active + calculating === division.maxProducts && !tobaccoBooster) {\\n let worstProd = \\\"none\\\"\\n let worstRating = Infinity\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress === 100 && product.stats.quality < worstRating) {\\n worstProd = prod\\n worstRating = product.stats.quality\\n }\\n }\\n for (const city of cities)\\n delete ta2DB[div + city + worstProd]\\n await proxy(ns, \\\"corporation.discontinueProduct\\\", div, worstProd)\\n division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n }\\n let researching = false\\n if (division.products.length <= division.maxProducts) {\\n //Are we researching one?\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress < 100) {\\n researching = true\\n break\\n }\\n }\\n }\\n let prodname = \\\"none:\\\" + Math.random()\\n if (hasDivDB[div].type === \\\"Tobacco\\\") {\\n prodname = cigaretts[Math.floor(Math.random() * cigaretts.length)]\\n while (division.products.includes(prodname)) {\\n prodname = cigaretts[Math.floor(Math.random() * cigaretts.length)]\\n }\\n }\\n else if (hasDivDB[div].type === \\\"Restaurant\\\") {\\n prodname = burgers[Math.floor(Math.random() * burgers.length)]\\n while (division.products.includes(prodname)) {\\n prodname = burgers[Math.floor(Math.random() * burgers.length)]\\n }\\n }\\n else if (hasDivDB[div].type === \\\"Computer Hardware\\\") {\\n prodname = hardwares[Math.floor(Math.random() * hardwares.length)]\\n while (division.products.includes(prodname)) {\\n prodname = hardwares[Math.floor(Math.random() * hardwares.length)]\\n }\\n }\\n let active2 = 0\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress === 100)\\n active2++\\n }\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n if (!researching && active2 < division.maxProducts && corp.funds > 200)\\n await proxy(ns, \\\"corporation.makeProduct\\\", div, \\\"Sector-12\\\", prodname, corp.funds / 100, corp.funds / 100)\\n }\\n}\\n/** @param {NS} ns */\\nasync function officeSize(ns, div, city) {\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n return office.size\\n}\\n/** @param {NS} ns */\\nasync function officeNumEmployee(ns, div, city) {\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n return office.numEmployees\\n}\\n/** @param {NS} ns */\\nasync function setJob(ns, div, city, job, total) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) await proxy(ns, \\\"corporation.setJobAssignment\\\", div, city, job, total)\\n else await proxy(ns, \\\"corporation.setAutoJobAssignment\\\", div, city, job, total)\\n}\\n/** @param {NS} ns */\\nasync function manageOffice(ns) {\\n const round = investOffer.round\\n let hasDiv2 = false\\n if (hasDivDB[div2]) {\\n let cityCount = 0\\n for (const city of cities) {\\n if (hasWarehouseDB[div2 + city])\\n cityCount++\\n }\\n if (cityCount === 6) hasDiv2 = true\\n }\\n let hasDiv3 = false\\n if (hasDivDB[div3]) {\\n let cityCount = 0\\n for (const city of cities) {\\n if (hasWarehouseDB[div3 + city]) {\\n cityCount++\\n }\\n }\\n if (cityCount === 6) hasDiv3 = true\\n }\\n\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n switch (hasDivDB[div].type) {\\n case \\\"Agriculture\\\":\\n switch (round) {\\n case 1: {\\n while (await officeSize(ns, div, city) < 4 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) {/*hireEmployee is our stoping point*/ }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n const rp = await getRP(ns, div)\\n if (rp < 60 && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", await officeNumEmployee(ns, div, city))\\n }\\n else if (rp >= 60 && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== 1\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", 1)\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", 1)\\n }\\n }\\n break\\n case 2: {\\n while (hasDiv2 && await officeSize(ns, div, city) < 8 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) <= await corpFunds(ns)) await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n const rp = await getRP(ns, div)\\n if (rp < 700 && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", await officeNumEmployee(ns, div, city))\\n }\\n else if (rp >= 700 && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 2.66)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office.numEmployees - 1 - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 2.66))) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 2.66))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const remainder = office.numEmployees - 1 - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 2.66)\\n await setJob(ns, div, city, \\\"Management\\\", remainder)\\n }\\n }\\n break\\n case 3: {\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (!hasDiv3\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - 1 - Math.floor(office.numEmployees / 3) - 1 - Math.floor(office.numEmployees / 4))) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 4))\\n const left = office.numEmployees - 1 - Math.floor(office.numEmployees / 3) - 1 - Math.floor(office.numEmployees / 4)\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n if (!hasDiv3) break\\n while (await officeSize(ns, div, city) < 8 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - 1 - Math.floor(office.numEmployees / 3) - 1 - Math.floor(office.numEmployees / 4)) {\\n await resetOffice(ns, div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 4))\\n const left = office.numEmployees - 1 - Math.floor(office.numEmployees / 3) - 1 - Math.floor(office.numEmployees / 4)\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n }\\n break\\n case 4: {\\n if (await officeSize(ns, div, city) < 60)\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city))\\n await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 2)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - 1 - Math.floor(office.numEmployees / 2) - 1 - Math.floor(office.numEmployees / 4)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 2))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 4))\\n const left = office.numEmployees - 1 - Math.floor(office.numEmployees / 2) - 1 - Math.floor(office.numEmployees / 4)\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n }\\n break\\n case 5: {\\n if (await officeSize(ns, div, city) < 300)\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city))\\n await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 2.5)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 2.5)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - 1 - Math.floor(office.numEmployees / 2.5) - Math.floor(office.numEmployees / 2.5) - 1) {\\n await resetOffice(ns, div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 2.5))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 2.5))\\n const left = office.numEmployees - 1 - Math.floor(office.numEmployees / 2.5) - Math.floor(office.numEmployees / 2.5) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n }\\n break\\n case \\\"Chemical\\\":\\n switch (round) {\\n case 2: {\\n while (await officeSize(ns, div, city) < 3 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n const rp = await getRP(ns, div)\\n if (rp < 390 && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office.numEmployees)\\n }\\n else if (rp >= 390 && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== 1\\n || office.employeeJobs.Engineer !== 1\\n || office.employeeJobs.Business !== 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", 1)\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n }\\n }\\n break\\n case 3: {\\n if (!hasDiv3) break\\n while (await officeSize(ns, div, city) < 8 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.max(1, Math.floor(office.numEmployees / 4))\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.max(1, Math.floor(office.numEmployees / 4)) - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.max(1, Math.floor(office.numEmployees / 4)))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 4))\\n const left = office.numEmployees - Math.max(1, Math.floor(office.numEmployees / 4)) - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n }\\n break\\n case 4: {\\n if (await officeSize(ns, div, city) < 60)\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city))\\n await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 4))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n }\\n break\\n case 5: {\\n if (await officeSize(ns, div, city) < 300)\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (await officeNumEmployee(ns, div, city) < officeSize(ns, div, city))\\n await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 3))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n }\\n break\\n case \\\"Tobacco\\\":\\n switch (round) {\\n case 3: {\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office.numEmployees)\\n }\\n else if (city === \\\"Sector-12\\\"\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - 1\\n await setJob(ns, div, city, \\\"Management\\\", left)\\n }\\n if (!hasDiv3) break\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const corpRev = corp.revenue\\n while (await officeSize(ns, div, city) < 106 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (corpRev > 50e9)\\n while (await officeSize(ns, div, city) < 226 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 20e9)\\n while (await officeSize(ns, div, city) < 200 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 10e9)\\n while (await officeSize(ns, div, city) < 176 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 5e9)\\n while (await officeSize(ns, div, city) < 156 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 2.5e9)\\n while (await officeSize(ns, div, city) < 146 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 1e9)\\n while (await officeSize(ns, div, city) < 136 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 5e8)\\n while (await officeSize(ns, div, city) < 116 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office2 = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster && office2.employeeJobs[\\\"Research & Development\\\"] !== office2.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office2.numEmployees)\\n }\\n else if (city === \\\"Sector-12\\\"\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office2.numEmployees / 3)\\n || office.employeeJobs.Engineer !== Math.floor(office2.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office2.numEmployees - Math.floor(office2.numEmployees / 3) - Math.floor(office2.numEmployees / 3) - 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office2.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office2.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const left = office2.numEmployees - Math.floor(office2.numEmployees / 3) - Math.floor(office2.numEmployees / 3) - 1\\n await setJob(ns, div, city, \\\"Management\\\", left)\\n }\\n }\\n break\\n case 4: {\\n const corp = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const corpRev = corp.revenue\\n if (await officeSize(ns, div, city) < 250)\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (corpRev > 2e12)\\n while (await officeSize(ns, div, city) < 380 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 1e12)\\n while (await officeSize(ns, div, city) < 360 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 400e9)\\n while (await officeSize(ns, div, city) < 320 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 200e9)\\n while (await officeSize(ns, div, city) < 290 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n else if (corpRev > 100e9)\\n while (await officeSize(ns, div, city) < 270 && await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1) * 1.5 <= await corpFunds(ns))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n if (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city))\\n await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office.numEmployees)\\n }\\n else if (city === \\\"Sector-12\\\"\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - 1\\n await setJob(ns, div, city, \\\"Management\\\", left)\\n }\\n }\\n break\\n case 5:\\n while (await officeSize(ns, div, city) < 1500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (city !== \\\"Sector-12\\\" && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office.numEmployees)\\n }\\n else if (city === \\\"Sector-12\\\"\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const left = office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Management\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Restaurant\\\":\\n switch (round) {\\n case 5:\\n while (await officeSize(ns, div, city) < 1500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (city !== \\\"Sector-12\\\" && office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Research & Development\\\", office.numEmployees)\\n }\\n else if (city === \\\"Sector-12\\\"\\n && (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1)) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n const left = office.numEmployees - Math.floor(office.numEmployees / 4) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Management\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Water Utilities\\\":\\n switch (round) {\\n case 5:\\n while (await officeSize(ns, div, city) < 6500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 3))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Computer Hardware\\\":\\n switch (round) {\\n case 5:\\n while (await officeSize(ns, div, city) < 4500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 3))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Refinery\\\":\\n switch (round) {\\n case 5:\\n while (await officeSize(ns, div, city) < 6500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 3))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Mining\\\":\\n switch (round) {\\n case 5:\\n while (await officeSize(ns, div, city) < 1500 && await corpFunds(ns) >= await proxy(ns, \\\"corporation.getOfficeSizeUpgradeCost\\\", div, city, 1))\\n await proxy(ns, \\\"corporation.upgradeOfficeSize\\\", div, city, 1)\\n while (await officeNumEmployee(ns, div, city) < await officeSize(ns, div, city) && await proxy(ns, \\\"corporation.hireEmployee\\\", div, city)) { }\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.employeeJobs.Unassigned > 0\\n || office.employeeJobs.Operations !== Math.floor(office.numEmployees / 4)\\n || office.employeeJobs.Engineer !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs.Business !== 1\\n || office.employeeJobs.Management !== Math.floor(office.numEmployees / 3)\\n || office.employeeJobs[\\\"Research & Development\\\"] !== office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1) {\\n await resetOffice(ns, div, city)\\n await setJob(ns, div, city, \\\"Operations\\\", Math.floor(office.numEmployees / 4))\\n await setJob(ns, div, city, \\\"Business\\\", 1)\\n await setJob(ns, div, city, \\\"Engineer\\\", Math.floor(office.numEmployees / 3))\\n await setJob(ns, div, city, \\\"Management\\\", Math.floor(office.numEmployees / 3))\\n const left = office.numEmployees - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 3) - Math.floor(office.numEmployees / 4) - 1\\n await setJob(ns, div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function resetOffice(ns, div, city) {\\n await setJob(ns, div, city, \\\"Operations\\\", 0)\\n await setJob(ns, div, city, \\\"Engineer\\\", 0)\\n await setJob(ns, div, city, \\\"Business\\\", 0)\\n await setJob(ns, div, city, \\\"Management\\\", 0)\\n await setJob(ns, div, city, \\\"Research & Development\\\", 0)\\n await setJob(ns, div, city, \\\"Intern\\\", 0)\\n}\\n/** @param {NS} ns */\\nasync function teaParty(ns) {\\n let needed = false\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n if (office.avgEnergy < office.maxEnergy - .5) {\\n await proxy(ns, \\\"corporation.buyTea\\\", div, city)\\n needed = true\\n }\\n if (office.avgMorale < office.maxMorale - 10) {\\n await proxy(ns, \\\"corporation.throwParty\\\", div, city, 500000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale - 5) {\\n await proxy(ns, \\\"corporation.throwParty\\\", div, city, 200000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale - .5) {\\n await proxy(ns, \\\"corporation.throwParty\\\", div, city, 100000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale) {\\n await proxy(ns, \\\"corporation.throwParty\\\", div, city, 50000)\\n needed = false\\n }\\n }\\n }\\n return needed\\n}\\n/** @param {NS} ns */\\nasync function purchase(ns) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const smartBuy = []\\n const warehouse = await proxy(ns, \\\"corporation.getWarehouse\\\", div, city)\\n if (!indDataDB[hasDivDB[div].type]) {\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n }\\n /* Process purchase of materials, not from smart supply */\\n for (const [matName, mat] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n // Smart supply\\n let buyAmt = await maxMatRequired(ns, div, city, matName)\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, matName)\\n buyAmt -= material.stored\\n if (!matDataDB[matName])\\n matDataDB[matName] = await proxy(ns, \\\"corporation.getMaterialData\\\", matName)\\n const maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / matDataDB[matName].size);\\n buyAmt = Math.min(buyAmt, maxAmt);\\n smartBuy[matName] = [buyAmt, mat];\\n } //End process purchase of materials\\n\\n // Use the materials already in the warehouse if the option is on.\\n for (const [matName, [buy, reqMat]] of Object.entries(smartBuy)) {\\n const buyAmt = buy\\n const mult = await getMult(ns, div, city)\\n if (mult[0] === 0) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, matName, 0)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, matName, \\\"MAX\\\", \\\"0\\\")\\n }\\n else if (buyAmt > 0) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, matName, buyAmt / 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, matName, 0, \\\"MP\\\")\\n }\\n else {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, matName, 0)\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, matName)\\n if (material.quality <= 1)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, matName, buyAmt / 10 * -1, \\\"0\\\")\\n else await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, matName, buyAmt / 10 * -1, \\\"MP\\\")\\n }\\n }\\n }//city\\n }//div\\n}\\n/** @param {NS} ns */\\nasync function importExport(ns) {\\n if (!researchedDB[\\\"Export\\\"]) return\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n if (!indDataDB[hasDivDB[div].type].makesMaterials) continue\\n for (const city of cities) {\\n //We make this. Export it\\n for (const name of Object.values(indDataDB[hasDivDB[div].type].producedMaterials)) {\\n if (name === \\\"Plants\\\") { //(IPROD+IINV/10)*(-1) (-IPROD-IINV/10)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div3, \\\"Sector-12\\\", name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div3, city, name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div2, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div2, city, name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div3, city, name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div3, \\\"Sector-12\\\", name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Chemicals\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div1, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div1, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Food\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div4, \\\"Sector-12\\\", name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div4, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div4, \\\"Sector-12\\\", name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div4, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Water\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div1, city, name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div2, city, name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div4, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div1, city, name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div2, city, name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div4, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Hardware\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div5, city, name)\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div8, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div5, city, name, `(IPROD+IINV/10)*(-1)`)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div8, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Metal\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div6, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div6, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n else if (name === \\\"Ore\\\") {\\n await proxyTry(ns, \\\"corporation.cancelExportMaterial\\\", div, city, div7, city, name)\\n await proxyTry(ns, \\\"corporation.exportMaterial\\\", div, city, div7, city, name, `(IPROD+IINV/10)*(-1)`)\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function optimizeMats(ns) {\\n const round = investOffer.round\\n let runningWorkers = 0\\n const results = []\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const type = hasDivDB[div].type\\n if (!indDataDB[type])\\n indDataDB[type] = await proxy(ns, \\\"corporation.getIndustryData\\\", type)\\n let { hardwareFactor, robotFactor, aiCoreFactor, realEstateFactor } = indDataDB[type]\\n if (isNaN(hardwareFactor)) hardwareFactor = 0\\n if (isNaN(robotFactor)) robotFactor = 0\\n if (isNaN(aiCoreFactor)) aiCoreFactor = 0\\n if (isNaN(realEstateFactor)) realEstateFactor = 0\\n\\n const divWeights = [hardwareFactor, robotFactor, aiCoreFactor, realEstateFactor]\\n if (!matDataDB[\\\"Hardware\\\"])\\n matDataDB[\\\"Hardware\\\"] = await proxy(ns, \\\"corporation.getMaterialData\\\", \\\"Hardware\\\")\\n if (!matDataDB[\\\"Robots\\\"])\\n matDataDB[\\\"Robots\\\"] = await proxy(ns, \\\"corporation.getMaterialData\\\", \\\"Robots\\\")\\n if (!matDataDB[\\\"AI Cores\\\"])\\n matDataDB[\\\"AI Cores\\\"] = await proxy(ns, \\\"corporation.getMaterialData\\\", \\\"AI Cores\\\")\\n if (!matDataDB[\\\"Real Estate\\\"])\\n matDataDB[\\\"Real Estate\\\"] = await proxy(ns, \\\"corporation.getMaterialData\\\", \\\"Real Estate\\\")\\n const matSizes = [\\\"Hardware\\\", \\\"Robots\\\", \\\"AI Cores\\\", \\\"Real Estate\\\"].map((mat) => matDataDB[mat].size)\\n let maxProd = await maxProduced(ns, div, city)\\n if (round < 3) maxProd *= 1.01\\n else maxProd *= 1.1\\n const warehouse = await proxy(ns, \\\"corporation.getWarehouse\\\", div, city)\\n //Start webworkers here\\n const worker = getWorker()\\n runningWorkers++\\n //Set up promise for when worker is done to run async\\n worker.onmessage = (msg) => {\\n //msg.data[x] should be: 0:results, 1:div, 2:city\\n results[msg.data[1] + msg.data[2]] = msg.data[0]\\n workers.push(worker)\\n runningWorkers--\\n delete workersWIP[div + city]\\n }\\n //Send data to worker now that we can handle the return\\n worker.postMessage([matSizes, divWeights, warehouse.size - maxProd, false, div, city])\\n workersWIP[div + city] = worker\\n }\\n }\\n //Wait for our workers to finish\\n while (runningWorkers > 0) await ns.asleep(4)\\n\\n //Process the results\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n //[Hardware, Robots, AI Cores, Real Estate]\\n const [hardware, robots, aicores, realestate] = results[div + city]\\n const hw = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, \\\"Hardware\\\")\\n const hardwareStored = hw.stored\\n if (hardwareStored === hardware) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Hardware\\\", 0)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Hardware\\\", 0, \\\"MP\\\")\\n }\\n else if (hardwareStored < hardware) {\\n if (round >= 4) await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Hardware\\\", (hardware - hardwareStored) / 10 / 10)\\n else await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Hardware\\\", (hardware - hardwareStored) / 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Hardware\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Hardware\\\", (hardwareStored - hardware) / 10 / 10, \\\"0\\\")\\n }\\n else await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Hardware\\\", (hardwareStored - hardware) / 10, \\\"MP\\\")\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Hardware\\\", 0)\\n }\\n const ro = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, \\\"Robots\\\")\\n const robotsStored = ro.stored\\n if (robotsStored === robots) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Robots\\\", 0)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Robots\\\", 0, \\\"MP\\\")\\n }\\n else if (robotsStored < robots) {\\n if (round >= 4) await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Robots\\\", (robots - robotsStored) / 10 / 10)\\n else await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Robots\\\", (robots - robotsStored) / 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Robots\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Robots\\\", (robotsStored - robots) / 10 / 10, \\\"0\\\")\\n }\\n else await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Robots\\\", (robotsStored - robots) / 10, \\\"MP\\\")\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Robots\\\", 0)\\n }\\n const ai = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, \\\"AI Cores\\\")\\n const aiCoresStored = ai.stored\\n if (aiCoresStored === aicores) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"AI Cores\\\", 0)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"AI Cores\\\", 0, \\\"MP\\\")\\n }\\n else if (aiCoresStored < aicores) {\\n if (round >= 4) await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"AI Cores\\\", (aicores - aiCoresStored) / 10 / 10)\\n else await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"AI Cores\\\", (aicores - aiCoresStored) / 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"AI Cores\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"AI Cores\\\", (aiCoresStored - aicores) / 10 / 10, \\\"0\\\")\\n }\\n else await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"AI Cores\\\", (aiCoresStored - aicores) / 10, \\\"MP\\\")\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"AI Cores\\\", 0)\\n }\\n const re = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, \\\"Real Estate\\\")\\n const realEstateStored = re.stored\\n if (realEstateStored === realestate) {\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Real Estate\\\", 0)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Real Estate\\\", 0, \\\"MP\\\")\\n }\\n else if (realEstateStored < realestate) {\\n if (round >= 4) await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Real Estate\\\", (realestate - realEstateStored) / 10 / 10)\\n else await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Real Estate\\\", (realestate - realEstateStored) / 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Real Estate\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Real Estate\\\", (realEstateStored - realestate) / 10 / 10, \\\"0\\\")\\n }\\n else await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, \\\"Real Estate\\\", (realEstateStored - realestate) / 10, \\\"MP\\\")\\n await proxy(ns, \\\"corporation.buyMaterial\\\", div, city, \\\"Real Estate\\\", 0)\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function maxProduction(ns, div, city) {\\n if (!hasWarehouseDB[div + city]) return [0, 0]\\n const mult = await getMult(ns, div, city)\\n return [10 * mult[0], 10 * mult[1]]\\n}\\n/** @param {NS} ns */\\nasync function maxMatRequired(ns, div, city, matID) {\\n if (!hasDivDB[div]) return 0\\n if (!hasWarehouseDB[div + city]) return 0\\n let productMult = 0\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n let products = 0\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, city, prod)\\n if (product.developmentProgress === 100)\\n products++\\n }\\n productMult = products\\n }\\n else productMult = 1\\n\\n for (const [matName, mat] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n if (matName !== matID) continue\\n // Smart supply\\n let required = 0\\n const mult = await getMult(ns, div, city)\\n if (hasDivDB[div].makesProducts) required += 10 * mult[1] * mat * productMult\\n if (indDataDB[hasDivDB[div].type].makesMaterials) required += 10 * mult[0] * mat\\n return required\\n } //End process purchase of materials\\n return 0\\n}\\n/** @param {NS} ns */\\nasync function maxProduced(ns, div, city) {\\n if (!hasWarehouseDB[div + city]) return 0\\n const mult = await getMult(ns, div, city)\\n const multMaterial = mult[0]\\n const multProduct = mult[1]\\n if (multMaterial === 0) return 0\\n\\n let totalSize = 0\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n for (const [matName, matAmount] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n if (matDataDB[matName] === undefined)\\n matDataDB[matName] = await proxy(ns, \\\"corporation.getMaterialData\\\", matName)\\n totalSize += await maxMatRequired(ns, div, city, matName) * matDataDB[matName].size\\n }\\n if (indDataDB[hasDivDB[div].type].makesMaterials)\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n if (matDataDB[mat] === undefined)\\n matDataDB[mat] = await proxy(ns, \\\"corporation.getMaterialData\\\", mat)\\n totalSize += matDataDB[mat].size * 10 * multMaterial\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, mat)\\n totalSize += material.stored * matDataDB[mat].size\\n }\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, city, prod)\\n if (product.developmentProgress === 100) {\\n totalSize += product.size * 10 * multProduct\\n totalSize += product.stored * product.size\\n }\\n }\\n return totalSize\\n}\\n/** @param {NS} ns */\\nasync function warehouseUpgrade(ns) {\\n const round = investOffer.round\\n let hasDiv2 = false\\n let count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n\\n let hasDiv3 = false\\n let cityCount = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div3 + city]) cityCount++\\n if (cityCount === 6) hasDiv3 = true\\n\\n while (count < 8) {\\n if (round >= 3) count++\\n let smartStorageIncrease = 0\\n const smartStorage = await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Storage\\\")\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (round === 2 && hasDivDB[div].type === \\\"Chemical\\\") continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const warehouse = await proxy(ns, \\\"corporation.getWarehouse\\\", div, city)\\n let divMult = researchedDB[div + \\\"Drones - Transport\\\"] ? 1.5 : 1\\n smartStorageIncrease += (warehouse.level * 100 * (1 + ((smartStorage + 1) * .1)) * divMult) - (warehouse.level * 100 * (1 + (smartStorage * .1)) * divMult)\\n }\\n }\\n const funds = await corpFunds(ns)\\n if ((hasDiv2 && smartStorage >= 30)\\n || (!hasDiv2 && smartStorage >= 10))\\n smartStorageIncrease = 0\\n\\n let bestUpgradeType = \\\"none\\\"\\n let bestUpgradeCity = \\\"none\\\"\\n let bestUpgradeRatio = 0\\n let bestAgriCity = \\\"none\\\"\\n let bestAgriRatio = 0\\n let bestChemCity = \\\"none\\\"\\n let bestChemRatio = 0\\n let bestWaterCity = \\\"none\\\"\\n let bestWaterRatio = 0\\n let bestComputerCity = \\\"none\\\"\\n let bestComputerRatio = 0\\n let bestRefineryCity = \\\"none\\\"\\n let bestRefineryRatio = 0\\n let bestMiningCity = \\\"none\\\"\\n let bestMiningRatio = 0\\n const smartUpgrade = await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Smart Storage\\\")\\n let smartRatio = smartStorageIncrease === 0 ? 0 : smartStorageIncrease / smartUpgrade\\n\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const warehouse = await proxy(ns, \\\"corporation.getWarehouse\\\", div, city)\\n const wUpgrade = await proxy(ns, \\\"corporation.getUpgradeWarehouseCost\\\", div, city)\\n const smartStorageMult = 1 + (smartStorage * .1)\\n let divMult = researchedDB[div + \\\"Drones - Transport\\\"] ? 1.5 : 1\\n let warehouseIncrease = ((warehouse.level + 1) * 100 * smartStorageMult * divMult) - warehouse.size\\n let warehouseRatio = warehouseIncrease / wUpgrade\\n //if (round === 2 && (warehouse.level === 2 || !hasDiv2) && hasDivDB[div].type === \\\"Chemical\\\") warehouseRatio = 0 //Early break on Chemical warehouse upgrade until we get all of Chemical\\n if (hasDivDB[div].type === \\\"Agriculture\\\" && warehouseRatio > bestAgriRatio) {\\n bestAgriCity = city\\n bestAgriRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Chemical\\\" && warehouseRatio > bestChemRatio) {\\n bestChemCity = city\\n bestChemRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Water Utilities\\\" && warehouseRatio > bestWaterRatio) {\\n bestWaterCity = city\\n bestWaterRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Computer Hardware\\\" && warehouseRatio > bestComputerRatio) {\\n bestComputerCity = city\\n bestComputerRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Refinery\\\" && warehouseRatio > bestRefineryRatio) {\\n bestRefineryCity = city\\n bestRefineryRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Mining\\\" && warehouseRatio > bestMiningRatio) {\\n bestMiningCity = city\\n bestMiningRatio = warehouseRatio\\n }\\n const maxProd = await maxProduction(ns, div, city)\\n if (round >= 3 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div4, city, \\\"Food\\\") && maxProd[0] > (await maxMatRequired(ns, div2, city, \\\"Plants\\\") + await maxMatRequired(ns, div3, \\\"Sector-12\\\", \\\"Plants\\\")))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round >= 3 && hasDivDB[div].type === \\\"Chemical\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div1, city, \\\"Chemicals\\\") || !hasDiv3)\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round >= 5 && hasDivDB[div].type === \\\"Water Utilities\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div1, city, \\\"Water\\\") + await maxMatRequired(ns, div2, city, \\\"Water\\\") + await maxMatRequired(ns, div4, city, \\\"Water\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round >= 5 && hasDivDB[div].type === \\\"Computer Hardware\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div5, city, \\\"Hardware\\\") + await maxMatRequired(ns, div8, city, \\\"Hardware\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round >= 5 && hasDivDB[div].type === \\\"Refinery\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div6, city, \\\"Metal\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round >= 5 && hasDivDB[div].type === \\\"Mining\\\") {\\n if (maxProd[0] > await maxMatRequired(ns, div7, city, \\\"Metal\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n else if (round === 2 && !hasDiv2 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if (round === 2 && hasDiv2 && warehouse.level >= 20 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if (round === 3 && !hasDiv3 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if (round === 3 && !hasDiv3 && warehouse.level >= 3 && hasDivDB[div].type === \\\"Chemical\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if (round === 3 && !hasDiv3 && hasDivDB[div].type === \\\"Tobacco\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if (round === 2 && ((hasDivDB[div].type === \\\"Chemical\\\" && (warehouse.level === 2 || !hasDiv2)))) {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n else if ((round >= 3) && [\\\"Tobacco\\\", \\\"Restaurant\\\"].includes(hasDivDB[div].type) && warehouse.level >= 5)\\n warehouseRatio = 0\\n //Round 2 - upgrade chem once\\n if (round === 2 && hasDivDB[div].type === \\\"Chemical\\\" && warehouse.level === 1) {\\n bestUpgradeType = div\\n bestUpgradeCity = city\\n bestUpgradeRatio = Infinity\\n }\\n else if (warehouseRatio > smartRatio && warehouseRatio > bestUpgradeRatio) {\\n bestUpgradeType = div\\n bestUpgradeCity = city\\n bestUpgradeRatio = warehouseRatio\\n }\\n else if (smartRatio > bestUpgradeRatio) {\\n bestUpgradeType = \\\"Smart\\\"\\n bestUpgradeRatio = smartRatio\\n }\\n }\\n }\\n if (![\\\"Smart\\\", \\\"none\\\"].includes(bestUpgradeType)) {\\n if (hasDivDB[bestUpgradeType].type === \\\"Agriculture\\\") {\\n bestUpgradeCity = bestAgriCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Chemical\\\") {\\n bestUpgradeCity = bestChemCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Water Utilities\\\") {\\n bestUpgradeCity = bestWaterCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Computer Hardware\\\") {\\n bestUpgradeCity = bestComputerCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Refinery\\\") {\\n bestUpgradeCity = bestRefineryCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Mining\\\") {\\n bestUpgradeCity = bestMiningCity\\n }\\n }\\n if (round >= 3) {\\n if (bestUpgradeType === \\\"none\\\") break\\n else if (bestUpgradeType === \\\"Smart\\\" && funds >= await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Smart Storage\\\") * 1.5) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Smart Storage\\\")\\n }\\n else if (bestUpgradeCity !== \\\"none\\\" && funds >= await proxy(ns, \\\"corporation.getUpgradeWarehouseCost\\\", bestUpgradeType, bestUpgradeCity) * 1.5) {\\n await proxy(ns, \\\"corporation.upgradeWarehouse\\\", bestUpgradeType, bestUpgradeCity)\\n }\\n else break\\n }\\n else {\\n if (bestUpgradeType === \\\"none\\\") break\\n else if (bestUpgradeType === \\\"Smart\\\" && funds >= await proxy(ns, \\\"corporation.getUpgradeLevelCost\\\", \\\"Smart Storage\\\")) {\\n await proxy(ns, \\\"corporation.levelUpgrade\\\", \\\"Smart Storage\\\")\\n }\\n else if (bestUpgradeCity !== \\\"none\\\" && funds >= await proxy(ns, \\\"corporation.getUpgradeWarehouseCost\\\", bestUpgradeType, bestUpgradeCity)) {\\n await proxy(ns, \\\"corporation.upgradeWarehouse\\\", bestUpgradeType, bestUpgradeCity)\\n }\\n else break\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function getSellPrice(ns, div, city, prod) {\\n const ta2 = ta2DB[div + city + prod]\\n if (ta2 === undefined || ta2.markupLimit === 0) return 0\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, city, prod)\\n const prodMarketPrice = 5 * product.productionCost\\n return (((ta2.markupLimit * Math.sqrt(1)) / Math.sqrt(1)) + prodMarketPrice) * 10\\n}\\n/** @param {NS} ns */\\nasync function sell(ns) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n const hasMTAII = await proxy(ns, \\\"corporation.hasResearched\\\", div, \\\"Market-TA.II\\\")\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n if (researchedDB[\\\"Market Research - Demand\\\"] && researchedDB[\\\"Market Data - Competition\\\"]) {\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n for (const prod of division.products) {\\n const product = await proxy(ns, \\\"corporation.getProduct\\\", div, city, prod)\\n if (product.developmentProgress !== 100 || product.stored === 0) continue\\n //Setting Market TA II if researchedDB\\n if (hasMTAII) { //I don't research it, but it could be there from manual purchase\\n await proxy(ns, \\\"corporation.setProductMarketTA2\\\", div, prod, true)\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", \\\"0\\\")\\n continue\\n }\\n\\n let ta2 = ta2DB[div + city + prod]\\n if (ta2 === undefined) { //No TA2 data\\n ta2DB[div + city + prod] = {\\n \\\"sellingPrice\\\": product.rating,\\n \\\"sellingQuantity\\\": product.stored,\\n \\\"markupLimit\\\": 0\\n }\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", (product.rating).toString())\\n continue\\n }\\n const prodMarketPrice = 5 * product.productionCost\\n if (ta2.markupLimit === 0) { //Not calculated yet\\n const actualSellAmount = product.actualSellAmount\\n if (actualSellAmount >= ta2.sellingQuantity / 10) { // We failed to set it high enough. Set it higher and try again\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice * 1000\\n ta2DB[div + city + prod].sellingQuantity = product.stored\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", (oldSalePrice * 1000).toString())\\n continue\\n }\\n else if (actualSellAmount <= ta2.sellingQuantity / 10 * .15) { //Not enough sold, lower the price!\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice / 3\\n ta2DB[div + city + prod].sellingQuantity = product.stored\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", (oldSalePrice / 3).toString())\\n continue\\n }\\n const mult = await getMult(ns, div, city)\\n const m = mult[1]\\n const markupLimit = (ta2.sellingPrice - prodMarketPrice) * Math.sqrt(actualSellAmount / m)\\n ta2DB[div + city + prod].markupLimit = markupLimit\\n ta2 = ta2DB[div + city + prod]\\n }\\n const prodStored = product.stored\\n let sellingPrice = (((ta2.markupLimit * Math.sqrt(prodStored)) / Math.sqrt(prodStored)) + prodMarketPrice) * 10\\n const priceMult = product.productionAmount / prodStored\\n if (priceMult !== Infinity) sellingPrice *= priceMult >= 1 ? 1 : priceMult\\n if (sellingPrice < 0 || isNaN(sellingPrice)) {\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice * 10\\n ta2DB[div + city + prod].sellingQuantity = prodStored\\n ta2DB[div + city + prod].markupLimit = 0\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", (oldSalePrice * 10).toString())\\n continue\\n }\\n await proxy(ns, \\\"corporation.sellProduct\\\", div, city, prod, \\\"MAX\\\", sellingPrice.toString())\\n } //Products\\n } //Product check\\n if (indDataDB[hasDivDB[div].type].producedMaterials)\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, mat)\\n if (material.stored === 0) continue\\n let exported = 0\\n for (const xp of material.exports) {\\n const expoMat = await proxy(ns, \\\"corporation.getMaterial\\\", xp.division, xp.city, mat)\\n exported += expoMat.importAmount\\n }\\n\\n //Set TA2 if we have it\\n if (researchedDB[div + \\\"Market-TA.II\\\"]) {\\n await proxy(ns, \\\"corporation.setMaterialMarketTA2\\\", div, city, mat, true)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", \\\"0\\\")\\n continue\\n }\\n let ta2 = ta2DB[div + city + mat]\\n if (ta2 === undefined) { //No TA2 data \\n ta2DB[div + city + mat] = {\\n \\\"sellingPrice\\\": material.marketPrice,\\n \\\"sellingQuantity\\\": material.stored + (exported * 10),\\n \\\"markupLimit\\\": 0\\n }\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", (material.marketPrice).toString())\\n continue\\n }\\n const prodMarketPrice = material.marketPrice\\n const mult = await getMult(ns, div, city)\\n const m = mult[0]\\n if (ta2.markupLimit === 0) { //Not calculated yet\\n const actualSellAmount = material.actualSellAmount\\n if (actualSellAmount >= (ta2.sellingQuantity) / 10) { // We failed to set it high enough. Set it higher and try again\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * 1.2\\n ta2DB[div + city + mat].sellingQuantity = material.stored + (exported * 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", (oldSalePrice * 1.2).toString())\\n continue\\n }\\n else if (actualSellAmount <= (ta2.sellingQuantity) / 10 * .1) { //Not enough sold, lower the price!\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * .9\\n ta2DB[div + city + mat].sellingQuantity = material.stored + (exported * 10)\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", (oldSalePrice * .9).toString())\\n continue\\n }\\n const markupLimit = (ta2.sellingPrice - prodMarketPrice) * Math.sqrt(actualSellAmount / m)\\n ta2DB[div + city + mat].markupLimit = markupLimit\\n ta2 = ta2DB[div + city + mat]\\n }\\n const prodStored = material.stored\\n let sellingPrice = (((ta2.markupLimit * Math.sqrt(prodStored)) / Math.sqrt(prodStored)) + prodMarketPrice) * 10\\n const priceMult = (material.productionAmount - exported) / prodStored\\n if (priceMult !== Infinity) sellingPrice *= priceMult >= 1 ? 1 : priceMult\\n if (sellingPrice < 0 || isNaN(sellingPrice)) {\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * 2\\n ta2DB[div + city + mat].sellingQuantity = prodStored + (exported * 10)\\n ta2DB[div + city + mat].markupLimit = 0\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", (oldSalePrice * 2).toString())\\n continue\\n }\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", sellingPrice.toString())\\n }\\n } //TA2\\n else { // No TA2\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].producedMaterials) {\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n const material = await proxy(ns, \\\"corporation.getMaterial\\\", div, city, mat)\\n if (material.stored === 0) continue\\n const marketPrice = material.marketPrice\\n if (!matDataDB[mat])\\n matDataDB[mat] = await proxy(ns, \\\"corporation.getMaterialData\\\", mat)\\n let price = marketPrice + (material.quality / matDataDB[mat].baseMarkup)\\n const maxProd = await maxProduction(ns, div, city)\\n const priceMult = maxProd[0] / (material.stored)\\n price *= priceMult >= 1 ? 1 : priceMult >= .6 ? priceMult : priceMult / 10\\n await proxy(ns, \\\"corporation.sellMaterial\\\", div, city, mat, \\\"MAX\\\", price)\\n }\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nasync function getMult(ns, div, city) {\\n if (!hasOfficeDB[div + city]) return [0, 0] //[Material, Product]\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n const operationEmployeesProduction = office.employeeProductionByJob.Operations\\n const engineerEmployeesProduction = office.employeeProductionByJob.Engineer\\n const managementEmployeesProduction = office.employeeProductionByJob.Management\\n const totalEmployeesProduction = operationEmployeesProduction + engineerEmployeesProduction + managementEmployeesProduction;\\n if (totalEmployeesProduction <= 0) return [0, 0]\\n const managementFactor = 1 + managementEmployeesProduction / (1.2 * totalEmployeesProduction)\\n const employeesProductionMultiplier = (Math.pow(operationEmployeesProduction, 0.4) + Math.pow(engineerEmployeesProduction, 0.3)) * managementFactor;\\n const balancingMultiplier = 0.05;\\n const officeMultiplierProduct = 0.5 * balancingMultiplier * employeesProductionMultiplier;\\n const officeMultiplierMaterial = balancingMultiplier * employeesProductionMultiplier;\\n\\n // Multiplier from Smart Factories\\n const upgradeMultiplier = 1 + (await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Factories\\\") * 0.03)\\n // Multiplier from researches\\n let researchMultiplier = 1\\n researchMultiplier *=\\n (researchedDB[div + \\\"Drones - Assembly\\\"] ? 1.2 : 1)\\n * (researchedDB[div + \\\"Self-Correcting Assemblers\\\"] ? 1.1 : 1);\\n if (hasDivDB[div].makesProducts) {\\n researchMultiplier *= (researchedDB[div + \\\"uPgrade: Fulcrum\\\"] ? 1.05 : 1);\\n }\\n let multSum = 0;\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", hasDivDB[div].type)\\n for (const scity of cities) {\\n if (!hasWarehouseDB[div + scity]) continue\\n const real = await proxy(ns, \\\"corporation.getMaterial\\\", div, scity, \\\"Real Estate\\\")\\n const hard = await proxy(ns, \\\"corporation.getMaterial\\\", div, scity, \\\"Hardware\\\")\\n const robo = await proxy(ns, \\\"corporation.getMaterial\\\", div, scity, \\\"Robots\\\")\\n const ai = await proxy(ns, \\\"corporation.getMaterial\\\", div, scity, \\\"AI Cores\\\")\\n let realestate = Math.pow(0.002 * real.stored + 1, indDataDB[hasDivDB[div].type].realEstateFactor)\\n let hardware = Math.pow(0.002 * hard.stored + 1, indDataDB[hasDivDB[div].type].hardwareFactor)\\n let robots = Math.pow(0.002 * robo.stored + 1, indDataDB[hasDivDB[div].type].robotFactor)\\n let aicores = Math.pow(0.002 * ai.stored + 1, indDataDB[hasDivDB[div].type].aiCoreFactor);\\n if (isNaN(realestate)) realestate = 1\\n if (isNaN(hardware)) hardware = 1\\n if (isNaN(robots)) robots = 1\\n if (isNaN(aicores)) aicores = 1\\n const cityMult =\\n realestate *\\n hardware *\\n robots *\\n aicores\\n multSum += Math.pow(cityMult, 0.73);\\n }\\n const productionMult = multSum < 1 ? 1 : multSum\\n const multMaterial = officeMultiplierMaterial * productionMult * upgradeMultiplier * researchMultiplier\\n const multProduct = officeMultiplierProduct * productionMult * upgradeMultiplier * researchMultiplier\\n return [multMaterial, multProduct]\\n}\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printRaw(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"puppet popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function updateHud(ns) {\\n clearLogs(ns)\\n const cObj = await proxy(ns, \\\"corporation.getCorporation\\\")\\n const bnMults = await getBNMults(ns)\\n update(ns, ns.sprintf(\\\"%s\\\", cObj.name))\\n update(ns, ns.sprintf(\\\"Funds: $%s Profit: $%s/s\\\", fNumber(ns, cObj.funds, 3), fNumber(ns, cObj.revenue - cObj.expenses, 3)))\\n const invest = investOffer\\n const upgrades = await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Neural Accelerators\\\")\\n + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Project Insight\\\")\\n + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Nuoptimal Nootropic Injector Implants\\\")\\n + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"FocusWires\\\")\\n + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Speech Processor Implants\\\")\\n + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"FocusWires\\\")\\n const offer = invest.round === 1 ? (round1Money * bnMults.CorporationValuation)\\n : invest.round === 2 ? (round2Money * bnMults.CorporationValuation)\\n : invest.round === 3 ? (round3Money * bnMults.CorporationValuation)\\n : invest.round === 4 ? (round4Money * bnMults.CorporationValuation)\\n : 0\\n const minRound = invest.round === 2 ? \\\"-BareMin 30b\\\" : \\\"\\\"\\n const produpgrades = await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Factories\\\") + await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Smart Storage\\\")\\n update(ns, ns.sprintf(\\\"Round: %s Offer: %s FundsReq: %s %s\\\", invest.round, fNumber(ns, invest.funds, 3), fNumber(ns, offer, 3), minRound))\\n update(ns, ns.sprintf(\\\"Empl Upgrades: %s Prod Upgrades: %s Profit Upgrades: %s Wilson: %s\\\", upgrades, produpgrades, await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"ABC SalesBots\\\"), await proxy(ns, \\\"corporation.getUpgradeLevel\\\", \\\"Wilson Analytics\\\")))\\n const state = cObj.nextState === \\\"PURCHASE\\\" ? \\\"START\\\"\\n : cObj.nextState === \\\"PRODUCTION\\\" ? \\\"PURCHASE\\\"\\n : cObj.nextState === \\\"EXPORT\\\" ? \\\"PRODUCTION\\\"\\n : cObj.nextState === \\\"SALE\\\" ? \\\"EXPORT\\\"\\n : \\\"SALE\\\"\\n update(ns, ns.sprintf(\\\"Stage: %s\\\", state))\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n const division = await proxy(ns, \\\"corporation.getDivision\\\", div)\\n update(ns, ns.sprintf(\\\"-%s(%s) Profit: $%s/s Awareness: %s Pop: %s\\\", div, division.type, fNumber(ns, division.lastCycleRevenue - division.lastCycleExpenses, 3), fNumber(ns, division.awareness, 3), fNumber(ns, division.popularity, 3)))\\n let wCount = 0\\n let wSpace = 0\\n let wSpaceUsed = 0\\n let oCount = 0\\n let oEmployees = 0\\n let oSize = 0\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n if (hasWarehouseDB[div + city]) {\\n wCount++\\n const warehouse = await proxy(ns, \\\"corporation.getWarehouse\\\", div, city)\\n wSpace += warehouse.size\\n wSpaceUsed += warehouse.sizeUsed\\n }\\n try {\\n const office = await proxy(ns, \\\"corporation.getOffice\\\", div, city)\\n oEmployees += office.numEmployees\\n oCount++\\n oSize += office.size\\n }\\n catch { }\\n }\\n update(ns, ns.sprintf(\\\" Warehouse Space: (%s/6) %s/%s Office Usage: (%s/6) %s/%s Research: %s\\\", wCount, Math.round(wSpaceUsed), Math.round(wSpace), oCount, oEmployees, oSize, fNumber(ns, division.researchPoints, 3)))\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = await proxy(ns, \\\"corporation.getIndustryData\\\", division.type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n for (const product of division.products) {\\n const prod = await proxy(ns, \\\"corporation.getProduct\\\", div, \\\"Sector-12\\\", product)\\n const prog = prod.developmentProgress\\n const sellPrice = await getSellPrice(ns, div, \\\"Sector-12\\\", product)\\n if (prog === 100) {\\n if (sellPrice === 0) update(ns, ns.sprintf(\\\" Calculating - %s\\\", product))\\n else update(ns, ns.printf(\\\" $%s - %s\\\", fNumber(ns, await getSellPrice(ns, div, \\\"Sector-12\\\", product), 3), product))\\n }\\n else {\\n update(ns, ns.sprintf(\\\" %s - %s\\\", fNumber(ns, prog, 2), product))\\n }\\n }\\n }\\n }\\n ns.ui.renderTail()\\n}\\n\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(19) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(19)\\n switch (result) {\\n case \\\"Reset TAII\\\":\\n if (!silent) ns.tprintf(\\\"Corp: Resetting TAII DB!\\\")\\n ta2DB = []\\n break\\n case \\\"popout\\\":\\n if (!silent) ns.tprintf(\\\"Corp: Enabling pop out\\\")\\n win = await makeNewWindow(\\\"Corp\\\", ns.ui.getTheme())\\n break\\n case \\\"nopopout\\\":\\n if (!silent) ns.tprintf(\\\"Corp: Disabling pop out\\\")\\n if (win) win.close()\\n win = false\\n break\\n case \\\"Silent\\\":\\n silent = true\\n break\\n default:\\n ns.tprintf(\\\"Invalid command received in corp: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction getWorker() {\\n if (workers.length) return workers.pop()\\n else {\\n const blob = new Blob([workerCode], { type: \\\"application/javascript\\\" })\\n const worker = new Worker(URL.createObjectURL(blob))\\n return worker\\n }\\n}\\nconst workerCode = `\\nfunction optimizeCorpoMaterials_raw(matSizes, divWeights, spaceConstraint, round) {\\n let p = divWeights.reduce((a, b) => a + b, 0);\\n let w = matSizes.reduce((a, b) => a + b, 0);\\n let r = [];\\n for (let i = 0; i < matSizes.length; ++i) {\\n let m = (spaceConstraint - 500 * ((matSizes[i] / divWeights[i]) * (p - divWeights[i]) - (w - matSizes[i]))) / (p / divWeights[i]) / matSizes[i];\\n if (divWeights[i] <= 0 || m < 0) {\\n return optimizeCorpoMaterials_raw(matSizes.toSpliced(i, 1), divWeights.toSpliced(i, 1), spaceConstraint, round).toSpliced(i, 0, 0);\\n } else {\\n if (round) m = Math.round(m);\\n r.push(m);\\n }\\n }\\n return r;\\n}\\n//event.data[x] should be: 0:matSizes, 1:divWeights, 2:spaceContraint, 3:round, 4:div, 5:city\\nonmessage = (event) => {postMessage([optimizeCorpoMaterials_raw(event.data[0], event.data[1], event.data[2], event.data[3]), event.data[4], event.data[5]]);}\\n`\\n\\n//Ram dodged functions below and their file writes\\nasync function proxy(ns, func, ...argmnts) { return await runIt(ns, \\\"SphyxOS/extras/nsProxy.js\\\", ns.getFunctionRamCost(func) + 1.6, [func, ...argmnts]) }\\nasync function proxyTry(ns, func, ...argmnts) { return await runIt(ns, \\\"SphyxOS/extras/nsProxyTry.js\\\", ns.getFunctionRamCost(func) + 1.6, [func, ...argmnts]) }\\nasync function getBNMults(ns) { return await runIt(ns, \\\"SphyxOS/basic/getbnmults.js\\\", 0, []) }\\n\\n/** @param {NS} ns */\\nasync function runIt(ns, script, scriptOverride, argmnts) {\\n let thispid = 0\\n let threads = 1\\n const scriptRam = scriptOverride === 0 ? ns.getScriptRam(script) : scriptOverride\\n\\n const threadsOnHome = Math.floor((ns.getServerMaxRam(\\\"home\\\") - ns.getServerUsedRam(\\\"home\\\")) / scriptRam)\\n if (threadsOnHome >= 1) {\\n thispid = ns.exec(script, \\\"home\\\", { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmnts)\\n if (thispid > 0)\\n threads--\\n }\\n if (threads >= 1) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n const tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n const threadsonserver = Math.floor(tmpramavailable / scriptRam)\\n // How many threads can we run? If we can run something, do it\\n if (threadsonserver <= 0) continue\\n ns.scp([script], server, \\\"home\\\")\\n thispid = ns.exec(script, server, { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmnts)\\n if (thispid === 0) continue\\n threads--\\n break\\n }// All servers\\n }\\n if (threads >= 1) ns.tprintf(\\\"Failed to allocate all threads for script: %s\\\", script)\\n await ns.nextPortWrite(thispid)\\n const result = ns.readPort(thispid)\\n return result\\n}\\n\\n/** @param {NS} ns */\\nfunction getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n}\\n/** @param {NS} ns */\\nfunction writeProxy(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxy.js\\\", data, \\\"w\\\")\\n}\\n\\nfunction writeProxyTry(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let result = false\\n try {\\n const res = nsFunction(...argmnts)\\n if (res) result = res\\n else result = true\\n }\\n catch { }\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxyTry.js\\\", data, \\\"w\\\")\\n}\\n\\nfunction writeBNMults(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,//Old\\n \\\"CloudServerCost\\\": 1,//New\\n \\\"CloudServerSoftcap\\\": 1,//Old\\n \\\"CloudServerSoftcap\\\": 1,//New\\n \\\"CloudServerLimit\\\": 1,//Old\\n \\\"CloudServerLimit\\\": 1,//New\\n \\\"CloudServerMaxRam\\\": 1,//Old\\n \\\"CloudServerMaxRam\\\": 1,//New\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n ns.atExit(() => port.write(mults))\\n}\\n`\\n ns.write(\\\"SphyxOS/basic/getbnmults.js\\\", data, \\\"w\\\")\\n}\\n\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\\nconst cities = [\\\"Sector-12\\\", \\\"Aevum\\\", \\\"Volhaven\\\", \\\"Chongqing\\\", \\\"New Tokyo\\\", \\\"Ishima\\\"]\\nconst industries = [div1, div2, div3, div4, div5, div6, div7, div8]\\nconst cigaretts = [\\\"Pall Mall\\\", \\\"Camel\\\", \\\"Marlboro\\\", \\\"Kool\\\", \\\"American Spirit\\\", \\\"Bastos\\\", \\\"Philip Morris\\\", \\\"USA Gold\\\", \\\"Winston\\\", \\\"Backwoods Smokes\\\", \\\"Capstan\\\", \\\"Chesterfield\\\", \\\"Davidoff\\\", \\\"Maverick\\\", \\\"Newport\\\", \\\"Black Devil\\\", \\\"Dunhill\\\", \\\"Rothman\\\\'s\\\"]\\nconst burgers = [\\\"Double Bacon Cheeseburger\\\", \\\"Plain Hamburger\\\", \\\"Pickle Burger\\\", \\\"Onion Burger\\\", \\\"Turkey Burger\\\", \\\"Mozza Burger\\\", \\\"Chili Cheeseburger\\\", \\\"Tropical Burger\\\", \\\"The BLT\\\", \\\"Spicy Extreem Burger\\\", \\\"Deconstructed Burger\\\", \\\"Junior Delux\\\"]\\nconst hardwares = [\\\"Home Entertainment Threater\\\", \\\"Next-Gen Graphics Card\\\", \\\"Portable Soldering Kit (PSK)\\\", \\\"Advanced Micro-Fluidics Home Kit\\\", \\\"xPhone MAX\\\", \\\"Hyper-RAM\\\", \\\"Superior xDisplay\\\", \\\"A Lamp (It's just a lamp)\\\", \\\"Personal Electric Transportation ULTRA\\\"]\\n\\nlet slp = ms => new Promise(r => setTimeout(r, ms));\\nasync function makeNewWindow(title = \\\"Default Window Title\\\", theme) {\\n // let win = open(\\\"\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n let win = open(\\\"main.bundle.js\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n let good = false;\\n let doc = 0;\\n while (!good) {\\n await slp(1000);\\n try {\\n doc = win[\\\"document\\\"];\\n doc.head.innerHTML = \\\"No.\\\";\\n good = true;\\n } catch {\\n good = false;\\n }\\n }\\n await slp(200);\\n doc.head.innerHTML = `\\n ${title} \\n `;\\n doc.body.innerHTML = `${title}
`;\\n win.clear = () => {\\n win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML = \\\"\\\";\\n }\\n win.header = (content) => {\\n win[\\\"document\\\"].body.innerHTML = `${content}
`;\\n }\\n win.update = (content) => {\\n win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML = win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innterHTML === \\\"\\\" ? content.replaceAll(\\\" \\\", \\\" \\\").replaceAll(\\\"\\\\r\\\", \\\" \\\").replaceAll(\\\"\\\\n\\\", \\\" \\\") : win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML + ` ` + content.replaceAll(\\\" \\\", \\\" \\\").replaceAll(\\\"\\\\r\\\", \\\" \\\").replaceAll(\\\"\\\\n\\\", \\\" \\\");\\n }\\n win.reopen = () => open(\\\"\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n win.focus()\\n return win;\\n}\""},{"filename":"SphyxOS/bins/darknet.jsx","file":"\"/**Author:\\n * Discord: Sphyxis\\n */\\nconst killPort = 24 //Kill Switch for all darknet scripts\\nconst cctFile = \\\"SphyxOS/bins/codingContracts.js\\\" //Add your .cct solver here\\nconst telemetryFile = \\\"SphyxOSUserData/darknet/telemetry.txt\\\" //I collect information on puzzle solvers\\nconst completeFile = \\\"SphyxOSUserData/darknet/complete.txt\\\" //Backup of all known passwords\\nconst inProgFile = \\\"SphyxOSUserData/darknet/inProg.txt\\\" //Backup of all in-progress information\\nconst reservedRam = 13.6 + 16//16 is extra. We need 13.6 over and above the script cost to run every command. Free mem until then\\nconst minResRam = 3 //Min reserve to start a script. Needed to run reallocateMemory and free the rest\\nconst rateMyPixWorkerStallMs = 5000 //Restart the RateMyPix webworker if candidate search stops responding\\nconst rateMyPixWorkerSearchMs = 1200 //Have RateMyPix workers return progress before the stall watchdog fires\\nlet complete //Module Scoped variable that contains all known passwords. All darknet scripts share this variable\\nlet inProgress //Contains all in-progress work. All darknet scripts share this variable\\nlet workingOn //Contains information on which servers are being worked on at the moment\\nlet telemetry //Contains all telemetry data\\nlet workingOnCCT //Flags if a .cct is being done. Only 1 at a time\\nlet modePhishing = true //If we do phishing\\nlet modeInduce = false //If we try to induce migration\\nlet modeShare = true //If we are sharing ram\\nlet modeStorm = false //If we are starting storms\\nlet modeShowMap = true //If we are showing the lab map as we solve it\\nlet modeStock = \\\"none\\\"\\nlet logOpened = false\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.ramOverride(3.05)\\n ns.disableLog(\\\"ALL\\\")\\n const me = ns.self().server\\n writeLabHunter(ns)\\n writeProxyLocal(ns)\\n writeProxyAuth(ns)\\n writeProxyHeartbleed(ns)\\n if (me === \\\"home\\\") {\\n await proxyAuth(ns, 1, \\\"darkweb\\\", \\\"\\\", \\\"scp\\\", ns.self().filename, \\\"darkweb\\\", \\\"home\\\")\\n await proxyAuth(ns, 1, \\\"darkweb\\\", \\\"\\\", \\\"scp\\\", \\\"SphyxOS/util.js\\\", \\\"darkweb\\\", \\\"home\\\")\\n ns.dnet.connectToSession(\\\"darkweb\\\", \\\"\\\")\\n ns.exec(ns.self().filename, \\\"darkweb\\\", { preventDuplicates: true })\\n return\\n }\\n\\n if (ns.pid < 40) {\\n ns.ramOverride(16)\\n ns.spawn(ns.self().filename, { preventDuplicates: true })\\n ns.exit()\\n }\\n ns.nextPortWrite(killPort).then(() => { ns.clearPort(26); ns.exit() })\\n while (me !== \\\"darkweb\\\" && ns.peek(26) === \\\"NULL PORT DATA\\\") await ns.asleep(2000)\\n if (me === \\\"darkweb\\\") { // One time startup routine\\n modePhishing = true\\n modeInduce = false\\n modeShare = true\\n modeShowMap = true\\n modeStorm = false\\n modeStock = \\\"none\\\"\\n logOpened = false\\n labComplete = false\\n labName = false\\n workingOnCCT = false\\n labState = null\\n labWorkerVisitStack = new Map() // workerId -> string[]\\n labInfluenceContextCache = new WeakMap()\\n labQuadrantBoundsCoordCache = new WeakMap()\\n labGoalwardDirsCache = new WeakMap()\\n getCommands(ns) //Start our command listener\\n ns.clearPort(26)\\n ns.writePort(26, ns.pid)\\n ns.atExit(() => { ns.clearPort(26) }, \\\"cleanup\\\")\\n if (!complete) try { complete = new Map(JSON.parse(ns.read(completeFile))) } catch { complete = new Map() }\\n updateFull(\\\"darkweb\\\", \\\"\\\", ns.dnet.getServerAuthDetails(\\\"darkweb\\\"))\\n if (!inProgress) try { inProgress = new Map(JSON.parse(ns.read(inProgFile))) } catch { inProgress = new Map() }\\n\\n workingOn = new Map()\\n if (await proxyAuth(ns, 1, me, complete.get(me).pw, \\\"scp\\\", telemetryFile, me, \\\"home\\\")) {\\n const telemetryData = JSON.parse(ns.read(telemetryFile))\\n telemetry = telemetryData\\n }\\n else telemetry = {} //Left as an object map, as it should not contain names that are prohibited\\n await proxyLocal(ns, 1, \\\"scp\\\", \\\"SphyxOS/extras/nsProxy.js\\\", \\\"home\\\") //Doesn't need to be awaited, but it lets me specify threads without more work\\n }\\n\\n while (ns.dnet.getBlockedRam(me) > 0 && await proxyHome(ns, \\\"getServerMaxRam\\\", me) - await proxyHome(ns, \\\"getServerUsedRam\\\", me) < reservedRam) {\\n if (!await threadedMemoryRealloc(ns, me, complete.get(me).pw)) break\\n }\\n await startup(ns) //Select the easiest ones to get into first, then go from there.\\n while (true) {\\n const serversRaw = await proxyLocal(ns, 1, \\\"dnet.probe\\\")\\n const serverArray = []\\n for (const server of serversRaw)\\n serverArray.push({ name: server.toString(), modelId: ns.dnet.getServerAuthDetails(server), cha: await proxyLocal(ns, 1, \\\"dnet.getServerRequiredCharismaLevel\\\", server) })\\n serverArray.sort((a, b) => a.cha - b.cha)\\n const servers = priorityArraySort(serverArray) //Sorts based on ease of hacking.\\n const files = await proxyLocal(ns, 1, \\\"ls\\\", me)\\n const cacheFiles = files.filter((f) => f.endsWith(\\\".cache\\\"))\\n if (cacheFiles.length > 0)\\n for (const file of cacheFiles)\\n await proxyLocal(ns, 1, \\\"dnet.openCache\\\", file, true)\\n if (modeStorm) {\\n const stormFiles = files.filter((f) => f.endsWith(\\\".exe\\\"))\\n if (stormFiles.length > 0) {\\n await proxyLocal(ns, 1, \\\"dnet.unleashStormSeed\\\")\\n ns.writePort(1, \\\"darknet storm off\\\")\\n modeStorm = false\\n }\\n }\\n const dataFiles = files.filter((f) => f.endsWith(\\\".data.txt\\\"))\\n dataFiles.forEach((f) => {\\n const content = ns.read(f)\\n if (content.startsWith(\\\"Server:\\\")) {//We have a new password to take and use What about names with spaces?\\n const splitContent = content.split(\\\" \\\")\\n splitContent.shift() //Good by Server:\\n const server = splitContent.shift()\\n splitContent.shift() //Good by Password:\\n const password = splitContent.join(\\\" \\\").replaceAll(\\\"\\\\\\\"\\\", \\\"\\\").toString()\\n updateFull(server, password, ns.dnet.getServerAuthDetails(server))\\n ns.mv(me, f, f.replaceAll(\\\"data\\\", \\\"processed\\\"))\\n }\\n else ns.mv(me, f, f.replaceAll(\\\"data\\\", \\\"processed\\\"))\\n })\\n const litFiles = await proxyLocal(ns, 1, \\\"ls\\\", me, \\\".lit\\\")\\n for (const file of litFiles)\\n await proxyAuth(ns, 1, me, complete.get(me).pw, \\\"rm\\\", file)\\n let foundWork = false\\n for (const serverRaw of servers) {\\n const server = serverRaw.toString()\\n if (workingOn.has(server)) continue\\n let details = ns.dnet.getServerAuthDetails(server)\\n if (!details.isConnectedToCurrentServer) continue\\n if (ns.dnet.getStasisLinkedServers().includes(ns.self().server) && details.modelId !== \\\"(The Labyrinth)\\\") continue\\n let result\\n if (!details.hasSession) {\\n updateWorkingOn(server, details, \\\"set\\\")\\n ns.atExit(() => {\\n updateWorkingOn(server, details, \\\"remove\\\")\\n })\\n result = await breakIn(ns, server, details)\\n updateWorkingOn(server, details, \\\"remove\\\")\\n ns.atExit(() => { })\\n if (result.success) foundWork = true\\n if (result?.silentFail) {\\n return\\n }\\n }\\n else result = { success: true }\\n details = ns.dnet.getServerAuthDetails(server)\\n if (details.hasSession) {\\n while (me !== \\\"home\\\" && details.isConnectedToCurrentServer && details.hasSession && ns.dnet.getBlockedRam(server) > 0 && await proxyLocal(ns, 1, \\\"getServerMaxRam\\\", server) - await proxyLocal(ns, 1, \\\"getServerUsedRam\\\", server) - minResRam < ns.self().ramUsage) {\\n if (!await threadedMemoryRealloc(ns, server, complete.get(server).pw, server)) break\\n details = ns.dnet.getServerAuthDetails(server)\\n }\\n details = ns.dnet.getServerAuthDetails(server)\\n if (details.isConnectedToCurrentServer && details.hasSession) {\\n const runningScripts = await proxyLocal(ns, 1, \\\"ps\\\", server)\\n if (details.isConnectedToCurrentServer && details.hasSession && runningScripts?.length === 0) {\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", ns.self().filename, server, \\\"home\\\")\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", \\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n\\n const threads = Math.floor((await proxyLocal(ns, 1, \\\"getServerMaxRam\\\", server) - await proxyLocal(ns, 1, \\\"getServerUsedRam\\\", server) - minResRam) / ns.self().ramUsage)\\n if (threads) ns.exec(ns.self().filename, server, { threads: 1, preventDuplicates: true })\\n }\\n }\\n }\\n await startup(ns)\\n }\\n\\n if (ns.dnet.getStasisLinkedServers().includes(ns.self().server)) {\\n if (await proxyHome(ns, \\\"getServerMaxRam\\\", ns.self().server) - await proxyHome(ns, \\\"getServerUsedRam\\\", ns.self().server) >= 13.6)\\n await proxyLocal(ns, true, \\\"dnet.setStasisLink\\\", false)\\n else {\\n ns.ramOverride(16)\\n await ns.dnet.setStasisLink(false)\\n ns.exit()\\n }\\n }\\n if (!foundWork) {\\n const servers = await proxyLocal(ns, 1, \\\"dnet.probe\\\")\\n for (const serverRaw of servers) {\\n const server = serverRaw.toString()\\n let details = ns.dnet.getServerAuthDetails(server)\\n if (details.hasSession && details.isConnectedToCurrentServer) {\\n const runningScripts = await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"ps\\\", server)\\n if (runningScripts?.length === 0) {\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", ns.self().filename, server, \\\"home\\\")\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", \\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n let threads = 0\\n while (!threads && ns.dnet.getBlockedRam(server) > 0) {\\n await threadedMemoryRealloc(ns, server, complete.get(server).pw)\\n threads = Math.floor((await proxyLocal(ns, 1, \\\"getServerMaxRam\\\", server) - await proxyLocal(ns, 1, \\\"getServerUsedRam\\\", server) - minResRam) / ns.self().ramUsage)\\n }\\n if (threads) ns.exec(ns.self().filename, server, { threads: 1, preventDuplicates: true })\\n }\\n if (ns.dnet.getBlockedRam(server) > 0) {\\n await threadedMemoryRealloc(ns, server, complete.get(server).pw)\\n }\\n }\\n }\\n if (modePhishing && ns.dnet.getBlockedRam(me) === 0) await proxyLocal(ns, true, \\\"dnet.phishingAttack\\\")\\n if (modeInduce && ns.dnet.getBlockedRam(me) === 0) {\\n const pushTargets = await proxyLocal(ns, 1, \\\"dnet.probe\\\")\\n let bestTarget = \\\"\\\"\\n let bestRam = 0\\n for (const serverRaw of pushTargets) {\\n const server = serverRaw.toString()\\n const details = ns.dnet.getServerAuthDetails(server)\\n if (server !== \\\"darkweb\\\" && details.modelId !== \\\"(The Labyrinth)\\\" && details.hasSession && details.isConnectedToCurrentServer && ns.dnet.getBlockedRam(server) === 0) {\\n if (await proxyHome(ns, \\\"getServerMaxRam\\\", server) > bestRam) {\\n bestTarget = server\\n bestRam = await proxyHome(ns, \\\"getServerMaxRam\\\", server)\\n }\\n }\\n }\\n if (bestRam > 0) await proxyAuth(ns, true, bestTarget, complete.get(bestTarget).pw, \\\"dnet.induceServerMigration\\\", bestTarget)\\n }\\n if (modeShare && ns.dnet.getBlockedRam(me) === 0) await proxyLocal(ns, true, \\\"share\\\")\\n if (modeStock !== \\\"none\\\" && ns.dnet.getBlockedRam(me) === 0) {\\n for (const sym of modeStock)\\n await proxyLocal(ns, true, \\\"dnet.promoteStock\\\", sym)\\n }\\n }\\n if (ns.dnet.getBlockedRam(me) > 0) {\\n await threadedMemoryRealloc(ns, me, complete.get(me).pw)\\n }\\n const ccts = await proxyLocal(ns, 1, \\\"ls\\\", me, \\\".cct\\\")\\n if (!workingOnCCT && ccts.length > 0) {\\n workingOnCCT = true\\n await runCCT(ns, me, \\\"darknet\\\", \\\"quiet\\\")\\n }\\n if (!modeInduce && !modePhishing && !modeShare && modeStock === \\\"none\\\" && !foundWork) await ns.asleep(200)\\n if (me === \\\"darkweb\\\") {\\n //ns.write(telemetryFile, JSON.stringify(telemetry), \\\"w\\\")\\n ns.write(completeFile, JSON.stringify([...complete]), \\\"w\\\")\\n ns.write(inProgFile, JSON.stringify([...inProgress]), \\\"w\\\")\\n //await proxyLocal(ns, 1, \\\"scp\\\", telemetryFile, \\\"home\\\", me) \\n }\\n }\\n}\\nfunction priorityArraySort(arr) {\\n const prioritySet = new Set(easyHacks)\\n const secondarySet = new Set(midHacks)\\n const tertiarySet = new Set(hardHacks)\\n const rank = (item) => {\\n if (prioritySet.has(item)) return 0\\n if (secondarySet.has(item)) return 1\\n if (tertiarySet.has(item)) return 2\\n return 3\\n }\\n return arr.slice().sort((a, b) => rank(a.modelId) - rank(b.modelId)).map((obj) => obj.name)\\n}\\n/** @param {NS} ns */\\nasync function startup(ns) {\\n const servers = await proxyLocal(ns, 1, \\\"dnet.probe\\\")\\n for (const serverRaw of servers) {\\n const server = serverRaw.toString()\\n if (workingOn.has(server)) continue\\n let details = ns.dnet.getServerAuthDetails(server)\\n if (complete.has(server) && details.isConnectedToCurrentServer) { //Help is on the way!\\n const result = ns.dnet.connectToSession(server, complete.get(server).pw)\\n if (!result.success) {\\n if (!validate(ns, server, complete.get(server).details)) complete.delete(server)\\n continue\\n }\\n details = ns.dnet.getServerAuthDetails(server)\\n if (details.hasSession && details.isConnectedToCurrentServer) {\\n const runningScripts = await proxyLocal(ns, 1, \\\"ps\\\", server)\\n if (details.isConnectedToCurrentServer && details.hasSession && await proxyLocal(ns, 1, \\\"getServerMaxRam\\\", server) - await proxyLocal(ns, 1, \\\"getServerUsedRam\\\", server) - minResRam > ns.self().ramUsage && runningScripts?.length === 0) {\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", ns.self().filename, server, \\\"home\\\")\\n await proxyAuth(ns, 1, server, complete.get(server).pw, \\\"scp\\\", \\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n\\n const threads = Math.floor((await proxyLocal(ns, 1, \\\"getServerMaxRam\\\", server) - await proxyLocal(ns, 1, \\\"getServerUsedRam\\\", server) - minResRam) / ns.self().ramUsage)\\n if (threads) ns.exec(ns.self().filename, server, { threads: 1, preventDuplicates: true })\\n }\\n }\\n }\\n }\\n}\\n/**\\n * @param {ServerAuthDetails} details\\n * @param {NS} ns\\n**/\\nasync function breakIn(ns, server, details) {\\n if (server === \\\"darkweb\\\") return { success: true }\\n if (complete.has(server)) {\\n let result = ns.dnet.connectToSession(server, complete.get(server).pw)\\n if (result.success) return result\\n else complete.delete(server)\\n }\\n let tries = 1\\n const player = await proxyLocal(ns, 1, \\\"getPlayer\\\")\\n const chaReq = await proxyLocal(ns, 1, \\\"dnet.getServerRequiredCharismaLevel\\\", server)\\n await validateProgress(ns, server)\\n switch (details.modelId) {\\n case \\\"DeskMemo_3.1\\\": {\\n const answerArray = details.passwordHint.split(\\\" \\\")\\n const answer = answerArray[answerArray.length - 1]\\n const result = await goToWork(ns, server, answer.toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"ZeroLogon\\\": {\\n const result = await goToWork(ns, server, \\\"\\\", tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"FreshInstall_1.0\\\": {\\n let result = false\\n if (details.passwordFormat === \\\"alphabetic\\\") {\\n if (details.passwordLength === 5) result = await goToWork(ns, server, \\\"admin\\\", tries++, details)\\n else if (details.passwordLength === 8) result = await goToWork(ns, server, \\\"password\\\", tries++, details)\\n }\\n else if (details.passwordFormat === \\\"numeric\\\") {\\n if (details.passwordLength === 5) result = await goToWork(ns, server, \\\"12345\\\", tries++, details)\\n else if (details.passwordLength === 4) result = await goToWork(ns, server, \\\"0000\\\", tries++, details)\\n }\\n if (result && (result.success || !serverCheck(ns, server, details, result))) return result\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"CloudBlare(tm)\\\": {\\n const result = await goToWork(ns, server, details.data.replace(/\\\\D/g, \\\"\\\").toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"Laika4\\\": {\\n if (details.passwordLength === 3) return await goToWork(ns, server, \\\"max\\\", tries++, details)\\n else if (details.passwordLength === 5) return await goToWork(ns, server, \\\"rover\\\", tries++, details)\\n else if (details.passwordLength === 4) {\\n let result = await goToWork(ns, server, \\\"fido\\\", tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n else {\\n result = await goToWork(ns, server, \\\"spot\\\", tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n }\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"BellaCuore\\\": {\\n let rawNumbers = details.data.split(\\\",\\\")\\n const numbers = []\\n if (rawNumbers.length > 1)\\n rawNumbers.forEach((n) => numbers.push(romanToDecimal(n)))\\n else numbers.push(romanToDecimal(rawNumbers[0]))\\n let result\\n if (numbers.length === 1) {\\n result = await goToWork(ns, server, numbers[0].toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n }\\n else { //We have a range of 2 numbers.\\n let pool = inProgress.get(server)?.currentPool ?? []\\n tries = inProgress.get(server)?.tries ?? 1\\n const high = numbers[0] > numbers[1] ? numbers[0] : numbers[1]\\n const low = numbers[0] < numbers[1] ? numbers[0] : numbers[1]\\n if (pool.length === 0) {\\n for (let i = low; i <= high; i++)\\n if (i.toString().length === details.passwordLength) pool.push(i)\\n }\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 2) return { success: false }\\n while (true) {\\n\\n inProgress.set(server, {\\n details: details,\\n currentPool: pool.slice(),\\n tries: tries\\n })\\n const testing = pool[Math.floor(pool.length / 2)]\\n let bleed\\n let running = 1\\n goToWork(ns, server, testing.toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((results) => {\\n running--\\n result = results\\n })\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running) await ns.asleep(4)\\n if (result.success || !await bleedCheck(ns, server, details, bleed)) return result\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== testing.toString()) continue\\n if (jsonLog.data.toString() === \\\"PARUM BREVIS\\\")\\n pool = pool.filter((p) => p > testing)\\n else if (jsonLog.data.toString() === \\\"ALTUS NIMIS\\\")\\n pool = pool.filter((p) => p < testing)\\n break\\n }\\n }\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"RateMyPix.Auth\\\": {\\n let testing\\n if (details.passwordFormat === \\\"numeric\\\") testing = numbers\\n else if (details.passwordFormat === \\\"alphabetic\\\") testing = lettersLCase.concat(lettersUCase)\\n else testing = numbers.concat(lettersLCase).concat(lettersUCase)\\n let worker\\n let i = inProgress.get(server)?.count ?? 0\\n tries = inProgress.get(server)?.tries ?? 1\\n let knownPool = Array.from(inProgress.get(server)?.knownPool ?? [])\\n let firstGuess = inProgress.get(server)?.firstGuess ?? false\\n let lastGuess = Array.from(inProgress.get(server)?.lastGuess ?? [])\\n let nextGuess = Array.from(inProgress.get(server)?.nextGuess ?? [])\\n let pixCursor = Array.from(inProgress.get(server)?.pixCursor ?? [])\\n const tested = new Set(inProgress.get(server)?.tested ?? [])\\n const testFeedback = Array.from(inProgress.get(server)?.testFeedback ?? [])\\n const record = () => {\\n inProgress.set(server, {\\n details: details,\\n knownPool: knownPool.slice(),\\n count: i,\\n tries: tries,\\n firstGuess: firstGuess,\\n lastGuess: Array.isArray(lastGuess) ? lastGuess.slice() : [],\\n nextGuess: Array.isArray(nextGuess) ? nextGuess.slice() : [],\\n pixCursor: Array.isArray(pixCursor) ? pixCursor.slice() : [],\\n tested: Array.from(tested),\\n testFeedback: testFeedback.slice()\\n })\\n }\\n const clearWorker = () => {\\n if (worker) {\\n worker.terminate()\\n worker = null\\n }\\n }\\n const isRateMyPixCandidateValid = (guess) => {\\n if (!Array.isArray(guess) || guess.length !== details.passwordLength) return false\\n const poolCounts = new Map()\\n for (const value of knownPool) poolCounts.set(value, (poolCounts.get(value) ?? 0) + 1)\\n for (const value of guess) {\\n const count = poolCounts.get(value) ?? 0\\n if (count <= 0) return false\\n poolCounts.set(value, count - 1)\\n }\\n for (const count of poolCounts.values()) if (count !== 0) return false\\n if (tested.has(guess.join(\\\",\\\"))) return false\\n for (const { guess: previousGuess, feedback } of testFeedback) {\\n let blk = 0\\n for (let x = 0; x < guess.length; x++) if (guess[x] === previousGuess[x]) blk++\\n if (blk !== Number(feedback.blk)) return false\\n }\\n return true\\n }\\n const requestNextPixGuess = async () => {\\n for (let attempt = 0; attempt < 2; attempt++) {\\n if (!worker) worker = getWorker()\\n let ready = false\\n let response = { guess: false, cursor: pixCursor.slice(), checked: 0, exhausted: false }\\n let failed = false\\n const startedAt = Date.now()\\n worker.onmessage = (msg) => {\\n try {\\n const rawResponse = msg.data[0]\\n response = Array.isArray(rawResponse)\\n ? { guess: rawResponse, cursor: rawResponse.slice(), checked: 0, exhausted: false }\\n : rawResponse\\n } catch { response = { guess: false, cursor: pixCursor.slice(), checked: 0, exhausted: false } }\\n ready = true\\n }\\n worker.onerror = (event) => {\\n event?.preventDefault?.()\\n failed = true\\n ready = true\\n }\\n worker.onmessageerror = () => {\\n failed = true\\n ready = true\\n }\\n try {\\n worker.postMessage([\\\"pixGetNextCode\\\", [tested, testFeedback, lastGuess, knownPool, pixCursor, rateMyPixWorkerSearchMs]])\\n }\\n catch {\\n failed = true\\n ready = true\\n }\\n while (!ready) {\\n try { ns.self().server }\\n catch {\\n return { silentFail: true }\\n }\\n if (Date.now() - startedAt > rateMyPixWorkerStallMs) {\\n clearWorker()\\n if (attempt === 0) break\\n return { stalled: true, nextGuess: false }\\n }\\n await ns.asleep(10)\\n }\\n if (!ready) continue\\n if (failed) {\\n clearWorker()\\n if (attempt === 0) continue\\n return { failed: true, nextGuess: false }\\n }\\n return {\\n nextGuess: response?.guess ?? false,\\n cursor: Array.isArray(response?.cursor) ? response.cursor : pixCursor.slice(),\\n checked: Number(response?.checked ?? 0),\\n exhausted: Boolean(response?.exhausted),\\n sawTestedCandidate: Boolean(response?.sawTestedCandidate)\\n }\\n }\\n return { stalled: true, nextGuess: false }\\n }\\n function allEqual(str) {\\n for (let i = 1; i < str.length; i++) {\\n if (str[i] !== str[0]) {\\n return false\\n }\\n }\\n return true\\n }\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n const processing = []\\n let bleedResults\\n let running = 0\\n while (knownPool.length < details.passwordLength && i < testing.length) {\\n const beingTested = player.skills.charisma < chaReq ? \\\"[\\\" : testing[i++]\\n const testGroup = []\\n for (let x = 0; x < details.passwordLength; x++)\\n testGroup.push(beingTested)\\n running++\\n goToWork(ns, server, testGroup.join(\\\"\\\").toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n if (i < testing.length && (running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue //Saving 1 maxThreads for heartbleed\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleed) => { //Bleed takes longer than auth at the same threads\\n running--\\n bleedResults = bleed\\n })\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) return results\\n if (!await bleedCheck(ns, server, details, bleedResults)) return { success: false }\\n for (const log of bleedResults.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.toString().includes(\\\"[\\\")) continue\\n if (jsonLog.passwordAttempted.toString().length !== details.passwordLength) continue\\n if (!allEqual(jsonLog.passwordAttempted.toString())) continue\\n if (tested.has(jsonLog.passwordAttempted.toString())) continue\\n tested.add(jsonLog.passwordAttempted.toString())\\n const tried = jsonLog.passwordAttempted.split(\\\"\\\")[0]\\n const response = jsonLog.data.split(\\\"/\\\")\\n if (response[0].toString() !== \\\"0\\\") {\\n const segmenter = new Intl.Segmenter(undefined, { granularity: \\\"grapheme\\\" }) //At this point, we could just .replaceAll() the pepper with something else, but why?\\n const currentMatch = Array.from(segmenter.segment(response[0])).length //Surprise! Each 🌶️ splits into multiple unicode points, with variants... Spicy indeed!!\\n let index\\n for (const test in testing)\\n if (testing[test].toString() === tried.toString()) {\\n index = Number(test)\\n break\\n }\\n for (let x = 0; x < currentMatch; x++)\\n knownPool.push(index)\\n }\\n }\\n tries++\\n record()\\n }\\n knownPool = knownPool.toSorted((a, b) => a - b)\\n if (!firstGuess) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (knownPool.length !== details.passwordLength) {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n let result\\n let running = 1\\n goToWork(ns, server, knownPool.map((index) => testing[index]).join(\\\"\\\").toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((resultRaw) => {\\n running--\\n result = resultRaw\\n })\\n running++\\n let bleed\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running > 0) await ns.asleep(4)\\n if (result.success) return result\\n if (!await bleedCheck(ns, server, details, bleed)) return { success: false }\\n let found = false\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.toString() !== knownPool.map((index) => testing[index]).join(\\\"\\\").toString()) continue\\n found = true\\n const response = jsonLog.data.split(\\\"/\\\")\\n if (response[0].toString() === \\\"0\\\") {\\n testFeedback.push({\\n guess: knownPool.slice(),\\n feedback: { blk: 0 },\\n response: response\\n })\\n }\\n else {\\n //Segmenter is overkill. You could just replaceAll instances of the pepper with something else\\n const segmenter = new Intl.Segmenter(undefined, { granularity: \\\"grapheme\\\" });\\n const currentMatch = Array.from(segmenter.segment(response[0])).length //Surprise! Each 🌶️ splits into multiple unicode points, with variants... Spicy indeed!!\\n testFeedback.push({\\n guess: knownPool.slice(),\\n feedback: { blk: currentMatch },\\n response: response\\n })\\n }\\n tested.add(knownPool.join(\\\",\\\"))\\n firstGuess = true\\n lastGuess = knownPool.slice()\\n nextGuess = []\\n pixCursor = lastGuess.slice()\\n record()\\n break\\n }\\n if (!found) {\\n clearWorker()\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n //webworker time!\\n worker = getWorker()\\n ns.atExit(() => {\\n clearWorker()\\n updateWorkingOn(server, details, \\\"remove\\\")\\n })\\n let pixNoProgressCycles = 0\\n while (true) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (nextGuess.length === 0) {\\n const previousPixCursor = Array.isArray(pixCursor) ? pixCursor.slice() : []\\n const workerResult = await requestNextPixGuess()\\n if (workerResult.silentFail) {\\n return { silentFail: true }\\n }\\n if (Array.isArray(workerResult.cursor)) pixCursor = workerResult.cursor.slice()\\n nextGuess = Array.isArray(workerResult.nextGuess) ? workerResult.nextGuess.slice() : []\\n record()\\n if (workerResult.stalled || workerResult.failed) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n if (workerResult.exhausted) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n if (!nextGuess || nextGuess.length === 0) {\\n const cursorAdvanced = Array.isArray(pixCursor)\\n && pixCursor.length > 0\\n && pixCursor.join(\\\",\\\") !== previousPixCursor.join(\\\",\\\")\\n if (!cursorAdvanced) {\\n pixNoProgressCycles++\\n clearWorker()\\n if (pixNoProgressCycles < 2) continue\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n pixNoProgressCycles = 0\\n continue\\n }\\n }\\n pixNoProgressCycles = 0\\n if (!nextGuess || nextGuess.length === 0) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n if (!isRateMyPixCandidateValid(nextGuess)) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n let result\\n let running = 1\\n goToWork(ns, server, nextGuess.map((index) => testing[index]).join(\\\"\\\").toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((resultRaw) => {\\n running--\\n result = resultRaw\\n })\\n let bleed\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running > 0) await ns.asleep(4)\\n\\n if (result.success) {\\n clearWorker()\\n return result\\n }\\n if (!await bleedCheck(ns, server, details, bleed)) {\\n clearWorker()\\n return { success: false }\\n }\\n let found = false\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== nextGuess.map((index) => testing[index]).join(\\\"\\\").toString()) continue\\n found = true\\n const response = jsonLog.data.split(\\\"/\\\")\\n\\n if (response[0].toString() === \\\"0\\\") {\\n testFeedback.push({\\n guess: nextGuess.slice(),\\n feedback: { blk: 0 },\\n response: response\\n })\\n }\\n else {\\n const segmenter = new Intl.Segmenter(undefined, { granularity: \\\"grapheme\\\" });\\n const currentMatch = Array.from(segmenter.segment(response[0])).length\\n testFeedback.push({\\n guess: nextGuess.slice(),\\n feedback: { blk: currentMatch },\\n response: response\\n })\\n }\\n tested.add(nextGuess.join(\\\",\\\"))\\n lastGuess = nextGuess.slice()\\n nextGuess = []\\n pixCursor = lastGuess.slice()\\n record()\\n break\\n }\\n if (!found) {\\n clearWorker()\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n }\\n case \\\"OctantVoxel\\\": {\\n const nums = details.data.split(\\\",\\\")\\n const result = await goToWork(ns, server, convertToBase10([nums[1], nums[0]]).toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n\\n case \\\"BigMo%od\\\": {\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 2) return { success: false }\\n let worker\\n const length = details.passwordLength\\n const MIN = 10 ** (length - 1)\\n const MAX = 10 ** length - 1\\n let tries = inProgress.get(server)?.tries ?? 1\\n let tripleConstraints = inProgress.get(server)?.tripleConstraints ?? []\\n let nextGuess = inProgress.get(server)?.nextGuess ?? \\\"\\\"\\n let lastGuess = inProgress.get(server)?.lastGuess ?? 0\\n\\n const tried = new Set(inProgress.get(server)?.tried ?? [])\\n const record = () => {\\n inProgress.set(server, {\\n details: details,\\n nextGuess: nextGuess,\\n lastGuess: lastGuess,\\n tries: tries,\\n tripleConstraints: tripleConstraints.slice(),\\n tried: Array.from(tried)\\n })\\n }\\n const clearWorker = () => {\\n if (worker) {\\n worker.terminate()\\n worker = null\\n }\\n }\\n\\n function parseTripleModuloLogs(logs, candidate) {\\n const out = []\\n for (const log of logs ?? []) {\\n try {\\n const j = JSON.parse(log)\\n if (j?.passwordAttempted.toString() === candidate) {\\n const k = Number(j.passwordAttempted)\\n const r = Number(j.data)\\n if (Number.isFinite(k) && Number.isFinite(r)) {\\n out.push({ k, r })\\n }\\n }\\n } catch {\\n continue\\n }\\n }\\n return out\\n }\\n worker = getWorker()\\n ns.atExit(() => {\\n clearWorker()\\n updateWorkingOn(server, details, \\\"remove\\\")\\n })\\n while (true) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n record()\\n if (nextGuess === \\\"\\\") {\\n let ready = false\\n worker.onmessage = (msg) => {\\n try { nextGuess = msg.data[0] } catch { nextGuess = false }\\n ready = true\\n record()\\n }\\n worker.postMessage([\\\"getNextCandidate\\\", [lastGuess, tripleConstraints, tries, MIN, MAX, tried]])\\n while (!ready) await ns.asleep(10)\\n try { ns.self().server }\\n catch {\\n return { silentFail: true }\\n }\\n if (!nextGuess) {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n let result\\n let bleed\\n let running = 1\\n goToWork(ns, server, nextGuess.toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((results) => {\\n running--\\n result = results\\n })\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running) await ns.asleep(4)\\n if (result.success || !await bleedCheck(ns, server, details, bleed)) {\\n clearWorker()\\n return result\\n }\\n let found = false\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== nextGuess.toString()) continue\\n found = true\\n break\\n }\\n if (!found) continue\\n const fresh = parseTripleModuloLogs(bleed.logs, nextGuess.toString()).filter(c => !tripleConstraints.some(x => x.k === c.k && x.r === c.r))\\n if (fresh.length > 0) tripleConstraints.push(...fresh)\\n tried.add(nextGuess)\\n lastGuess = Number(nextGuess)\\n nextGuess = \\\"\\\"\\n }\\n }\\n case \\\"Factori-Os\\\": {\\n tries = inProgress.get(server)?.tries ?? 1\\n let primeCounter = inProgress.get(server)?.primeCounter ?? 0\\n const primeMap = new Map(inProgress.get(server)?.primeMap || [])\\n const processed = new Set(inProgress.get(server)?.processed || [])\\n const primes = inProgress.get(server)?.primes || []\\n const record = () => inProgress.set(server, {\\n details: details,\\n primeCounter: primeCounter,\\n primeMap: Array.from(primeMap),\\n processed: Array.from(processed),\\n primes: primes,\\n tries: tries\\n })\\n\\n if (details.passwordLength === 1) { //Seperate optimal solver\\n const testingOrder = [0, 7, 2, 3, 6, 5, 4, 8, 9]\\n let candidates = inProgress.get(server)?.candidates ?? [1, 2, 3, 4, 5, 6, 7, 8, 9]\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n while (primeCounter < testingOrder.length) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n record()\\n const d = BigInt(testingOrder[primeCounter])\\n if (candidates.length === 1) {\\n const result = await goToWork(ns, server, candidates[0].toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n else {\\n let divides = false\\n const maxThreads = d.toString() === \\\"0\\\" ? maxTotalThreads : Math.floor(maxTotalThreads / 2)\\n let running = 1\\n let result\\n let bleed\\n goToWork(ns, server, d.toString(), tries++, details, maxThreads).then((results) => {\\n running--\\n result = results\\n })\\n\\n if (d.toString() !== \\\"0\\\") {\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n }\\n while (running) await ns.asleep(4)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n if (d.toString() !== \\\"0\\\") {\\n if (!await bleedCheck(ns, server, details, bleed)) return { success: false }\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== d.toString()) continue\\n if (jsonLog.data === \\\"true\\\")\\n divides = true\\n break\\n }\\n candidates = candidates.filter(n => divides ? BigInt(n) % d === 0n : BigInt(n) % d !== 0n)\\n }\\n primeCounter++\\n }\\n }\\n record()\\n if (candidates.length === 1) {\\n const result = await goToWork(ns, server, candidates[0].toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n const sortedPrimeGroup = [...smallPrimes, ...largePrimes].filter(p => (p).toString().length <= details.passwordLength)\\n const sortedBigIntPrimes = sortedPrimeGroup.map(BigInt)\\n if (primeMap.size === 0)\\n sortedPrimeGroup.forEach((p) => primeMap.set(p.toString(), true))\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n let left = 0\\n let firstGuess = true\\n let base = BigInt(primes.reduce((acc, val) => acc * val, 1))\\n if (base.toString().length === details.passwordLength) firstGuess = false //Only start this guess if it could work\\n left = firstGuess ? 1 : 2 //We might make a guess against our base now.\\n for (const [key, entry] of primeMap.entries())\\n if (entry && (BigInt(key) * base).toString().length <= details.passwordLength)\\n left++\\n if (details.passwordLength < 4 && maxTotalThreads / 6 >= 2) left = left > 6 ? 6 : left\\n else if (details.passwordLength >= 4 && maxTotalThreads / 13 >= 2) left = left > 13 ? 13 : left\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / left))\\n let running = 0\\n let processing = []\\n let bleedResults\\n while (primeMap.size) {\\n if (!firstGuess) {\\n firstGuess = true\\n running++\\n goToWork(ns, server, base.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n }\\n else {\\n const prime = BigInt(sortedPrimeGroup[primeCounter++])\\n const candidate = prime * base\\n if (primeMap.get(prime.toString()) && candidate.toString().length <= details.passwordLength) {\\n running++\\n goToWork(ns, server, candidate.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n }\\n }\\n if (primeCounter < sortedPrimeGroup.length && (running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue //Saving 1 maxThreads for heartbleed\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleed) => { //Bleed takes longer than auth at the same threads\\n running--\\n bleedResults = bleed\\n })\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) {\\n return results\\n }\\n if (!await bleedCheck(ns, server, details, bleedResults)) return { success: false }\\n const newPrimes = []\\n for (const log of bleedResults.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n const attempted = BigInt(jsonLog.passwordAttempted)\\n if (attempted.toString() === base.toString()) {\\n continue\\n }\\n if (processed.has(attempted.toString())) {\\n continue\\n }\\n const tested = attempted / base\\n let basePrime = 0\\n for (const prime of sortedBigIntPrimes)\\n if (tested % prime === 0n) {\\n basePrime = Number(prime)\\n break\\n }\\n if (jsonLog.data === \\\"true\\\") {\\n newPrimes.push(basePrime)\\n }\\n else {\\n primeMap.delete(basePrime.toString())\\n }\\n processed.add(attempted.toString())\\n }\\n primes.push(...newPrimes)\\n primeCounter = 0\\n tries++\\n processing = []\\n bleedResults = []\\n base = BigInt(primes.reduce((acc, val) => acc * val, 1))\\n if (base.toString().length === details.passwordLength) firstGuess = false //Only start this guess if it could work\\n left = firstGuess ? 1 : 2\\n for (const [key, entry] of primeMap.entries())\\n if (entry && (Number(key) * Number(base)).toString().length <= details.passwordLength)\\n left++\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / left))\\n }\\n if (details.passwordLength < 4 && maxTotalThreads / 6 >= 2) left = left > 6 ? 6 : left\\n else if (details.passwordLength >= 4 && maxTotalThreads / 13 >= 2) left = left > 13 ? 13 : left\\n record()\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"AccountsManager_4.2\\\": {\\n const numbers = details.passwordHint.match(/\\\\d+/g).map(Number)\\n let pool = inProgress.get(server)?.pool ?? []\\n tries = inProgress.get(server)?.tries ?? 1\\n\\n if (pool.length === 0) {\\n for (let i = numbers[0]; i <= numbers[1]; i++)\\n if (i.toString().length === details.passwordLength) pool.push(i)\\n }\\n const record = () => inProgress.set(server, {\\n details: details,\\n pool: pool.slice(),\\n tries: tries\\n })\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 2) return { success: false }\\n while (pool.length > 0) {\\n const maxThreads = Math.floor(maxTotalThreads / 2)\\n record()\\n const testing = pool[Math.floor(pool.length / 2)]\\n let result\\n let bleed\\n let running = 1\\n goToWork(ns, server, testing.toString(), tries++, details, maxThreads).then((results) => {\\n running--\\n result = results\\n })\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running) await ns.asleep(4)\\n if (result.success || !await bleedCheck(ns, server, details, bleed)) return result\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== testing.toString()) continue\\n if (jsonLog.data === \\\"Lower\\\") {\\n const newPool = pool.filter((p) => p < Number(testing))\\n pool = newPool\\n }\\n else if (jsonLog.data === \\\"Higher\\\") {\\n const newPool = pool.filter((p) => p > Number(testing))\\n pool = newPool\\n }\\n break\\n }\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"OpenWebAccessPoint\\\": {\\n tries = inProgress.get(server)?.tries ?? 1\\n let pool = new Set(inProgress.get(server)?.pool ?? [])\\n function record() {\\n inProgress.set(server, {\\n details: details,\\n tries: tries,\\n pool: Array.from(pool)\\n })\\n }\\n function extractPassword(str, hostname, length) {\\n const escaped = hostname.replace(/[.*+?^${}()|[\\\\]\\\\\\\\]/g, '\\\\\\\\$&')\\n const pattern = `(?:^|\\\\\\\\s)${escaped}:(.{${length}})(?=\\\\\\\\s|$)`\\n const regex = new RegExp(pattern)\\n const match = regex.exec(str)\\n return match ? match[1].toString() : null\\n }\\n function collectSegments(str, len = details.passwordLength, pwFormat = details.passwordFormat) {\\n const out = new Set()\\n //if (str.includes(\\\" \\\")) return []\\n for (let i = 0; i <= str.length - len; i++) {\\n const test = str.slice(i, i + len)\\n if (pwFormat === \\\"numeric\\\" && isNumeric(test)) out.add(test)\\n else if (pwFormat === \\\"alphabetic\\\" && isAlphabetic(test)) out.add(test)\\n else if (pwFormat === \\\"alphanumeric\\\" && isAlphanumeric(test)) out.add(test)\\n }\\n return Array.from(out)\\n }\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 2) return { success: false }\\n let running = 0\\n if (pool.size === 0) {\\n running++\\n goToWork(ns, server, \\\"\\\", tries++, details, Math.floor(maxTotalThreads / 2)).then(() => {\\n running--\\n })\\n let bleed\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n bleed = bleedRaw\\n running--\\n })\\n while (running > 0) await ns.asleep(4)\\n if (!await bleedCheck(ns, server, details, bleed)) return { success: false }\\n let answer\\n for (const log of bleed.logs) {\\n answer = extractPassword(log, server, details.passwordLength)\\n if (log.includes(\\\"There's definitely nothing in that password...\\\")) answer = \\\"\\\"\\n if (answer != null) break\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (!jsonLog?.data) continue\\n const segments = collectSegments(jsonLog.data)\\n segments.forEach((s) => pool.add(s))\\n }\\n if (answer != null) {\\n const result = await goToWork(ns, server, answer.toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n else {\\n failureReport(ns, server, details)\\n return result\\n }\\n }\\n record()\\n }\\n running = 0\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 4) return { success: false }\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / 4))\\n while (pool.size > 0) {\\n running++\\n goToWork(ns, server, \\\"\\\", tries, details, maxThreads).then(() => {\\n running--\\n })\\n if ((running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue\\n let bleed\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleedRaw) => {\\n bleed = bleedRaw\\n running--\\n })\\n while (running > 0) await ns.asleep(4)\\n if (!await bleedCheck(ns, server, details, bleed)) return { success: false }\\n let answer\\n for (const log of bleed.logs) {\\n const testPool = new Set()\\n answer = extractPassword(log, server, details.passwordLength)\\n if (log.includes(\\\"There's definitely nothing in that password...\\\")) answer = \\\"\\\"\\n if (answer != null) break\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (!jsonLog?.data) continue\\n const segments = collectSegments(jsonLog.data)\\n segments.forEach((s) => { if (pool.has(s)) testPool.add(s) })\\n pool = new Set(Array.from(testPool))\\n if (pool.size === 1) break\\n }\\n if (answer != null) {\\n const result = await goToWork(ns, server, answer.toString(), tries, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n else {\\n failureReport(ns, server, details)\\n return result\\n }\\n }\\n if (pool.size === 1) {\\n const result = await goToWork(ns, server, pool.values().next().value, tries, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n else {\\n failureReport(ns, server, details)\\n return result\\n }\\n }\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / 4))\\n tries++\\n record()\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"NIL\\\": {\\n const length = details.passwordLength\\n let testing\\n if (details.passwordFormat === \\\"numeric\\\") testing = numbers\\n else if (details.passwordFormat === \\\"alphabetic\\\") testing = lettersLCase.concat(lettersUCase)\\n else testing = lettersLCase.concat(lettersUCase).concat(numbers)\\n let i = inProgress.get(server)?.count ?? 0\\n tries = inProgress.get(server)?.tries ?? 1\\n const correct = inProgress.get(server)?.correct ?? []\\n if (correct.length === 0)\\n for (let check = 0; check < length; check++)\\n correct.push(\\\"*\\\")\\n\\n let running = 0\\n let processing = []\\n let bleedResults\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n while (i < testing.length) {\\n //Slam it with blanks until we have the Cha to do it\\n const beingTested = player.skills.charisma < chaReq ? \\\"[\\\" : testing[i++].toString()\\n const testArray = correct.map((a) => a === \\\"*\\\" ? beingTested : a)\\n running++\\n goToWork(ns, server, testArray.join(\\\"\\\").toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n if (i < testing.length && (running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleed) => {\\n running--\\n bleedResults = bleed\\n })\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) return results\\n if (!await bleedCheck(ns, server, details, bleedResults)) return { success: false }\\n for (const log of bleedResults.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.includes(\\\"[\\\") || !jsonLog.data || jsonLog.data === \\\"\\\") continue\\n if (jsonLog.passwordAttempted.toString().length !== details.passwordLength) continue\\n const response = jsonLog.data.split(\\\",\\\")\\n const pwAttempt = jsonLog.passwordAttempted.split(\\\"\\\")\\n for (let check = 0; check < response.length; check++) {\\n if (response[check] === \\\"yes\\\") correct[check] = pwAttempt[check].toString()\\n }\\n }\\n tries++\\n if (correct.reduce((acc, val) => acc + (val === \\\"*\\\"), 0) === 0) {\\n const results = await goToWork(ns, server, correct.join(\\\"\\\").toString(), tries, details)\\n if (results.success || !serverCheck(ns, server, details, results)) return results\\n else {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n }\\n inProgress.set(server, {\\n details: details,\\n correct: correct,\\n count: i\\n })\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"DeepGreen\\\": {\\n // A variation on Knuth\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n const testFeedback = inProgress.get(server)?.testFeedback ?? []\\n const tested = new Set(inProgress.get(server)?.tested ?? [])\\n tries = inProgress.get(server)?.tries ?? 1\\n let firstFeedback\\n let lastGuess = Array.from(inProgress.get(server)?.lastGuess ?? [])\\n let nextGuess = Array.from(inProgress.get(server)?.nextGuess ?? [])\\n let deepGreenCursor = Array.from(inProgress.get(server)?.deepGreenCursor ?? [])\\n let currentTestRaw = inProgress.get(server)?.currentTestRaw ?? 0\\n let i = inProgress.get(server)?.count ?? 0\\n let countHasCycled = inProgress.get(server)?.countHasCycled ?? false\\n let feedback\\n let pool\\n let worker\\n if (details.passwordFormat === \\\"numeric\\\") pool = numbers\\n else if (details.passwordFormat === \\\"alphanumeric\\\") pool = numbers.concat(lettersLCase).concat(lettersUCase)\\n else pool = lettersLCase.concat(lettersUCase)\\n const record = () => inProgress.set(server, {\\n details: details,\\n count: i,\\n currentTestRaw: currentTestRaw,\\n testFeedback: testFeedback.slice(),\\n tested: Array.from(tested),\\n lastGuess: lastGuess.slice(),\\n nextGuess: nextGuess.slice(),\\n deepGreenCursor: Array.isArray(deepGreenCursor) ? deepGreenCursor.slice() : [],\\n tries,\\n countHasCycled,\\n })\\n const clearWorker = () => {\\n if (worker) {\\n worker.terminate()\\n worker = null\\n }\\n }\\n const isDeepGreenCandidateValid = (guess) => {\\n if (!Array.isArray(guess) || guess.length !== details.passwordLength) return false\\n for (const value of guess) {\\n if (!Number.isInteger(value) || value < 0 || value >= pool.length) return false\\n }\\n if (tested.has(guess.join(\\\",\\\"))) return false\\n for (const { guess: previousGuess, feedback } of testFeedback) {\\n const expectedBlk = Number(feedback.blk)\\n const expectedWht = Number(feedback.wht)\\n let blk = 0\\n const guessCount = new Map()\\n const candidateCount = new Map()\\n for (let x = 0; x < guess.length; x++) {\\n if (guess[x] === previousGuess[x]) {\\n blk++\\n }\\n else {\\n guessCount.set(previousGuess[x], (guessCount.get(previousGuess[x]) ?? 0) + 1)\\n candidateCount.set(guess[x], (candidateCount.get(guess[x]) ?? 0) + 1)\\n }\\n }\\n let wht = 0\\n for (const [value, count] of guessCount.entries()) {\\n wht += Math.min(count, candidateCount.get(value) ?? 0)\\n }\\n if (blk !== expectedBlk || wht !== expectedWht) return false\\n }\\n return true\\n }\\n const requestNextDeepGreenGuess = async () => {\\n for (let attempt = 0; attempt < 2; attempt++) {\\n if (!worker) worker = getWorker()\\n let ready = false\\n let response = { guess: false, cursor: deepGreenCursor.slice(), checked: 0, exhausted: false }\\n let failed = false\\n const startedAt = Date.now()\\n worker.onmessage = (msg) => {\\n try {\\n const rawResponse = msg.data[0]\\n response = Array.isArray(rawResponse)\\n ? { guess: rawResponse, cursor: rawResponse.slice(), checked: 0, exhausted: false }\\n : rawResponse\\n } catch { response = { guess: false, cursor: deepGreenCursor.slice(), checked: 0, exhausted: false } }\\n ready = true\\n }\\n worker.onerror = (event) => {\\n event?.preventDefault?.()\\n failed = true\\n ready = true\\n }\\n worker.onmessageerror = () => {\\n failed = true\\n ready = true\\n }\\n try {\\n worker.postMessage([\\\"getNextCode\\\", [tested, testFeedback, lastGuess, pool, deepGreenCursor, rateMyPixWorkerSearchMs]])\\n }\\n catch {\\n failed = true\\n ready = true\\n }\\n while (!ready) {\\n try { ns.self().server }\\n catch {\\n return { silentFail: true }\\n }\\n if (Date.now() - startedAt > rateMyPixWorkerStallMs) {\\n clearWorker()\\n if (attempt === 0) break\\n return { stalled: true, nextGuess: false }\\n }\\n await ns.asleep(10)\\n }\\n if (!ready) continue\\n if (failed) {\\n clearWorker()\\n if (attempt === 0) continue\\n return { failed: true, nextGuess: false }\\n }\\n return {\\n nextGuess: response?.guess ?? false,\\n cursor: Array.isArray(response?.cursor) ? response.cursor : deepGreenCursor.slice(),\\n checked: Number(response?.checked ?? 0),\\n exhausted: Boolean(response?.exhausted),\\n sawTestedCandidate: Boolean(response?.sawTestedCandidate)\\n }\\n }\\n return { stalled: true, nextGuess: false }\\n }\\n if (!countHasCycled) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n let processing = []\\n let bleedResults\\n let running = 0\\n while (true) {\\n const firstGuess = []\\n for (let test = 0; test < details.passwordLength; test++) {\\n firstGuess.push(currentTestRaw++)\\n if (currentTestRaw === pool.length) {\\n countHasCycled = true\\n if (test === details.passwordLength) currentTestRaw = 1\\n else currentTestRaw = 0\\n }\\n }\\n running++\\n goToWork(ns, server, firstGuess.map((index) => pool[index]).join(\\\"\\\").toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n if ((running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleed) => {\\n running--\\n bleedResults = bleed\\n })\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) return results\\n if (!await bleedCheck(ns, server, details, bleedResults)) return { success: false }\\n const checked = new Set()\\n for (const log of bleedResults.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.toString().length !== details.passwordLength) continue\\n if (jsonLog.passwordAttempted.toString() === \\\"[\\\") continue\\n if (checked.has(jsonLog.passwordAttempted.toString())) continue\\n if (!jsonLog?.data) continue\\n checked.add(jsonLog.passwordAttempted.toString())\\n const response = jsonLog.data.split(\\\",\\\")\\n firstFeedback = {\\n blk: Number(response[0]),\\n wht: Number(response[1])\\n }\\n const convertedGuess = []\\n for (const char of jsonLog.passwordAttempted.split(\\\"\\\")) {\\n for (const index in pool)\\n if (pool[index].toString() === char.toString()) {\\n convertedGuess.push(Number(index))\\n break\\n }\\n }\\n testFeedback.push({\\n guess: [...convertedGuess],\\n feedback: firstFeedback\\n })\\n tested.add(convertedGuess.join(\\\",\\\"))\\n }\\n lastGuess = []\\n for (let i = 0; i < details.passwordLength; i++)\\n lastGuess.push(0)\\n deepGreenCursor = lastGuess.slice()\\n tries++\\n processing = []\\n bleedResults = undefined\\n record()\\n if (countHasCycled) break\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n }\\n }\\n }\\n worker = getWorker()\\n ns.atExit(() => {\\n clearWorker()\\n updateWorkingOn(server, details, \\\"remove\\\")\\n })\\n let deepGreenNoProgressCycles = 0\\n while (true) {\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (nextGuess.length === 0) {\\n const previousDeepGreenCursor = Array.isArray(deepGreenCursor) ? deepGreenCursor.slice() : []\\n const workerResult = await requestNextDeepGreenGuess()\\n if (workerResult.silentFail) {\\n return { silentFail: true }\\n }\\n if (Array.isArray(workerResult.cursor)) deepGreenCursor = workerResult.cursor.slice()\\n nextGuess = Array.isArray(workerResult.nextGuess) ? workerResult.nextGuess.slice() : []\\n record()\\n if (workerResult.stalled || workerResult.failed) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n if (workerResult.exhausted) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n if (!nextGuess || nextGuess.length === 0) {\\n const cursorAdvanced = Array.isArray(deepGreenCursor)\\n && deepGreenCursor.length > 0\\n && deepGreenCursor.join(\\\",\\\") !== previousDeepGreenCursor.join(\\\",\\\")\\n if (!cursorAdvanced) {\\n deepGreenNoProgressCycles++\\n clearWorker()\\n if (deepGreenNoProgressCycles < 2) continue\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n deepGreenNoProgressCycles = 0\\n continue\\n }\\n }\\n deepGreenNoProgressCycles = 0\\n if (!isDeepGreenCandidateValid(nextGuess)) {\\n failureReport(ns, server, details)\\n clearWorker()\\n return { success: false }\\n }\\n let result\\n let running = 1\\n goToWork(ns, server, nextGuess.map((index) => pool[index]).join(\\\"\\\").toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((results) => {\\n running--\\n result = results\\n })\\n let bleed\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedRaw) => {\\n running--\\n bleed = bleedRaw\\n })\\n while (running) await ns.asleep(4)\\n if (result.success) {\\n clearWorker()\\n return result\\n }\\n if (!await bleedCheck(ns, server, details, bleed)) {\\n clearWorker()\\n return { success: false }\\n }\\n let found = false\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== nextGuess.map((index) => pool[index]).join(\\\"\\\").toString()) continue\\n found = true\\n const response = jsonLog.data.split(\\\",\\\")\\n feedback = {\\n blk: Number(response[0]),\\n wht: Number(response[1])\\n }\\n break //Only process 1 log at a time now\\n }\\n if (!found) continue\\n testFeedback.push({\\n guess: nextGuess.slice(),\\n feedback: feedback\\n })\\n tested.add(nextGuess.join(\\\",\\\"))\\n\\n lastGuess = nextGuess.slice()\\n deepGreenCursor = lastGuess.slice()\\n nextGuess = []\\n record()\\n }\\n }\\n case \\\"Pr0verFl0\\\": {\\n const length = details.passwordLength\\n let testing = []\\n for (let i = 0; i < length * 2; i++)\\n testing.push(\\\"1\\\")\\n const result = await goToWork(ns, server, testing.join(\\\"\\\").toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"PHP 5.4\\\": {\\n let worker\\n const clearWorker = () => {\\n if (worker) {\\n worker.terminate()\\n worker = null\\n }\\n }\\n const testing = details.data.split(\\\"\\\")\\n tries = inProgress.get(server)?.tries ?? 1\\n let nextGuess = inProgress.get(server)?.nextGuess ?? []\\n const guessed = new Set(inProgress.get(server)?.guessed ?? [])\\n const restraints = inProgress.get(server)?.restraints ?? []\\n const record = () => inProgress.set(server, {\\n details: details,\\n tries: tries,\\n nextGuess: nextGuess.slice(),\\n guessed: Array.from(guessed),\\n restraints: restraints.slice()\\n })\\n worker = getWorker()\\n ns.atExit(() => {\\n clearWorker()\\n updateWorkingOn(server, details, \\\"remove\\\")\\n })\\n let maxTotalThreads = await getMaxAuthThreads(ns)\\n let totalPermutations = Number(permutationCount(testing))\\n let rate = totalPermutations > 10 ? 10 : totalPermutations\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / rate))\\n if (details.passwordLength <= 4) {\\n let running = 0\\n let started = 0\\n const processing = []\\n while (true) {\\n if (nextGuess.length === 0) {\\n let ready = false\\n worker.onmessage = (msg) => {\\n try { nextGuess = msg.data[0] }\\n catch {\\n nextGuess = false\\n }\\n ready = true\\n record()\\n }\\n worker.postMessage([\\\"getNextUniquePermutation\\\", [testing, guessed, restraints]])\\n while (!ready) await ns.asleep(4)\\n try { ns.self().server }\\n catch {\\n return { silentFail: true }\\n }\\n if (!nextGuess) {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n if (nextGuess && nextGuess.length > 0) {\\n running++\\n started++\\n goToWork(ns, server, nextGuess.join(\\\"\\\").toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n guessed.add(nextGuess.join(\\\",\\\"))\\n nextGuess = []\\n if ((started * maxThreads) + maxThreads <= maxTotalThreads) continue\\n }\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing) {\\n if (results.success) {\\n clearWorker()\\n return results\\n }\\n }\\n if (!serverCheck(ns, server, details, processing[processing.length - 1])) {\\n clearWorker()\\n return { success: false }\\n }\\n tries++\\n processing.length = 0\\n started = 0\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n totalPermutations = Number(permutationCount(testing))\\n rate = totalPermutations > 10 ? 10 : totalPermutations\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / rate))\\n }\\n record()\\n if (!nextGuess) {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n }\\n }\\n else {\\n while (true) {\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n }\\n if (nextGuess.length === 0) {\\n let ready = false\\n worker.onmessage = (msg) => {\\n try { nextGuess = msg.data[0] } catch { nextGuess = false }\\n ready = true\\n record()\\n }\\n worker.postMessage([\\\"getNextUniquePermutation\\\", [testing, guessed, restraints]])\\n while (!ready) await ns.asleep(4)\\n try { ns.self().server }\\n catch {\\n return { silentFail: true }\\n }\\n }\\n if (!nextGuess || nextGuess.length === 0) break\\n const result = await goToWork(ns, server, nextGuess.join(\\\"\\\").toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) {\\n clearWorker()\\n return result\\n }\\n guessed.add(nextGuess.join(\\\",\\\"))\\n if (details.passwordLength >= 5) {\\n const bleed = await bleedGrab(ns, server, 999)\\n if (!await bleedCheck(ns, server, details, bleed)) {\\n clearWorker()\\n return { success: false }\\n }\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== nextGuess.join(\\\"\\\").toString()) continue\\n const response = Number(jsonLog.data.split(\\\":\\\")[1])\\n restraints.push({ guess: nextGuess.join(\\\"\\\").toString(), rms: response })\\n break\\n }\\n }\\n nextGuess = []\\n }\\n }\\n clearWorker()\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"110100100\\\": {\\n const values = details.data.split(\\\" \\\")\\n const answer = values.map(binary => String.fromCharCode(parseInt(binary, 2))).join('')\\n const result = await goToWork(ns, server, answer.toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"2G_cellular\\\": {\\n let testing\\n if (details.passwordFormat === \\\"numeric\\\") testing = numbers\\n else if (details.passwordFormat === \\\"alphabetic\\\") testing = lettersLCase.concat(lettersUCase)\\n else testing = lettersLCase.concat(lettersUCase).concat(numbers)\\n let i = inProgress.get(server)?.count ?? 0\\n const correct = inProgress.get(server)?.correct ?? []\\n tries = inProgress.get(server)?.tries ?? 1\\n let totalDelay = inProgress.get(server)?.totalDelay ?? 0\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n let threadsFactor = 1 / (1 + 0.2 * (maxThreads - 1))\\n let sharedCharsExtraTime = (correct.length + 1) * 50 * threadsFactor\\n let running = 0\\n let processing = []\\n let extraTime = 10\\n let testPool = new Set()\\n const record = () => inProgress.set(server, {\\n details: details,\\n correct: correct.slice(),\\n totalDelay: totalDelay,\\n count: i,\\n tries: tries\\n })\\n while (correct.length < details.passwordLength) {\\n //Slam it with blanks until we have the Cha to do it\\n const testChar = player.skills.charisma < chaReq ? \\\"[\\\" : testing[i++]\\n const guess = correct.concat([testChar]).join(\\\"\\\").toString()\\n running++\\n goToWork(ns, server, guess.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push({ guess: guess.toString(), results: results })\\n })\\n testPool.add(testChar.toString())\\n const mult = correct.length === details.passwordLength - 1 ? 1 : 2\\n if (i < testing.length && (running * maxThreads) + (maxThreads * mult) <= maxTotalThreads) continue //Saving 1 maxThreads for heartbleed\\n let bleed\\n if (mult === 2) {\\n running++\\n totalDelay += Math.floor(sharedCharsExtraTime + extraTime + 0.5)\\n bleedGrab(ns, server, 999, maxThreads, Math.ceil(sharedCharsExtraTime + extraTime)).then((bleedRaw) => { //Bleed takes longer than auth at the same threads\\n running--\\n bleed = bleedRaw\\n })\\n }\\n while (running > 0) await ns.asleep(4)\\n tries++\\n if (mult === 1)\\n for (const { guess, results } of processing) {\\n if (results.success || !serverCheck(ns, server, details, results)) return results\\n const status = results?.success ? \\\"success\\\" : (results?.message ?? \\\"failed\\\")\\n }\\n processing = []\\n if (mult === 2) {\\n if (!await bleedCheck(ns, server, details, bleed)) return { success: false }\\n let bestChar = \\\"[\\\"\\n let base = 0\\n const checked = new Set()\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.includes(\\\"[\\\")) continue\\n const attempted = jsonLog.passwordAttempted?.toString() ?? \\\"\\\"\\n if (attempted.includes(\\\"[\\\")) continue\\n if (attempted.length !== correct.length + 1) continue\\n if (!attempted.startsWith(correct.join(\\\"\\\"))) continue\\n\\n const tested = attempted.split(\\\"\\\").pop()\\n if (tested == undefined || checked.has(tested.toString())) {\\n continue\\n }\\n checked.add(tested.toString())\\n testPool.delete(tested.toString())\\n\\n const response = Number(jsonLog.data.split(\\\":\\\")[1].replaceAll(\\\"ms\\\", \\\"\\\").trim())\\n if (!Number.isFinite(response)) {\\n continue\\n }\\n\\n if (base === 0) {\\n base = response\\n bestChar = tested\\n }\\n else if (base > response + 0.001) {\\n correct.push(bestChar)\\n i = 0\\n testPool = new Set()\\n break\\n }\\n else if (response > base + 0.001) {\\n correct.push(tested)\\n i = 0\\n testPool = new Set()\\n break\\n }\\n }\\n if (testPool.size === 1) { //We skipped it, because we didn't catch it in the bleed. It took too long\\n correct.push(testPool.values().next().value)\\n i = 0\\n extraTime += 5\\n }\\n if (testPool.size > 1) { //We skipped it and others\\n i = 0\\n extraTime += 5\\n }\\n testPool = new Set()\\n }\\n if (i === testing.length - 1) { //We are on the last character choice. Has to be it.\\n correct.push(testing[testing.length - 1])\\n i = 0\\n }\\n if (i === testing.length) { //We failed this pass \\n correct.pop()\\n extraTime += 5\\n i = 0\\n }\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / 11))\\n threadsFactor = 1 / (1 + 0.2 * (maxThreads - 1))\\n }\\n sharedCharsExtraTime = (correct.length + 1) * 50 * threadsFactor\\n record()\\n }\\n const results = await goToWork(ns, server, correct.join(\\\"\\\").toString(), tries, details)\\n if (results.success || !serverCheck(ns, server, details, results)) return results\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"EuroZone Free\\\": {\\n tries = inProgress.get(server)?.tries ?? 1\\n let pool = euCountries.filter((p) => p.length === details.passwordLength)\\n const guessed = new Set(inProgress.get(server)?.guessed ?? [])\\n pool = pool.filter(p => !guessed.has(p))\\n let maxTotalThreads = await getMaxAuthThreads(ns)\\n let rate = pool.length > 10 ? 10 : pool.length\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / rate))\\n let running = 0\\n const processing = []\\n while (pool.length) {\\n const guess = pool.pop()\\n if (guessed.has(guess)) continue\\n running++\\n goToWork(ns, server, guess.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n guessed.add(guess.toString())\\n if (pool.length > 0 && (running * maxThreads) + maxThreads <= maxTotalThreads) continue\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) return results\\n if (!serverCheck(ns, server, details, processing[processing.length - 1])) return { success: false }\\n tries++\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n rate = pool.length > 10 ? 10 : pool.length\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / rate))\\n }\\n inProgress.set(server, {\\n details: details,\\n tries: tries,\\n guessed: Array.from(guessed)\\n })\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"PrimeTime 2\\\": {\\n const testing = Number(details.data)\\n let result = false\\n for (let i = largePrimes.length - 1; i >= 0; i--)\\n if (testing % largePrimes[i] === 0) {\\n result = await goToWork(ns, server, largePrimes[i].toString(), tries++, details)\\n break\\n }\\n if (result && (result.success || !serverCheck(ns, server, details, result))) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"MathML\\\": {\\n const finishedExpression = []\\n let expression = details.data.split(\\\",\\\")\\n for (const exp of expression) {\\n if (exp.includes(\\\"alert\\\") || exp.includes(\\\"globalThis\\\") || exp.includes(\\\"you\\\")) continue\\n const finished = exp.replaceAll(\\\"➖\\\", \\\"-\\\").replaceAll(\\\"➕\\\", \\\"+\\\").replaceAll(\\\"ҳ\\\", \\\"*\\\").replaceAll(\\\"÷\\\", \\\"/\\\").replaceAll(\\\"ns.exit()\\\", \\\"\\\")\\n finishedExpression.push(finished)\\n }\\n let answer\\n try { answer = eval(finishedExpression.join(\\\"\\\").trim()) }\\n catch {\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n const result = await goToWork(ns, server, answer.toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return result\\n }\\n case \\\"TopPass\\\": {\\n let pool\\n tries = inProgress.get(server)?.tries ?? 1\\n const guessed = new Set(inProgress.get(server)?.guessed ?? [])\\n if (details.passwordFormat === \\\"numeric\\\")\\n pool = commonPWDict.filter((f) => f.length === details.passwordLength && isNumeric(f))\\n else if (details.passwordFormat === \\\"alphabetic\\\")\\n pool = commonPWDict.filter((f) => f.length === details.passwordLength && isAlphabetic(f))\\n else pool = commonPWDict.filter((f) => f.length === details.passwordLength && isAlphanumeric(f))\\n pool = pool.filter(p => !guessed.has(p))\\n let maxTotalThreads = await getMaxAuthThreads(ns)\\n let running = 0\\n const processing = []\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / Math.floor(pool.length, 10)))\\n while (pool.length > 0) {\\n const guess = pool.pop()\\n if (guessed.has(guess)) continue\\n running++\\n goToWork(ns, server, guess.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n guessed.add(guess.toString())\\n if (pool.length > 0 && (running * maxThreads) + maxThreads <= maxTotalThreads) continue\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) {\\n return results\\n }\\n if (!serverCheck(ns, server, details, processing[processing.length - 1])) return { success: false }\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n }\\n tries++\\n if (pool.length > 0) maxThreads = Math.max(1, Math.floor(maxTotalThreads / Math.min(pool.length, 10)))\\n inProgress.set(server, {\\n details: details,\\n tries: tries,\\n guessed: Array.from(guessed)\\n })\\n }\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"OrdoXenos\\\": {\\n const parts = details.data.split(\\\";\\\")\\n const maskStr = parts.pop().trim()\\n const encrypted = parts.join(\\\";\\\")\\n const mask = maskStr.split(/\\\\s+/).map(b => parseInt(b, 2))\\n let decoded = \\\"\\\"\\n for (let i = 0; i < encrypted.length; i++) {\\n decoded += String.fromCharCode(encrypted.charCodeAt(i) ^ mask[i])\\n }\\n const result = await goToWork(ns, server, decoded.toString(), tries++, details)\\n if (result.success || !serverCheck(ns, server, details, result)) return result\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n case \\\"KingOfTheHill\\\": {\\n const length = details.passwordLength\\n const MIN = Math.pow(10, length - 1)\\n const MAX = Math.pow(10, length) - 1\\n const trueHillMinWidth = Math.max(1, Math.pow(10, length - 2))\\n const minHillSpacing = 3 * Math.pow(10, length - 2)\\n let tries = inProgress.get(server)?.tries || 1\\n let guessed = new Set(inProgress.get(server)?.guessed || [])\\n let guessedAltitudes = inProgress.get(server)?.guessedAltitudes || {}\\n let solved = false\\n let solvedResult = null\\n let maxTotalThreads = await getMaxAuthThreads(ns, true)\\n if (maxTotalThreads < 3) return { success: false }\\n function record() {\\n inProgress.set(server, {\\n details: details,\\n tries: tries,\\n guessed: Array.from(guessed),\\n guessedAltitudes: guessedAltitudes\\n })\\n }\\n async function getAltitude(x) {\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n }\\n if (guessed.has(x)) return guessedAltitudes[x] //Don't guess again. This is all that really has to be recorded\\n let altitude = -Infinity\\n let result\\n let running = 0\\n running++\\n goToWork(ns, server, x.toString(), tries++, details, Math.floor(maxTotalThreads / 2)).then((results) => {\\n result = results\\n running--\\n })\\n let bleed\\n running++\\n bleedGrab(ns, server, 999, Math.floor(maxTotalThreads / 2)).then((bleedResults) => { //Bleed takes longer than auth at the same threads\\n running--\\n bleed = bleedResults\\n })\\n while (running > 0) await ns.asleep(4)\\n if (result.success || !serverCheck(ns, server, details, result) || !await bleedCheck(ns, server, details, bleed)) {\\n solved = true\\n solvedResult = result\\n return Infinity\\n }\\n for (const log of bleed.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog?.passwordAttempted.toString() !== x.toString()) continue\\n altitude = Number(jsonLog.data)\\n break\\n }\\n guessed.add(x)\\n guessedAltitudes[x] = altitude\\n record()\\n return altitude\\n }\\n //We only really need to record guesses and their answers at this point. The rest is procedural, and will always follow the same path\\n const candidateQueue = []\\n const stepBonus = length >= 3 ? minHillSpacing : 0 //Length 3 is guaranteed to have extra hills, 2 can but only at high difficulty\\n let running = 0\\n let processing = []\\n let bleedResults\\n let needsTesting = []\\n if (length === 1) {\\n for (let x = 0; x <= 9 && !solved; x++) {\\n if (!guessed.has(x)) needsTesting.push(x)//await getAltitude(x)\\n }\\n } else {\\n //The true hill could be at the extreem of left or right. So, start in a way that we will catch these cases\\n if (!guessed.has(MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2))))) needsTesting.push(MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2))))\\n if (!guessed.has(MAX - (Math.max(0, Math.floor(trueHillMinWidth / 2))))) needsTesting.push(MAX - (Math.max(0, Math.floor(trueHillMinWidth / 2))))\\n for (let step = Math.ceil((MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2)))) + trueHillMinWidth); step < MAX && !solved; step += Math.max(4, Math.ceil((trueHillMinWidth + stepBonus) / 2))) {\\n if (!guessed.has(step)) needsTesting.push(step)\\n }\\n }\\n maxTotalThreads = await getMaxAuthThreads(ns, true)\\n let maxThreads = Math.max(1, Math.floor(maxTotalThreads / (needsTesting.length + 1)))\\n while (needsTesting.length > 0) {\\n const test = needsTesting.pop()\\n running++\\n goToWork(ns, server, test.toString(), tries, details, maxThreads).then((results) => {\\n running--\\n processing.push(results)\\n })\\n if (needsTesting.length > 0 && (running * maxThreads) + (maxThreads * 2) <= maxTotalThreads) continue //Saving 1 maxThreads for heartbleed\\n running++\\n bleedGrab(ns, server, 999, maxThreads).then((bleed) => { //Bleed takes longer than auth at the same threads\\n running--\\n bleedResults = bleed\\n })\\n while (running > 0) await ns.asleep(4)\\n for (const results of processing)\\n if (results.success) return results\\n if (!await bleedCheck(ns, server, details, bleedResults)) return { success: false }\\n for (const log of bleedResults.logs) {\\n let jsonLog\\n try { jsonLog = JSON.parse(log) } catch { continue }\\n if (jsonLog.passwordAttempted.toString().length !== details.passwordLength) continue\\n if (!isNumeric(jsonLog.passwordAttempted)) continue\\n const altitude = Number(jsonLog.data)\\n guessed.add(Number(jsonLog.passwordAttempted))\\n guessedAltitudes[Number(jsonLog.passwordAttempted)] = altitude\\n }\\n const newMax = await getMaxAuthThreads(ns, true)\\n if (newMax > maxTotalThreads) {\\n maxTotalThreads = newMax\\n maxThreads = Math.max(1, Math.floor(maxTotalThreads / (needsTesting.length + 1)))\\n }\\n tries++\\n record()\\n }\\n //Now that the coarse scan is out of the way, start the climbs.\\n //The true hill could be at the extreem of left or right. So, start in a way that we will catch these cases\\n candidateQueue.push({ x: (MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2)))), alt: await getAltitude((MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2))))) })\\n candidateQueue.push({ x: (MAX - (Math.max(0, Math.floor(trueHillMinWidth / 2)))), alt: await getAltitude((MAX - (Math.max(0, Math.floor(trueHillMinWidth / 2))))) })\\n for (let step = Math.ceil((MIN + (Math.max(0, Math.floor(trueHillMinWidth / 2)))) + trueHillMinWidth); step < MAX && !solved; step += Math.max(4, Math.ceil((trueHillMinWidth + stepBonus) / 2))) {\\n candidateQueue.push({ x: step, alt: await getAltitude(step) })\\n }\\n\\n candidateQueue.sort((a, b) => b.alt - a.alt)\\n for (const test of candidateQueue) {\\n if (solved) break\\n //Each test is a possible true hill, sorted by highest first\\n //Get direction\\n let direction = 0\\n if (test.x < MAX) {\\n let checkPoint = await getAltitude(test.x + 1) //Test 1 to the right\\n if (test.alt > checkPoint) direction = -1 //We are moving left\\n else if (test.alt < checkPoint) direction = 1 //We are moving right\\n }\\n else {\\n let checkPoint = await getAltitude(test.x - 1) //Test 1 to the left\\n if (test.alt < checkPoint) direction = -1 //We are moving left\\n else if (test.alt > checkPoint) direction = 1 //We are moving right\\n }\\n if (solved) break\\n if (direction === 0) continue\\n //Climb and refine that hill.\\n let step = length === 1 ? 1 : length === 2 ? 2 : Math.ceil((minHillSpacing + trueHillMinWidth) / 3)\\n let pivot = test\\n while (!solved) {\\n //If checked1 is higher, we have a new pivot and need to check around it\\n //Even if it's higher, we could be on the other side of the hill and need to change direction\\n //If it's lower, we keep our pivot point and still halve the step.\\n let checked1 = await getAltitude(Math.max(MIN, Math.min(MAX, pivot.x + (direction * step))))\\n if (checked1 > pivot.alt) {\\n pivot = { x: Math.max(MIN, Math.min(MAX, pivot.x + (direction * step))), alt: checked1 }\\n step = Math.ceil(step / 2)\\n continue\\n }\\n let checked2 = await getAltitude(Math.max(MIN, Math.min(MAX, pivot.x + (direction * step * -1))))\\n if (checked2 > pivot.alt) {\\n pivot = { x: Math.max(MIN, Math.min(MAX, pivot.x + (direction * step * -1))), alt: checked2 }\\n step = Math.ceil(step / 2)\\n direction *= -1\\n continue\\n }\\n if (step === 1) break\\n step = Math.ceil(step / 2)\\n }\\n }\\n if (solved) return solvedResult\\n failureReport(ns, server, details)\\n return { success: false }\\n }\\n /**\\n * The Labyrinth solver is needlessly complex. It was born of boredom and testing out Claude Code vs Codex side to side\\n * for both raw creation ability, troubleshooting, error finding, and all sorts of work tasks such as suggesting alternatives, adding\\n * diagnostics, removing unneeded pathing code, etc.\\n * It is a combination of Frontier Claiming to allow multiple workers to do different things in tandem, claim handoff/retarget to a closer worker,\\n * and the raw power of the Dijkstra routing algorithm - which is what a*(a Star) is based off of.\\n * The Labyrinth is split into 4 quadrants. We will call them 1, 2, 3 and 4 or top right, top left, bottom left, bottom right with the start being\\n * in quadrant 2. Quadrant 4 is split into 4 of it's own subquadrants, with the end goal being it it's sub quadrant 4\\n * As a network system engineer, I threw out the old solver once I realized that this was actually a basic routed network.\\n * \\n * \\n * Let me explain:\\n * \\n * You know the dimensions of each Labyrinth based on the charisma required for it.\\n * With that knowledge, you can split the Labyrinth up into 4 seperate quadrants with boundary walls between them.\\n * You now have 4 quadrants, or rather you have 4 subnets.\\n * Each room has a unique coordinate, or MAC address.\\n * You have rooms with 3 or 4 exits. These are routers\\n * You have rooms with 2 exits. These are corridors, or higher cost routes.\\n * You have rooms with 1 exit. These are dead ends, or stub nodes.\\n * You have 1 passageway into a different quadrant on their border walls. These are gateways.\\n * You know the exit nodes are in quadrant 4's sub-quadrant 4. Since all MAC addresses are known by map position, you know your general target.\\n * \\n * You have everything you need to build up a routed network with the Dijkstra routing protocol. Just add each node to the routing table for that subnet.\\n * This isolates (as subnets tend to do), the larger broadcast traffic you may need to send out. It only has to reach everything in that quadrant/subnet. After\\n * that you can stop it's progress. This is why subnets were invented in the first place, to stop broadcast traffic from taking down the whole network.\\n * \\n * This avoids flood fills at all cost. Instead prefering a Dijkstra route. It moves 1 space at a time and then finds it's next hop from the routing table,\\n * but it knows it's full route when it's created so it can do a handoff easier.\\n * Dead end detection is done using known wall locations, and rather than doing a flood fill of the area it walks the wall. This removes all the checks for\\n * the larger areas of unexplored space. It also respects the subnet it is in. Once a dead end is located, it is cached for future lookups and to\\n * prevent a worker from claiming that frontier.\\n * \\n * So, your goal - translated into a network packet - is simple. Move from quadrant 2 to quadrant 4 sub-quadrant 4. Your starting objective is to find the\\n * gateway into the next quadrant. Once there, find the gateway into quadrant 4. Once there, find the path to sub-quadrant 4 (specifically the bottom right\\n * of it) and explore it.\\n * \\n * The conclusion? Tie, with the tie breaker going to Codex.\\n * With the release of GPT 5.5 and Opus 4.7 things have change.\\n * -With GPT 5.5, on the highest thinking level, I get about 2 days of actually sitting at the computer and trying stuff out. After that, my ~$28ca subscription\\n * runs out of weekly (5 day) allotment of tokens.\\n * -With the same subscription level for Claude Code, Opus 4.7 required the medium setting be used - or it risked using all it's 5 hour allotment immediately.\\n * -Using medium thinking, it is just as capable as Codex if not more capable. Opus 4.7 on Medium seems to be a better choice than GPT 5.5 on it's highest.\\n * -I get around 1-5 requests every 5 hours with Opus 4.7, usually running out of my 5 day allotment within 1 - 2 days. While the product was better,\\n * I got very little done with Opus 4.7 overall\\n * -One sad thing to note, I tried to get a prompt from Opus 4.7 3 times, and it failed to remember the prompt but used up my tokens. I then asked it to do\\n * something simple at it's highest thought and it immediately ran out of my 5 hour allotment.\\n * \\n * Both subscriptions cost the same, but I feel that you require the $100-$200+/m subscription for Opus in order to use it properly, while the $100/m sub for\\n * GPT 5.5 will actually let you code all day, with multiple prompts churning at once and not run out of your 5 hour/day allotment, unless you work more than\\n * 5 days a week or play with it over the weekend. I would highly recommend a ChatGPT Plus subscription to anyone who wants to dabble. Stay away from\\n * Claude unless your employer buys you the $200 subscription.\\n * \\n * Don't become reliant on it though. It need to remain a tool. A helper. You should always have in mind what your code is supposed to do so you can\\n * trouble shoot things when AI gets it wrong. And you will need to troubleshoot.\\n * \\n * Now, take all of the above and scrap it. While it worked perfectly, it was a 11k+ line script AND when testing at max charisma the Lab was actually lagging\\n * \\n * Instead, I lifted a few working things from the previous version.\\n * -Goalward directions are based on quadrant, and it points to the quadrant boarder (including moves that end up at the boarder wall), or the exit area\\n * -Forward directions are based on quadrant, they are directions that are not goalward (say right or left when the goal is down) but still give forward progress\\n * -Alt directions are based on quadrant, they are the direction in the opposit way of the goal\\n * -Dead end room detection will walk the walls to see if an area is enclosed\\n * -Quadrants are ranked in priority (Start is least, the end quadrant is the highest)\\n * -You cannot move into a worse rank quadrant\\n * -The exit quadrant is broken up into it's own subquadrants, with the exit sub quadrant being the bottom right of those sub quadrants\\n * -Dead end detection is disabled if the path goes through the exit subquadrant\\n * -Within the exit subquadrant, pathways are marked as blocked only when they have been fully searched\\n * -If a worker leave the exit subquadrant, it's goalward move will be into the exit subquadrant\\n * \\n * Movement choices:\\n * -First, depending on location, dead end room detection will filter out any rooms that lead into dead ends\\n * -1 If all exits have been explored, the worker will take the exit that is closest the the possible goalward crossing\\n * -2 The worker will pick the goalward movement that has not been explored yet\\n * -3 If there is a tie for 2, it will choose the route with the least cost. If that is a tie, the route of the lowest number/direction is chosen\\n * -4 The worker will pick the forward movement that has not been explored yet\\n * -5 If there is a tie for 4, the same things in 3 apply\\n * -6 If we are here, and there is an alt direction to take, take it\\n * -7 We likely have to backtrack into an area that's not blocked\\n * \\n * \\n * \\n * Have fun\\n * -Sphyxis\\n */\\n case \\\"(The Labyrinth)\\\": {\\n if (labComplete !== false) return { success: false }\\n let lastBlockedRam = Infinity\\n while (ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer) {\\n const blockedRam = ns.dnet.getBlockedRam(ns.self().server)\\n if (blockedRam <= 0) break\\n if (blockedRam >= lastBlockedRam) break\\n lastBlockedRam = blockedRam\\n if (!await threadedMemoryRealloc(ns, ns.self().server, complete.get(ns.self().server).pw)) return { success: false }\\n }\\n\\n if (!ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer) return { success: false }\\n if (player.skills.charisma < chaReq) return { success: false }\\n if (!ns.dnet.getStasisLinkedServers().includes(ns.self().server) && ns.dnet.getStasisLinkLimit() > ns.dnet.getStasisLinkedServers().length) {\\n const freeRam = await proxyHome(ns, \\\"getServerMaxRam\\\", ns.self().server) - await proxyHome(ns, \\\"getServerUsedRam\\\", ns.self().server)\\n if (freeRam >= 13.6) {\\n await proxyLocal(ns, true, \\\"dnet.setStasisLink\\\")\\n } else {\\n ns.ramOverride(16)\\n await ns.dnet.setStasisLink()\\n ns.exit()\\n }\\n }\\n if (!ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer) {\\n if (ns.dnet.getStasisLinkedServers().includes(ns.self().server)) await proxyLocal(ns, true, \\\"dnet.setStasisLink\\\", false)\\n return { success: false }\\n }\\n if (!labName) {\\n labName = server\\n // First worker on a fresh maze name: clear any stale frozen ring\\n // from a previous run. Per-worker spawns within the same maze\\n // keep accumulating into the same ring so we see all workers'\\n // recent decisions in one place.\\n const initialLabState = getLabState(server, details)\\n if (!initialLabState.layout) {\\n initialLabState.layout = getEstimatedLabLayout(chaReq)\\n if (initialLabState.layout) {\\n syncLabDisplayMap(initialLabState, true)\\n inProgress.set(server, initialLabState)\\n }\\n }\\n }\\n tries = 1\\n const workerId = ns.self().server + \\\"-\\\" + ns.pid\\n const failLab = (reason) => {\\n return { success: false }\\n }\\n let claim = null\\n let skippedClaimKeys = new Set()\\n let labWorker = 0\\n let trackedLease = null\\n let noClaimPasses = 0\\n let labExitHookRegistered = false\\n\\n const markSkippedClaim = (badClaim) => {\\n const key = typeof badClaim?.key === \\\"string\\\" && badClaim.key ? badClaim.key : (Number.isInteger(badClaim?.x) && Number.isInteger(badClaim?.y) ? getLabKey(badClaim.x, badClaim.y) : \\\"\\\")\\n if (!key) return\\n skippedClaimKeys.add(key)\\n if (skippedClaimKeys.size > 64) skippedClaimKeys = new Set([key])\\n }\\n const pickLabClaimAt = (x, y) => pickGreedyStepLegacy(server, workerId, x, y, skippedClaimKeys)\\n const updateTrackedLease = (nextClaim = null) => {\\n if (trackedLease) {\\n trackedLease.server = server\\n trackedLease.claim = nextClaim ?? null\\n trackedLease.workerId = workerId\\n return\\n }\\n trackedLease = { server, claim: nextClaim ?? null, workerId }\\n }\\n const releaseTrackedLease = () => {\\n trackedLease = null\\n }\\n const syncLabExit = () => {\\n if (labExitHookRegistered) return\\n labExitHookRegistered = true\\n ns.atExit(() => {\\n clearLabWorkerPosition(server, workerId)\\n })\\n }\\n const shouldPersistLabState = () => labComplete === false || inProgress.has(server)\\n const refreshLabState = () => {\\n if (!shouldPersistLabState()) return\\n const state = inProgress.get(server)\\n if (state?.layout && state.layout.estimated !== true) return\\n ensureLabLayout(server, details, chaReq)\\n }\\n const prepareLabEntry = async () => {\\n let lastBlocked = Infinity\\n while (ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer) {\\n const blocked = ns.dnet.getBlockedRam(ns.self().server)\\n if (blocked <= 0) break\\n if (blocked >= lastBlocked) break\\n lastBlocked = blocked\\n if (!await threadedMemoryRealloc(ns, ns.self().server, complete.get(ns.self().server).pw)) return false\\n }\\n if (!ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer) return false\\n if (!ns.dnet.getStasisLinkedServers().includes(ns.self().server)\\n && ns.dnet.getStasisLinkLimit() > ns.dnet.getStasisLinkedServers().length\\n && await proxyHome(ns, \\\"getServerMaxRam\\\", ns.self().server) - await proxyHome(ns, \\\"getServerUsedRam\\\", ns.self().server) >= 13.6) {\\n await proxyLocal(ns, true, \\\"dnet.setStasisLink\\\")\\n }\\n return ns.dnet.getServerAuthDetails(server).isConnectedToCurrentServer\\n }\\n const launchLabWorker = async () => {\\n let pid = await startLabWorker(ns, server)\\n if (pid) return pid\\n if (!await prepareLabEntry()) {\\n return 0\\n }\\n pid = await startLabWorker(ns, server)\\n return pid\\n }\\n\\n const stopLabWorker = async (pid = labWorker) => {\\n if (!pid) return\\n await proxyHome(ns, \\\"kill\\\", pid)\\n clearLabWorkerPosition(server, workerId)\\n if (labWorker === pid) labWorker = 0\\n syncLabExit()\\n }\\n const adoptSharedBootstrap = () => {\\n return false\\n }\\n const commitBootstrapRoom = (roomReport) => {\\n const [bootstrapX, bootstrapY] = Array.isArray(roomReport?.coords)\\n ? roomReport.coords\\n : [1, 1]\\n recordLabRoom(server, details, bootstrapX, bootstrapY, roomReport, [])\\n const [rootX, rootY] = getLabActualCoords(bootstrapX, bootstrapY, roomReport, inProgress.get(server))\\n const bootstrapState = inProgress.get(server)\\n addLabStartMarker(bootstrapState, rootX, rootY, workerId)\\n inProgress.set(server, bootstrapState)\\n updateLabWorkerPosition(server, details, workerId, rootX, rootY)\\n // Fresh maze entry — drop any stale visit history from a prior run.\\n clearLabWorkerVisitStack(workerId)\\n updateTrackedLease(null)\\n syncLabExit()\\n return { success: true }\\n }\\n const bootstrapLabyrinth = async () => {\\n const probe = await labWork(ns, labWorker, labCurrentRoomCommand)\\n if (probe?.workerExited) {\\n clearLabWorkerPosition(server, workerId)\\n resetLabWorkerRef()\\n if (adoptSharedBootstrap()) return { success: true }\\n return failLab(\\\"bootstrap-worker-exited\\\")\\n }\\n if (probe?.finished) {\\n const completedState = getCompletedLabStateRef(inProgress.get(server) ?? getLabCompleteState())\\n return finalizeLabCompletion(probe.authResults.data, completedState, tries + 1)\\n }\\n if (probe?.report?.success === false) {\\n if (adoptSharedBootstrap()) return { success: true }\\n await stopLabWorker()\\n return failLab(\\\"bootstrap-report-failed\\\")\\n }\\n const probeReport = probe?.report\\n if (probeReport) return commitBootstrapRoom(probeReport)\\n if (!serverCheck(ns, server, details, probe?.authResults)) {\\n if (adoptSharedBootstrap()) return { success: true }\\n await stopLabWorker()\\n return failLab(\\\"bootstrap-lost-server\\\")\\n }\\n if (adoptSharedBootstrap()) return { success: true }\\n await stopLabWorker()\\n return failLab(\\\"bootstrap-no-report\\\")\\n }\\n const releaseLease = () => {\\n releaseTrackedLease()\\n claim = null\\n syncLabExit()\\n }\\n const resetLabWorkerRef = (pid = labWorker) => {\\n if (labWorker === pid) labWorker = 0\\n syncLabExit()\\n }\\n const stopAllLabWorkers = async () => {\\n if (labWorker) await stopLabWorker(labWorker)\\n }\\n const finalizeLabCompletion = async (answer, completedState, triesUsed) => {\\n const existingCompletedState = getLabCompleteState()\\n const existingCompletedAnswer = getLabCompleteAnswer()\\n if (existingCompletedState?.details?.modelId === \\\"(The Labyrinth)\\\" && existingCompletedState.rooms) {\\n completedState = getCompletedLabStateRef(existingCompletedState)\\n if (typeof existingCompletedAnswer === \\\"string\\\" && existingCompletedAnswer) answer = existingCompletedAnswer\\n }\\n clearLabWorkerPosition(server, workerId)\\n setCompletedLabState(answer, completedState, server)\\n inProgress.delete(server)\\n releaseTrackedLease()\\n claim = null\\n //if (labName === server) labName = false\\n await stopAllLabWorkers()\\n syncLabExit()\\n updateFull(server, answer, details)\\n updateTelemetry(details, triesUsed, server)\\n return { success: true, data: answer }\\n }\\n const loseLabyrinth = async () => {\\n clearLabWorkerPosition(server, workerId)\\n await stopAllLabWorkers()\\n releaseLease()\\n }\\n function getLabRootRoom(server) {\\n if (!labState || labState.serverName !== server) return null\\n if (typeof labState.rootKey !== \\\"string\\\" || !labState.rootKey) return null\\n return labState.rooms?.[labState.rootKey] ?? null\\n }\\n const rootRoom = getLabRootRoom(server)\\n if (!rootRoom?.jsonLog) {\\n ns.clearPort(ns.pid)\\n labWorker = await launchLabWorker()\\n if (labWorker === 0) return failLab(\\\"launch-worker-bootstrap\\\")\\n syncLabExit()\\n const bootstrapResult = await bootstrapLabyrinth()\\n if (bootstrapResult?.success !== true) return failLab(\\\"bootstrap\\\")\\n if (bootstrapResult?.data) return bootstrapResult\\n }\\n ensureLabLayout(server, details, chaReq)\\n syncLabExit()\\n\\n // Once bootstrap has pinned this process's room, every later position\\n // update must come from movement. Do not re-labreport to recover a\\n // lost worker position; stop this worker instead.\\n if (!labWorker) {\\n ns.clearPort(ns.pid)\\n labWorker = await launchLabWorker()\\n if (labWorker === 0) return failLab(\\\"launch-worker-init\\\")\\n }\\n if (!getLabWorkerPosition(server, workerId)) {\\n await stopLabWorker()\\n return failLab(\\\"init-missing-position\\\")\\n }\\n\\n while (labComplete === false) {\\n const workerPosition = getLabWorkerPosition(server, workerId)\\n if (!workerPosition) return failLab(\\\"missing-position\\\")\\n const [startX, startY] = workerPosition\\n if (!claim) {\\n updateTrackedLease(null)\\n // Standard picker chain. When all of those return null (typical\\n // for secondary workers entering a maze where the primary already\\n // claimed everything, or for a worker whose only candidates trip\\n // the heuristic filters), fall through to the routing-tree\\n // \\\"nearest goalforward\\\" claimer that ignores those heuristics and\\n // simply picks the closest reachable frontier. This is what\\n // keeps the worker from doing nothing on entry.\\n claim = pickLabClaimAt(startX, startY)\\n updateTrackedLease(claim)\\n } else {\\n updateTrackedLease(claim)\\n }\\n\\n if (!claim) {\\n // Picker found no candidate this iteration. pickGreedyStep\\n // should only return null when this worker has no useful work.\\n // Clear skipped claims once, then stop this worker instead of\\n // spinning an awaited idle loop while other workers continue.\\n if (skippedClaimKeys.size > 0 && noClaimPasses === 0) {\\n skippedClaimKeys.clear()\\n noClaimPasses++\\n continue\\n }\\n await stopLabWorker()\\n return failLab(\\\"no-claim\\\")\\n }\\n noClaimPasses = 0\\n\\n let roomReport = getLabRoomReport(server, claim.x, claim.y) || false\\n const currentPosition = getLabWorkerPosition(server, workerId)\\n if (!currentPosition) return failLab(\\\"missing-current-position\\\")\\n const [currentX, currentY] = currentPosition\\n const claimRoom = getLabRoom(server, claim.x, claim.y)\\n if (claimRoom?.claimedBy && claimRoom.claimedBy !== workerId) {\\n releaseLease()\\n claim = null\\n continue\\n }\\n // NOTE: in darknetBasic the greedy picker intentionally returns\\n // already-explored targets for backsteps and explored goalward /\\n // forward priorities. The legacy \\\"reject explored claim\\\" guard\\n // here would release the claim and loop synchronously on the same\\n // pick, hanging the renderer. Trust the picker — if it returned an\\n // explored target, walking there is the desired behaviour.\\n if (currentX !== claim.x || currentY !== claim.y) {\\n const moved = await walkLabToTarget(ns, server, details, workerId, labWorker, claim, { maxSteps: labWalkStepChunk, reason: claim.gateway ? \\\"gateway-claim\\\" : \\\"claim\\\" })\\n tries += moved.stepsTaken ?? 0\\n if (moved.finished) {\\n const completedState = getCompletedLabStateRef(inProgress.get(server) ?? getLabCompleteState())\\n if (completedState?.layout && Number.isInteger(moved.exitX) && Number.isInteger(moved.exitY)) {\\n completedState.layout.finishX = moved.exitX\\n completedState.layout.finishY = moved.exitY\\n }\\n if (completedState && Number.isInteger(moved.exitX) && Number.isInteger(moved.exitY)) completedState.finishKey = getLabKey(moved.exitX, moved.exitY)\\n await finalizeLabCompletion(moved.authResults.data, completedState, tries)\\n return moved.authResults\\n }\\n if (moved.workerExited) {\\n releaseLease()\\n clearLabWorkerPosition(server, workerId)\\n resetLabWorkerRef()\\n return failLab(\\\"claim-worker-exited\\\")\\n }\\n if (moved.lostServer) {\\n releaseLease()\\n await stopLabWorker()\\n return failLab(\\\"claim-lost-server\\\")\\n }\\n if (moved.quadrantCrossed) {\\n // Crossed into a more-goalward quadrant mid-walk. Drop the\\n // existing claim so the picker chain re-runs from the new\\n // in-quadrant position; this gives claimImmediateGoalwardCrossing\\n // and claimAdjacentLabRoom first crack at any local goalward\\n // frontier before the routed picker reaches for distant work.\\n releaseLease()\\n claim = null\\n continue\\n }\\n if (moved.stepLimit && (moved.stepsTaken ?? 0) > 0) {\\n skippedClaimKeys.clear()\\n continue\\n }\\n if (moved.arrived !== true) {\\n if ((moved.noRoute || moved.blocked || (moved.stepsTaken ?? 0) === 0) && claim) {\\n markSkippedClaim(claim)\\n }\\n releaseLease()\\n claim = null\\n continue\\n }\\n if (moved.report) roomReport = moved.report\\n }\\n if (!roomReport) {\\n releaseLease()\\n continue\\n }\\n // walkLabToTarget already called updateLabWorkerPosition and (for\\n // newly-discovered rooms) recordLabRoom on its final step. The\\n // legacy duplicate calls below ran no-op guard paths every claim\\n // arrival; eliminating them removes one redundant pair of\\n // inProgress.set + state-version bumps per step.\\n const arrivalRoom = inProgress.get(server)?.rooms?.[claim.key]\\n const roomX = arrivalRoom?.x ?? claim.x\\n const roomY = arrivalRoom?.y ?? claim.y\\n skippedClaimKeys.clear()\\n releaseTrackedLease()\\n claim = pickLabClaimAt(roomX, roomY)\\n updateTrackedLease(claim)\\n }\\n await loseLabyrinth()\\n return failLab(\\\"lab-complete-loop-ended\\\")\\n }\\n case \\\"\\\": {\\n return { success: false }\\n }\\n default:\\n ns.tprintRaw(\\\"WARNING: Unknown modelID for \\\" + server + \\\": \\\" + details.modelId + \\\" Details: \\\" + JSON.stringify(details))\\n return { success: false }\\n\\n }\\n}\\nfunction failureReport(ns, server, details) {\\n ns.tprintf(\\\"ERROR: Failure Report for %s vs %s %s Length: %s Type: %s\\\", ns.self().server, server, details.modelId, details.passwordLength, details.passwordFormat)\\n inProgress.delete(server)\\n}\\n/** @param {NS} ns */\\nasync function validateProgress(ns, server) {\\n if (inProgress.has(server) && !validate(ns, server, inProgress.get(server).details)) inProgress.delete(server)\\n}\\n/** @param {NS} ns */\\nfunction authDetailsMatch(details, currentDetails) {\\n return !((details.modelId !== \\\"(The Labyrinth)\\\" && details.data !== currentDetails.data)\\n || details.modelId !== currentDetails.modelId\\n || details.passwordFormat !== currentDetails.passwordFormat\\n || details.passwordHint !== currentDetails.passwordHint\\n || details.passwordLength !== currentDetails.passwordLength)\\n}\\n/** @param {NS} ns */\\nfunction validate(ns, server, details) {\\n return authDetailsMatch(details, ns.dnet.getServerAuthDetails(server))\\n}\\n/** @param {NS} ns */\\nfunction serverCheck(ns, server, details, result) {\\n // Sync — ns.dnet.getServerAuthDetails is a synchronous game query. Was\\n // declared async historically; the now-removed `await` on every\\n // walkLabToTarget step paid a microtask hop for nothing. Per-step\\n // microtask cost is small individually but stacks up across thousands\\n // of moves, and matters more when the labWorker round-trip itself is\\n // the only other yield point.\\n if (!result) return false\\n const details2 = ns.dnet.getServerAuthDetails(server)\\n if (connectFailures.includes(result.message) || !authDetailsMatch(details, details2)) return false\\n return Boolean(details2.isConnectedToCurrentServer)\\n}\\n/** @param {NS} ns */\\nasync function bleedCheck(ns, server, details, bleed) {\\n if (!bleed || !bleed?.logs) return false\\n const details2 = ns.dnet.getServerAuthDetails(server)\\n if (connectFailures.includes(bleed.message) || !authDetailsMatch(details, details2)) return false\\n return Boolean(details2.isConnectedToCurrentServer)\\n}\\nasync function threadedMemoryRealloc(ns, server, password) {\\n const result = await proxyAuth(ns, \\\"split\\\", server, password, \\\"dnet.memoryReallocation\\\", server)\\n return result.success\\n}\\n//Write a heartbleed proxy file and add a function for it\\nasync function bleedGrab(ns, server, logs = 999, maxThreads = true, additionalMsec = 0) {\\n const results = await proxyHeartbleed(ns, server, logs, maxThreads, additionalMsec)\\n return results\\n}\\n/** @param {NS} ns */\\nfunction updateFull(server, password, details) {\\n complete.set(server.toString(), { pw: password.toString(), details: details })\\n}\\n/** @param {NS} ns */\\nfunction updateWorkingOn(server, details, action) {\\n if (details.modelId === \\\"(The Labyrinth)\\\") return\\n if (action === \\\"remove\\\")\\n workingOn.delete(server)\\n else if (action === \\\"set\\\")\\n workingOn.set(server, true)\\n}\\n/** @param {NS} ns */\\nfunction updateTelemetry(details, tries, server) {\\n if (tries === 0) return\\n let key\\n if (details.modelId === \\\"(The Labyrinth)\\\") key = details.modelId + server\\n else key = details.modelId + details.passwordFormat + String(details.passwordLength)\\n if (!telemetry[key]) telemetry[key] = []\\n telemetry[key].push(tries)\\n}\\n/** @param {NS} ns */\\nasync function goToWork(ns, server, answer, tries, details, useMaxThreads = true) {\\n const results = await proxyLocal(ns, useMaxThreads, \\\"dnet.authenticate\\\", server, answer)\\n if (results.success) {\\n ns.dnet.connectToSession(server, answer)\\n if (details.modelId !== \\\"(The Labyrinth)\\\") {\\n inProgress.delete(server)\\n }\\n else {\\n const completedState = getCompletedLabStateRef(inProgress.get(server))\\n setCompletedLabState(answer, completedState, server)\\n inProgress.delete(server)\\n }\\n updateFull(server, answer, details)\\n updateTelemetry(details, tries, server)\\n }\\n return results\\n}\\n\\nasync function readQueuedPort(ns, port) {\\n let result = ns.readPort(port)\\n if (result !== \\\"NULL PORT DATA\\\") return result\\n await ns.nextPortWrite(port)\\n return ns.readPort(port)\\n}\\n\\nfunction romanToDecimal(details) {\\n if (details === \\\"nulla\\\") return 0\\n const values = {\\n I: 1,\\n V: 5,\\n X: 10,\\n L: 50,\\n C: 100,\\n D: 500,\\n M: 1000\\n }\\n let total = 0;\\n const romanNums = details.split(\\\"\\\")\\n for (let i = 0; i < romanNums.length; i++) {\\n const current = values[romanNums[i]]\\n const next = values[romanNums[i + 1]]\\n if (next && current < next) {\\n total -= current\\n } else {\\n total += current\\n }\\n }\\n return total\\n}\\n//Handles fractions... Damn you\\nfunction convertToBase10(value) {//numberStr, base) {\\n function charToValue(char) {\\n if (char >= '0' && char <= '9') return char.charCodeAt(0) - 48\\n if (char >= 'A' && char <= 'Z') return char.charCodeAt(0) - 55\\n if (char >= 'a' && char <= 'z') return char.charCodeAt(0) - 87\\n throw new Error(`Invalid digit: ${char}`)\\n }\\n const numberStr = value[0]\\n const base = value[1]\\n const [intPart, fracPart = \\\"\\\"] = numberStr.split('.')\\n let result = 0\\n // Integer part\\n for (let i = 0; i < intPart.length; i++) {\\n const digit = charToValue(intPart[i])\\n result += digit * Math.pow(base, intPart.length - i - 1)\\n }\\n // Fractional part\\n for (let i = 0; i < fracPart.length; i++) {\\n const digit = charToValue(fracPart[i])\\n result += digit * Math.pow(base, -(i + 1))\\n }\\n return result\\n}\\nfunction isNumeric(value) {\\n if (value === true || value === false) return false\\n if (typeof value === \\\"number\\\") return true\\n if (typeof value !== \\\"string\\\") return false\\n const testing = value.split(\\\"\\\")\\n for (const test of testing)\\n if (test >= '0' && test <= \\\"9\\\") continue\\n else return false\\n return true\\n}\\nfunction isAlphabetic(value) {\\n for (const test of value.split(\\\"\\\"))\\n if (!lettersLCase.concat(lettersUCase).includes(test.toString())) return false\\n return true\\n}\\nfunction isAlphanumeric(value) {\\n let numeric = false\\n let alphabetic = false\\n for (const test of value.split(\\\"\\\")) {\\n if (test >= '0' && test <= \\\"9\\\") numeric = true\\n else if (lettersLCase.concat(lettersUCase).includes(test.toString())) alphabetic = true\\n }\\n return numeric && alphabetic\\n}\\nfunction factorial(n) {\\n let result = 1n\\n for (let i = 2n; i <= n; i++) {\\n result *= i\\n }\\n return result\\n}\\nfunction permutationCount(arr) {\\n const counts = new Map()\\n for (const v of arr) {\\n counts.set(v, (counts.get(v) || 0) + 1)\\n }\\n let numerator = factorial(BigInt(arr.length))\\n let denominator = 1n\\n for (const count of counts.values()) {\\n denominator *= factorial(BigInt(count))\\n }\\n return numerator / denominator\\n}\\nfunction getWorker() {\\n const blob = new Blob([workerCode], { type: \\\"application/javascript\\\" })\\n const worker = new Worker(URL.createObjectURL(blob))\\n return worker\\n}\\n\\nconst workerCode = `\\n// Does this candidate satisfy all constraints?\\nfunction candidateSatisfiesAll(x, constraints) {\\n for (const { k, r } of constraints) {\\n const m = k % 32;\\n if (m === 0) continue;\\n if ((x % k) % m !== r) return false;\\n }\\n return true;\\n}\\n\\n// Extended GCD for modular inverse with a save return of null on 0\\nfunction modInverse(a, m) {\\n a = ((a % m) + m) % m;\\n if (m === 0) return null;\\n\\n let m0 = m;\\n let x0 = 0, x1 = 1;\\n\\n while (a > 1) {\\n if (m === 0) return null;\\n\\n const q = Math.floor(a / m);\\n [a, m] = [m, a % m];\\n [x0, x1] = [x1 - q * x0, x0];\\n }\\n\\n if (x1 < 0) x1 += m0;\\n return x1;\\n}\\n\\n\\n// Combine two modular constraints using CRT\\nfunction combineModConstraints(a1, m1, a2, m2) {\\n // Enforce integer invariants early\\n if (\\n !Number.isInteger(a1) ||\\n !Number.isInteger(m1) ||\\n !Number.isInteger(a2) ||\\n !Number.isInteger(m2)) { return null; }\\n\\n const d = gcd(m1, m2);\\n if ((a2 - a1) % d !== 0) return null;\\n const m1d = m1 / d;\\n const m2d = m2 / d;\\n const inv = modInverse(m1d, m2d);\\n if (inv === null) return null;\\n const t = ((a2 - a1) / d) % m2d;\\n let x = a1 + m1 * ((t * inv) % m2d);\\n const mod = m1 * m2d;\\n\\n // Normalize\\n x = ((x % mod) + mod) % mod;\\n\\n // Final safety gate\\n if (!Number.isInteger(x) || !Number.isInteger(mod)) return null;\\n\\n return { x, mod };\\n}\\n\\n\\n// Greatest common divisor\\nfunction gcd(a, b) {\\n a = Math.abs(a);\\n b = Math.abs(b);\\n while (b !== 0) {\\n const t = b;\\n b = a % b;\\n a = t;\\n }\\n return a;\\n}\\n\\n//Entry point\\nfunction getNextCandidate(data) {\\n let [candidate, tripleConstraints, tries, MIN, MAX, tried] = data;\\n const testGroup = [31, 29, 28, 27, 25, 23, 19, 17, 13, 11];\\n \\n // Phase 0 - baseline tests, adaptive to length. Will go 1 over max as it tends to save 1 try\\n let testedValue = 1;\\n for (const p of testGroup) {\\n testedValue *= p;\\n if (!tried.has(p)) return p;\\n if (testedValue > MAX) break;\\n }\\n\\n // Phase 2: CRT\\n const crtConstraints = tripleConstraints\\n .map(({ k, r }) => ({ a: r, m: k % 32 }))\\n .filter(c => c.m !== 0);\\n\\n if (crtConstraints.length > 0) {\\n let crt = { x: crtConstraints[0].a, mod: crtConstraints[0].m };\\n let valid = true;\\n\\n for (let i = 1; i < crtConstraints.length; i++) {\\n const res = combineModConstraints(\\n crt.x,\\n crt.mod,\\n crtConstraints[i].a,\\n crtConstraints[i].m\\n );\\n\\n if (res === null) {\\n valid = false;\\n break;\\n }\\n\\n crt = res;\\n }\\n\\n if (valid) {\\n let x = crt.x;\\n const mod = crt.mod;\\n\\n if (x < MIN) x += Math.ceil((MIN - x) / mod) * mod;\\n\\n while (x <= MAX) {\\n if (!tried.has(x) && candidateSatisfiesAll(x, tripleConstraints)) {\\n return x;\\n }\\n x += mod;\\n }\\n }\\n }\\n \\n // Phase 3 - brute force with what we have\\n let next = candidate + 1;\\n let issue = false\\n while (!candidateSatisfiesAll(next, tripleConstraints) || tried.has(next)) {\\n next++;\\n if (next > MAX) {\\n if (issue) throw new Error(\\\"No possible code found for BigMod\\\");\\n next = MIN;\\n issue = true;\\n }\\n }\\n return next;\\n}\\nfunction getNextCode([tested, testFeedback, lastGuessRaw, pool, cursorRaw, timeBudgetMs]) {\\n const length = lastGuessRaw.length;\\n const candidate = new Array(length);\\n const deadline = Date.now() + Math.max(50, Number(timeBudgetMs) || 1000);\\n const TIMEOUT = { timeout: true };\\n let checked = 0;\\n let sawTestedCandidate = false;\\n let lastChecked = [];\\n\\n function isValidCursor(cursor) {\\n if (!Array.isArray(cursor) || cursor.length !== length) return false;\\n for (const value of cursor) {\\n if (!Number.isInteger(value) || value < 0 || value >= pool.length) return false;\\n }\\n return true;\\n }\\n\\n const cursor = isValidCursor(cursorRaw)\\n ? cursorRaw.slice()\\n : isValidCursor(lastGuessRaw)\\n ? lastGuessRaw.slice()\\n : null;\\n if (cursor) lastChecked = cursor.slice();\\n\\n function updatePrunedCursor(pos) {\\n const pruned = candidate.slice(0, pos);\\n while (pruned.length < length) pruned.push(pool.length - 1);\\n lastChecked = pruned;\\n }\\n\\n function dfs(pos, cursorRelation) {\\n if (Date.now() > deadline) return TIMEOUT;\\n if (pos === length) {\\n if (cursor && cursorRelation !== 1) return null;\\n checked++;\\n const key = candidate.join(\\\",\\\");\\n if (!tested.has(key) && isPossible(candidate, testFeedback)) {\\n lastChecked = candidate.slice();\\n return candidate.slice();\\n }\\n if (tested.has(key)) sawTestedCandidate = true;\\n lastChecked = candidate.slice();\\n return null;\\n }\\n\\n for (let d = 0; d < pool.length; d++) {\\n let nextCursorRelation = cursorRelation;\\n if (cursor && cursorRelation === 0) {\\n if (d < cursor[pos]) continue;\\n if (d > cursor[pos]) nextCursorRelation = 1;\\n }\\n candidate[pos] = d;\\n\\n if (!prefixPossible(candidate, pos + 1, testFeedback)) {\\n updatePrunedCursor(pos + 1);\\n continue;\\n }\\n\\n const result = dfs(pos + 1, nextCursorRelation);\\n if (result === TIMEOUT || result) return result;\\n }\\n return null;\\n }\\n\\n const result = dfs(0, cursor ? 0 : 1);\\n if (result === TIMEOUT) {\\n return { guess: null, cursor: lastChecked.slice(), checked, exhausted: false, sawTestedCandidate };\\n }\\n if (!result) {\\n return { guess: null, cursor: lastChecked.slice(), checked, exhausted: true, sawTestedCandidate };\\n }\\n return { guess: result, cursor: result.slice(), checked, exhausted: false, sawTestedCandidate };\\n}\\n\\nfunction prefixPossible(candidate, len, testFeedback) {\\n for (const { guess, feedback } of testFeedback) {\\n const targetBlk = Number(feedback.blk);\\n\\n let blk = 0;\\n for (let i = 0; i < len; i++) {\\n if (candidate[i] === guess[i]) {\\n blk++;\\n if (blk > targetBlk) return false;\\n }\\n }\\n\\n const remaining = guess.length - len;\\n if (blk + remaining < targetBlk) return false;\\n }\\n return true;\\n}\\n\\n\\nfunction scoreFast(guessRaw, codeRaw, expected) {\\n let blk = 0, wht = 0;\\n const guessCount = new Map();\\n const codeCount = new Map();\\n\\n for (let i = 0; i < guessRaw.length; i++) {\\n if (guessRaw[i] === codeRaw[i]) {\\n blk++;\\n if (blk > expected.blk) return null;\\n } else {\\n guessCount.set(guessRaw[i], (guessCount.get(guessRaw[i]) || 0) + 1);\\n codeCount.set(codeRaw[i], (codeCount.get(codeRaw[i]) || 0) + 1);\\n }\\n }\\n\\n for (const [k, v] of guessCount) {\\n if (codeCount.has(k)) {\\n wht += Math.min(v, codeCount.get(k));\\n if (blk + wht > expected.blk + expected.wht) return null;\\n }\\n }\\n\\n return { blk, wht };\\n}\\nfunction* digitArraysFrom(start, pool) {\\n const arr = start.slice();\\n if (!increment(arr, pool)) return;\\n\\n while (true) {\\n yield arr.slice();\\n if (!increment(arr, pool)) return;\\n }\\n}\\n\\nfunction increment(arr, pool) {\\n const base = pool.length;\\n let i = arr.length - 1;\\n\\n while (i >= 0) {\\n if (arr[i] < base - 1) {\\n arr[i]++;\\n return true;\\n }\\n arr[i] = 0;\\n i--;\\n }\\n return false;\\n}\\nfunction isPossible(testRaw, testFeedback) {\\n for (const { guess, feedback } of testFeedback) {\\n const expected = {\\n blk: Number(feedback.blk),\\n wht: Number(feedback.wht)\\n };\\n\\n const s = scoreFast(guess, testRaw, expected);\\n\\n if (s === null) return false;\\n\\n // Final exact check (scoreFast may early-exit before full count)\\n if (s.blk !== expected.blk || s.wht !== expected.wht) {\\n return false;\\n }\\n }\\n return true;\\n}\\n\\nfunction getNextUniquePermutation([array, guessed, restraints]) {\\n let bestResult = [];\\n let lowestScore = Infinity;\\n let found = false;\\n const nums = [...array].sort(); // sort to group duplicates\\n const used = Array(nums.length).fill(false);\\n\\n function squaredDistance(a, b) {\\n let sum = 0;\\n for (let i = 0; i < a.length; i++) {\\n const d = a[i] - b[i];\\n sum += d * d;\\n }\\n return sum;\\n }\\n function rmsError(candidate, tests) {\\n let error = 0;\\n for (const { guess, rms } of tests) {\\n const g = guess.split(\\\"\\\").map(Number);\\n const sse = squaredDistance(candidate, g);\\n const expected = rms * rms * candidate.length;\\n error += Math.abs(sse - expected);\\n }\\n return error\\n }\\n\\n function backtrack(current) {\\n if (current.length === nums.length) {\\n if (guessed.has(current.join(\\\",\\\"))) return;\\n if (restraints.length === 0) {\\n bestResult = current.slice();\\n found = true;\\n return;\\n }\\n else {\\n const testScore = rmsError(current, restraints);\\n if (testScore < lowestScore) {\\n //We need to save memory. No slicing here.\\n for (let i = 0; i < current.length; i++)\\n bestResult[i] = current[i];\\n lowestScore = testScore;\\n return;\\n }\\n }\\n }\\n for (let i = 0; i < nums.length; i++) {\\n // Skip already-used elements\\n if (used[i]) continue;\\n // Skip duplicates:\\n // only allow the first unused instance\\n if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) continue;\\n used[i] = true;\\n current.push(nums[i]);\\n backtrack(current);\\n if (restraints.length === 0 && found) break\\n current.pop();\\n used[i] = false;\\n };\\n };\\n backtrack([]);\\n return bestResult;\\n}\\n// ==============================\\n// PIX BLACK-ONLY MULTISET SOLVER\\n// ==============================\\nfunction pixGetNextCode([tested, testFeedback, lastGuessRaw, pool, cursorRaw, timeBudgetMs]) {\\n const sortedPool = pool.slice().sort((a, b) => a - b);\\n const length = sortedPool.length;\\n const candidate = new Array(length);\\n const deadline = Date.now() + Math.max(50, Number(timeBudgetMs) || 1000);\\n const TIMEOUT = { timeout: true };\\n\\n // Build multiset\\n const values = [];\\n const counts = [];\\n for (const v of sortedPool) {\\n const i = values.indexOf(v);\\n if (i === -1) {\\n values.push(v);\\n counts.push(1);\\n } else {\\n counts[i]++;\\n }\\n }\\n\\n let checked = 0;\\n let sawTestedCandidate = false;\\n let lastChecked = [];\\n\\n function hasSameMultiset(candidateRaw) {\\n if (!Array.isArray(candidateRaw) || candidateRaw.length !== length) return false;\\n const remaining = new Map();\\n for (const v of sortedPool) remaining.set(v, (remaining.get(v) || 0) + 1);\\n for (const v of candidateRaw) {\\n const count = remaining.get(v) || 0;\\n if (count <= 0) return false;\\n remaining.set(v, count - 1);\\n }\\n for (const count of remaining.values()) if (count !== 0) return false;\\n return true;\\n }\\n\\n const cursor = hasSameMultiset(cursorRaw)\\n ? cursorRaw.slice()\\n : hasSameMultiset(lastGuessRaw)\\n ? lastGuessRaw.slice()\\n : null;\\n if (cursor) lastChecked = cursor.slice();\\n const valueIndexByKey = new Map();\\n for (let i = 0; i < values.length; i++) valueIndexByKey.set(values[i], i);\\n const openCountsScratch = new Array(values.length).fill(0);\\n const feedbackConstraints = testFeedback.map(({ guess, feedback }) => ({\\n guess,\\n required: Number(feedback.blk)\\n }));\\n\\n function maxRemainingExactMatches(guess, pos) {\\n openCountsScratch.fill(0);\\n for (let i = pos; i < length; i++) {\\n const valueIndex = valueIndexByKey.get(guess[i]);\\n if (valueIndex !== undefined) openCountsScratch[valueIndex]++;\\n }\\n let max = 0;\\n for (let i = 0; i < values.length; i++) {\\n max += Math.min(counts[i], openCountsScratch[i]);\\n }\\n return max;\\n }\\n\\n function updatePrunedCursor(pos) {\\n const pruned = candidate.slice(0, pos);\\n for (let i = values.length - 1; i >= 0; i--) {\\n for (let count = 0; count < counts[i]; count++) pruned.push(values[i]);\\n }\\n lastChecked = pruned;\\n }\\n\\n function candidateMatchesFeedback(testRaw) {\\n for (const { guess, required } of feedbackConstraints) {\\n let blk = 0;\\n for (let i = 0; i < length; i++) {\\n if (testRaw[i] === guess[i]) blk++;\\n }\\n if (blk !== required) return false;\\n }\\n return true;\\n }\\n\\n function dfs(pos, cursorRelation) {\\n if (Date.now() > deadline) return TIMEOUT;\\n\\n for (const constraint of feedbackConstraints) {\\n const { guess, required } = constraint;\\n let blk = 0;\\n for (let i = 0; i < pos; i++) {\\n if (candidate[i] === guess[i]) blk++;\\n }\\n\\n // Upper bound: too many matches already\\n if (blk > required) {\\n updatePrunedCursor(pos);\\n return null;\\n }\\n\\n // Lower bound: cannot possibly reach required matches\\n if (blk + maxRemainingExactMatches(guess, pos) < required) {\\n updatePrunedCursor(pos);\\n return null;\\n }\\n }\\n\\n if (pos === length) {\\n if (cursor && cursorRelation !== 1) return null;\\n checked++;\\n lastChecked = candidate.slice();\\n const key = candidate.join(\\\",\\\");\\n\\n if (!candidateMatchesFeedback(candidate)) return null;\\n if (tested.has(key)) {\\n sawTestedCandidate = true;\\n return null;\\n }\\n return candidate.slice();\\n }\\n\\n for (let i = 0; i < values.length; i++) {\\n if (counts[i] === 0) continue;\\n const value = values[i];\\n let nextCursorRelation = cursorRelation;\\n if (cursor && cursorRelation === 0) {\\n if (value < cursor[pos]) continue;\\n if (value > cursor[pos]) nextCursorRelation = 1;\\n }\\n candidate[pos] = value;\\n counts[i]--;\\n const result = dfs(pos + 1, nextCursorRelation);\\n if (result === TIMEOUT || result) {\\n counts[i]++;\\n return result;\\n }\\n updatePrunedCursor(pos + 1);\\n counts[i]++;\\n }\\n return null;\\n }\\n\\n function validateFeedbackAgainstPool(pool, testFeedback) {\\n const poolCounts = {};\\n for (const v of pool) {\\n poolCounts[v] = (poolCounts[v] || 0) + 1;\\n }\\n for (const { guess } of testFeedback) {\\n const guessCounts = {};\\n for (const v of guess) {\\n guessCounts[v] = (guessCounts[v] || 0) + 1;\\n }\\n for (const k in guessCounts) {\\n if (!poolCounts[k] || guessCounts[k] > poolCounts[k]) {\\n throw new Error(\\n \\\"Feedback guess contains symbols not compatible with pool\\\"\\n );\\n }\\n }\\n }\\n }\\n validateFeedbackAgainstPool(sortedPool, testFeedback);\\n const result = dfs(0, cursor ? 0 : 1);\\n if (result === TIMEOUT) {\\n return { guess: null, cursor: lastChecked.slice(), checked, exhausted: false, sawTestedCandidate };\\n }\\n if (!result) {\\n return { guess: null, cursor: lastChecked.slice(), checked, exhausted: true, sawTestedCandidate };\\n }\\n return { guess: result, cursor: result.slice(), checked, exhausted: false, sawTestedCandidate };\\n}\\nonmessage = (event) => {\\n try {\\n postMessage([eval(event.data[0])(event.data[1])]);\\n } catch (e) {\\n postMessage(null); // always return something\\n }\\n};\\n`;\\n//Ram dodged functions below and their file writes\\nasync function proxyHome(ns, func, ...argmnts) { return await runIt(ns, \\\"SphyxOS/extras/nsProxy.js\\\", [func, ...argmnts], ns.getFunctionRamCost(func) + 1.6, 1, true) }\\nasync function proxyLocal(ns, useMaxThreads, func, ...argmnts) { return await runIt(ns, \\\"SphyxOS/extras/nsProxy.js\\\", [func, ...argmnts], ns.getFunctionRamCost(func) + 1.6, useMaxThreads) }\\nasync function proxyAuth(ns, useMaxThreads, server, password, func, ...argmnts) { return await runIt(ns, \\\"SphyxOS/extras/nsProxyAuth.js\\\", [server, password, func, ...argmnts], ns.getFunctionRamCost(func) + 1.6 + 0.05, useMaxThreads) }\\nasync function proxyHeartbleed(ns, server, logs, maxThreads, additionalMsec) { return await runIt(ns, \\\"SphyxOS/darknet/heartbleed.js\\\", [\\\"dnet.heartbleed\\\", server, logs, additionalMsec], ns.getFunctionRamCost(\\\"dnet.heartbleed\\\") + 1.6, maxThreads) }\\nasync function runCCT(ns, server, ...argmnts) {\\n ns.atExit(() => {\\n workingOnCCT = false\\n })\\n await runIt(ns, cctFile, [server, ...argmnts], 1.3 + 0.2 + 1.6, 1, \\\"home\\\")\\n workingOnCCT = false\\n ns.atExit(() => { })\\n}\\n/** @param {NS} ns */\\nasync function runIt(ns, script, argmts, scriptOverride, useMaxThreads = true, onHome = false) {\\n let threads = isNumeric(useMaxThreads) ? useMaxThreads : onHome ? 1 : Math.floor((await proxyHome(ns, \\\"getServerMaxRam\\\", onHome ? \\\"home\\\" : ns.self().server) - await proxyHome(ns, \\\"getServerUsedRam\\\", onHome ? \\\"home\\\" : ns.self().server)) / scriptOverride)\\n if (useMaxThreads === \\\"split\\\") {\\n let lastPid = 0\\n while (threads--) { //If you do --threads here it will reach 0 to fast.\\n lastPid = ns.exec(script, ns.self().server, { ramOverride: scriptOverride, threads: 1, temporary: true }, ...argmts)\\n if (lastPid === 0) {\\n throw new Error(ns.self().server + \\\" Failed to run \\\" + script)\\n }\\n if (threads > 0) ns.nextPortWrite(lastPid).then(() => ns.clearPort(lastPid))\\n }\\n return await returnPort(ns, lastPid)\\n }\\n const thisPid = ns.exec(script, onHome ? \\\"home\\\" : ns.self().server, { ramOverride: scriptOverride, threads: threads, temporary: true }, ...argmts)\\n if (thisPid === 0) {\\n throw new Error(ns.self().server + \\\" Failed to run \\\" + script)\\n }\\n return await returnPort(ns, thisPid)\\n}\\n/** @param {NS} ns */\\nasync function getMaxAuthThreads(ns, heartBleed = false, server = ns.self().server) {\\n const serverRam = await proxyHome(ns, \\\"getServerMaxRam\\\", server) - await proxyHome(ns, \\\"getServerUsedRam\\\", server)\\n const cost = heartBleed ? ns.getFunctionRamCost(\\\"dnet.heartbleed\\\") + 1.6 : ns.getFunctionRamCost(\\\"dnet.authenticate\\\") + 1.6\\n return Math.floor(serverRam / cost)\\n}\\nasync function returnPort(ns, portPid) {\\n const result = ns.readPort(portPid)\\n if (result !== \\\"NULL PORT DATA\\\") return result\\n await ns.nextPortWrite(portPid)\\n return ns.readPort(portPid)\\n}\\nfunction writeProxyLocal(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxy.js\\\", data, \\\"w\\\")\\n}\\n\\nfunction writeProxyHeartbleed(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n const result = await ns.dnet.heartbleed(ns.args[1], { logsToCapture: ns.args[2], additionalMsec: ns.args[3] })\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}`\\n ns.write(\\\"SphyxOS/darknet/heartbleed.js\\\", data, \\\"w\\\")\\n}\\nfunction writeProxyAuth(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [server, password, func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n ns.dnet.connectToSession(server, password)\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxyAuth.js\\\", data, \\\"w\\\")\\n}\\nconst easyHacks = [\\\"DeskMemo_3.1\\\", \\\"ZeroLogon\\\", \\\"FreshInstall_1.0\\\", \\\"CloudBlare(tm)\\\", \\\"Laika4\\\", \\\"OctantVoxel\\\", \\\"Pr0verFl0\\\", \\\"110100100\\\", \\\"PrimeTime 2\\\", \\\"MathML\\\", \\\"OrdoXenos\\\", \\\"(The Labyrinth)\\\"]\\nconst midHacks = [\\\"OpenWebAccessPoint\\\", \\\"EuroZone Free\\\", \\\"TopPass\\\"]\\nconst hardHacks = [\\\"BellaCuore\\\", \\\"RateMyPix.Auth\\\", \\\"BigMo%od\\\", \\\"Factori-Os\\\", \\\"AccountsManager_4.2\\\", \\\"NIL\\\", \\\"DeepGreen\\\", \\\"PHP 5.4\\\", \\\"2G_cellular\\\", \\\"KingOfTheHill\\\"]\\n\\n\\nconst connectFailures = [\\\"Not Enough Charisma\\\", \\\"Direct Connection Required\\\", \\\"Service Unavailable\\\", \\\"Not Found\\\", \\\"Request Timeout\\\"]\\nconst numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\\nconst lettersLCase = [\\\"a\\\", \\\"b\\\", \\\"c\\\", \\\"d\\\", \\\"e\\\", \\\"f\\\", \\\"g\\\", \\\"h\\\", \\\"i\\\", \\\"j\\\", \\\"k\\\", \\\"l\\\", \\\"m\\\", \\\"n\\\", \\\"o\\\", \\\"p\\\", \\\"q\\\", \\\"r\\\", \\\"s\\\", \\\"t\\\", \\\"u\\\", \\\"v\\\", \\\"w\\\", \\\"x\\\", \\\"y\\\", \\\"z\\\"]\\nconst lettersUCase = [\\\"A\\\", \\\"B\\\", \\\"C\\\", \\\"D\\\", \\\"E\\\", \\\"F\\\", \\\"G\\\", \\\"H\\\", \\\"I\\\", \\\"J\\\", \\\"K\\\", \\\"L\\\", \\\"M\\\", \\\"N\\\", \\\"O\\\", \\\"P\\\", \\\"Q\\\", \\\"R\\\", \\\"S\\\", \\\"T\\\", \\\"U\\\", \\\"V\\\", \\\"W\\\", \\\"X\\\", \\\"Y\\\", \\\"Z\\\"]\\nconst euCountries =\\n [\\\"Austria\\\", \\\"Belgium\\\", \\\"Bulgaria\\\", \\\"Croatia\\\", \\\"Republic of Cyprus\\\", \\\"Czech Republic\\\", \\\"Denmark\\\", \\\"Estonia\\\", \\\"Finland\\\", \\\"France\\\", \\\"Germany\\\", \\\"Greece\\\", \\\"Hungary\\\",\\n \\\"Ireland\\\", \\\"Italy\\\", \\\"Latvia\\\", \\\"Lithuania\\\", \\\"Luxembourg\\\", \\\"Malta\\\", \\\"Netherlands\\\", \\\"Poland\\\", \\\"Portugal\\\", \\\"Romania\\\", \\\"Slovakia\\\", \\\"Slovenia\\\", \\\"Spain\\\", \\\"Sweden\\\"]\\nconst smallPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]\\nconst largePrimes = [\\n 1069, 1409, 1471, 1567, 1597, 1601, 1697, 1747, 1801, 1889, 1979, 1999, 2063, 2207, 2371, 2503, 2539, 2693, 2741,\\n 2753, 2801, 2819, 2837, 2909, 2939, 3169, 3389, 3571, 3761, 3881, 4217, 4289, 4547, 4729, 4789, 4877, 4943, 4951,\\n 4957, 5393, 5417, 5419, 5441, 5519, 5527, 5647, 5779, 5881, 6007, 6089, 6133, 6389, 6451, 6469, 6547, 6661, 6719,\\n 6841, 7103, 7549, 7559, 7573, 7691, 7753, 7867, 8053, 8081, 8221, 8329, 8599, 8677, 8761, 8839, 8963, 9103, 9199,\\n 9343, 9467, 9551, 9601, 9739, 9749, 9859]\\nconst commonPWDict =\\n [\\\"123456\\\", \\\"password\\\", \\\"12345678\\\", \\\"qwerty\\\", \\\"123456789\\\", \\\"12345\\\", \\\"1234\\\", \\\"111111\\\", \\\"1234567\\\", \\\"dragon\\\", \\\"123123\\\", \\\"baseball\\\", \\\"abc123\\\", \\\"football\\\", \\\"monkey\\\", \\\"letmein\\\",\\n \\\"696969\\\", \\\"shadow\\\", \\\"master\\\", \\\"666666\\\", \\\"qwertyuiop\\\", \\\"123321\\\", \\\"mustang\\\", \\\"1234567890\\\", \\\"michael\\\", \\\"654321\\\", \\\"superman\\\", \\\"1qaz2wsx\\\", \\\"7777777\\\", \\\"121212\\\", \\\"0\\\", \\\"qazwsx\\\",\\n \\\"123qwe\\\", \\\"trustno1\\\", \\\"jordan\\\", \\\"jennifer\\\", \\\"zxcvbnm\\\", \\\"asdfgh\\\", \\\"hunter\\\", \\\"buster\\\", \\\"soccer\\\", \\\"harley\\\", \\\"batman\\\", \\\"andrew\\\", \\\"tigger\\\", \\\"sunshine\\\", \\\"iloveyou\\\", \\\"2000\\\",\\n \\\"charlie\\\", \\\"robert\\\", \\\"thomas\\\", \\\"hockey\\\", \\\"ranger\\\", \\\"daniel\\\", \\\"starwars\\\", \\\"112233\\\", \\\"george\\\", \\\"computer\\\", \\\"michelle\\\", \\\"jessica\\\", \\\"pepper\\\", \\\"1111\\\", \\\"zxcvbn\\\", \\\"555555\\\",\\n \\\"11111111\\\", \\\"131313\\\", \\\"freedom\\\", \\\"777777\\\", \\\"pass\\\", \\\"maggie\\\", \\\"159753\\\", \\\"aaaaaa\\\", \\\"ginger\\\", \\\"princess\\\", \\\"joshua\\\", \\\"cheese\\\", \\\"amanda\\\", \\\"summer\\\", \\\"love\\\", \\\"ashley\\\", \\\"6969\\\",\\n \\\"nicole\\\", \\\"chelsea\\\", \\\"biteme\\\", \\\"matthew\\\", \\\"access\\\", \\\"yankees\\\", \\\"987654321\\\", \\\"dallas\\\", \\\"austin\\\", \\\"thunder\\\", \\\"taylor\\\", \\\"matrix\\\"]\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(25) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(25)\\n if (result?.syms) {\\n if (!silent) {\\n if (modeStock === \\\"none\\\" && result.syms.length > 0) ns.tprintf(\\\"DarkNet will now push stocks.\\\")\\n else if (modeStock !== \\\"none\\\" && modeStock.length > 0 && result.syms.length === 0) ns.tprintf(\\\"DarkNet will stop pushing stocks.\\\")\\n }\\n modeStock = result.syms.length === 0 ? \\\"none\\\" : result.syms\\n continue\\n }\\n switch (result) {\\n case \\\"silent\\\":\\n silent = true\\n break;\\n case \\\"phishingOn\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet is now Phishing\\\")\\n modePhishing = true\\n break\\n case \\\"phishingOff\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet has stopped Phishing\\\")\\n modePhishing = false\\n break\\n case \\\"inducingOn\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet is now Inducing Migrations\\\")\\n modeInduce = true\\n break\\n case \\\"inducingOff\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet has stopped Inducing Migrations\\\")\\n modeInduce = false\\n break\\n case \\\"sharingOn\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet is now Sharing RAM\\\")\\n modeShare = true\\n break\\n case \\\"sharingOff\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet has stopped Sharing RAM\\\")\\n modeShare = false\\n break\\n case \\\"showmapOn\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet will now show the Lab map\\\")\\n modeShowMap = true\\n if (labName) startMapDisplay(ns)\\n break\\n case \\\"showmapOff\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet will stop showing the Lab map\\\")\\n modeShowMap = false\\n ns.ui.closeTail()\\n break\\n case \\\"stormOn\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet will now attempt to start a webstorm\\\")\\n modeStorm = true\\n break\\n case \\\"stormOff\\\":\\n if (!silent) ns.tprintf(\\\"DarkNet will no longer attempt to start a webstorm\\\")\\n modeStorm = false\\n break\\n default:\\n ns.tprintf(\\\"Invalid command received in darknet: %s\\\", result)\\n break;\\n }\\n }\\n //Look into mutation observers: https://developer.mozilla.org/en-US/docs/web/api/mutationobserver\\n if (!logOpened && labName && modeShowMap && ns.self().tailProperties === null) {\\n startMapDisplay(ns)\\n }\\n else if (logOpened && labName && modeShowMap && ns.self().tailProperties === null) {\\n modeShowMap = false\\n logOpened = false\\n ns.writePort(1, \\\"darknet map off\\\")\\n }\\n await ns.asleep(200)\\n }\\n}\\n// ----- Configuration --------------------------------------------------------\\nlet labName = false\\nconst labWalkStepChunk = 1\\nconst refreshMs = 200\\nconst cellSize = 15\\nconst cellGap = 2\\nconst labWorkerScriptPath = \\\"SphyxOS/darknet/labHunter.js\\\"\\n\\n// Lab map characters (display + auth-data parsing).\\nconst labMapFill = \\\"█\\\"\\nconst labMapPossibleHall = \\\"·\\\"\\nconst labMapUnknownRoom = labMapPossibleHall\\nconst labMapOpen = \\\" \\\"\\nconst labMapStart = \\\"S\\\"\\nconst labMapFinish = \\\"X\\\"\\nconst labMapWorker = \\\"o\\\"\\nconst labCurrentRoomCommand = \\\"nothing\\\"\\n\\n// Direction table. Movement is on a 2-step grid so walls / hallways live on\\n// the odd offsets between rooms.\\nconst labDirections = {\\n north: { dx: 0, dy: -2, back: \\\"south\\\" },\\n south: { dx: 0, dy: 2, back: \\\"north\\\" },\\n east: { dx: 2, dy: 0, back: \\\"west\\\" },\\n west: { dx: -2, dy: 0, back: \\\"east\\\" }\\n}\\nconst labDirectionEntries = Object.entries(labDirections)\\nconst labDirectionIndex = { north: 0, east: 1, south: 2, west: 3 }\\nconst labPackedCoordOffset = 4096\\nconst labPackedCoordSpan = labPackedCoordOffset * 2\\nconst labEndpointOffsetChoices = 3\\nconst labEndpointOffsetStep = 2\\nconst labEndpointMaxOffset = labEndpointOffsetStep * (labEndpointOffsetChoices - 1)\\nconst labDeadAreaDrainBudget = 32\\n\\n// Maze dimensions keyed by required charisma level (Bitburner labyrinth tiers).\\nconst labDimensionsByCha = {\\n 300: { mazeWidth: 20, mazeHeight: 14, offsetStartAndEnd: false },\\n 600: { mazeWidth: 30, mazeHeight: 20, offsetStartAndEnd: false },\\n 1500: { mazeWidth: 40, mazeHeight: 26, offsetStartAndEnd: false },\\n 2500: { mazeWidth: 60, mazeHeight: 40, offsetStartAndEnd: true },\\n 3000: { mazeWidth: 60, mazeHeight: 40, offsetStartAndEnd: true },\\n 3500: { mazeWidth: 60, mazeHeight: 40, offsetStartAndEnd: true },\\n 4000: { mazeWidth: 60, mazeHeight: 40, offsetStartAndEnd: true }\\n}\\n\\n// ----- Module state ---------------------------------------------------------\\n// labState holds all the per-labyrinth data. Reset by ensureLabState when\\n// the case block is entered with a new server name.\\nlet labState = null\\nlet labComplete = false\\nlet labWorkerVisitStack = new Map() // workerId -> string[]\\nlet labInfluenceContextCache = new WeakMap()\\nlet labQuadrantBoundsCoordCache = new WeakMap()\\nlet labGoalwardDirsCache = new WeakMap()\\nlet labCoordParseCache = new Map()\\n\\n// ----- Coord and key helpers ------------------------------------------------\\nfunction getLabKey(x, y) { return `${x},${y}` }\\nfunction getLabCoordsFromKey(key) {\\n if (typeof key !== \\\"string\\\") return null\\n const cached = labCoordParseCache.get(key)\\n if (cached) return cached\\n const comma = key.indexOf(\\\",\\\")\\n if (comma <= 0 || comma !== key.lastIndexOf(\\\",\\\")) return null\\n const x = Number(key.slice(0, comma))\\n const y = Number(key.slice(comma + 1))\\n if (!Number.isInteger(x) || !Number.isInteger(y)) return null\\n const coords = [x, y]\\n labCoordParseCache.set(key, coords)\\n return coords\\n}\\n\\n\\n// ----- Auth-result parsing — the \\\"new worker\\\" pattern -----------------------\\n// Every move goes through ns.dnet.authenticate(server, dir). The response\\n// includes a message (\\\"You have moved to X, Y.\\\" / \\\"You are still at X, Y.\\\")\\n// and a data string that is the maze ASCII with an \\\"@\\\" marker on the\\n// worker's current cell. We parse coords from the message and the four\\n// exit walls from the cells immediately around \\\"@\\\". No separate\\n// currentRoom command is needed for normal walking.\\nfunction getLabRawCoordsFromAuthResult(result) {\\n const message = typeof result?.message === \\\"string\\\" ? result.message : \\\"\\\"\\n let idx = message.indexOf(\\\"You have moved to\\\")\\n if (idx >= 0) idx += 17\\n else {\\n idx = message.indexOf(\\\"You are still at\\\")\\n if (idx >= 0) idx += 16\\n }\\n if (idx < 0) return null\\n const parseNumber = () => {\\n while (idx < message.length && message.charCodeAt(idx) <= 32) idx++\\n let sign = 1\\n if (message[idx] === \\\"-\\\") { sign = -1; idx++ }\\n let value = 0\\n let sawDigit = false\\n while (idx < message.length) {\\n const code = message.charCodeAt(idx)\\n if (code < 48 || code > 57) break\\n value = value * 10 + code - 48\\n sawDigit = true\\n idx++\\n }\\n return sawDigit ? value * sign : null\\n }\\n const rawX = parseNumber()\\n while (idx < message.length && (message.charCodeAt(idx) <= 32 || message[idx] === \\\",\\\")) idx++\\n const rawY = parseNumber()\\n if (!Number.isInteger(rawX) || !Number.isInteger(rawY)) return null\\n return [rawX, rawY]\\n}\\n// ----- Coord translation ----------------------------------------------------\\n// First worker's first room pins coordOffset; every later report (any\\n// worker) uses the same offset so they all share a single coordinate frame.\\nfunction getLabActualCoords(x, y, report, state = null) {\\n if (Array.isArray(report?.coords) && Number.isInteger(report.coords[0]) && Number.isInteger(report.coords[1])) {\\n const offsetX = Number.isInteger(state?.coordOffsetX) ? state.coordOffsetX : 0\\n const offsetY = Number.isInteger(state?.coordOffsetY) ? state.coordOffsetY : 0\\n return [report.coords[0] + offsetX, report.coords[1] + offsetY]\\n }\\n return [x, y]\\n}\\nfunction sanitizeLabRoomExits(state, x, y, exits) {\\n // Force walls at the layout boundary so the picker can't plan a step\\n // outside the maze rectangle. The finish cell sits ON the boundary and\\n // is the one allowed exception.\\n const cleanExits = { ...exits }\\n if (x === 1) cleanExits.west = false\\n if (y === 1) cleanExits.north = false\\n if (!state?.layout) return cleanExits\\n if (x <= state.layout.minX) cleanExits.west = false\\n if (y <= state.layout.minY) cleanExits.north = false\\n if (Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)) {\\n if (x >= state.layout.maxX && !(state.layout.finishX === x && state.layout.finishY === y)) cleanExits.east = false\\n if (y >= state.layout.maxY && !(state.layout.finishX === x && state.layout.finishY === y)) cleanExits.south = false\\n }\\n return cleanExits\\n}\\nfunction getLabMoveCoords(currentX, currentY, expectedX, expectedY, report, state = null) {\\n const [actualX, actualY] = getLabActualCoords(expectedX, expectedY, report, state)\\n if (actualX === currentX && actualY === currentY) return { status: \\\"blocked\\\", x: currentX, y: currentY }\\n if (actualX === expectedX && actualY === expectedY) return { status: \\\"moved\\\", x: expectedX, y: expectedY }\\n return { status: \\\"mismatch\\\", x: currentX, y: currentY, reportedX: actualX, reportedY: actualY }\\n}\\n\\n// ----- Layout ---------------------------------------------------------------\\nfunction getLabDimensions(chaReq) {\\n if (!Number.isFinite(chaReq)) return null\\n const tiers = Object.keys(labDimensionsByCha).map(Number).sort((a, b) => a - b)\\n let chosen = null\\n for (const tier of tiers) if (chaReq <= tier) { chosen = tier; break }\\n if (chosen === null) chosen = tiers[tiers.length - 1]\\n return labDimensionsByCha[chosen]\\n}\\nfunction getEstimatedLabLayout(chaReq) {\\n const dim = getLabDimensions(chaReq)\\n if (!dim) return null\\n const width = dim.mazeWidth + 1\\n const height = dim.mazeHeight + 1\\n const maxX = width - 2\\n const maxY = height - 2\\n return {\\n startX: 1, startY: 1,\\n minX: 1, minY: 1,\\n maxX, maxY,\\n finishX: null, finishY: null,\\n goalX: maxX, goalY: maxY,\\n offsetStartAndEnd: dim.offsetStartAndEnd === true\\n }\\n}\\nfunction getLabDisplayLayoutKey(layout) {\\n if (!layout) return \\\"\\\"\\n return [layout.minX, layout.minY, layout.maxX, layout.maxY, layout.goalX, layout.goalY, layout.offsetStartAndEnd === true ? 1 : 0].join(\\\":\\\")\\n}\\n\\n// ----- Influence context + goalward direction logic -------------------------\\n// Drives \\\"which direction(s) are goalward from (x, y)?\\\". Before a\\n// quadrant boundary is crossed, movement that keeps the worker attached\\n// to that target wall is goalward. After crossing, that old boundary is\\n// no longer goalward; the next target is the exit quadrant/subquadrant.\\n// Cached per-(state, signature, x, y).\\nfunction getLabQuadrantSide(value, midpoint) { return value >= midpoint ? 1 : -1 }\\nfunction getLabQuadrantKeyFromSides(sideX, sideY) { return `${sideX},${sideY}` }\\nfunction getLabInfluenceContext(state) {\\n const layout = state?.layout\\n if (!layout || ![layout.minX, layout.minY, layout.maxX, layout.maxY].every(Number.isFinite)) return null\\n const layoutKey = getLabDisplayLayoutKey(layout)\\n const cached = labInfluenceContextCache.get(state)\\n if (cached?.layoutKey === layoutKey) return cached.context\\n const midX = (layout.minX + layout.maxX) / 2\\n const midY = (layout.minY + layout.maxY) / 2\\n const startX = Number.isFinite(layout.startX) ? layout.startX : layout.minX\\n const startY = Number.isFinite(layout.startY) ? layout.startY : layout.minY\\n const goalX = Number.isFinite(layout.goalX) ? layout.goalX : layout.maxX\\n const goalY = Number.isFinite(layout.goalY) ? layout.goalY : layout.maxY\\n const startSideX = getLabQuadrantSide(startX, midX)\\n const startSideY = getLabQuadrantSide(startY, midY)\\n const goalSideX = getLabQuadrantSide(goalX, midX)\\n const goalSideY = getLabQuadrantSide(goalY, midY)\\n const exitTargetX = goalSideX === 1 ? layout.maxX : layout.minX\\n const exitTargetY = goalSideY === 1 ? layout.maxY : layout.minY\\n const context = {\\n state, layout, midX, midY, startX, startY, goalX, goalY,\\n startSideX, startSideY, goalSideX, goalSideY, exitTargetX, exitTargetY,\\n signature: `${layoutKey}:${startSideX}:${startSideY}:${goalSideX}:${goalSideY}:${goalX}:${goalY}`\\n }\\n labInfluenceContextCache.set(state, { layoutKey, context })\\n return context\\n}\\nfunction getLabInfluenceSignature(context) {\\n return typeof context?.signature === \\\"string\\\" ? context.signature : \\\"\\\"\\n}\\nfunction getLabQuadrantBounds(sideX, sideY, context) {\\n const layout = context?.layout\\n if (!layout || ![-1, 1].includes(sideX) || ![-1, 1].includes(sideY)) return null\\n const xParity = ((layout.startX ?? 1) & 1)\\n const yParity = ((layout.startY ?? 1) & 1)\\n const rightMinX = context.midX + (((context.midX & 1) === xParity) ? 0 : 1)\\n const leftMaxX = rightMinX - 2\\n const southMinY = context.midY + (((context.midY & 1) === yParity) ? 0 : 1)\\n const northMaxY = southMinY - 2\\n return {\\n sideX, sideY,\\n key: getLabQuadrantKeyFromSides(sideX, sideY),\\n minX: sideX < 0 ? layout.minX : rightMinX,\\n maxX: sideX < 0 ? leftMaxX : layout.maxX,\\n minY: sideY < 0 ? layout.minY : southMinY,\\n maxY: sideY < 0 ? northMaxY : layout.maxY\\n }\\n}\\nfunction getLabQuadrantBoundsForCoords(x, y, context) {\\n if (!context) return null\\n const state = context.state\\n const sideX = getLabQuadrantSide(x, context.midX)\\n const sideY = getLabQuadrantSide(y, context.midY)\\n if (!state) return getLabQuadrantBounds(sideX, sideY, context)\\n const signature = getLabInfluenceSignature(context)\\n let cache = labQuadrantBoundsCoordCache.get(state)\\n if (!cache || cache.signature !== signature) {\\n cache = { signature, map: new Map() }\\n labQuadrantBoundsCoordCache.set(state, cache)\\n }\\n const key = getLabKey(x, y)\\n if (!cache.map.has(key)) cache.map.set(key, getLabQuadrantBounds(sideX, sideY, context))\\n return cache.map.get(key)\\n}\\nfunction getLabEndpointOffsetMax(context) {\\n const layout = context?.layout\\n return layout?.offsetStartAndEnd === true ? labEndpointMaxOffset : 0\\n}\\nfunction getLabEndpointRange(anchor, inward, minLimit, maxLimit, parity, maxOffset) {\\n if (!Number.isInteger(anchor) || ![-1, 1].includes(inward)) return null\\n let min = Math.max(minLimit, Math.min(anchor, anchor + inward * maxOffset))\\n let max = Math.min(maxLimit, Math.max(anchor, anchor + inward * maxOffset))\\n while (min <= max && (min & 1) !== parity) min++\\n while (max >= min && (max & 1) !== parity) max--\\n return min <= max ? { min, max } : null\\n}\\nfunction isLabRoomParity(x, y, context) {\\n if (!Number.isInteger(x) || !Number.isInteger(y)) return false\\n const xParity = ((context?.layout?.startX ?? 1) & 1)\\n const yParity = ((context?.layout?.startY ?? 1) & 1)\\n return (x & 1) === xParity && (y & 1) === yParity\\n}\\n// Bounds of the \\\"exit sub-quadrant\\\" — the half of the goal quadrant that\\n// hugs the actual exit corner. The exit cell itself plus every cell on a\\n// path that ENDS in this region must remain discoverable; unexplored\\n// frontier cells stay protected, while explored cul-de-sacs can still be\\n// marked dead so workers do not bounce inside the exit area.\\nfunction getLabExitSubquadrantBounds(context) {\\n // Protected endpoint footprint only: official offsets are 0, 2, or 4.\\n if (!context) return null\\n const goalBounds = getLabQuadrantBounds(context.goalSideX, context.goalSideY, context)\\n if (!goalBounds) return null\\n const xParity = ((context.layout?.startX ?? 1) & 1)\\n const yParity = ((context.layout?.startY ?? 1) & 1)\\n const maxOffset = getLabEndpointOffsetMax(context)\\n const inwardX = context.goalSideX > 0 ? -1 : 1\\n const inwardY = context.goalSideY > 0 ? -1 : 1\\n const xRange = getLabEndpointRange(context.exitTargetX, inwardX, goalBounds.minX, goalBounds.maxX, xParity, maxOffset)\\n const yRange = getLabEndpointRange(context.exitTargetY, inwardY, goalBounds.minY, goalBounds.maxY, yParity, maxOffset)\\n if (!xRange || !yRange) return null\\n const minX = xRange.min, maxX = xRange.max, minY = yRange.min, maxY = yRange.max\\n return { minX, maxX, minY, maxY }\\n}\\nfunction isLabInExitSubquadrant(x, y, context) {\\n const bounds = getLabExitSubquadrantBounds(context)\\n if (!bounds) return false\\n return isLabRoomParity(x, y, context)\\n && x >= bounds.minX && x <= bounds.maxX && y >= bounds.minY && y <= bounds.maxY\\n}\\nfunction getLabStartSubquadrantBounds(context) {\\n // Protected start footprint only: official offsets are 0, 2, or 4.\\n if (!context) return null\\n const startBounds = getLabQuadrantBounds(context.startSideX, context.startSideY, context)\\n if (!startBounds) return null\\n const xParity = ((context.layout?.startX ?? 1) & 1)\\n const yParity = ((context.layout?.startY ?? 1) & 1)\\n const maxOffset = getLabEndpointOffsetMax(context)\\n const inwardX = context.startSideX < 0 ? 1 : -1\\n const inwardY = context.startSideY < 0 ? 1 : -1\\n const xRange = getLabEndpointRange(context.startX, inwardX, startBounds.minX, startBounds.maxX, xParity, maxOffset)\\n const yRange = getLabEndpointRange(context.startY, inwardY, startBounds.minY, startBounds.maxY, yParity, maxOffset)\\n if (!xRange || !yRange) return null\\n const minX = xRange.min, maxX = xRange.max, minY = yRange.min, maxY = yRange.max\\n return { minX, maxX, minY, maxY }\\n}\\nfunction isLabInStartSubquadrant(x, y, context) {\\n const bounds = getLabStartSubquadrantBounds(context)\\n if (!bounds) return false\\n return isLabRoomParity(x, y, context)\\n && x >= bounds.minX && x <= bounds.maxX && y >= bounds.minY && y <= bounds.maxY\\n}\\nfunction isLabInExitQuadrant(x, y, context) {\\n const bounds = getLabQuadrantBoundsForCoords(x, y, context)\\n return Boolean(bounds && bounds.sideX === context?.goalSideX && bounds.sideY === context?.goalSideY)\\n}\\nfunction isLabInStartQuadrant(x, y, context) {\\n const bounds = getLabQuadrantBoundsForCoords(x, y, context)\\n return Boolean(bounds && bounds.sideX === context?.startSideX && bounds.sideY === context?.startSideY)\\n}\\nfunction getLabExitFocusPointRank(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!context) return 0\\n if (!isLabInExitQuadrant(x, y, context)) return 3\\n return isLabInExitSubquadrant(x, y, context) ? 0 : 1\\n}\\nfunction getLabExitFocusMoveRank(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context || !isLabInExitQuadrant(fromX, fromY, context)) return 0\\n return getLabExitFocusPointRank(state, toX, toY, context)\\n}\\nfunction isLabQuadrantCrossing(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context) return false\\n const fromBounds = getLabQuadrantBoundsForCoords(fromX, fromY, context)\\n const toBounds = getLabQuadrantBoundsForCoords(toX, toY, context)\\n if (!fromBounds || !toBounds) return false\\n return fromBounds.key !== toBounds.key\\n}\\nfunction isLabSameQuadrantMove(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context) return true\\n const fromBounds = getLabQuadrantBoundsForCoords(fromX, fromY, context)\\n const toBounds = getLabQuadrantBoundsForCoords(toX, toY, context)\\n return Boolean(fromBounds && toBounds && fromBounds.key === toBounds.key)\\n}\\nfunction isLabSameQuadrantCell(state, anchorX, anchorY, x, y, context = getLabInfluenceContext(state)) {\\n return isLabSameQuadrantMove(state, anchorX, anchorY, x, y, context)\\n}\\nfunction getLabEdgeKey(x, y, dir) {\\n const delta = labDirections[dir]\\n if (!delta || !Number.isInteger(x) || !Number.isInteger(y)) return \\\"\\\"\\n const a = getLabKey(x, y)\\n const b = getLabKey(x + delta.dx, y + delta.dy)\\n return a < b ? `${a}|${b}` : `${b}|${a}`\\n}\\nfunction getLabQuadrantTransitionKey(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context) return \\\"\\\"\\n const fromBounds = getLabQuadrantBoundsForCoords(fromX, fromY, context)\\n const toBounds = getLabQuadrantBoundsForCoords(toX, toY, context)\\n if (!fromBounds || !toBounds || fromBounds.key === toBounds.key) return \\\"\\\"\\n return fromBounds.key < toBounds.key ? `${fromBounds.key}|${toBounds.key}` : `${toBounds.key}|${fromBounds.key}`\\n}\\nfunction getLabQuadrantTransitionForDir(state, x, y, dir, context = getLabInfluenceContext(state)) {\\n const delta = labDirections[dir]\\n if (!delta) return null\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n const transitionKey = getLabQuadrantTransitionKey(state, x, y, nx, ny, context)\\n if (!transitionKey) return null\\n return {\\n transitionKey,\\n edgeKey: getLabEdgeKey(x, y, dir),\\n toX: nx,\\n toY: ny\\n }\\n}\\nfunction getLabQuadrantGoalDistance(bounds, context) {\\n if (!bounds || !context) return Infinity\\n return (bounds.sideX === context.goalSideX ? 0 : 1) + (bounds.sideY === context.goalSideY ? 0 : 1)\\n}\\nfunction getLabQuadrantProgressRank(bounds, context) {\\n const distance = getLabQuadrantGoalDistance(bounds, context)\\n return Number.isFinite(distance) ? 2 - distance : -Infinity\\n}\\nfunction isLabMoreGoalwardQuadrantMove(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context) return false\\n const fromBounds = getLabQuadrantBoundsForCoords(fromX, fromY, context)\\n const toBounds = getLabQuadrantBoundsForCoords(toX, toY, context)\\n if (!fromBounds || !toBounds || fromBounds.key === toBounds.key) return false\\n return getLabQuadrantProgressRank(toBounds, context) > getLabQuadrantProgressRank(fromBounds, context)\\n}\\nfunction isLabWorseQuadrantMove(state, fromX, fromY, toX, toY, context = getLabInfluenceContext(state)) {\\n if (!context) return false\\n const fromBounds = getLabQuadrantBoundsForCoords(fromX, fromY, context)\\n const toBounds = getLabQuadrantBoundsForCoords(toX, toY, context)\\n if (!fromBounds || !toBounds || fromBounds.key === toBounds.key) return false\\n return getLabQuadrantProgressRank(toBounds, context) < getLabQuadrantProgressRank(fromBounds, context)\\n}\\nfunction getLabQuadrantEntryBlockKey(x, y, dir) {\\n return Number.isInteger(x) && Number.isInteger(y) && labDirections[dir] ? `${getLabKey(x, y)}:${dir}` : \\\"\\\"\\n}\\nfunction isLabQuadrantEntryBlocked(state, x, y, dir) {\\n const key = getLabQuadrantEntryBlockKey(x, y, dir)\\n return Boolean(key && Object.prototype.hasOwnProperty.call(ensureLabQuadrantEntryBlockSection(state), key))\\n}\\nfunction recordLabQuadrantEntryBlock(state, fromX, fromY, toX, toY, dir, context = getLabInfluenceContext(state)) {\\n if (!state || !isLabMoreGoalwardQuadrantMove(state, fromX, fromY, toX, toY, context)) return false\\n const backDir = labDirections[dir]?.back\\n const blockKey = getLabQuadrantEntryBlockKey(toX, toY, backDir)\\n if (!blockKey) return false\\n const blocks = ensureLabQuadrantEntryBlockSection(state)\\n if (Object.prototype.hasOwnProperty.call(blocks, blockKey)) return false\\n const crossing = getLabQuadrantTransitionForDir(state, fromX, fromY, dir, context)\\n blocks[blockKey] = {\\n fromKey: getLabKey(toX, toY),\\n toKey: getLabKey(fromX, fromY),\\n dir: backDir,\\n edgeKey: getLabEdgeKey(fromX, fromY, dir),\\n transitionKey: crossing?.transitionKey ?? \\\"\\\"\\n }\\n return true\\n}\\nfunction isLabKnownGatewayQuadrantCrossing(state, x, y, dir, context = getLabInfluenceContext(state)) {\\n const crossing = getLabQuadrantTransitionForDir(state, x, y, dir, context)\\n if (!crossing) return false\\n const gateway = ensureLabQuadrantGatewaySection(state)[crossing.transitionKey]\\n return Boolean(gateway?.edgeKey && gateway.edgeKey === crossing.edgeKey)\\n}\\nfunction isLabLiveQuadrantCrossing(state, x, y, dir, context = getLabInfluenceContext(state)) {\\n const delta = labDirections[dir]\\n const crossing = getLabQuadrantTransitionForDir(state, x, y, dir, context)\\n if (!delta || !crossing) return false\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (!isLabMoreGoalwardQuadrantMove(state, x, y, nx, ny, context)) return false\\n const gateway = ensureLabQuadrantGatewaySection(state)[crossing.transitionKey]\\n return !(gateway?.edgeKey && gateway.edgeKey !== crossing.edgeKey)\\n}\\nfunction isLabKnownQuadrantGatewayCell(state, x, y) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n const key = getLabKey(x, y)\\n for (const gateway of Object.values(ensureLabQuadrantGatewaySection(state))) {\\n if (gateway?.fromKey === key || gateway?.toKey === key) return true\\n }\\n return false\\n}\\nfunction getLabQuadrantGatewaySignature(state) {\\n if (!state) return \\\"\\\"\\n return Object.entries(ensureLabQuadrantGatewaySection(state))\\n .filter(([, gateway]) => gateway?.edgeKey)\\n .map(([transitionKey, gateway]) => `${transitionKey}=${gateway.edgeKey}`)\\n .sort()\\n .join(\\\";\\\")\\n}\\nfunction getLabQuadrantTransitionCells(state, context = getLabInfluenceContext(state)) {\\n const layout = state?.layout\\n if (!layout || !context) return {}\\n const signature = getLabInfluenceSignature(context)\\n const cache = ensureLabQuadrantTransitionCellCache(state)\\n if (cache.signature === signature && cache.byTransition && typeof cache.byTransition === \\\"object\\\") return cache.byTransition\\n const byTransition = {}\\n for (let y = layout.minY; y <= layout.maxY; y += 2) {\\n for (let x = layout.minX; x <= layout.maxX; x += 2) {\\n for (const [dir, delta] of labDirectionEntries) {\\n const crossing = getLabQuadrantTransitionForDir(state, x, y, dir, context)\\n if (!crossing) continue\\n const entry = {\\n x,\\n y,\\n dir,\\n toX: crossing.toX,\\n toY: crossing.toY,\\n wallX: x + delta.dx / 2,\\n wallY: y + delta.dy / 2,\\n edgeKey: crossing.edgeKey,\\n transitionKey: crossing.transitionKey\\n }\\n if (!Array.isArray(byTransition[crossing.transitionKey])) byTransition[crossing.transitionKey] = []\\n byTransition[crossing.transitionKey].push(entry)\\n }\\n }\\n }\\n cache.signature = signature\\n cache.byTransition = byTransition\\n return byTransition\\n}\\nfunction applyLabQuadrantGatewayWalls(state, transitionKey = \\\"\\\") {\\n if (!state?.rooms || !state.layout) return false\\n const context = getLabInfluenceContext(state)\\n if (!context) return false\\n let changed = false\\n const byTransition = getLabQuadrantTransitionCells(state, context)\\n const transitionKeys = transitionKey ? [transitionKey] : Object.keys(byTransition)\\n for (const key of transitionKeys) {\\n const activeGateway = ensureLabQuadrantGatewaySection(state)[key]\\n const entries = byTransition[key]\\n if (!activeGateway?.edgeKey || !Array.isArray(entries)) continue\\n for (const entry of entries) {\\n if (entry.edgeKey === activeGateway.edgeKey) continue\\n if (setLabDisplayCharAtCoords(state, entry.wallX, entry.wallY, labMapFill)) changed = true\\n }\\n }\\n if (changed) {\\n state.displayVersion = (state.displayVersion ?? 0) + 1\\n state.displayOutputKey = \\\"\\\"\\n }\\n return changed\\n}\\nfunction refreshLabGatewayTransitionDeadKnowledge(state, transitionKey, context = getLabInfluenceContext(state)) {\\n if (!state?.rooms || !transitionKey || !context) return false\\n const entries = getLabQuadrantTransitionCells(state, context)[transitionKey]\\n if (!Array.isArray(entries) || entries.length === 0) return false\\n const routeGate = createLabMoveGate(state, { context })\\n const seen = new Set()\\n const deadFrontiers = []\\n for (const entry of entries) {\\n if (!entry || !Number.isInteger(entry.x) || !Number.isInteger(entry.y)) continue\\n const key = getLabKey(entry.x, entry.y)\\n if (seen.has(key)) continue\\n seen.add(key)\\n const room = state.rooms[key]\\n if (!room || room.explored === true || isLabProtectedDeadAreaCell(state, entry.x, entry.y, context)) continue\\n const cost = getLabPotentialGoalCost(state, entry.x, entry.y, routeGate, context, {\\n allowStartSubquadrantExplored: true,\\n boundQuadrant: true,\\n forceRefresh: true,\\n originX: entry.x,\\n originY: entry.y\\n })\\n if (!Number.isFinite(cost)) deadFrontiers.push(entry)\\n }\\n let changed = false\\n for (const entry of deadFrontiers) {\\n const escapeDir = getLabKnownFrontierEscapeDir(state, entry.x, entry.y)\\n if (appendLabDeadEndEntry(state, getLabKey(entry.x, entry.y), escapeDir)) changed = true\\n }\\n for (const key of seen) {\\n const coords = getLabCoordsFromKey(key)\\n if (!coords) continue\\n if (evaluateLabFrontierLeavesAround(state, coords[0], coords[1])) changed = true\\n enqueueLabDeadAreaAround(state, coords[0], coords[1], context)\\n if (reevaluateLabDeadEnd(state, coords[0], coords[1])) changed = true\\n }\\n if (drainLabDeadAreaQueue(state, context)) changed = true\\n return changed\\n}\\nfunction recordLabQuadrantGateway(state, x, y, dir, context = getLabInfluenceContext(state)) {\\n const crossing = getLabQuadrantTransitionForDir(state, x, y, dir, context)\\n if (!crossing) return false\\n const gateways = ensureLabQuadrantGatewaySection(state)\\n const existing = gateways[crossing.transitionKey]\\n if (existing?.edgeKey) {\\n applyLabQuadrantGatewayWalls(state, crossing.transitionKey)\\n return false\\n }\\n gateways[crossing.transitionKey] = {\\n edgeKey: crossing.edgeKey,\\n fromKey: getLabKey(x, y),\\n toKey: getLabKey(crossing.toX, crossing.toY),\\n x,\\n y,\\n dir\\n }\\n applyLabQuadrantGatewayWalls(state, crossing.transitionKey)\\n refreshLabGatewayTransitionDeadKnowledge(state, crossing.transitionKey, context)\\n return true\\n}\\nfunction recordLabQuadrantGatewaysFromExits(state, x, y, exits, context = getLabInfluenceContext(state)) {\\n if (!state || !exits) return false\\n let changed = false\\n for (const [dir] of labDirectionEntries) {\\n if (exits[dir] === true && recordLabQuadrantGateway(state, x, y, dir, context)) changed = true\\n }\\n return changed\\n}\\nfunction getLabGoalwardDirsForQuadrant(bounds, context) {\\n if (!bounds || !context) return []\\n const dirs = []\\n if (bounds.sideX !== context.goalSideX) dirs.push(context.goalSideX > bounds.sideX ? \\\"east\\\" : \\\"west\\\")\\n if (bounds.sideY !== context.goalSideY) dirs.push(context.goalSideY > bounds.sideY ? \\\"south\\\" : \\\"north\\\")\\n return dirs\\n}\\nfunction addLabGoalDir(dirs, dir) {\\n if (labDirections[dir] && !dirs.includes(dir)) dirs.push(dir)\\n}\\nfunction getLabExitTargetDirs(x, y, context) {\\n const dirs = []\\n if (!context) return dirs\\n if (context.exitTargetX > x) addLabGoalDir(dirs, \\\"east\\\")\\n else if (context.exitTargetX < x) addLabGoalDir(dirs, \\\"west\\\")\\n if (context.exitTargetY > y) addLabGoalDir(dirs, \\\"south\\\")\\n else if (context.exitTargetY < y) addLabGoalDir(dirs, \\\"north\\\")\\n return dirs\\n}\\nfunction addLabWallAttachedGoalDirs(dirs, x, y, bounds, context) {\\n if (!bounds || !context) return dirs\\n if (bounds.sideX !== context.goalSideX) {\\n const targetWallX = context.goalSideX > bounds.sideX ? bounds.maxX : bounds.minX\\n if (x === targetWallX) {\\n addLabGoalDir(dirs, \\\"north\\\")\\n addLabGoalDir(dirs, \\\"south\\\")\\n }\\n } else {\\n if (x === context.exitTargetX) {\\n addLabGoalDir(dirs, \\\"north\\\")\\n addLabGoalDir(dirs, \\\"south\\\")\\n }\\n }\\n if (bounds.sideY !== context.goalSideY) {\\n const targetWallY = context.goalSideY > bounds.sideY ? bounds.maxY : bounds.minY\\n if (y === targetWallY) {\\n addLabGoalDir(dirs, \\\"east\\\")\\n addLabGoalDir(dirs, \\\"west\\\")\\n }\\n } else {\\n if (y === context.exitTargetY) {\\n addLabGoalDir(dirs, \\\"east\\\")\\n addLabGoalDir(dirs, \\\"west\\\")\\n }\\n }\\n return dirs\\n}\\nfunction computeLabImmediateGoalwardDirs(x, y, bounds, context) {\\n if (bounds.sideX !== context.goalSideX || bounds.sideY !== context.goalSideY) {\\n return addLabWallAttachedGoalDirs(getLabGoalwardDirsForQuadrant(bounds, context), x, y, bounds, context)\\n }\\n const dirs = getLabExitTargetDirs(x, y, context)\\n if (isLabInExitSubquadrant(x, y, context)) return dirs\\n return addLabWallAttachedGoalDirs(dirs, x, y, bounds, context)\\n}\\nfunction getLabImmediateGoalwardDirs(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!context) return []\\n const bounds = getLabQuadrantBoundsForCoords(x, y, context)\\n if (!bounds) return []\\n if (state) {\\n const signature = getLabInfluenceSignature(context)\\n let cache = labGoalwardDirsCache.get(state)\\n if (!cache || cache.signature !== signature) {\\n cache = { signature, map: new Map() }\\n labGoalwardDirsCache.set(state, cache)\\n }\\n const key = getLabKey(x, y)\\n const cached = cache.map.get(key)\\n if (cached) return cached\\n const dirs = computeLabImmediateGoalwardDirs(x, y, bounds, context)\\n cache.map.set(key, dirs)\\n return dirs\\n }\\n return computeLabImmediateGoalwardDirs(x, y, bounds, context)\\n}\\n\\n// ----- Visit stack ----------------------------------------------------------\\n// Per-worker history of forward steps. Pop returns the dir that brought\\n// the worker to its current cell; its inverse is the only valid backstep.\\nfunction getLabWorkerVisitStack(workerId) {\\n let stack = labWorkerVisitStack.get(workerId)\\n if (!Array.isArray(stack)) {\\n stack = []\\n labWorkerVisitStack.set(workerId, stack)\\n }\\n return stack\\n}\\nfunction pushLabWorkerVisit(workerId, dir) {\\n if (!workerId || typeof dir !== \\\"string\\\" || !dir) return\\n getLabWorkerVisitStack(workerId).push(dir)\\n}\\nfunction popLabWorkerVisit(workerId) {\\n if (!workerId) return \\\"\\\"\\n const stack = getLabWorkerVisitStack(workerId)\\n return stack.length > 0 ? stack.pop() : \\\"\\\"\\n}\\nfunction peekLabWorkerVisit(workerId) {\\n if (!workerId) return \\\"\\\"\\n const stack = labWorkerVisitStack.get(workerId)\\n return Array.isArray(stack) && stack.length > 0 ? stack[stack.length - 1] : \\\"\\\"\\n}\\nfunction clearLabWorkerVisitStack(workerId) {\\n if (workerId) labWorkerVisitStack.delete(workerId)\\n}\\n\\n// ----- State / room helpers -------------------------------------------------\\nfunction ensureLabDeadEndEntries(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n const priorEntries = state.deadEndEntries\\n const legacyEscapeEntries = state.deadEndEscapeEntries\\n const legacyEscape = state.deadEndEscape\\n if (!priorEntries || typeof priorEntries !== \\\"object\\\" || Array.isArray(priorEntries)) {\\n state.deadEndEntries = {}\\n }\\n const entries = state.deadEndEntries\\n const absorbEntry = (key, escape) => {\\n if (typeof key !== \\\"string\\\" || !key) return\\n if (Object.prototype.hasOwnProperty.call(entries, key)) return\\n entries[key] = typeof escape === \\\"string\\\" && labDirections[escape] ? escape : \\\"\\\"\\n }\\n if (Array.isArray(priorEntries)) {\\n for (const entry of priorEntries) {\\n if (Array.isArray(entry) && entry.length >= 2) absorbEntry(entry[0], entry[1])\\n }\\n }\\n if (Array.isArray(legacyEscapeEntries)) {\\n for (const entry of legacyEscapeEntries) {\\n if (Array.isArray(entry) && entry.length >= 2) absorbEntry(entry[0], entry[1])\\n }\\n }\\n if (legacyEscape instanceof Map) {\\n for (const [key, escape] of legacyEscape.entries()) absorbEntry(key, escape)\\n } else if (Array.isArray(legacyEscape)) {\\n for (const entry of legacyEscape) {\\n if (Array.isArray(entry) && entry.length >= 2) absorbEntry(entry[0], entry[1])\\n }\\n }\\n if (Object.prototype.hasOwnProperty.call(state, \\\"deadEndEscapeEntries\\\")) delete state.deadEndEscapeEntries\\n if (Object.prototype.hasOwnProperty.call(state, \\\"deadEndEscape\\\")) delete state.deadEndEscape\\n return entries\\n}\\nfunction syncLabDeadEndSnapshot(state) {\\n ensureLabDeadEndEntries(state)\\n}\\nfunction reviveLabDeadEndMap(state) {\\n ensureLabDeadEndEntries(state)\\n return state\\n}\\nfunction ensureLabQuadrantGatewaySection(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.quadrantGateways || typeof state.quadrantGateways !== \\\"object\\\" || Array.isArray(state.quadrantGateways)) {\\n state.quadrantGateways = {}\\n }\\n return state.quadrantGateways\\n}\\nfunction ensureLabQuadrantEntryBlockSection(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.quadrantEntryBlocks || typeof state.quadrantEntryBlocks !== \\\"object\\\" || Array.isArray(state.quadrantEntryBlocks)) {\\n state.quadrantEntryBlocks = {}\\n }\\n return state.quadrantEntryBlocks\\n}\\nfunction ensureLabDeadAreaQueue(state) {\\n if (!state || typeof state !== \\\"object\\\") return []\\n if (!Array.isArray(state.deadAreaQueue)) state.deadAreaQueue = []\\n if (!state.deadAreaQueued || typeof state.deadAreaQueued !== \\\"object\\\" || Array.isArray(state.deadAreaQueued)) {\\n state.deadAreaQueued = {}\\n for (const key of state.deadAreaQueue) {\\n if (typeof key === \\\"string\\\" && key) state.deadAreaQueued[key] = true\\n }\\n }\\n return state.deadAreaQueue\\n}\\nfunction ensureLabDeadRouteCosts(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.deadRouteCosts || typeof state.deadRouteCosts !== \\\"object\\\" || Array.isArray(state.deadRouteCosts)) state.deadRouteCosts = {}\\n return state.deadRouteCosts\\n}\\nfunction ensureLabFrontierRouteCache(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.frontierRouteCache || typeof state.frontierRouteCache !== \\\"object\\\" || Array.isArray(state.frontierRouteCache)) state.frontierRouteCache = {}\\n return state.frontierRouteCache\\n}\\nfunction ensureLabDeadPrefilterChecks(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.deadPrefilterChecks || typeof state.deadPrefilterChecks !== \\\"object\\\" || Array.isArray(state.deadPrefilterChecks)) state.deadPrefilterChecks = {}\\n return state.deadPrefilterChecks\\n}\\nfunction ensureLabDeadKnowledgeChecks(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.deadKnowledgeChecks || typeof state.deadKnowledgeChecks !== \\\"object\\\" || Array.isArray(state.deadKnowledgeChecks)) state.deadKnowledgeChecks = {}\\n return state.deadKnowledgeChecks\\n}\\nfunction ensureLabDeadAreaEdgeCache(state) {\\n if (!state || typeof state !== \\\"object\\\") return {}\\n if (!state.deadAreaEdgeCache || typeof state.deadAreaEdgeCache !== \\\"object\\\" || Array.isArray(state.deadAreaEdgeCache)) state.deadAreaEdgeCache = {}\\n return state.deadAreaEdgeCache\\n}\\nfunction ensureLabQuadrantTransitionCellCache(state) {\\n if (!state || typeof state !== \\\"object\\\") return { signature: \\\"\\\", byTransition: {} }\\n if (!state.quadrantTransitionCells || typeof state.quadrantTransitionCells !== \\\"object\\\" || Array.isArray(state.quadrantTransitionCells)) {\\n state.quadrantTransitionCells = { signature: \\\"\\\", byTransition: {} }\\n }\\n if (!state.quadrantTransitionCells.byTransition || typeof state.quadrantTransitionCells.byTransition !== \\\"object\\\" || Array.isArray(state.quadrantTransitionCells.byTransition)) {\\n state.quadrantTransitionCells.byTransition = {}\\n }\\n return state.quadrantTransitionCells\\n}\\nfunction setLabDeadRouteCost(state, x, y, cost) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y)) return\\n ensureLabDeadRouteCosts(state)[getLabKey(x, y)] = Number.isFinite(cost) ? cost : Number.POSITIVE_INFINITY\\n}\\nfunction getLabDeadRouteCost(state, x, y) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y)) return Number.POSITIVE_INFINITY\\n const value = ensureLabDeadRouteCosts(state)[getLabKey(x, y)]\\n if (Number.isFinite(value)) return value\\n if (value && typeof value === \\\"object\\\" && Number.isFinite(value.cost)) return value.cost\\n return Number.POSITIVE_INFINITY\\n}\\nfunction hasLabDeadRouteCost(state, x, y) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n const value = ensureLabDeadRouteCosts(state)[getLabKey(x, y)]\\n return Number.isFinite(value) || value === Number.POSITIVE_INFINITY\\n || Boolean(value && typeof value === \\\"object\\\" && (Number.isFinite(value.cost) || value.cost === Number.POSITIVE_INFINITY))\\n}\\nfunction enqueueLabDeadAreaSource(state, x, y) {\\n if (!state?.rooms || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n const key = getLabKey(x, y)\\n const room = state.rooms[key]\\n if (!room?.explored || !room.exits) return false\\n const queue = ensureLabDeadAreaQueue(state)\\n if (state.deadAreaQueued?.[key] === true) return false\\n state.deadAreaQueued[key] = true\\n queue.push(key)\\n return true\\n}\\nfunction enqueueLabDeadAreaAround(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!state?.rooms || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n let changed = enqueueLabDeadAreaSource(state, x, y)\\n for (const [, delta] of labDirectionEntries) {\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (context && !isLabSameQuadrantMove(state, x, y, nx, ny, context)) continue\\n if (enqueueLabDeadAreaSource(state, nx, ny)) changed = true\\n }\\n return changed\\n}\\nfunction reviveLabQuadrantGateways(state) {\\n ensureLabQuadrantGatewaySection(state)\\n return state\\n}\\nfunction reviveLabQuadrantEntryBlocks(state) {\\n ensureLabQuadrantEntryBlockSection(state)\\n return state\\n}\\nfunction syncLabSharedSections(state) {\\n syncLabDeadEndSnapshot(state)\\n reviveLabQuadrantGateways(state)\\n reviveLabQuadrantEntryBlocks(state)\\n ensureLabDeadAreaQueue(state)\\n ensureLabDeadRouteCosts(state)\\n ensureLabFrontierRouteCache(state)\\n ensureLabDeadPrefilterChecks(state)\\n ensureLabDeadKnowledgeChecks(state)\\n ensureLabDeadAreaEdgeCache(state)\\n ensureLabQuadrantTransitionCellCache(state)\\n return state\\n}\\nfunction reviveLabState(state, server) {\\n if (!state || typeof state !== \\\"object\\\" || !state.rooms) return null\\n state.serverName = state.serverName || server\\n if (!state.workers || typeof state.workers !== \\\"object\\\") state.workers = {}\\n if (!Array.isArray(state.displayMap)) state.displayMap = []\\n if (!Array.isArray(state.displayDirtyCells)) state.displayDirtyCells = []\\n if (!state.displayDirtyLookup || typeof state.displayDirtyLookup !== \\\"object\\\" || Array.isArray(state.displayDirtyLookup)) state.displayDirtyLookup = {}\\n if (!Array.isArray(state.startKeys)) state.startKeys = []\\n state.workersVersion = state.workersVersion ?? 0\\n state.displayVersion = state.displayVersion ?? 0\\n state.displayLayoutKey = state.displayLayoutKey ?? \\\"\\\"\\n state.displayOutputKey = state.displayOutputKey ?? \\\"\\\"\\n state.displayOutputLayoutKey = state.displayOutputLayoutKey ?? \\\"\\\"\\n syncLabSharedSections(state)\\n return state\\n}\\nfunction ensureLabState(server) {\\n if (labState && labState.serverName === server) return labState\\n const existing = typeof inProgress?.get === \\\"function\\\" ? reviveLabState(inProgress.get(server), server) : null\\n if (existing) {\\n labState = existing\\n labComplete = false\\n labWorkerVisitStack = new Map()\\n if (typeof inProgress?.set === \\\"function\\\") inProgress.set(server, labState)\\n return labState\\n }\\n // New server (or first call): blow away module state for this run.\\n labState = {\\n serverName: server,\\n rooms: {},\\n layout: null,\\n workers: {},\\n workersVersion: 0,\\n displayMap: [],\\n displayDirtyCells: [],\\n displayDirtyLookup: {},\\n displayLayoutKey: \\\"\\\",\\n displayVersion: 0,\\n displayOutputKey: \\\"\\\",\\n displayOutputLayoutKey: \\\"\\\",\\n displayOutputRows: null,\\n rootKey: \\\"\\\",\\n finishKey: \\\"\\\",\\n coordOffsetX: 0,\\n coordOffsetY: 0,\\n startKeys: [],\\n deadEndEntries: {},\\n deadRouteCosts: {},\\n frontierRouteCache: {},\\n deadPrefilterChecks: {},\\n deadKnowledgeChecks: {},\\n deadAreaEdgeCache: {},\\n deadAreaQueue: [],\\n deadAreaQueued: {},\\n quadrantGateways: {},\\n quadrantEntryBlocks: {},\\n quadrantTransitionCells: { signature: \\\"\\\", byTransition: {} }\\n }\\n labComplete = false\\n labWorkerVisitStack = new Map()\\n return labState\\n}\\nfunction ensureLabRoom(state, x, y, path = []) {\\n const key = getLabKey(x, y)\\n if (!state.rooms[key]) {\\n state.rooms[key] = {\\n x, y,\\n path: path.slice(),\\n jsonLog: null,\\n exits: null,\\n explored: false\\n }\\n } else if (path.length > 0 && state.rootKey !== key\\n && (state.rooms[key].path.length === 0 || path.length < state.rooms[key].path.length)) {\\n state.rooms[key].path = path.slice()\\n }\\n return state.rooms[key]\\n}\\nfunction ensureLabDisplayDirtyCells(state) {\\n if (!state || typeof state !== \\\"object\\\") return []\\n if (!Array.isArray(state.displayDirtyCells)) state.displayDirtyCells = []\\n if (!state.displayDirtyLookup || typeof state.displayDirtyLookup !== \\\"object\\\" || Array.isArray(state.displayDirtyLookup)) state.displayDirtyLookup = {}\\n return state.displayDirtyCells\\n}\\nfunction markLabDisplayDirtyCell(state, boardX, boardY) {\\n if (!state || !Number.isInteger(boardX) || !Number.isInteger(boardY)) return false\\n const key = `${boardX},${boardY}`\\n ensureLabDisplayDirtyCells(state)\\n if (state.displayDirtyLookup[key] === true) return false\\n state.displayDirtyLookup[key] = true\\n state.displayDirtyCells.push([boardX, boardY])\\n return true\\n}\\nfunction markLabDisplayDirtyCoords(state, x, y) {\\n const info = getLabBoardInfo(state?.layout)\\n if (!info) return false\\n return markLabDisplayDirtyCell(state, x - info.originX, y - info.originY)\\n}\\nfunction consumeLabDisplayDirtyCells(state) {\\n if (!state) return []\\n const cells = Array.isArray(state.displayDirtyCells) ? state.displayDirtyCells : []\\n state.displayDirtyCells = []\\n state.displayDirtyLookup = {}\\n return cells\\n}\\nfunction markAllLabDisplayCellsDirty(state) {\\n const displayMap = state?.displayMap\\n if (!Array.isArray(displayMap)) return\\n for (let y = 0; y < displayMap.length; y++) {\\n const row = typeof displayMap[y] === \\\"string\\\" ? displayMap[y] : \\\"\\\"\\n for (let x = 0; x < row.length; x++) markLabDisplayDirtyCell(state, x, y)\\n }\\n}\\nfunction addLabStartMarker(state, x, y) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y)) return\\n const key = getLabKey(x, y)\\n if (!state.startKeys.includes(key)) {\\n state.startKeys.push(key)\\n markLabDisplayDirtyCoords(state, x, y)\\n }\\n}\\nfunction setLabWorkerPosition(state, workerId, x, y) {\\n if (!state.workers) state.workers = {}\\n const existing = state.workers[workerId]\\n if (existing && existing.x === x && existing.y === y) return\\n if (existing) markLabDisplayDirtyCoords(state, existing.x, existing.y)\\n state.workers[workerId] = { x, y }\\n markLabDisplayDirtyCoords(state, x, y)\\n state.workersVersion = (state.workersVersion ?? 0) + 1\\n}\\n\\nfunction recordLabRoom(a, b, c, d, e, f, g) {\\n let state, x, y, report, path, allowOverwrite\\n if (typeof a === \\\"string\\\") {\\n // OLD: server, details, x, y, report, path, allowOverwrite\\n state = getLabState(a, b)\\n x = c; y = d; report = e\\n path = Array.isArray(f) ? f : []\\n allowOverwrite = g === true\\n } else {\\n // NEW: state, x, y, report, path, allowOverwrite\\n state = a\\n x = b; y = c; report = d\\n path = Array.isArray(e) ? e : []\\n allowOverwrite = f === true\\n }\\n if (!state || typeof state !== \\\"object\\\" || !state.rooms) return\\n\\n if (!state.rootKey\\n && path.length === 0\\n && Array.isArray(report?.coords)\\n && Number.isInteger(report.coords[0])\\n && Number.isInteger(report.coords[1])) {\\n state.coordOffsetX = x - report.coords[0]\\n state.coordOffsetY = y - report.coords[1]\\n }\\n const [actualX, actualY] = getLabActualCoords(x, y, report, state)\\n if (path.length === 0 && !state.rootKey) state.rootKey = getLabKey(actualX, actualY)\\n const room = ensureLabRoom(state, actualX, actualY, path)\\n if (state.rootKey === getLabKey(actualX, actualY)) room.path = []\\n const nextExits = sanitizeLabRoomExits(state, actualX, actualY, {\\n north: report?.north === true,\\n east: report?.east === true,\\n south: report?.south === true,\\n west: report?.west === true\\n })\\n const wasExplored = room.explored === true\\n const exitsConflict = wasExplored\\n && room.exits\\n && labDirectionEntries.some(([dir]) => room.exits[dir] !== nextExits[dir])\\n if (exitsConflict && !allowOverwrite) return\\n const roomKey = getLabKey(actualX, actualY)\\n const pathImproved = state.rootKey !== roomKey\\n && path.length > 0\\n && (room.path.length === 0 || path.length < room.path.length)\\n if (wasExplored && !exitsConflict && !pathImproved) {\\n room.jsonLog = report\\n return\\n }\\n room.jsonLog = report\\n room.exits = nextExits\\n room.explored = true\\n if (state.rootKey === roomKey) room.path = []\\n else if (pathImproved) room.path = path.slice()\\n recordLabQuadrantGatewaysFromExits(state, actualX, actualY, room.exits)\\n\\n for (const [dir, delta] of labDirectionEntries) {\\n const nextX = actualX + delta.dx\\n const nextY = actualY + delta.dy\\n const nextKey = getLabKey(nextX, nextY)\\n if (!room.exits[dir]) {\\n const stale = state.rooms[nextKey]\\n const blockedPath = path.concat(dir)\\n if (stale && !stale.explored && Array.isArray(stale.path)\\n && stale.path.length === blockedPath.length\\n && stale.path.every((step, index) => step === blockedPath[index])) {\\n delete state.rooms[nextKey]\\n }\\n continue\\n }\\n if (isLabQuadrantEntryBlocked(state, actualX, actualY, dir)) continue\\n if (state.layout && (nextX < state.layout.minX || nextX > state.layout.maxX\\n || nextY < state.layout.minY || nextY > state.layout.maxY)) continue\\n ensureLabRoom(state, nextX, nextY, path.concat(dir))\\n }\\n\\n // Maze-exit detection. Until finishX/Y is set, sanitizeLabRoomExits\\n // leaves boundary openings alone — the auth data can carry an open\\n // exit pointing outside the layout rectangle, which is the maze's\\n // exit cell. When we see one, pin finishX/Y, extend the layout\\n // rectangle to include it, and trigger a display rebuild so the X\\n // marker shows up immediately rather than waiting for the worker to\\n // physically step into the exit.\\n if (state.layout && !Number.isInteger(state.layout.finishX)) {\\n for (const [dir, delta] of labDirectionEntries) {\\n if (room.exits[dir] !== true) continue\\n const nx = actualX + delta.dx\\n const ny = actualY + delta.dy\\n const layout = state.layout\\n if (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY) {\\n layout.finishX = nx\\n layout.finishY = ny\\n state.finishKey = getLabKey(nx, ny)\\n // Re-pin goalX/goalY at the discovered exit cell. The layout's\\n // initial goal coords come from getEstimatedLabLayout which\\n // assumes the bottom-right corner — for any maze whose exit is\\n // at a different corner that estimate is wrong, and the cached\\n // influence context computed from it leaves goalSideX/goalSideY\\n // pointing at the wrong quadrant. Goalward dirs in the picker\\n // would then chase the wrong corner. Updating goalX/Y here\\n // changes the layoutKey, invalidates the influence-context\\n // cache, and the next picker call recomputes with the correct\\n // goal-quadrant orientation.\\n layout.goalX = nx\\n layout.goalY = ny\\n if (nx > layout.maxX) layout.maxX = nx\\n if (ny > layout.maxY) layout.maxY = ny\\n if (nx < layout.minX) layout.minX = nx\\n if (ny < layout.minY) layout.minY = ny\\n // Stale protected-area marks may have been written under the old\\n // goal orientation. Prune only those; keep dead-room knowledge\\n // so other workers do not re-enter exhausted branches.\\n pruneLabProtectedDeadMarks(state)\\n syncLabDisplayMap(state, true)\\n state.displayVersion = (state.displayVersion ?? 0) + 1\\n state.displayOutputKey = \\\"\\\"\\n break\\n }\\n }\\n }\\n\\n syncLabDisplayMap(state)\\n updateLabDisplayFromRoom(state, room)\\n // Predictive dead-end marking for unexplored neighbours. When the new\\n // wall info on this room leaves a frontier without a potential route\\n // to a goalward quadrant border or exit area, mark that neighbour dead\\n // before any worker tries to step into it.\\n updateLabDeadKnowledgeFromRoom(state, actualX, actualY)\\n}\\n\\n\\n// ----- Display map ----------------------------------------------------------\\nfunction getLabBoardInfo(layout) {\\n if (!layout) return null\\n const { minX, minY, maxX, maxY, goalX, goalY } = layout\\n return {\\n minX, minY, maxX, maxY, goalX, goalY,\\n originX: minX - 1,\\n originY: minY - 1,\\n width: maxX - minX + 3,\\n height: maxY - minY + 3\\n }\\n}\\nfunction setLabDisplayChar(state, boardX, boardY, char) {\\n const displayMap = state?.displayMap\\n if (!Array.isArray(displayMap) || !Number.isInteger(boardX) || !Number.isInteger(boardY)) return false\\n if (boardY < 0 || boardY >= displayMap.length) return false\\n const row = displayMap[boardY]\\n if (typeof row !== \\\"string\\\" || boardX < 0 || boardX >= row.length) return false\\n if (row[boardX] === char) return false\\n displayMap[boardY] = row.slice(0, boardX) + char + row.slice(boardX + 1)\\n markLabDisplayDirtyCell(state, boardX, boardY)\\n return true\\n}\\nfunction setLabDisplayCharAtCoords(state, x, y, char) {\\n const info = getLabBoardInfo(state?.layout)\\n if (!info) return false\\n return setLabDisplayChar(state, x - info.originX, y - info.originY, char)\\n}\\nfunction createLabDisplayMap(layout) {\\n const info = getLabBoardInfo(layout)\\n if (!info) return []\\n return Array.from({ length: info.height }, (_, rowIndex) => {\\n let row = \\\"\\\"\\n for (let colIndex = 0; colIndex < info.width; colIndex++) {\\n const x = info.originX + colIndex\\n const y = info.originY + rowIndex\\n const inBounds = x >= info.minX && x <= info.maxX && y >= info.minY && y <= info.maxY\\n if (!inBounds || (x % 2 === 0 && y % 2 === 0)) row += labMapFill\\n else if (x % 2 === 1 && y % 2 === 1) row += labMapUnknownRoom\\n else row += labMapPossibleHall\\n }\\n return row\\n })\\n}\\nfunction updateLabDisplayFromRoom(state, room) {\\n const info = getLabBoardInfo(state?.layout)\\n if (!info || !room || !Array.isArray(state.displayMap)) return\\n if (room.x < info.minX || room.x > info.maxX || room.y < info.minY || room.y > info.maxY) return\\n let changed = setLabDisplayChar(state, room.x - info.originX, room.y - info.originY,\\n room.explored ? labMapOpen : labMapUnknownRoom)\\n for (const [dir, delta] of labDirectionEntries) {\\n const exitState = room.exits?.[dir]\\n if (exitState !== true && exitState !== false) continue\\n changed = setLabDisplayCharAtCoords(state, room.x + delta.dx / 2, room.y + delta.dy / 2,\\n exitState ? labMapOpen : labMapFill) || changed\\n }\\n if (changed) {\\n state.displayVersion = (state.displayVersion ?? 0) + 1\\n state.displayOutputKey = \\\"\\\"\\n }\\n}\\nfunction syncLabDisplayMap(state, forceRebuild = false) {\\n if (!state?.layout) {\\n state.displayLayoutKey = \\\"\\\"\\n if (!Array.isArray(state.displayMap)) state.displayMap = []\\n return state.displayMap\\n }\\n const layoutKey = getLabDisplayLayoutKey(state.layout)\\n if (forceRebuild || !Array.isArray(state.displayMap) || state.displayLayoutKey !== layoutKey) {\\n state.displayMap = createLabDisplayMap(state.layout)\\n state.displayDirtyCells = []\\n state.displayDirtyLookup = {}\\n markAllLabDisplayCellsDirty(state)\\n state.displayLayoutKey = layoutKey\\n for (const room of Object.values(state.rooms)) updateLabDisplayFromRoom(state, room)\\n for (const transitionKey of Object.keys(ensureLabQuadrantGatewaySection(state))) {\\n applyLabQuadrantGatewayWalls(state, transitionKey)\\n }\\n state.displayVersion = (state.displayVersion ?? 0) + 1\\n state.displayOutputKey = \\\"\\\"\\n }\\n return state.displayMap\\n}\\nfunction buildLabMapOutput(boardRows, layout, workers = {}, anchors = {}) {\\n const info = getLabBoardInfo(layout)\\n if (!info) return Array.isArray(boardRows) ? boardRows.slice() : []\\n const rows = Array.isArray(boardRows) ? boardRows.slice() : []\\n const dirtyCells = Array.isArray(anchors.dirtyCells) ? anchors.dirtyCells : []\\n const dirtyLookup = {}\\n for (const cell of dirtyCells) {\\n if (!Array.isArray(cell) || cell.length < 2) continue\\n dirtyLookup[`${cell[0]},${cell[1]}`] = true\\n }\\n const markDirty = (boardX, boardY) => {\\n if (!Number.isInteger(boardX) || !Number.isInteger(boardY)) return\\n const key = `${boardX},${boardY}`\\n if (dirtyLookup[key] === true) return\\n dirtyLookup[key] = true\\n dirtyCells.push([boardX, boardY])\\n }\\n const setCell = (x, y, value) => {\\n const boardX = x - info.originX\\n const boardY = y - info.originY\\n if (boardY < 0 || boardY >= rows.length) return\\n const row = rows[boardY]\\n if (typeof row !== \\\"string\\\" || boardX < 0 || boardX >= row.length) return\\n if (row[boardX] === value) return\\n rows[boardY] = row.slice(0, boardX) + value + row.slice(boardX + 1)\\n markDirty(boardX, boardY)\\n }\\n for (const worker of Object.values(workers ?? {})) {\\n if (!worker || !Number.isInteger(worker.x) || !Number.isInteger(worker.y)) continue\\n setCell(worker.x, worker.y, labMapWorker)\\n }\\n const startCoords = Array.isArray(anchors.startCoords) ? anchors.startCoords : []\\n const finishX = Number.isInteger(anchors.finishX) ? anchors.finishX : layout?.finishX\\n const finishY = Number.isInteger(anchors.finishY) ? anchors.finishY : layout?.finishY\\n if (Number.isInteger(finishX) && Number.isInteger(finishY)) setCell(finishX, finishY, labMapFinish)\\n for (const [startX, startY] of startCoords) {\\n if (Number.isInteger(startX) && Number.isInteger(startY)) setCell(startX, startY, labMapStart)\\n }\\n return rows\\n}\\nfunction getLabBoardRowChar(rows, boardX, boardY) {\\n const row = Array.isArray(rows) && typeof rows[boardY] === \\\"string\\\" ? rows[boardY] : \\\"\\\"\\n return boardX >= 0 && boardX < row.length ? row[boardX] : labMapFill\\n}\\nfunction patchLabMapOutputRows(previousRows, boardRows, layout, workers = {}, anchors = {}) {\\n const info = getLabBoardInfo(layout)\\n if (!info || !Array.isArray(previousRows)) return buildLabMapOutput(boardRows, layout, workers, anchors)\\n const rows = previousRows.slice()\\n const dirtyCells = Array.isArray(anchors.dirtyCells) ? anchors.dirtyCells : []\\n const workerCells = {}\\n for (const worker of Object.values(workers ?? {})) {\\n if (!worker || !Number.isInteger(worker.x) || !Number.isInteger(worker.y)) continue\\n workerCells[`${worker.x - info.originX},${worker.y - info.originY}`] = true\\n }\\n const startCells = {}\\n const startCoords = Array.isArray(anchors.startCoords) ? anchors.startCoords : []\\n for (const [startX, startY] of startCoords) {\\n if (Number.isInteger(startX) && Number.isInteger(startY)) startCells[`${startX - info.originX},${startY - info.originY}`] = true\\n }\\n const finishX = Number.isInteger(anchors.finishX) ? anchors.finishX : layout?.finishX\\n const finishY = Number.isInteger(anchors.finishY) ? anchors.finishY : layout?.finishY\\n const finishBoardX = Number.isInteger(finishX) ? finishX - info.originX : null\\n const finishBoardY = Number.isInteger(finishY) ? finishY - info.originY : null\\n const setCell = (boardX, boardY) => {\\n if (!Number.isInteger(boardX) || !Number.isInteger(boardY) || boardY < 0 || boardY >= rows.length) return\\n const row = typeof rows[boardY] === \\\"string\\\" ? rows[boardY] : \\\"\\\"\\n if (boardX < 0 || boardX >= row.length) return\\n const key = `${boardX},${boardY}`\\n let value = getLabBoardRowChar(boardRows, boardX, boardY)\\n if (workerCells[key] === true) value = labMapWorker\\n if (finishBoardX === boardX && finishBoardY === boardY) value = labMapFinish\\n if (startCells[key] === true) value = labMapStart\\n if (row[boardX] === value) return\\n rows[boardY] = row.slice(0, boardX) + value + row.slice(boardX + 1)\\n }\\n for (const cell of dirtyCells) {\\n if (!Array.isArray(cell) || cell.length < 2) continue\\n setCell(cell[0], cell[1])\\n }\\n return rows\\n}\\nfunction buildLabMapObject(state, forceRebuild = false) {\\n if (!state?.layout) return []\\n const startCoords = state.startKeys\\n .map((key) => state.rooms[key]).filter(Boolean)\\n .map((room) => [room.x, room.y])\\n if (startCoords.length === 0 && state.rootKey && state.rooms[state.rootKey]) {\\n startCoords.push([state.rooms[state.rootKey].x, state.rooms[state.rootKey].y])\\n }\\n const board = syncLabDisplayMap(state, forceRebuild)\\n const anchorKey = `${startCoords.map((p) => p.join(\\\",\\\")).join(\\\";\\\")}|${state.layout.finishX},${state.layout.finishY}`\\n const outputKey = `${state.displayLayoutKey}|${state.displayVersion ?? 0}|${state.workersVersion ?? 0}|${anchorKey}`\\n const hasPendingDirtyCells = Array.isArray(state.displayDirtyCells) && state.displayDirtyCells.length > 0\\n if (!forceRebuild && !hasPendingDirtyCells && state.displayOutputKey === outputKey && Array.isArray(state.displayOutputRows)) {\\n return state.displayOutputRows\\n }\\n const dirtyCells = consumeLabDisplayDirtyCells(state)\\n const anchors = {\\n startCoords,\\n finishX: state.layout.finishX,\\n finishY: state.layout.finishY,\\n dirtyCells\\n }\\n const canPatch = !forceRebuild\\n && Array.isArray(state.displayOutputRows)\\n && state.displayOutputLayoutKey === state.displayLayoutKey\\n && dirtyCells.length > 0\\n const rows = canPatch\\n ? patchLabMapOutputRows(state.displayOutputRows, board, state.layout, state.workers, anchors)\\n : buildLabMapOutput(board, state.layout, state.workers, anchors)\\n state.displayOutputKey = outputKey\\n state.displayOutputLayoutKey = state.displayLayoutKey\\n state.displayOutputRows = rows\\n state.displayOutputDirtyCells = dirtyCells\\n return rows\\n}\\nfunction buildLabMapSnapshotRows(state) {\\n if (!state?.layout || !Array.isArray(state.displayMap)) return []\\n const startCoords = state.startKeys\\n .map((key) => state.rooms[key]).filter(Boolean)\\n .map((room) => [room.x, room.y])\\n if (startCoords.length === 0 && state.rootKey && state.rooms[state.rootKey]) {\\n startCoords.push([state.rooms[state.rootKey].x, state.rooms[state.rootKey].y])\\n }\\n return buildLabMapOutput(state.displayMap, state.layout, state.workers, {\\n startCoords,\\n finishX: state.layout.finishX,\\n finishY: state.layout.finishY,\\n dirtyCells: []\\n })\\n}\\nfunction getLabMapSourceKey(state) {\\n if (!state?.layout) return \\\"\\\"\\n const startKey = Array.isArray(state.startKeys) ? state.startKeys.join(\\\";\\\") : \\\"\\\"\\n return `${state.displayLayoutKey}|${state.displayVersion ?? 0}|${state.workersVersion ?? 0}|${state.rootKey ?? \\\"\\\"}|${startKey}|${state.layout.finishX},${state.layout.finishY}`\\n}\\nfunction getLabMapDimensions(map = []) {\\n if (!Array.isArray(map)) return { cols: 0, rows: 0 }\\n let cols = 0\\n for (const line of map) if (typeof line === \\\"string\\\" && line.length > cols) cols = line.length\\n return { cols, rows: map.length }\\n}\\n\\n// ----- Worker process -------------------------------------------------------\\nasync function labWork(ns, labWorker, dir) {\\n if (!labWorker) return { finished: false, workerExited: true, authResults: false }\\n ns.clearPort(ns.pid)\\n ns.writePort(labWorker, dir.toString())\\n return await readQueuedPort(ns, ns.pid)\\n}\\nasync function startLabWorker(ns, server) {\\n const host = ns.self().server\\n const scriptRam = 2\\n const freeRam = await proxyHome(ns, \\\"getServerMaxRam\\\", host) - await proxyHome(ns, \\\"getServerUsedRam\\\", host)\\n const threads = Math.floor(freeRam / scriptRam)\\n if (threads < 1) return 0\\n return ns.exec(labWorkerScriptPath, host, { threads, temporary: true }, server, ns.pid)\\n}\\n// labHunter — written to disk once per run and ns.exec'd. Listens on its\\n// own pid for a direction, calls ns.dnet.authenticate (or labreport for the\\n// bootstrap probe), writes the result to the outer process's pid port,\\n// exits only when authenticate returns a solved result instead of another\\n// labyrinth room report.\\nfunction writeLabHunter(ns) {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n let finalMessage = { finished: false, workerExited: true, authResults: false }\\n const sanitizeAuthResult = (result, includeData = false) => ({\\n success: Boolean(result?.success),\\n code: result?.code ?? null,\\n message: typeof result?.message === \\\"string\\\" ? result.message : \\\"\\\",\\n data: includeData ? (typeof result?.data === \\\"string\\\" ? result.data : result?.data ?? null) : null\\n })\\n const sanitizeLabReport = (report) => {\\n if (!report || typeof report !== \\\"object\\\") return false\\n return {\\n success: report.success !== false,\\n coords: Array.isArray(report.coords) ? report.coords.slice() : null,\\n north: Boolean(report.north),\\n east: Boolean(report.east),\\n south: Boolean(report.south),\\n west: Boolean(report.west)\\n }\\n }\\n const getRawCoordsFromAuthResult = (result) => {\\n const message = typeof result?.message === \\\"string\\\" ? result.message : \\\"\\\"\\n let idx = message.indexOf(\\\"You have moved to\\\")\\n if (idx >= 0) idx += 17\\n else {\\n idx = message.indexOf(\\\"You are still at\\\")\\n if (idx >= 0) idx += 16\\n }\\n if (idx < 0) return null\\n const parseNumber = () => {\\n while (idx < message.length && message.charCodeAt(idx) <= 32) idx++\\n let sign = 1\\n if (message[idx] === \\\"-\\\") { sign = -1; idx++ }\\n let value = 0\\n let sawDigit = false\\n while (idx < message.length) {\\n const code = message.charCodeAt(idx)\\n if (code < 48 || code > 57) break\\n value = value * 10 + code - 48\\n sawDigit = true\\n idx++\\n }\\n return sawDigit ? value * sign : null\\n }\\n const rawX = parseNumber()\\n while (idx < message.length && (message.charCodeAt(idx) <= 32 || message[idx] === \\\",\\\")) idx++\\n const rawY = parseNumber()\\n return Number.isInteger(rawX) && Number.isInteger(rawY) ? [rawX, rawY] : null\\n }\\n const parseAuthDataExits = (data) => {\\n if (typeof data !== \\\"string\\\") return null\\n const at = data.indexOf(\\\"@\\\")\\n if (at < 0) return null\\n const fillChar = ${JSON.stringify(labMapFill)}\\n const rowStart = data.lastIndexOf(\\\"\\\\\\\\n\\\", at - 1) + 1\\n let rowEnd = data.indexOf(\\\"\\\\\\\\n\\\", at)\\n if (rowEnd < 0) rowEnd = data.length\\n if (rowEnd > rowStart && data.charCodeAt(rowEnd - 1) === 13) rowEnd--\\n const atX = at - rowStart\\n const isOpenAt = (idx, start, end) => idx >= start && idx < end && data[idx] !== fillChar && data.charCodeAt(idx) !== 10 && data.charCodeAt(idx) !== 13\\n const rowAt = (start, x) => {\\n if (start < 0) return null\\n let end = data.indexOf(\\\"\\\\\\\\n\\\", start)\\n if (end < 0) end = data.length\\n if (end > start && data.charCodeAt(end - 1) === 13) end--\\n return { start, end, idx: start + x }\\n }\\n const prevBreak = rowStart > 0 ? data.lastIndexOf(\\\"\\\\\\\\n\\\", rowStart - 2) : -1\\n let prevEnd = rowStart > 0 ? rowStart - 1 : -1\\n if (prevEnd > 0 && data.charCodeAt(prevEnd - 1) === 13) prevEnd--\\n const prevStart = rowStart > 0 ? prevBreak + 1 : -1\\n const nextBreak = data.indexOf(\\\"\\\\\\\\n\\\", rowEnd)\\n const next = nextBreak >= 0 ? rowAt(nextBreak + 1, atX) : null\\n return {\\n north: isOpenAt(prevStart + atX, prevStart, prevEnd),\\n east: isOpenAt(at + 1, rowStart, rowEnd),\\n south: next ? isOpenAt(next.idx, next.start, next.end) : false,\\n west: isOpenAt(at - 1, rowStart, rowEnd)\\n }\\n }\\n const getAuthLabReport = (result) => {\\n const coords = getRawCoordsFromAuthResult(result)\\n const exits = parseAuthDataExits(result?.data)\\n if (!Array.isArray(coords) || !exits) return false\\n return {\\n success: true,\\n coords,\\n north: exits.north === true,\\n east: exits.east === true,\\n south: exits.south === true,\\n west: exits.west === true\\n }\\n }\\n const currentRoomCommand = ${JSON.stringify(labCurrentRoomCommand)}\\n ns.nextPortWrite(24).then(() => { ns.clearPort(26); ns.exit() })\\n ns.atExit(() => { ns.writePort(ns.args[1], finalMessage) })\\n while (true) {\\n let dir = ns.readPort(ns.pid)\\n if (dir === \\\"NULL PORT DATA\\\") {\\n await ns.nextPortWrite(ns.pid)\\n dir = ns.readPort(ns.pid)\\n }\\n if (typeof dir !== \\\"string\\\") dir = \\\"\\\"\\n if (dir === currentRoomCommand) {\\n ns.writePort(ns.args[1], { finished: false, report: sanitizeLabReport(await ns.dnet.labreport()), authResults: false })\\n continue\\n }\\n const results = await ns.dnet.authenticate(ns.args[0], dir)\\n const movementReport = getAuthLabReport(results)\\n const response = {\\n finished: Boolean(results?.success) && !movementReport,\\n report: movementReport,\\n authResults: sanitizeAuthResult(results, Boolean(results?.success) && !movementReport),\\n dir\\n }\\n if (response.finished) {\\n finalMessage = response\\n ns.writePort(ns.args[1], response)\\n ns.exit()\\n } else {\\n ns.writePort(ns.args[1], response)\\n }\\n }\\n}`\\n ns.write(labWorkerScriptPath, data, \\\"w\\\")\\n}\\n\\n// ----- Picker — pickGreedyStep ----------------------------------------------\\n// Priority chain:\\n// 1. Unexplored goalward\\n// 2. Unexplored forward (off-axis)\\n// 3. Bounded route through explored rooms to the nearest viable frontier.\\n// 4. Backstep from exhausted rooms.\\n//\\n// Once inside the exit quadrant, same-quadrant and exit-subquadrant\\n// routes outrank shorter paths that leave through an old boundary.\\n//\\n// Back direction is the inverse of the visit-stack top. It is still\\n// checked against dead-room markers unless it is crossing quadrants or\\n// following a recorded dead-area escape.\\n// ============================================================================\\n// Dead-end tracking.\\n//\\n// A \\\"dead end\\\" is a room from which only one open exit still leads to a\\n// non-dead cell — that one direction is the room's escape. Leaves\\n// (1-exit rooms) are dead with escape = the entry exit. Corridors whose\\n// far end is dead become dead with escape = the surviving direction.\\n// Propagation is incremental: when a room is newly marked dead, every\\n// open neighbour is re-evaluated, which can trigger further marking up\\n// the chain.\\n//\\n// Stored on labState.deadEndEntries as one append-only section:\\n// { [roomKey]: escapeDir }\\n// Every worker reads this same object; a worker that walks into an\\n// already-marked dead-end cell uses the escape immediately rather than\\n// re-deriving anything.\\n// Sealed cells (zero live exits) get escape = \\\"\\\" — the picker treats\\n// these as terminal.\\n// ============================================================================\\nfunction appendLabDeadEndEntry(state, key, escape = \\\"\\\") {\\n if (!state || typeof key !== \\\"string\\\" || !key) return false\\n const coords = getLabCoordsFromKey(key)\\n if (coords && isLabProtectedDeadAreaCell(state, coords[0], coords[1])) return false\\n const entries = ensureLabDeadEndEntries(state)\\n if (Object.prototype.hasOwnProperty.call(entries, key)) return false\\n entries[key] = typeof escape === \\\"string\\\" && labDirections[escape] ? escape : \\\"\\\"\\n if (coords) {\\n setLabDeadRouteCost(state, coords[0], coords[1], Number.POSITIVE_INFINITY)\\n enqueueLabDeadAreaAround(state, coords[0], coords[1])\\n }\\n return true\\n}\\nfunction isLabDeadEndRoom(state, x, y) {\\n if (!state) return false\\n if (isLabProtectedDeadAreaCell(state, x, y)) return false\\n const entries = ensureLabDeadEndEntries(state)\\n return Object.prototype.hasOwnProperty.call(entries, getLabKey(x, y))\\n}\\nfunction getLabDeadEndEscape(state, x, y) {\\n if (!state) return null\\n if (isLabProtectedDeadAreaCell(state, x, y)) return null\\n const entries = ensureLabDeadEndEntries(state)\\n const key = getLabKey(x, y)\\n return Object.prototype.hasOwnProperty.call(entries, key) ? entries[key] : null\\n}\\nfunction canLabDeadEscapeReachOpen(state, currentX, currentY, dir, context = getLabInfluenceContext(state)) {\\n const delta = labDirections[dir]\\n const layout = state?.layout\\n if (!delta || !layout) return false\\n const seen = new Set([getLabKey(currentX, currentY)])\\n let x = currentX + delta.dx\\n let y = currentY + delta.dy\\n const roomCols = Math.floor((layout.maxX - layout.minX) / 2) + 1\\n const roomRows = Math.floor((layout.maxY - layout.minY) / 2) + 1\\n const maxSteps = Math.max(16, roomCols * roomRows)\\n for (let step = 0; step < maxSteps; step++) {\\n if (x < layout.minX || x > layout.maxX || y < layout.minY || y > layout.maxY) return false\\n if (!isLabSameQuadrantCell(state, currentX, currentY, x, y, context)) return false\\n const key = getLabKey(x, y)\\n if (seen.has(key)) return false\\n if (!isLabDeadEndRoom(state, x, y)) return true\\n seen.add(key)\\n const escape = getLabDeadEndEscape(state, x, y)\\n const escapeDelta = labDirections[escape]\\n if (!escapeDelta) return false\\n x += escapeDelta.dx\\n y += escapeDelta.dy\\n }\\n return false\\n}\\nfunction createLabMoveGate(state, options = {}) {\\n const context = options?.context ?? getLabInfluenceContext(state)\\n const skipKeys = getLabPickSkipSet(options)\\n const moveCache = new Map()\\n const deadRoomCache = new Map()\\n const escapeCache = new Map()\\n const checkDeadRoom = (x, y) => {\\n const key = getLabKey(x, y)\\n if (!deadRoomCache.has(key)) deadRoomCache.set(key, isLabDeadEndRoom(state, x, y))\\n return deadRoomCache.get(key)\\n }\\n const getEscape = (x, y) => {\\n const key = getLabKey(x, y)\\n if (!escapeCache.has(key)) escapeCache.set(key, getLabDeadEndEscape(state, x, y))\\n return escapeCache.get(key)\\n }\\n const check = (currentX, currentY, dir, checkOptions = {}) => {\\n const cacheKey = `${getLabKey(currentX, currentY)}:${dir}:${checkOptions.ignoreSkip === true ? 1 : 0}`\\n if (moveCache.has(cacheKey)) return moveCache.get(cacheKey)\\n const delta = labDirections[dir]\\n if (!state || !delta || !Number.isInteger(currentX) || !Number.isInteger(currentY)) {\\n const result = { allowed: false, reason: \\\"invalid\\\" }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const nextX = currentX + delta.dx\\n const nextY = currentY + delta.dy\\n if (isLabQuadrantEntryBlocked(state, currentX, currentY, dir)) {\\n const result = { allowed: false, reason: \\\"quadrant-entry\\\", x: nextX, y: nextY }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const crossing = getLabQuadrantTransitionForDir(state, currentX, currentY, dir, context)\\n if (crossing) {\\n const currentRoom = state.rooms?.[getLabKey(currentX, currentY)]\\n if (currentRoom?.explored === true && currentRoom.exits?.[dir] !== true) {\\n const result = { allowed: false, reason: \\\"wall\\\", x: nextX, y: nextY, crossing, gateway: false }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const nextRoom = state.rooms?.[getLabKey(nextX, nextY)]\\n const back = labDirections[dir].back\\n if (nextRoom?.explored === true && nextRoom.exits?.[back] === false) {\\n const result = { allowed: false, reason: \\\"back-wall\\\", x: nextX, y: nextY, crossing, gateway: false }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const gateway = ensureLabQuadrantGatewaySection(state)[crossing.transitionKey]\\n if (!isLabLiveQuadrantCrossing(state, currentX, currentY, dir, context)) {\\n const reason = gateway?.edgeKey && gateway.edgeKey !== crossing.edgeKey ? \\\"quadrant-wall\\\" : \\\"worse-quadrant\\\"\\n const result = { allowed: false, reason, x: nextX, y: nextY, crossing, gateway: false }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const result = {\\n allowed: true,\\n reason: \\\"quadrant-gateway\\\",\\n x: nextX,\\n y: nextY,\\n crossing,\\n gateway: Boolean(gateway?.edgeKey && gateway.edgeKey === crossing.edgeKey)\\n }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n if (checkOptions.ignoreSkip !== true && isLabPickSkipped(skipKeys, nextX, nextY)) {\\n const result = { allowed: false, reason: \\\"skipped\\\", x: nextX, y: nextY }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n if (!checkDeadRoom(nextX, nextY)) {\\n const result = { allowed: true, reason: \\\"open\\\", x: nextX, y: nextY }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const escape = getEscape(currentX, currentY)\\n if (escape && escape === dir && canLabDeadEscapeReachOpen(state, currentX, currentY, dir, context)) {\\n const result = { allowed: true, reason: \\\"dead-escape\\\", x: nextX, y: nextY }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n const result = { allowed: false, reason: \\\"dead\\\", x: nextX, y: nextY }\\n moveCache.set(cacheKey, result)\\n return result\\n }\\n return { context, check, isDeadRoom: checkDeadRoom, getEscape }\\n}\\nfunction isLabDeadMoveBlocked(state, currentX, currentY, dir, context = getLabInfluenceContext(state)) {\\n return !createLabMoveGate(state, { context }).check(currentX, currentY, dir).allowed\\n}\\nfunction canLabDeadNeighbourCarryEscape(state, dirFromCurrent, neighbourX, neighbourY) {\\n const neighbourEscape = getLabDeadEndEscape(state, neighbourX, neighbourY)\\n if (!neighbourEscape) return false\\n return neighbourEscape !== labDirections[dirFromCurrent]?.back\\n}\\nfunction getLabKnownFrontierEscapeDir(state, x, y) {\\n const candidates = []\\n for (const [dir, delta] of labDirectionEntries) {\\n if (isLabQuadrantEntryBlocked(state, x, y, dir)) continue\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (!isLabSameQuadrantMove(state, x, y, nx, ny)) continue\\n if (isLabWorseQuadrantMove(state, x, y, nx, ny)) continue\\n const neighbour = state?.rooms?.[getLabKey(nx, ny)]\\n const back = labDirections[dir].back\\n if (neighbour?.explored && neighbour.exits?.[back] === true) {\\n candidates.push({\\n dir,\\n protectedRank: isLabProtectedDeadAreaCell(state, nx, ny) ? 0 : 1,\\n deadRank: isLabDeadEndRoom(state, nx, ny) ? 1 : 0,\\n pathLength: Array.isArray(neighbour.path) ? neighbour.path.length : 9999,\\n dirIndex: labDirectionIndex[dir] ?? 99\\n })\\n }\\n }\\n candidates.sort((a, b) => a.protectedRank - b.protectedRank\\n || a.deadRank - b.deadRank\\n || a.pathLength - b.pathLength\\n || a.dirIndex - b.dirIndex)\\n return candidates[0]?.dir ?? \\\"\\\"\\n}\\nfunction reevaluateLabDeadEnd(state, x, y) {\\n // Recompute (x, y)'s dead status from current room exits + neighbour\\n // dead flags. Returns true iff the result differs from the previous\\n // value (so the caller can decide to propagate). Never marks protected\\n // endpoint cells.\\n const key = getLabKey(x, y)\\n const room = state?.rooms?.[key]\\n if (!room?.explored || !room.exits) return false\\n const context = getLabInfluenceContext(state)\\n if (isLabProtectedDeadAreaCell(state, x, y, context)) return false\\n if (state.layout && Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)\\n && state.layout.finishX === x && state.layout.finishY === y) return false\\n const wasDead = isLabDeadEndRoom(state, x, y)\\n const previousEscape = wasDead ? getLabDeadEndEscape(state, x, y) : null\\n const deadRouteOptions = { allowStartSubquadrantExplored: true }\\n const layout = state.layout\\n const routeGate = createLabMoveGate(state, { context })\\n let survivingDir = \\\"\\\"\\n let survivingCount = 0\\n let survivingFrontierCount = 0\\n let survivingQuadrantExitCount = 0\\n for (const [dir, delta] of labDirectionEntries) {\\n if (room.exits?.[dir] !== true) continue\\n if (isLabQuadrantEntryBlocked(state, x, y, dir)) continue\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (layout && (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY)) continue\\n if (isLabWorseQuadrantMove(state, x, y, nx, ny, context)) continue\\n if (!isLabSameQuadrantMove(state, x, y, nx, ny, context)) {\\n if (!isLabLiveQuadrantCrossing(state, x, y, dir, context)) continue\\n survivingCount++\\n survivingQuadrantExitCount++\\n survivingDir = dir\\n continue\\n }\\n const neighbourDead = isLabDeadEndRoom(state, nx, ny)\\n if (neighbourDead && (!wasDead || previousEscape !== dir || !canLabDeadNeighbourCarryEscape(state, dir, nx, ny))) continue\\n const neighbour = state.rooms?.[getLabKey(nx, ny)]\\n if (neighbour?.explored !== true) {\\n if (!hasLabPotentialRouteToLiveTarget(state, nx, ny, routeGate, context, { ...deadRouteOptions, boundQuadrant: true, forceRefresh: true, originX: nx, originY: ny })) {\\n appendLabDeadEndEntry(state, getLabKey(nx, ny), labDirections[dir].back)\\n continue\\n }\\n survivingFrontierCount++\\n }\\n survivingCount++\\n survivingDir = dir\\n }\\n // If ANY surviving exit points at an unexplored frontier, the cell is\\n // not yet a dead-end — that frontier might lead to anywhere, including\\n // the goal. Hold off on marking until enough exploration has resolved\\n // every neighbour into either a confirmed dead cell or a confirmed\\n // alive (explored) one.\\n if (survivingFrontierCount > 0) {\\n return false\\n }\\n if (survivingQuadrantExitCount > 0) {\\n return false\\n }\\n if (survivingCount >= 2) {\\n return false\\n }\\n // 0 or 1 surviving live exits. Default: mark dead with escape =\\n // surviving dir (or \\\"\\\" when fully sealed). Only true live endpoints\\n // keep this room alive; the start subquadrant is traversable, not a goal.\\n if (survivingCount === 1 && context) {\\n const delta = labDirections[survivingDir]\\n const sx = x + (delta?.dx ?? 0)\\n const sy = y + (delta?.dy ?? 0)\\n if (isLabProtectedDeadSurvivalCell(state, sx, sy, context)) {\\n return false\\n }\\n }\\n const nextEscape = survivingCount === 1 ? survivingDir : \\\"\\\"\\n if (wasDead && previousEscape === nextEscape) return false\\n return appendLabDeadEndEntry(state, key, nextEscape)\\n}\\n// Predictive dead-end marker for an UNEXPLORED frontier cell. Explored\\n// neighbours are treated as blocked for the potential-route check; the\\n// frontier only stays live if unknown space can still reach a goalward\\n// quadrant border pathway or the exit area.\\nfunction evaluateLabFrontierLeaf(state, x, y) {\\n if (!state?.layout) return false\\n const key = getLabKey(x, y)\\n const room = state.rooms?.[key]\\n if (!room || room.explored) return false\\n if (Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)\\n && state.layout.finishX === x && state.layout.finishY === y) return false\\n if (isLabDeadEndRoom(state, x, y)) return false\\n // Frontier cells INSIDE the exit sub-quadrant are part of the goal\\n // area and must stay reachable — even one-opening pockets there\\n // could turn out to be the gateway to the exit cell once explored.\\n const context = getLabInfluenceContext(state)\\n if (isLabProtectedDeadAreaCell(state, x, y, context)) return false\\n if (context && isLabInExitSubquadrant(x, y, context)) return false\\n if (context && isLabInStartSubquadrant(x, y, context)) return false\\n const routeGate = createLabMoveGate(state, { context })\\n if (hasLabPotentialRouteToLiveTarget(state, x, y, routeGate, context, { allowStartSubquadrantExplored: true, boundQuadrant: true, forceRefresh: true, originX: x, originY: y })) return false\\n const escapeDir = getLabKnownFrontierEscapeDir(state, x, y)\\n const delta = labDirections[escapeDir]\\n if (!appendLabDeadEndEntry(state, key, escapeDir)) return false\\n if (delta) propagateLabDeadEndFromRoom(state, x + delta.dx, y + delta.dy)\\n return true\\n}\\nfunction evaluateLabFrontierLeavesAround(state, x, y) {\\n if (!state?.layout) return false\\n let changed = false\\n for (const [, delta] of labDirectionEntries) {\\n if (evaluateLabFrontierLeaf(state, x + delta.dx, y + delta.dy)) changed = true\\n }\\n return changed\\n}\\nfunction isLabPotentialTouchingExploredBlocked(state, x, y, fromX, fromY, context = getLabInfluenceContext(state), options = {}) {\\n if (!state?.rooms || !context) return false\\n if (!Number.isInteger(x) || !Number.isInteger(y)) return true\\n if (options?.originX === x && options?.originY === y) return false\\n if (isLabProtectedDeadAreaCell(state, x, y, context)) return false\\n const room = state.rooms[getLabKey(x, y)]\\n if (room?.explored === true) return false\\n const allowStartExplored = (options?.allowStartSubquadrantExplored === true || options?.allowStartQuadrantExplored === true)\\n && Number.isInteger(options?.originX)\\n && Number.isInteger(options?.originY)\\n && isLabInStartSubquadrant(options.originX, options.originY, context)\\n && isLabInStartSubquadrant(x, y, context)\\n if (allowStartExplored) return false\\n if (isLabInExitSubquadrant(x, y, context)) return false\\n for (const [dir, delta] of labDirectionEntries) {\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (nx === fromX && ny === fromY) continue\\n const neighbour = state.rooms[getLabKey(nx, ny)]\\n const back = labDirections[dir].back\\n if (neighbour?.explored === true && neighbour.exits?.[back] === true) return true\\n }\\n return false\\n}\\nfunction getLabDirectionBetween(fromX, fromY, toX, toY) {\\n for (const [dir, delta] of labDirectionEntries) {\\n if (fromX + delta.dx === toX && fromY + delta.dy === toY) return dir\\n }\\n return \\\"\\\"\\n}\\nfunction isLabProtectedDeadAreaCell(state, x, y, context = getLabInfluenceContext(state)) {\\n const key = getLabKey(x, y)\\n if (state?.layout && Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)\\n && state.layout.finishX === x && state.layout.finishY === y) return true\\n if (isLabKnownQuadrantGatewayCell(state, x, y)) return true\\n if (Array.isArray(state?.startKeys) && state.startKeys.includes(key)) {\\n return Boolean(context && isLabInStartSubquadrant(x, y, context))\\n }\\n const room = state?.rooms?.[key]\\n return Boolean(context\\n && room?.explored !== true\\n && (isLabInExitSubquadrant(x, y, context) || isLabInStartSubquadrant(x, y, context)))\\n}\\nfunction isLabProtectedDeadSurvivalCell(state, x, y, context = getLabInfluenceContext(state)) {\\n if (state?.layout && Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)\\n && state.layout.finishX === x && state.layout.finishY === y) return true\\n if (isLabKnownQuadrantGatewayCell(state, x, y)) return true\\n const room = state?.rooms?.[getLabKey(x, y)]\\n return Boolean(context && room?.explored !== true && isLabInExitSubquadrant(x, y, context))\\n}\\nfunction pruneLabProtectedDeadMarks(state) {\\n ensureLabDeadEndEntries(state)\\n return false\\n}\\nfunction getLabDeadAreaEdgeCacheKey(state, sourceX, sourceY, dir, context = getLabInfluenceContext(state)) {\\n const signature = `${getLabInfluenceSignature(context)}|${getLabQuadrantGatewaySignature(state)}`\\n return `${signature}|${getLabKey(sourceX, sourceY)}:${dir}`\\n}\\nfunction setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, status, context = getLabInfluenceContext(state)) {\\n if (!state || !labDirections[dir]) return false\\n ensureLabDeadAreaEdgeCache(state)[getLabDeadAreaEdgeCacheKey(state, sourceX, sourceY, dir, context)] = status\\n return true\\n}\\nfunction getLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, context = getLabInfluenceContext(state)) {\\n if (!state || !labDirections[dir]) return \\\"\\\"\\n return ensureLabDeadAreaEdgeCache(state)[getLabDeadAreaEdgeCacheKey(state, sourceX, sourceY, dir, context)] ?? \\\"\\\"\\n}\\nfunction markLabDeadAreaFromEdge(state, sourceX, sourceY, dir, context = getLabInfluenceContext(state)) {\\n const cached = getLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, context)\\n if (cached === \\\"closed\\\" || cached === \\\"blocked\\\") return false\\n const sourceRoom = state?.rooms?.[getLabKey(sourceX, sourceY)]\\n const delta = labDirections[dir]\\n const layout = state?.layout\\n if (!sourceRoom?.explored || !delta || !layout) return false\\n if (sourceRoom.exits?.[dir] !== true) {\\n if (sourceRoom.exits?.[dir] === false) setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"blocked\\\", context)\\n return false\\n }\\n if (isLabQuadrantEntryBlocked(state, sourceX, sourceY, dir)) {\\n setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"blocked\\\", context)\\n return false\\n }\\n const startX = sourceX + delta.dx\\n const startY = sourceY + delta.dy\\n if (startX < layout.minX || startX > layout.maxX || startY < layout.minY || startY > layout.maxY) {\\n setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"blocked\\\", context)\\n return false\\n }\\n if (!isLabSameQuadrantMove(state, sourceX, sourceY, startX, startY, context)) {\\n if (isLabLiveQuadrantCrossing(state, sourceX, sourceY, dir, context)) return false\\n setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"blocked\\\", context)\\n return false\\n }\\n if (isLabWorseQuadrantMove(state, sourceX, sourceY, startX, startY, context)) {\\n setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"blocked\\\", context)\\n return false\\n }\\n const sourceKey = getLabKey(sourceX, sourceY)\\n const startKey = getLabKey(startX, startY)\\n const startRoom = state.rooms?.[startKey]\\n if (!startRoom || isLabProtectedDeadAreaCell(state, startX, startY, context)) return false\\n\\n const queue = [{ x: startX, y: startY, key: startKey, escape: delta.back }]\\n const seen = new Set([sourceKey])\\n const branchRooms = []\\n let head = 0\\n while (head < queue.length) {\\n const node = queue[head++]\\n if (seen.has(node.key)) continue\\n seen.add(node.key)\\n const room = state.rooms?.[node.key]\\n if (!room) return false\\n if (!room.explored) {\\n if (!isLabDeadEndRoom(state, node.x, node.y)) return false\\n continue\\n }\\n if (isLabProtectedDeadAreaCell(state, node.x, node.y, context)) return false\\n branchRooms.push(node)\\n for (const [nextDir, nextDelta] of labDirectionEntries) {\\n if (room.exits?.[nextDir] !== true) continue\\n if (isLabQuadrantEntryBlocked(state, node.x, node.y, nextDir)) continue\\n const nx = node.x + nextDelta.dx\\n const ny = node.y + nextDelta.dy\\n if (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY) return false\\n if (!isLabSameQuadrantMove(state, node.x, node.y, nx, ny, context)) {\\n if (isLabLiveQuadrantCrossing(state, node.x, node.y, nextDir, context)) return false\\n continue\\n }\\n if (isLabWorseQuadrantMove(state, node.x, node.y, nx, ny, context)) continue\\n const nextKey = getLabKey(nx, ny)\\n if (seen.has(nextKey)) continue\\n const nextRoom = state.rooms?.[nextKey]\\n if (!nextRoom) return false\\n if (!nextRoom.explored && !isLabDeadEndRoom(state, nx, ny)) return false\\n queue.push({ x: nx, y: ny, key: nextKey, escape: getLabDirectionBetween(nx, ny, node.x, node.y) })\\n }\\n }\\n if (branchRooms.length === 0) return false\\n let changed = false\\n for (const room of branchRooms) {\\n if (!room.escape || isLabProtectedDeadAreaCell(state, room.x, room.y, context)) continue\\n if (appendLabDeadEndEntry(state, room.key, room.escape)) changed = true\\n }\\n setLabDeadAreaEdgeCached(state, sourceX, sourceY, dir, \\\"closed\\\", context)\\n return changed\\n}\\nfunction evaluateLabDeadAreasAround(state, x, y) {\\n if (!state?.layout) return false\\n const context = getLabInfluenceContext(state)\\n enqueueLabDeadAreaAround(state, x, y, context)\\n const sourceKeys = new Set([getLabKey(x, y)])\\n const seedRoom = state.rooms?.[getLabKey(x, y)]\\n if (seedRoom?.explored && seedRoom.exits) {\\n for (const [, delta] of labDirectionEntries) {\\n const neighbour = state.rooms?.[getLabKey(x + delta.dx, y + delta.dy)]\\n if (neighbour?.explored && isLabSameQuadrantMove(state, x, y, neighbour.x, neighbour.y, context)) {\\n sourceKeys.add(getLabKey(neighbour.x, neighbour.y))\\n }\\n }\\n }\\n let changed = false\\n for (const key of sourceKeys) {\\n const room = state.rooms?.[key]\\n if (!room?.explored || !room.exits) continue\\n for (const [dir] of labDirectionEntries) {\\n if (markLabDeadAreaFromEdge(state, room.x, room.y, dir, context)) changed = true\\n }\\n }\\n if (changed) {\\n for (const key of sourceKeys) {\\n const room = state.rooms?.[key]\\n if (room?.explored) propagateLabDeadEndFromRoom(state, room.x, room.y)\\n }\\n }\\n return changed\\n}\\nfunction drainLabDeadAreaQueue(state, context = getLabInfluenceContext(state), budget = labDeadAreaDrainBudget) {\\n if (!state?.layout || !state.rooms || !context) return false\\n const queue = ensureLabDeadAreaQueue(state)\\n let changed = false\\n let processed = 0\\n while (queue.length > 0 && processed < budget) {\\n const key = queue.pop()\\n processed++\\n if (state.deadAreaQueued) delete state.deadAreaQueued[key]\\n if (typeof key !== \\\"string\\\" || !key) continue\\n const room = state.rooms[key]\\n if (!room?.explored || !room.exits) continue\\n let sourceChanged = false\\n if (evaluateLabFrontierLeavesAround(state, room.x, room.y)) sourceChanged = true\\n for (const [dir] of labDirectionEntries) {\\n if (markLabDeadAreaFromEdge(state, room.x, room.y, dir, context)) sourceChanged = true\\n }\\n if (reevaluateLabDeadEnd(state, room.x, room.y)) sourceChanged = true\\n if (sourceChanged) {\\n changed = true\\n propagateLabDeadEndFromRoom(state, room.x, room.y)\\n }\\n }\\n return changed\\n}\\nfunction propagateLabDeadEndFromRoom(state, x, y) {\\n const queue = [getLabKey(x, y)]\\n const seen = new Set()\\n const context = getLabInfluenceContext(state)\\n let head = 0\\n while (head < queue.length) {\\n const key = queue[head++]\\n if (seen.has(key)) continue\\n seen.add(key)\\n const coords = getLabCoordsFromKey(key)\\n if (!coords) continue\\n const cellX = coords[0]\\n const cellY = coords[1]\\n if (!reevaluateLabDeadEnd(state, cellX, cellY)) continue\\n const room = state?.rooms?.[key]\\n if (!room?.explored || !room.exits) continue\\n for (const [dir, delta] of labDirectionEntries) {\\n if (room.exits?.[dir] !== true) continue\\n if (isLabQuadrantEntryBlocked(state, cellX, cellY, dir)) continue\\n if (!isLabSameQuadrantMove(state, cellX, cellY, cellX + delta.dx, cellY + delta.dy, context)) continue\\n if (isLabWorseQuadrantMove(state, cellX, cellY, cellX + delta.dx, cellY + delta.dy, context)) continue\\n const nkey = getLabKey(cellX + delta.dx, cellY + delta.dy)\\n if (!seen.has(nkey)) queue.push(nkey)\\n }\\n }\\n}\\nfunction getLabDeadCheckKey(state, x, y, context = getLabInfluenceContext(state)) {\\n const signature = `${getLabInfluenceSignature(context)}|${getLabQuadrantGatewaySignature(state)}`\\n return `${signature}|${getLabKey(x, y)}`\\n}\\nfunction getLabRoomExitSignature(room) {\\n if (!room?.exits) return \\\"\\\"\\n return labDirectionEntries.map(([dir]) => room.exits?.[dir] === true ? \\\"1\\\" : \\\"0\\\").join(\\\"\\\")\\n}\\nfunction updateLabDeadKnowledgeFromRoom(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!state?.rooms || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n const room = state.rooms[getLabKey(x, y)]\\n if (!room?.explored || !room.exits) return false\\n const key = getLabDeadCheckKey(state, x, y, context)\\n const exitSignature = getLabRoomExitSignature(room)\\n const checks = ensureLabDeadKnowledgeChecks(state)\\n if (checks[key] === exitSignature) return false\\n checks[key] = exitSignature\\n ensureLabDeadPrefilterChecks(state)[key] = exitSignature\\n let changed = evaluateLabFrontierLeavesAround(state, x, y)\\n if (evaluateLabDeadAreasAround(state, x, y)) changed = true\\n propagateLabDeadEndFromRoom(state, x, y)\\n if (drainLabDeadAreaQueue(state, context)) changed = true\\n return changed\\n}\\nfunction prepareLabDeadRoomMoveFilter(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!state?.rooms || !Number.isInteger(x) || !Number.isInteger(y)) return false\\n let changed = drainLabDeadAreaQueue(state, context)\\n const room = state.rooms[getLabKey(x, y)]\\n if (!room?.explored || !room.exits) return changed\\n const key = getLabDeadCheckKey(state, x, y, context)\\n const exitSignature = getLabRoomExitSignature(room)\\n if (ensureLabDeadKnowledgeChecks(state)[key] === exitSignature) return changed\\n const checks = ensureLabDeadPrefilterChecks(state)\\n if (checks[key] === exitSignature) return changed\\n checks[key] = exitSignature\\n if (evaluateLabFrontierLeavesAround(state, x, y)) changed = true\\n enqueueLabDeadAreaAround(state, x, y, context)\\n if (drainLabDeadAreaQueue(state, context)) changed = true\\n return changed\\n}\\n\\n// ============================================================================\\n// pickGreedyStep — direction picker with the priority chain\\n//\\n// FORCED ESCAPE. If the current cell is a marked dead-end with a non-\\n// empty escape direction, return that direction immediately. Workers\\n// entering a dead-end pocket (including new workers spawning into one)\\n// take the recorded one-way exit without re-deriving anything.\\n//\\n// ALL-EXPLORED COST GATE. If every gated exit in the current choice set\\n// has already been explored, choose the lowest cached dead-route cost.\\n// This reads deadRouteCosts only; it does not run a fresh BFS.\\n//\\n// PRIORITY 1 — goal-forward. Any open exit that's in the influence\\n// context's goalDirs (toward the cross-quadrant boundary or, inside\\n// the goal quadrant, toward the exit corner). Excludes the back\\n// direction. Ties broken by: unexplored neighbour first; when both\\n// candidates are unexplored inside this same picker tier, lowest\\n// dead-route potential cost; then lowest labDirectionIndex\\n// (north < east < south < west) for deterministic choices.\\n//\\n// PRIORITY 2 — side-forward. Open exits that are not goal-forward and\\n// not the back direction. Same-tier tiebreakers match priority 1.\\n//\\n// PRIORITY 3 — backstep. Only fires when both priorities above are\\n// empty. Uses the visit-stack inverse so the worker retraces exactly\\n// the path it walked.\\n//\\n// Dead-end gating: candidates whose neighbour cell is in the\\n// deadEndEntries section are filtered out unless they cross quadrants or\\n// follow a recorded dead-area escape.\\n// ============================================================================\\nfunction getLabPickSkipSet(options = {}) {\\n const skipKeys = options?.skipKeys\\n if (skipKeys instanceof Set) return skipKeys\\n if (Array.isArray(skipKeys)) return new Set(skipKeys)\\n return null\\n}\\nfunction isLabPickSkipped(skipKeys, x, y) {\\n return skipKeys instanceof Set && skipKeys.has(getLabKey(x, y))\\n}\\nfunction isLabPotentialGoalCell(state, x, y, context = getLabInfluenceContext(state)) {\\n const layout = state?.layout\\n if (!layout) return false\\n if (Number.isInteger(layout.finishX) && Number.isInteger(layout.finishY)) {\\n return x === layout.finishX && y === layout.finishY\\n }\\n if (context && isLabInExitSubquadrant(x, y, context)) return true\\n return x === layout.goalX && y === layout.goalY\\n}\\nfunction isLabPotentialQuadrantBorderPathway(state, x, y, gate, context = gate?.context ?? getLabInfluenceContext(state)) {\\n const layout = state?.layout\\n if (!layout || !context) return false\\n if (x < layout.minX || x > layout.maxX || y < layout.minY || y > layout.maxY) return false\\n for (const [dir] of labDirectionEntries) {\\n if (isLabQuadrantEntryBlocked(state, x, y, dir)) continue\\n const crossing = getLabQuadrantTransitionForDir(state, x, y, dir, context)\\n if (!crossing) continue\\n if (!isLabLiveQuadrantCrossing(state, x, y, dir, context)) continue\\n const gateResult = gate?.check\\n ? gate.check(x, y, dir, { ignoreSkip: true })\\n : createLabMoveGate(state, { context }).check(x, y, dir, { ignoreSkip: true })\\n if (gateResult.allowed === true) return true\\n }\\n return false\\n}\\nfunction isLabPotentialLiveTarget(state, x, y, gate, context = gate?.context ?? getLabInfluenceContext(state), options = {}) {\\n return isLabPotentialGoalCell(state, x, y, context)\\n || isLabPotentialQuadrantBorderPathway(state, x, y, gate, context)\\n}\\nfunction canLabPotentialTraverse(state, x, y, dir, gate, context = getLabInfluenceContext(state), options = {}) {\\n const delta = labDirections[dir]\\n const layout = state?.layout\\n if (!delta || !layout) return false\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY) return false\\n const originX = Number.isInteger(options.originX) ? options.originX : x\\n const originY = Number.isInteger(options.originY) ? options.originY : y\\n if (options?.boundQuadrant === true) {\\n if (!isLabSameQuadrantCell(state, originX, originY, nx, ny, context)) return false\\n }\\n const room = state.rooms?.[getLabKey(x, y)]\\n const allowExitExplored = Boolean(context && isLabInExitSubquadrant(x, y, context))\\n const allowStartExplored = (options?.allowStartSubquadrantExplored === true || options?.allowStartQuadrantExplored === true)\\n && context\\n && isLabInStartSubquadrant(originX, originY, context)\\n && isLabInStartSubquadrant(x, y, context)\\n if (!allowStartExplored && !allowExitExplored && room?.explored === true) return false\\n if (room?.explored && room.exits?.[dir] !== true) return false\\n const nextRoom = state.rooms?.[getLabKey(nx, ny)]\\n const nextAllowExitExplored = Boolean(context && isLabInExitSubquadrant(nx, ny, context))\\n if (!allowStartExplored && !nextAllowExitExplored && nextRoom?.explored === true) return false\\n if (nextRoom?.explored !== true && isLabPotentialTouchingExploredBlocked(state, nx, ny, x, y, context, options)) return false\\n const back = labDirections[dir].back\\n if (nextRoom?.explored && nextRoom.exits?.[back] === false) return false\\n const gateResult = gate?.check\\n ? gate.check(x, y, dir, { ignoreSkip: true })\\n : createLabMoveGate(state, { context }).check(x, y, dir, { ignoreSkip: true })\\n return gateResult.allowed === true\\n}\\nfunction hasLabPotentialRouteToLiveTarget(state, startX, startY, gate, context = gate?.context ?? getLabInfluenceContext(state), options = {}) {\\n return Number.isFinite(getLabPotentialGoalCost(state, startX, startY, gate, context, options))\\n}\\nfunction backfillLabPotentialGoalCosts(state, targetKeys, visitedKeys, routeGate, context, options = {}) {\\n if (!state || !(visitedKeys instanceof Set) || !Array.isArray(targetKeys) || targetKeys.length === 0) return false\\n const queue = []\\n const distances = new Map()\\n for (const key of targetKeys) {\\n if (!visitedKeys.has(key) || distances.has(key)) continue\\n const coords = getLabCoordsFromKey(key)\\n if (!coords) continue\\n distances.set(key, 0)\\n queue.push({ x: coords[0], y: coords[1], key, distance: 0 })\\n }\\n let head = 0\\n while (head < queue.length) {\\n const node = queue[head++]\\n for (const [dir, delta] of labDirectionEntries) {\\n const px = node.x - delta.dx\\n const py = node.y - delta.dy\\n const pkey = getLabKey(px, py)\\n if (!visitedKeys.has(pkey) || distances.has(pkey)) continue\\n if (!canLabPotentialTraverse(state, px, py, dir, routeGate, context, options)) continue\\n const distance = node.distance + 1\\n distances.set(pkey, distance)\\n queue.push({ x: px, y: py, key: pkey, distance })\\n }\\n }\\n for (const key of visitedKeys) {\\n const coords = getLabCoordsFromKey(key)\\n if (!coords) continue\\n setLabDeadRouteCost(state, coords[0], coords[1], distances.has(key) ? distances.get(key) : Number.POSITIVE_INFINITY)\\n }\\n return true\\n}\\nfunction getLabPotentialGoalCost(state, startX, startY, gate, context = gate?.context ?? getLabInfluenceContext(state), options = {}) {\\n const layout = state?.layout\\n const routeGate = gate?.check ? gate : createLabMoveGate(state, { context })\\n if (options?.forceRefresh !== true && hasLabDeadRouteCost(state, startX, startY)) {\\n return getLabDeadRouteCost(state, startX, startY)\\n }\\n const remember = (cost) => {\\n setLabDeadRouteCost(state, startX, startY, cost)\\n return cost\\n }\\n if (!layout || !Number.isInteger(startX) || !Number.isInteger(startY)) return remember(Number.POSITIVE_INFINITY)\\n if (startX < layout.minX || startX > layout.maxX || startY < layout.minY || startY > layout.maxY) return remember(Number.POSITIVE_INFINITY)\\n if (routeGate.isDeadRoom?.(startX, startY) === true) return remember(Number.POSITIVE_INFINITY)\\n const routeOptions = options?.boundQuadrant === true && (!Number.isInteger(options.originX) || !Number.isInteger(options.originY))\\n ? { ...options, originX: startX, originY: startY }\\n : options\\n if (isLabPotentialLiveTarget(state, startX, startY, routeGate, context, routeOptions)) return remember(0)\\n const startKey = getLabKey(startX, startY)\\n const visited = new Set([startKey])\\n const targetKeys = []\\n const queue = [{ x: startX, y: startY, key: startKey, distance: 0 }]\\n let bestDistance = Number.POSITIVE_INFINITY\\n let head = 0\\n while (head < queue.length) {\\n const node = queue[head++]\\n if (isLabPotentialLiveTarget(state, node.x, node.y, routeGate, context, routeOptions)) {\\n targetKeys.push(node.key)\\n if (node.distance < bestDistance) bestDistance = node.distance\\n }\\n for (const [dir, delta] of labDirectionEntries) {\\n if (!canLabPotentialTraverse(state, node.x, node.y, dir, routeGate, context, routeOptions)) continue\\n const nx = node.x + delta.dx\\n const ny = node.y + delta.dy\\n const key = getLabKey(nx, ny)\\n if (visited.has(key)) continue\\n if (routeGate.isDeadRoom?.(nx, ny) === true) continue\\n const distance = node.distance + 1\\n visited.add(key)\\n queue.push({ x: nx, y: ny, key, distance })\\n }\\n }\\n if (targetKeys.length > 0) {\\n backfillLabPotentialGoalCosts(state, targetKeys, visited, routeGate, context, routeOptions)\\n return remember(bestDistance)\\n }\\n for (const key of visited) {\\n const coords = getLabCoordsFromKey(key)\\n if (coords) setLabDeadRouteCost(state, coords[0], coords[1], Number.POSITIVE_INFINITY)\\n }\\n return remember(Number.POSITIVE_INFINITY)\\n}\\nfunction getLabMovePotentialCost(state, move, gate, context = gate?.context ?? getLabInfluenceContext(state), options = {}) {\\n if (!move) return Number.POSITIVE_INFINITY\\n return getLabDeadRouteCost(state, move.x, move.y)\\n}\\nfunction isLabKnownDeadPotentialCell(state, x, y, context = getLabInfluenceContext(state)) {\\n if (!hasLabDeadRouteCost(state, x, y)) return false\\n if (isLabProtectedDeadAreaCell(state, x, y, context)) return false\\n return !Number.isFinite(getLabDeadRouteCost(state, x, y))\\n}\\nfunction isLabDeadMovePrefilterBlocked(state, currentX, currentY, dir, gate, context = gate?.context ?? getLabInfluenceContext(state)) {\\n const delta = labDirections[dir]\\n if (!delta) return true\\n const nextX = currentX + delta.dx\\n const nextY = currentY + delta.dy\\n const crossing = getLabQuadrantTransitionForDir(state, currentX, currentY, dir, context)\\n if (crossing) return !isLabLiveQuadrantCrossing(state, currentX, currentY, dir, context)\\n const targetDead = gate?.isDeadRoom\\n ? gate.isDeadRoom(nextX, nextY)\\n : isLabDeadEndRoom(state, nextX, nextY)\\n if (!targetDead && !isLabKnownDeadPotentialCell(state, nextX, nextY, context)) return false\\n const currentDead = gate?.isDeadRoom\\n ? gate.isDeadRoom(currentX, currentY)\\n : isLabDeadEndRoom(state, currentX, currentY)\\n if (!currentDead) return true\\n const escape = gate?.getEscape ? gate.getEscape(currentX, currentY) : getLabDeadEndEscape(state, currentX, currentY)\\n return !(escape && escape === dir && canLabDeadEscapeReachOpen(state, currentX, currentY, dir, context))\\n}\\nfunction addLabPotentialMoveCosts(state, moves, gate, options = {}) {\\n if (!Array.isArray(moves) || moves.length === 0) return moves\\n const context = gate?.context ?? getLabInfluenceContext(state)\\n const costCache = new Map()\\n const knownCache = new Map()\\n for (const move of moves) {\\n if (!move) continue\\n const key = getLabKey(move.x, move.y)\\n if (!costCache.has(key)) costCache.set(key, getLabMovePotentialCost(state, move, gate, context, options))\\n if (!knownCache.has(key)) knownCache.set(key, hasLabDeadRouteCost(state, move.x, move.y))\\n move.potentialCost = costCache.get(key)\\n move.potentialCostKnown = knownCache.get(key)\\n }\\n return moves\\n}\\nfunction getLabPotentialCostRank(candidate) {\\n return Number.isFinite(candidate?.potentialCost) ? candidate.potentialCost : Number.POSITIVE_INFINITY\\n}\\nfunction compareLabStepCandidate(a, b) {\\n const exitFocusDelta = (a.exitFocusRank ?? 0) - (b.exitFocusRank ?? 0)\\n if (exitFocusDelta !== 0) return exitFocusDelta\\n if (a.explored !== b.explored) return a.explored ? 1 : -1\\n // Dead-route cost is only a same-tier tiebreaker for two unexplored choices.\\n // The caller must split candidates into movement tiers before sorting here.\\n if (a.explored === false && b.explored === false) {\\n const potentialA = getLabPotentialCostRank(a)\\n const potentialB = getLabPotentialCostRank(b)\\n if (potentialA !== potentialB) return potentialA - potentialB\\n }\\n return (a.dirIndex ?? 99) - (b.dirIndex ?? 99)\\n}\\nfunction pickFirstLabCandidate(candidates) {\\n if (candidates.length === 0) return null\\n candidates.sort(compareLabStepCandidate)\\n const pick = candidates[0]\\n return { x: pick.x, y: pick.y, dir: pick.dir, backstep: Boolean(pick.isBack) }\\n}\\nfunction compareLabExploredCostCandidate(a, b) {\\n const exitFocusDelta = (a.exitFocusRank ?? 0) - (b.exitFocusRank ?? 0)\\n if (exitFocusDelta !== 0) return exitFocusDelta\\n const potentialA = getLabPotentialCostRank(a)\\n const potentialB = getLabPotentialCostRank(b)\\n if (potentialA !== potentialB) return potentialA - potentialB\\n return (a.dirIndex ?? 99) - (b.dirIndex ?? 99)\\n}\\nfunction pickFirstLabExploredCostCandidate(candidates) {\\n if (candidates.length === 0 || candidates.some((move) => move?.explored !== true)) return null\\n candidates.sort(compareLabExploredCostCandidate)\\n const pick = candidates[0]\\n return { x: pick.x, y: pick.y, dir: pick.dir, backstep: Boolean(pick.isBack) }\\n}\\nfunction getLabGoalDirRank(dir, goalDirs) {\\n const rank = Array.isArray(goalDirs) ? goalDirs.indexOf(dir) : -1\\n return rank >= 0 ? rank : 99\\n}\\nfunction getLabMoveGoalRank(move, goalDirs) {\\n if (move?.gateway) return -1\\n return getLabGoalDirRank(move?.dir, goalDirs)\\n}\\nfunction compareLabGoalCandidate(a, b, _goalDirs) {\\n return compareLabStepCandidate(a, b)\\n}\\nfunction pickFirstLabGoalCandidate(candidates, goalDirs) {\\n if (candidates.length === 0) return null\\n candidates.sort((a, b) => compareLabGoalCandidate(a, b, goalDirs))\\n const pick = candidates[0]\\n return { x: pick.x, y: pick.y, dir: pick.dir, backstep: false }\\n}\\nfunction pickFirstLabAllowedForwardCandidate(candidates) {\\n const moves = candidates.filter((move) => !move.isBack)\\n if (moves.length === 0) return null\\n const unexploredPick = pickFirstLabCandidate(moves.filter((move) => !move.explored))\\n if (unexploredPick) return unexploredPick\\n const liveExploredPick = pickFirstLabExploredCostCandidate(moves)\\n if (liveExploredPick) return liveExploredPick\\n return pickFirstLabCandidate(moves)\\n}\\nfunction pickLabExitSubquadrantForwardMove(eligibleMoves, goalDirs, context = null, options = {}) {\\n const forwardMoves = eligibleMoves.filter((move) => !move.isBack)\\n const moves = options?.stayInExitSubquadrant === true && context\\n ? forwardMoves.filter((move) => isLabInExitSubquadrant(move.x, move.y, context))\\n : forwardMoves\\n if (moves.length === 0) return null\\n if (Array.isArray(goalDirs) && goalDirs.length > 0) {\\n const goalForwardMoves = moves.filter((move) => goalDirs.includes(move.dir))\\n const unexploredGoalForward = goalForwardMoves.filter((move) => !move.explored)\\n const goalPick = unexploredGoalForward.length > 0\\n ? pickFirstLabCandidate(unexploredGoalForward)\\n : pickFirstLabExploredCostCandidate(goalForwardMoves)\\n if (goalPick) return goalPick\\n }\\n const unexploredForward = moves.filter((move) => !move.explored)\\n const unexploredPick = pickFirstLabCandidate(unexploredForward)\\n if (unexploredPick) return unexploredPick\\n return pickFirstLabExploredCostCandidate(moves) ?? pickFirstLabCandidate(moves)\\n}\\nfunction getLabEligibleMovesForRoom(state, x, y, gate, options = {}) {\\n const room = state?.rooms?.[getLabKey(x, y)]\\n if (!room?.explored || !room.exits) return []\\n const layout = state.layout\\n const backDir = typeof options?.backDir === \\\"string\\\" ? options.backDir : \\\"\\\"\\n const moves = []\\n for (const [dir, delta] of labDirectionEntries) {\\n if (room.exits?.[dir] !== true) continue\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (layout && (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY)) continue\\n if (isLabDeadMovePrefilterBlocked(state, x, y, dir, gate, gate.context)) continue\\n const isBack = Boolean(backDir && dir === backDir)\\n const gateResult = gate.check(x, y, dir, { ignoreSkip: isBack })\\n if (!gateResult.allowed) continue\\n const nextRoom = state.rooms?.[getLabKey(nx, ny)]\\n moves.push({\\n dir,\\n x: nx,\\n y: ny,\\n explored: nextRoom?.explored === true,\\n dirIndex: labDirectionIndex[dir] ?? 99,\\n isBack,\\n gateway: gateResult.gateway === true,\\n exitFocusRank: getLabExitFocusMoveRank(state, x, y, nx, ny, gate.context)\\n })\\n }\\n return moves\\n}\\nfunction getLabEmergencyDeadEscapeMove(state, x, y, backDir = \\\"\\\", context = getLabInfluenceContext(state)) {\\n const room = state?.rooms?.[getLabKey(x, y)]\\n const layout = state?.layout\\n if (!room?.explored || !room.exits || !layout) return null\\n const candidates = []\\n for (const [dir, delta] of labDirectionEntries) {\\n if (room.exits?.[dir] !== true) continue\\n if (isLabQuadrantEntryBlocked(state, x, y, dir)) continue\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY) continue\\n if (!isLabSameQuadrantMove(state, x, y, nx, ny, context)) continue\\n if (isLabWorseQuadrantMove(state, x, y, nx, ny, context)) continue\\n if (!isLabDeadEndRoom(state, nx, ny)) continue\\n if (!canLabDeadEscapeReachOpen(state, x, y, dir, context)) continue\\n candidates.push({\\n dir,\\n x: nx,\\n y: ny,\\n backRank: backDir && dir === backDir ? 0 : 1,\\n dirIndex: labDirectionIndex[dir] ?? 99\\n })\\n }\\n if (candidates.length === 0) return null\\n candidates.sort((a, b) => a.backRank - b.backRank || a.dirIndex - b.dirIndex)\\n const pick = candidates[0]\\n appendLabDeadEndEntry(state, getLabKey(x, y), pick.dir)\\n return { x: pick.x, y: pick.y, dir: pick.dir, backstep: Boolean(backDir && pick.dir === backDir) }\\n}\\nfunction getLabFrontierRouteCacheKey(state, x, y, context = getLabInfluenceContext(state)) {\\n const gatewaySignature = getLabQuadrantGatewaySignature(state)\\n const signature = `${getLabInfluenceSignature(context)}|${gatewaySignature}`\\n return signature ? `${signature}|${getLabKey(x, y)}` : getLabKey(x, y)\\n}\\nfunction getCachedLabFrontierRoute(state, x, y, gate, backDir = \\\"\\\", options = {}) {\\n const context = gate?.context ?? getLabInfluenceContext(state)\\n const entry = ensureLabFrontierRouteCache(state)[getLabFrontierRouteCacheKey(state, x, y, context)]\\n if (!entry || typeof entry.dir !== \\\"string\\\" || !labDirections[entry.dir]) return null\\n if (options?.allowBackStart !== true && backDir && entry.dir === backDir) return null\\n if (entry.targetKey && state?.rooms?.[entry.targetKey]?.explored === true) return null\\n if (isLabDeadMovePrefilterBlocked(state, x, y, entry.dir, gate, context)) return null\\n const gateResult = gate?.check ? gate.check(x, y, entry.dir, { ignoreSkip: entry.dir === backDir }) : null\\n if (!gateResult?.allowed) return null\\n const delta = labDirections[entry.dir]\\n return {\\n x: x + delta.dx,\\n y: y + delta.dy,\\n dir: entry.dir,\\n backstep: Boolean(backDir && entry.dir === backDir),\\n exitFocusRank: entry.exitFocusRank ?? 0,\\n targetExitFocusRank: entry.targetExitFocusRank ?? 0\\n }\\n}\\nfunction setLabFrontierRouteCacheEntry(state, x, y, entry, context = getLabInfluenceContext(state)) {\\n if (!state || !Number.isInteger(x) || !Number.isInteger(y) || !entry || !labDirections[entry.dir]) return false\\n const key = getLabFrontierRouteCacheKey(state, x, y, context)\\n const cache = ensureLabFrontierRouteCache(state)\\n const existing = cache[key]\\n const next = {\\n dir: entry.dir,\\n targetKey: typeof entry.targetKey === \\\"string\\\" ? entry.targetKey : \\\"\\\",\\n distance: Number.isFinite(entry.distance) ? entry.distance : Number.POSITIVE_INFINITY,\\n goalRank: Number.isFinite(entry.goalRank) ? entry.goalRank : Number.POSITIVE_INFINITY,\\n targetGoalRank: Number.isFinite(entry.targetGoalRank) ? entry.targetGoalRank : Number.POSITIVE_INFINITY,\\n exitFocusRank: Number.isFinite(entry.exitFocusRank) ? entry.exitFocusRank : 0,\\n targetExitFocusRank: Number.isFinite(entry.targetExitFocusRank) ? entry.targetExitFocusRank : 0,\\n dirIndex: labDirectionIndex[entry.dir] ?? 99\\n }\\n const existingStale = Boolean(existing?.targetKey && state.rooms?.[existing.targetKey]?.explored === true)\\n if (!existing || existingStale\\n || next.exitFocusRank < (existing.exitFocusRank ?? 0)\\n || (next.exitFocusRank === (existing.exitFocusRank ?? 0) && next.targetExitFocusRank < (existing.targetExitFocusRank ?? 0))\\n || (next.exitFocusRank === (existing.exitFocusRank ?? 0) && next.targetExitFocusRank === (existing.targetExitFocusRank ?? 0) && next.distance < (existing.distance ?? Number.POSITIVE_INFINITY))\\n || (next.exitFocusRank === (existing.exitFocusRank ?? 0) && next.targetExitFocusRank === (existing.targetExitFocusRank ?? 0) && next.distance === (existing.distance ?? Number.POSITIVE_INFINITY) && next.goalRank < (existing.goalRank ?? Number.POSITIVE_INFINITY))\\n || (next.exitFocusRank === (existing.exitFocusRank ?? 0) && next.targetExitFocusRank === (existing.targetExitFocusRank ?? 0) && next.distance === (existing.distance ?? Number.POSITIVE_INFINITY) && next.goalRank === (existing.goalRank ?? Number.POSITIVE_INFINITY) && next.targetGoalRank < (existing.targetGoalRank ?? Number.POSITIVE_INFINITY))\\n || (next.exitFocusRank === (existing.exitFocusRank ?? 0) && next.targetExitFocusRank === (existing.targetExitFocusRank ?? 0) && next.distance === (existing.distance ?? Number.POSITIVE_INFINITY) && next.goalRank === (existing.goalRank ?? Number.POSITIVE_INFINITY) && next.targetGoalRank === (existing.targetGoalRank ?? Number.POSITIVE_INFINITY) && next.dirIndex < (existing.dirIndex ?? 99))) {\\n cache[key] = next\\n return true\\n }\\n return false\\n}\\nfunction backfillLabFrontierRouteCache(state, best, nodeByKey, context = getLabInfluenceContext(state)) {\\n if (!state || !best?.sourceKey || !best.targetKey || !(nodeByKey instanceof Map)) return false\\n const nodes = []\\n let cursor = nodeByKey.get(best.sourceKey)\\n while (cursor) {\\n nodes.push(cursor)\\n if (!cursor.parentKey) break\\n cursor = nodeByKey.get(cursor.parentKey)\\n }\\n nodes.reverse()\\n if (nodes.length === 0) return false\\n let changed = false\\n for (let i = 0; i < nodes.length; i++) {\\n const node = nodes[i]\\n const nextNode = nodes[i + 1]\\n const dir = nextNode ? getLabDirectionBetween(node.x, node.y, nextNode.x, nextNode.y) : getLabDirectionBetween(node.x, node.y, best.targetX, best.targetY)\\n if (!dir) continue\\n if (setLabFrontierRouteCacheEntry(state, node.x, node.y, {\\n dir,\\n targetKey: best.targetKey,\\n distance: Math.max(1, best.distance - node.distance),\\n goalRank: best.goalRank,\\n targetGoalRank: best.targetGoalRank,\\n exitFocusRank: Math.max(node.pathExitFocusRank ?? 0, best.targetExitFocusRank ?? 0),\\n targetExitFocusRank: best.targetExitFocusRank\\n }, context)) changed = true\\n }\\n return changed\\n}\\nfunction pickLabRouteToFrontier(state, workerId, x, y, skipKeys, backDir, gate = createLabMoveGate(state, { skipKeys }), eligibleStartMoves = null, options = {}) {\\n const startRoom = state?.rooms?.[getLabKey(x, y)]\\n if (!startRoom?.explored || !startRoom.exits) return null\\n const layout = state.layout\\n const context = gate.context\\n const cached = getCachedLabFrontierRoute(state, x, y, gate, backDir, options)\\n if (cached) return cached\\n const startGoalDirs = context ? getLabImmediateGoalwardDirs(state, x, y, context) : []\\n const startInExitQuadrant = Boolean(context && isLabInExitQuadrant(x, y, context))\\n const allowBackStart = options?.allowBackStart === true\\n const startKey = getLabKey(x, y)\\n const visited = new Set([startKey])\\n const nodeByKey = new Map([[startKey, { key: startKey, x, y, distance: 0, parentKey: \\\"\\\", dirFromParent: \\\"\\\", pathExitFocusRank: 0 }]])\\n const queue = []\\n const addRouteNode = (dir, nx, ny, distance, firstDirGoalRank = null, pathExitFocusRank = 0, parentKey = startKey, dirFromParent = dir) => {\\n const key = getLabKey(nx, ny)\\n if (visited.has(key)) return\\n const nextRoom = state.rooms?.[key]\\n if (!nextRoom?.explored) return\\n visited.add(key)\\n const node = {\\n key,\\n x: nx,\\n y: ny,\\n firstDir: dir,\\n distance,\\n firstDirGoalRank: Number.isFinite(firstDirGoalRank) ? firstDirGoalRank : getLabGoalDirRank(dir, startGoalDirs),\\n firstDirIndex: labDirectionIndex[dir] ?? 99,\\n pathExitFocusRank: Number.isFinite(pathExitFocusRank) ? pathExitFocusRank : 0,\\n parentKey,\\n dirFromParent\\n }\\n nodeByKey.set(key, node)\\n queue.push(node)\\n }\\n const startEdges = []\\n const startMoves = Array.isArray(eligibleStartMoves) ? eligibleStartMoves : null\\n if (startMoves) {\\n for (const move of startMoves) {\\n if (!move || (!allowBackStart && move.isBack)) continue\\n const nextRoom = state.rooms?.[getLabKey(move.x, move.y)]\\n if (!nextRoom?.explored) continue\\n startEdges.push({\\n dir: move.dir,\\n x: move.x,\\n y: move.y,\\n goalRank: getLabMoveGoalRank(move, startGoalDirs),\\n exitFocusRank: move.exitFocusRank ?? 0,\\n backRank: backDir && move.dir === backDir ? 1 : 0,\\n dirIndex: move.dirIndex\\n })\\n }\\n }\\n if (!startMoves) for (const [dir, delta] of labDirectionEntries) {\\n if (startRoom.exits?.[dir] !== true) continue\\n const nx = x + delta.dx\\n const ny = y + delta.dy\\n if (layout && (nx < layout.minX || nx > layout.maxX || ny < layout.minY || ny > layout.maxY)) continue\\n if (isLabDeadMovePrefilterBlocked(state, x, y, dir, gate, context)) continue\\n const gateResult = gate.check(x, y, dir)\\n if (!gateResult.allowed) continue\\n const nextRoom = state.rooms?.[getLabKey(nx, ny)]\\n if (!nextRoom?.explored) continue\\n startEdges.push({\\n dir,\\n x: nx,\\n y: ny,\\n goalRank: gateResult.gateway ? -1 : getLabGoalDirRank(dir, startGoalDirs),\\n exitFocusRank: getLabExitFocusMoveRank(state, x, y, nx, ny, context),\\n backRank: backDir && dir === backDir ? 1 : 0,\\n dirIndex: labDirectionIndex[dir] ?? 99\\n })\\n }\\n startEdges.sort((a, b) => a.exitFocusRank - b.exitFocusRank || a.goalRank - b.goalRank || a.backRank - b.backRank || a.dirIndex - b.dirIndex)\\n for (const edge of startEdges) addRouteNode(edge.dir, edge.x, edge.y, 1, edge.goalRank, edge.exitFocusRank)\\n\\n let best = null\\n let head = 0\\n while (head < queue.length) {\\n const node = queue[head++]\\n const nodeRoom = state.rooms?.[getLabKey(node.x, node.y)]\\n if (!nodeRoom?.explored || !nodeRoom.exits) continue\\n const nodeGoalDirs = context ? getLabImmediateGoalwardDirs(state, node.x, node.y, context) : []\\n const edges = []\\n for (const move of getLabEligibleMovesForRoom(state, node.x, node.y, gate)) {\\n const key = getLabKey(move.x, move.y)\\n edges.push({\\n dir: move.dir,\\n x: move.x,\\n y: move.y,\\n key,\\n goalRank: getLabMoveGoalRank(move, nodeGoalDirs),\\n exitFocusRank: move.exitFocusRank ?? 0,\\n dirIndex: move.dirIndex\\n })\\n }\\n edges.sort((a, b) => a.exitFocusRank - b.exitFocusRank || a.goalRank - b.goalRank || a.dirIndex - b.dirIndex)\\n for (const edge of edges) {\\n const nextRoom = state.rooms?.[edge.key]\\n if (!nextRoom?.explored) {\\n const firstDelta = labDirections[node.firstDir]\\n if (!firstDelta) continue\\n const pathExitFocusRank = Math.max(node.pathExitFocusRank ?? 0, edge.exitFocusRank ?? 0)\\n const candidate = {\\n x: x + firstDelta.dx,\\n y: y + firstDelta.dy,\\n dir: node.firstDir,\\n sourceKey: getLabKey(node.x, node.y),\\n targetKey: edge.key,\\n targetX: edge.x,\\n targetY: edge.y,\\n distance: node.distance + 1,\\n goalRank: node.firstDirGoalRank,\\n exitFocusRank: pathExitFocusRank,\\n targetExitFocusRank: startInExitQuadrant ? getLabExitFocusPointRank(state, edge.x, edge.y, context) : 0,\\n targetGoalRank: edge.goalRank,\\n dirIndex: node.firstDirIndex\\n }\\n if (!best\\n || candidate.exitFocusRank < best.exitFocusRank\\n || (candidate.exitFocusRank === best.exitFocusRank && candidate.targetExitFocusRank < best.targetExitFocusRank)\\n || (candidate.exitFocusRank === best.exitFocusRank && candidate.targetExitFocusRank === best.targetExitFocusRank && candidate.distance < best.distance)\\n || (candidate.exitFocusRank === best.exitFocusRank && candidate.targetExitFocusRank === best.targetExitFocusRank && candidate.distance === best.distance && candidate.goalRank < best.goalRank)\\n || (candidate.exitFocusRank === best.exitFocusRank && candidate.targetExitFocusRank === best.targetExitFocusRank && candidate.distance === best.distance && candidate.goalRank === best.goalRank && candidate.targetGoalRank < best.targetGoalRank)\\n || (candidate.exitFocusRank === best.exitFocusRank && candidate.targetExitFocusRank === best.targetExitFocusRank && candidate.distance === best.distance && candidate.goalRank === best.goalRank && candidate.targetGoalRank === best.targetGoalRank && candidate.dirIndex < best.dirIndex)) {\\n best = candidate\\n }\\n continue\\n }\\n if (!visited.has(edge.key)) {\\n visited.add(edge.key)\\n const nextNode = {\\n key: edge.key,\\n x: edge.x,\\n y: edge.y,\\n firstDir: node.firstDir,\\n distance: node.distance + 1,\\n firstDirGoalRank: node.firstDirGoalRank,\\n firstDirIndex: node.firstDirIndex,\\n pathExitFocusRank: Math.max(node.pathExitFocusRank ?? 0, edge.exitFocusRank ?? 0),\\n parentKey: node.key,\\n dirFromParent: edge.dir\\n }\\n nodeByKey.set(edge.key, nextNode)\\n queue.push(nextNode)\\n }\\n }\\n }\\n if (!best) return null\\n backfillLabFrontierRouteCache(state, best, nodeByKey, context)\\n return {\\n x: best.x,\\n y: best.y,\\n dir: best.dir,\\n backstep: Boolean(backDir && best.dir === backDir),\\n exitFocusRank: best.exitFocusRank,\\n targetExitFocusRank: best.targetExitFocusRank\\n }\\n}\\nfunction pickGreedyStep(state, workerId, x, y, options = {}) {\\n const room = state?.rooms?.[getLabKey(x, y)]\\n if (!room?.explored || !room.exits) return null\\n const skipKeys = getLabPickSkipSet(options)\\n const context = getLabInfluenceContext(state)\\n prepareLabDeadRoomMoveFilter(state, x, y, context)\\n const inExitQuadrant = Boolean(context && isLabInExitQuadrant(x, y, context))\\n const inExitSubquadrant = Boolean(context && isLabInExitSubquadrant(x, y, context))\\n const gate = createLabMoveGate(state, { skipKeys, context })\\n const roomPath = Array.isArray(room.path) ? room.path : []\\n const lastForwardDir = peekLabWorkerVisit(workerId) || roomPath[roomPath.length - 1] || \\\"\\\"\\n const backDir = labDirections[lastForwardDir]?.back ?? \\\"\\\"\\n const rawEligibleMoves = getLabEligibleMovesForRoom(state, x, y, gate, { backDir })\\n const emergencyEscape = rawEligibleMoves.length === 0 && gate.isDeadRoom(x, y) === true\\n ? getLabEmergencyDeadEscapeMove(state, x, y, backDir, context)\\n : null\\n if (emergencyEscape) return emergencyEscape\\n // Forced dead-end escape. If the worker is already inside a marked\\n // dead area, leave before considering any picker bucket. This prevents\\n // exit-zone workers from spending extra decisions in a known dead room.\\n const escape = gate.getEscape(x, y)\\n if (escape && room.exits[escape] === true) {\\n const escapeMove = rawEligibleMoves.find((move) => move.dir === escape)\\n if (escapeMove) {\\n const lastPushed = peekLabWorkerVisit(workerId)\\n const isBackstep = lastPushed && labDirections[lastPushed]?.back === escape\\n return { x: escapeMove.x, y: escapeMove.y, dir: escape, backstep: !!isBackstep }\\n }\\n }\\n const eligibleMoves = addLabPotentialMoveCosts(state, rawEligibleMoves, gate, { originX: x, originY: y })\\n const forwardMoves = eligibleMoves.filter((move) => !move.isBack)\\n const hasForwardMove = forwardMoves.length > 0\\n const goalDirs = context ? getLabImmediateGoalwardDirs(state, x, y, context) : []\\n if (inExitSubquadrant) {\\n const exitInsideForwardPick = pickLabExitSubquadrantForwardMove(eligibleMoves, goalDirs, context, { stayInExitSubquadrant: true })\\n if (exitInsideForwardPick) return exitInsideForwardPick\\n const exitInsideRoute = pickLabRouteToFrontier(state, workerId, x, y, skipKeys, backDir, gate, eligibleMoves, { allowBackStart: !hasForwardMove })\\n if (exitInsideRoute && exitInsideRoute.targetExitFocusRank === 0) return exitInsideRoute\\n const exitForwardPick = pickLabExitSubquadrantForwardMove(eligibleMoves, goalDirs, context)\\n if (exitForwardPick) return exitForwardPick\\n } else if (inExitQuadrant) {\\n const exitReturnRoute = pickLabRouteToFrontier(state, workerId, x, y, skipKeys, backDir, gate, eligibleMoves, { allowBackStart: !hasForwardMove })\\n if (exitReturnRoute && exitReturnRoute.targetExitFocusRank === 0) return exitReturnRoute\\n }\\n if (context && isLabInExitSubquadrant(x, y, context) && goalDirs.length > 0) {\\n const exitTargetMoves = eligibleMoves.filter((move) => goalDirs.includes(move.dir))\\n const unexploredExitTargetMoves = exitTargetMoves.filter((move) => !move.explored)\\n const exitTargetPick = unexploredExitTargetMoves.length > 0\\n ? pickFirstLabCandidate(unexploredExitTargetMoves)\\n : pickFirstLabExploredCostCandidate(exitTargetMoves)\\n if (exitTargetPick) return exitTargetPick\\n }\\n if (eligibleMoves.length > 0 && eligibleMoves.every((move) => move.explored)) {\\n const liveExploredMoves = eligibleMoves.filter((move) => !hasForwardMove || !move.isBack)\\n const exploredPick = pickFirstLabExploredCostCandidate(liveExploredMoves)\\n if (exploredPick) return exploredPick\\n const exploredForwardPick = pickFirstLabAllowedForwardCandidate(eligibleMoves)\\n if (exploredForwardPick) return exploredForwardPick\\n }\\n const unexploredGatewayForward = []\\n const unexploredGoalForward = []\\n const unexploredSideForward = []\\n let backCandidate = null\\n for (const candidate of eligibleMoves) {\\n // Candidate was already filtered by getLabEligibleMovesForRoom.\\n if (candidate.isBack) { backCandidate = candidate; continue }\\n if (candidate.explored) continue\\n if (candidate.gateway && (candidate.exitFocusRank ?? 0) < 3) unexploredGatewayForward.push(candidate)\\n else if (goalDirs.includes(candidate.dir)) unexploredGoalForward.push(candidate)\\n else unexploredSideForward.push(candidate)\\n }\\n // Deterministic ordering happens inside each priority bucket. Cost is\\n // only considered when two candidates in that same bucket are unexplored.\\n const immediateGateway = pickFirstLabCandidate(unexploredGatewayForward)\\n if (immediateGateway) return immediateGateway\\n const immediateGoal = pickFirstLabGoalCandidate(unexploredGoalForward, goalDirs)\\n if (immediateGoal) return immediateGoal\\n const immediateSide = pickFirstLabCandidate(unexploredSideForward)\\n if (immediateSide) return immediateSide\\n const routed = pickLabRouteToFrontier(state, workerId, x, y, skipKeys, backDir, gate, eligibleMoves)\\n if (routed) return routed\\n const forwardFallback = pickFirstLabAllowedForwardCandidate(eligibleMoves)\\n if (forwardFallback) return forwardFallback\\n if (backCandidate) {\\n return { x: backCandidate.x, y: backCandidate.y, dir: backCandidate.dir, backstep: true }\\n }\\n return null\\n}\\n\\n// ----- Walk one step --------------------------------------------------------\\n// Sends `dir` to the labHunter, parses the auth result, updates worker\\n// position, maintains the visit stack, records the destination room when\\n// it carries new exit information.\\nfunction getLabExitCoordsFromStep(state, currentX, currentY, dir, result) {\\n const authResult = result?.authResults ?? result\\n const rawCoords = getLabRawCoordsFromAuthResult(authResult)\\n if (Array.isArray(rawCoords)) {\\n const [actualX, actualY] = getLabActualCoords(rawCoords[0], rawCoords[1], { coords: rawCoords }, state)\\n if (Number.isInteger(actualX) && Number.isInteger(actualY)) return [actualX, actualY]\\n }\\n const delta = labDirections[dir]\\n if (delta && Number.isInteger(currentX) && Number.isInteger(currentY)) {\\n return [currentX + delta.dx, currentY + delta.dy]\\n }\\n return [null, null]\\n}\\nfunction recordLabFinishCell(state, finishX, finishY, workerId = \\\"\\\") {\\n if (!state?.layout || !Number.isInteger(finishX) || !Number.isInteger(finishY)) return false\\n if (Number.isInteger(state.layout.finishX) && Number.isInteger(state.layout.finishY)) {\\n return state.layout.finishX === finishX && state.layout.finishY === finishY\\n }\\n let extended = false\\n if (finishX > state.layout.maxX) { state.layout.maxX = finishX; extended = true }\\n if (finishY > state.layout.maxY) { state.layout.maxY = finishY; extended = true }\\n if (finishX < state.layout.minX) { state.layout.minX = finishX; extended = true }\\n if (finishY < state.layout.minY) { state.layout.minY = finishY; extended = true }\\n state.layout.finishX = finishX\\n state.layout.finishY = finishY\\n state.layout.goalX = finishX\\n state.layout.goalY = finishY\\n state.finishKey = getLabKey(finishX, finishY)\\n if (workerId) state.finishWorkerId = workerId\\n markLabDisplayDirtyCoords(state, finishX, finishY)\\n pruneLabProtectedDeadMarks(state)\\n if (extended) syncLabDisplayMap(state, true)\\n state.displayVersion = (state.displayVersion ?? 0) + 1\\n state.displayOutputKey = \\\"\\\"\\n return true\\n}\\nasync function walkOneStep(ns, server, details, workerId, labWorker, dir, currentX, currentY) {\\n const state = labState\\n const context = getLabInfluenceContext(state)\\n prepareLabDeadRoomMoveFilter(state, currentX, currentY, context)\\n const moveGate = createLabMoveGate(state, { context })\\n if (isLabDeadMovePrefilterBlocked(state, currentX, currentY, dir, moveGate, context)) {\\n syncLabToInProgress(server)\\n return { blocked: true, deadEndBlocked: true, currentX, currentY }\\n }\\n const gateResult = moveGate.check(currentX, currentY, dir)\\n if (!gateResult.allowed) {\\n syncLabToInProgress(server)\\n return { blocked: true, deadEndBlocked: gateResult.reason === \\\"dead\\\", currentX, currentY }\\n }\\n const result = await labWork(ns, labWorker, dir)\\n if (result?.workerExited) return { workerExited: true }\\n const resultReport = result?.report || false\\n if (!resultReport && result?.authResults?.success === false && details && !serverCheck(ns, server, details, result.authResults)) {\\n return { lostServer: true, currentX, currentY }\\n }\\n if (result?.finished && !resultReport) {\\n // Record the exit cell on the live state so the display draws the\\n // X marker. Coords come from the auth result's \\\"You have moved to\\n // X, Y.\\\" message; we translate via the same coord-offset frame as\\n // every other room. If the exit lies past the layout's bounding\\n // rectangle (it always does — the exit is one step beyond the\\n // outermost row of rooms), extend the bounds and rebuild the\\n // display map so the cell is actually inside the rendered board.\\n const resultDir = typeof result.dir === \\\"string\\\" && labDirections[result.dir] ? result.dir : dir\\n const [exitX, exitY] = getLabExitCoordsFromStep(state, currentX, currentY, resultDir, result)\\n recordLabFinishCell(state, exitX, exitY, workerId)\\n syncLabToInProgress(server)\\n const finalExitX = Number.isInteger(state?.layout?.finishX) ? state.layout.finishX : exitX\\n const finalExitY = Number.isInteger(state?.layout?.finishY) ? state.layout.finishY : exitY\\n return { finished: true, authResults: result.authResults, exitX: finalExitX, exitY: finalExitY }\\n }\\n const report = resultReport\\n if (!report) return { blocked: true, currentX, currentY }\\n const delta = labDirections[dir]\\n const expectedX = delta ? currentX + delta.dx : currentX\\n const expectedY = delta ? currentY + delta.dy : currentY\\n const moveCoords = getLabMoveCoords(currentX, currentY, expectedX, expectedY, report, state)\\n if (moveCoords.status === \\\"blocked\\\") {\\n const currentPath = state.rooms?.[getLabKey(currentX, currentY)]?.path ?? []\\n recordLabRoom(state, currentX, currentY, report, currentPath, true)\\n syncLabToInProgress(server)\\n return { blocked: true, currentX, currentY }\\n }\\n if (moveCoords.status === \\\"mismatch\\\") {\\n const actual = state.rooms?.[getLabKey(moveCoords.reportedX, moveCoords.reportedY)]\\n recordLabRoom(state, moveCoords.reportedX, moveCoords.reportedY, report, actual?.path ?? [], true)\\n setLabWorkerPosition(state, workerId, moveCoords.reportedX, moveCoords.reportedY)\\n syncLabToInProgress(server)\\n return { desynced: true, currentX: moveCoords.reportedX, currentY: moveCoords.reportedY }\\n }\\n const newX = moveCoords.x\\n const newY = moveCoords.y\\n const entryBlockChanged = recordLabQuadrantEntryBlock(state, currentX, currentY, newX, newY, dir, context)\\n setLabWorkerPosition(state, workerId, newX, newY)\\n // Visit-stack maintenance: if this dir undoes the last push, pop;\\n // otherwise push. Auto-detection means callers don't have to declare\\n // intent and the stack stays consistent.\\n const lastPushedDir = peekLabWorkerVisit(workerId)\\n if (lastPushedDir && labDirections[lastPushedDir]?.back === dir) popLabWorkerVisit(workerId)\\n else pushLabWorkerVisit(workerId, dir)\\n // Only pay the recordLabRoom cost when the destination has new info.\\n const destRoom = state.rooms?.[getLabKey(newX, newY)]\\n if (!destRoom?.jsonLog) {\\n const sourcePath = state.rooms?.[getLabKey(currentX, currentY)]?.path ?? []\\n recordLabRoom(state, newX, newY, report, sourcePath.concat(dir))\\n }\\n if (entryBlockChanged) {\\n updateLabDeadKnowledgeFromRoom(state, currentX, currentY, context)\\n updateLabDeadKnowledgeFromRoom(state, newX, newY, context)\\n }\\n syncLabToInProgress(server)\\n return { moved: true, currentX: newX, currentY: newY, quadrantCrossed: Boolean(gateResult.crossing) }\\n}\\n\\n// ----- Display app — labmap (stays external to the case body) --------------\\nfunction getReactLib() {\\n return globalThis[\\\"React\\\"] ?? globalThis[\\\"window\\\"]?.React\\n}\\nconst labCanvasUnknownPresentation = { fill: \\\"#082536\\\", stroke: \\\"#0e7490\\\", alpha: 0.55, label: \\\"\\\", labelColor: \\\"#67e8f9\\\" }\\nconst labCanvasFillPresentation = { fill: \\\"#030712\\\", stroke: \\\"#111827\\\", alpha: 1, label: \\\"\\\", labelColor: \\\"#020617\\\" }\\nconst labCanvasOpenPresentation = { fill: \\\"#147044\\\", stroke: \\\"#34d399\\\", alpha: 1, label: \\\"\\\", labelColor: \\\"#bbf7d0\\\", glow: \\\"#34d399\\\" }\\nconst labCanvasStartPresentation = { fill: \\\"#86efac\\\", stroke: \\\"#f0fdf4\\\", alpha: 1, label: \\\"S\\\", labelColor: \\\"#022c22\\\" }\\nconst labCanvasFinishPresentation = { fill: \\\"#ef4444\\\", stroke: \\\"#fecaca\\\", alpha: 1, label: \\\"X\\\", labelColor: \\\"#450a0a\\\" }\\nconst labCanvasWorkerPresentation = { fill: \\\"#06b6d4\\\", stroke: \\\"#cffafe\\\", alpha: 1, label: \\\"o\\\", labelColor: \\\"#042f2e\\\" }\\nfunction getLabCanvasCellPresentation(char) {\\n if (char === \\\"·\\\" || char === labMapPossibleHall || char === labMapUnknownRoom) {\\n return labCanvasUnknownPresentation\\n }\\n switch (char) {\\n case labMapFill: return labCanvasFillPresentation\\n case labMapOpen: return labCanvasOpenPresentation\\n case labMapStart: return labCanvasStartPresentation\\n case labMapFinish: return labCanvasFinishPresentation\\n case labMapWorker: return labCanvasWorkerPresentation\\n default: return { fill: \\\"#111827\\\", stroke: \\\"#1f2937\\\", alpha: 1, label: (char ?? \\\"\\\").trim(), labelColor: \\\"#64748b\\\" }\\n }\\n}\\n/** @param {NS} ns */\\nfunction autoSizeLabTail(ns, map) {\\n const { cols, rows } = getLabMapDimensions(map)\\n const width = Math.max(360, 46 + (cols * (cellSize + cellGap)))\\n const height = Math.max(268, 162 + (rows * (cellSize + cellGap)))\\n if (ns.self().tailProperties.height !== height || ns.self().tailProperties.width !== width)\\n ns.ui.resizeTail(width, height)\\n}\\nfunction drawLabMapCanvas(canvas, map, options = {}) {\\n if (!canvas || !Array.isArray(map)) return\\n const { cols, rows } = getLabMapDimensions(map)\\n const previousMap = Array.isArray(options.previousMap) ? options.previousMap : null\\n const previousDimensions = getLabMapDimensions(previousMap ?? [])\\n const previousCols = previousDimensions.cols\\n const previousRows = previousDimensions.rows\\n const firstDraw = canvas._labHasDrawn !== true\\n const pixelRatio = firstDraw\\n ? Math.max(1, Math.min(2, globalThis?.devicePixelRatio ?? 1))\\n : (canvas._labPixelRatio ?? Math.max(1, Math.min(2, globalThis?.devicePixelRatio ?? 1)))\\n const width = Math.max(1, cols * cellSize + Math.max(0, cols - 1) * cellGap)\\n const height = Math.max(1, rows * cellSize + Math.max(0, rows - 1) * cellGap)\\n const canvasWidth = Math.ceil(width * pixelRatio)\\n const canvasHeight = Math.ceil(height * pixelRatio)\\n if (firstDraw) {\\n if (canvas.width !== canvasWidth) canvas.width = canvasWidth\\n if (canvas.height !== canvasHeight) canvas.height = canvasHeight\\n if (canvas.style.width !== `${width}px`) canvas.style.width = `${width}px`\\n if (canvas.style.height !== `${height}px`) canvas.style.height = `${height}px`\\n }\\n const ctx = canvas.getContext(\\\"2d\\\")\\n if (!ctx) return\\n ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0)\\n const fullRedraw = firstDraw\\n const background = \\\"#020617\\\"\\n if (fullRedraw) {\\n ctx.fillStyle = background\\n ctx.fillRect(0, 0, width, height)\\n }\\n ctx.textAlign = \\\"center\\\"\\n ctx.textBaseline = \\\"middle\\\"\\n ctx.font = `700 ${Math.max(8, cellSize - 4)}px monospace`\\n let curFill = \\\"\\\", curStroke = \\\"\\\", curAlpha = 1, curBlur = 0, curShadowColor = \\\"\\\"\\n let lineWidthSet = false\\n const setFill = (v) => { if (curFill !== v) { ctx.fillStyle = v; curFill = v } }\\n const setStroke = (v) => { if (curStroke !== v) { ctx.strokeStyle = v; curStroke = v } }\\n const setAlpha = (v) => { if (curAlpha !== v) { ctx.globalAlpha = v; curAlpha = v } }\\n const setBlur = (v) => { if (curBlur !== v) { ctx.shadowBlur = v; curBlur = v } }\\n const setShadowColor = (v) => { if (curShadowColor !== v) { ctx.shadowColor = v; curShadowColor = v } }\\n const strokeInset = 0.5\\n const strokeSize = Math.max(1, cellSize - 1)\\n const halfCell = cellSize / 2\\n const stride = cellSize + cellGap\\n const drawCell = (x, y, char, needsClear) => {\\n const cell = getLabCanvasCellPresentation(char)\\n const px = x * stride\\n const py = y * stride\\n const cellAlpha = cell.alpha ?? 1\\n if (needsClear) {\\n setBlur(0); setAlpha(1); setFill(background)\\n ctx.fillRect(px, py, Math.min(stride, width - px), Math.min(stride, height - py))\\n }\\n setAlpha(cellAlpha)\\n if (cell.glow) { setShadowColor(cell.glow); setBlur(cellSize * 0.35) }\\n else setBlur(0)\\n setFill(cell.fill)\\n ctx.fillRect(px, py, cellSize, cellSize)\\n if (cell.glow) setBlur(0)\\n setAlpha(Math.min(1, cellAlpha + 0.2))\\n setStroke(cell.stroke)\\n if (!lineWidthSet) { ctx.lineWidth = 1; lineWidthSet = true }\\n ctx.strokeRect(px + strokeInset, py + strokeInset, strokeSize, strokeSize)\\n if (cell.label) {\\n setAlpha(1); setFill(cell.labelColor)\\n ctx.fillText(cell.label, px + halfCell, py + halfCell + 0.5)\\n }\\n }\\n if (fullRedraw) {\\n for (let y = 0; y < rows; y++) {\\n const row = typeof map[y] === \\\"string\\\" ? map[y] : \\\"\\\"\\n for (let x = 0; x < cols; x++) drawCell(x, y, row[x] ?? labMapFill, false)\\n }\\n canvas._labHasDrawn = true\\n canvas._labPixelRatio = pixelRatio\\n setAlpha(1); setBlur(0)\\n return\\n }\\n // Incremental dirty-rect path. Reuse the dirty bitmap across frames via\\n // canvas._labDirty; per-frame work bounded by changed cells, not grid size.\\n let dirty = canvas._labDirty\\n const total = cols * rows\\n if (!(dirty instanceof Uint8Array) || dirty.length !== total) {\\n dirty = new Uint8Array(total)\\n canvas._labDirty = dirty\\n }\\n let dirtyList = canvas._labDirtyList\\n if (!Array.isArray(dirtyList)) { dirtyList = []; canvas._labDirtyList = dirtyList }\\n for (let i = 0; i < dirtyList.length; i++) dirty[dirtyList[i]] = 0\\n dirtyList.length = 0\\n const markDirty = (x, y) => {\\n if (x < 0 || x >= cols || y < 0 || y >= rows) return\\n const idx = y * cols + x\\n if (dirty[idx] === 0) { dirty[idx] = 1; dirtyList.push(idx) }\\n }\\n const fillCharCode = labMapFill.charCodeAt(0)\\n const openCharCode = labMapOpen.charCodeAt(0)\\n if (!previousMap || previousMap.length === 0) {\\n canvas._labHasDrawn = true\\n canvas._labPixelRatio = pixelRatio\\n setAlpha(1); setBlur(0)\\n return\\n }\\n const markChangedCell = (x, y) => {\\n if (x < 0 || x >= cols || y < 0 || y >= rows) return\\n const row = typeof map[y] === \\\"string\\\" ? map[y] : \\\"\\\"\\n const previousRow = typeof previousMap?.[y] === \\\"string\\\" ? previousMap[y] : \\\"\\\"\\n const newCode = x < row.length ? row.charCodeAt(x) : fillCharCode\\n const oldCode = x < previousRow.length ? previousRow.charCodeAt(x) : fillCharCode\\n if (newCode === oldCode) return\\n const involvesGlow = newCode === openCharCode || oldCode === openCharCode\\n if (involvesGlow) {\\n markDirty(x - 1, y - 1); markDirty(x, y - 1); markDirty(x + 1, y - 1)\\n markDirty(x - 1, y); markDirty(x, y); markDirty(x + 1, y)\\n markDirty(x - 1, y + 1); markDirty(x, y + 1); markDirty(x + 1, y + 1)\\n } else {\\n markDirty(x, y)\\n }\\n }\\n const suppliedDirtyCells = Array.isArray(options.dirtyCells) ? options.dirtyCells : []\\n for (const cell of suppliedDirtyCells) {\\n if (!Array.isArray(cell) || cell.length < 2) continue\\n markChangedCell(cell[0], cell[1])\\n }\\n for (let i = 0; i < dirtyList.length; i++) {\\n const idx = dirtyList[i]\\n const y = (idx / cols) | 0\\n const x = idx - y * cols\\n const row = typeof map[y] === \\\"string\\\" ? map[y] : \\\"\\\"\\n const newCode = x < row.length ? row.charCodeAt(x) : fillCharCode\\n const newChar = String.fromCharCode(newCode)\\n const newlyExposed = x >= previousCols || y >= previousRows\\n let needsClear = newlyExposed || (newCode !== fillCharCode && (getLabCanvasCellPresentation(newChar).alpha ?? 1) < 1)\\n if (!needsClear) {\\n for (let dy = -1; dy <= 1 && !needsClear; dy++) {\\n const ny = y + dy\\n if (ny < 0 || ny >= rows) continue\\n const prevRow = typeof previousMap?.[ny] === \\\"string\\\" ? previousMap[ny] : \\\"\\\"\\n if (prevRow.length === 0) continue\\n for (let dx = -1; dx <= 1; dx++) {\\n const nx = x + dx\\n if (nx < 0 || nx >= prevRow.length) continue\\n if (prevRow.charCodeAt(nx) === openCharCode) { needsClear = true; break }\\n }\\n }\\n }\\n drawCell(x, y, newChar, needsClear)\\n }\\n canvas._labHasDrawn = true\\n canvas._labPixelRatio = pixelRatio\\n setAlpha(1); setBlur(0)\\n}\\nfunction startMapDisplay(ns, options = {}) {\\n const React = getReactLib()\\n ns.ui.openTail()\\n logOpened = true\\n if (!React) return\\n ns.clearLog()\\n ns.printRaw(React.createElement(LabMapApp, { ns, options }))\\n}\\nfunction LabMapApp({ ns }) {\\n const React = getReactLib()\\n if (!React) return null\\n const e = React.createElement\\n const canvasRef = React.useRef(null)\\n const lastDrawnMapRef = React.useRef([])\\n const lastSizeKeyRef = React.useRef(\\\"\\\")\\n const [snapshot, setSnapshot] = React.useState({ map: [], versionKey: \\\"\\\", hasData: false, fullRedraw: true, dirtyCells: null })\\n React.useEffect(() => {\\n let cancelled = false\\n let timer = 0\\n let lastVersionKey = null\\n let lastNonEmptyMap = []\\n const tick = () => {\\n const sourceKey = getLabMapSourceKey(labState)\\n if (!cancelled && sourceKey !== lastVersionKey) {\\n const rows = labState ? buildLabMapObject(labState) : []\\n const versionKey = labState?.displayOutputKey || sourceKey\\n let nextMap = rows.length > 0 ? rows : lastNonEmptyMap\\n if (rows.length > 0) lastNonEmptyMap = rows\\n lastVersionKey = sourceKey\\n if (nextMap.length > 0 && !lastSizeKeyRef.current) {\\n const { cols, rows: rowCount } = getLabMapDimensions(nextMap)\\n const sizeKey = `${cols}x${rowCount}`\\n lastSizeKeyRef.current = sizeKey\\n autoSizeLabTail(ns, nextMap)\\n }\\n const fullRedraw = lastDrawnMapRef.current.length === 0\\n setSnapshot({ map: nextMap, versionKey, hasData: nextMap.length > 0, fullRedraw, dirtyCells: labState?.displayOutputDirtyCells ?? null })\\n }\\n if (!cancelled && modeShowMap) timer = setTimeout(tick, refreshMs)\\n }\\n tick()\\n return () => { cancelled = true; if (timer) clearTimeout(timer) }\\n }, [ns])\\n React.useEffect(() => {\\n if (!snapshot.hasData) return\\n drawLabMapCanvas(canvasRef.current, snapshot.map, {\\n previousMap: lastDrawnMapRef.current,\\n fullRedraw: snapshot.fullRedraw,\\n dirtyCells: snapshot.dirtyCells\\n })\\n lastDrawnMapRef.current = snapshot.map\\n }, [snapshot.versionKey, snapshot.hasData, snapshot.fullRedraw, snapshot.dirtyCells])\\n const containerStyle = {\\n padding: \\\"14px\\\",\\n background: \\\"linear-gradient(135deg, rgba(2, 6, 23, 0.98), rgba(8, 13, 34, 0.98))\\\",\\n color: \\\"#f8fafc\\\",\\n fontFamily: \\\"monospace\\\",\\n minHeight: \\\"100%\\\"\\n }\\n const headerStyle = { color: \\\"#22d3ee\\\", fontSize: \\\"12px\\\", marginBottom: \\\"10px\\\" }\\n return e(\\\"div\\\", { style: containerStyle },\\n e(\\\"div\\\", { style: headerStyle }, labState?.serverName ?? \\\"labTest\\\"),\\n e(\\\"canvas\\\", { ref: canvasRef })\\n )\\n}\\nlet labCompleteAnswer = \\\"\\\"\\nlet labCompleteMap = null\\nlet labCompleteServerName = \\\"\\\"\\n\\n// ---------------------------------------------------------------------------\\n// State lookup. In the old solver this returned a per-server entry from\\n// the inProgress Map (creating one if missing). Here we have a single\\n// labState; redirect to ensureLabState which creates / returns it.\\n// ---------------------------------------------------------------------------\\nfunction getLabState(server, details) {\\n const state = ensureLabState(server)\\n if (details && !state.details) state.details = details\\n return state\\n}\\n\\n// ---------------------------------------------------------------------------\\n// Root room lookup — returns the start cell for `server` if labState is\\n// bound to that server and a rootKey has been pinned, else null.\\n// ---------------------------------------------------------------------------\\nfunction getLabRootRoom(server) {\\n if (!labState || labState.serverName !== server) return null\\n if (typeof labState.rootKey !== \\\"string\\\" || !labState.rootKey) return null\\n return labState.rooms?.[labState.rootKey] ?? null\\n}\\n\\n// ---------------------------------------------------------------------------\\n// Single-room and worker-position accessors. The old solver's APIs took\\n// a server name; we just check it matches the bound state and read from\\n// labState.\\n// ---------------------------------------------------------------------------\\nfunction getLabRoom(server, x, y) {\\n if (!labState || labState.serverName !== server) return null\\n return labState.rooms?.[getLabKey(x, y)] ?? null\\n}\\nfunction getLabRoomReport(server, x, y) {\\n return getLabRoom(server, x, y)?.jsonLog ?? false\\n}\\nfunction getLabWorkerPosition(server, workerId) {\\n if (!labState || labState.serverName !== server) return null\\n const worker = labState.workers?.[workerId]\\n if (!worker) return null\\n return [worker.x, worker.y]\\n}\\nfunction updateLabWorkerPosition(server, details, workerId, x, y) {\\n const state = getLabState(server, details)\\n setLabWorkerPosition(state, workerId, x, y)\\n}\\nfunction clearLabWorkerPosition(server, workerId) {\\n if (!labState || labState.serverName !== server) return\\n if (labState.workers?.[workerId]) {\\n markLabDisplayDirtyCoords(labState, labState.workers[workerId].x, labState.workers[workerId].y)\\n delete labState.workers[workerId]\\n labState.workersVersion = (labState.workersVersion ?? 0) + 1\\n }\\n clearLabWorkerVisitStack(workerId)\\n}\\n\\nfunction ensureLabLayout(server, details, chaReq) {\\n const state = getLabState(server, details)\\n if (!state.layout) {\\n state.layout = getEstimatedLabLayout(chaReq)\\n syncLabDisplayMap(state, true)\\n }\\n return state.layout\\n}\\n\\n// ---------------------------------------------------------------------------\\n// Completion bookkeeping. Keep the live labyrinth state object intact so\\n// shared sections such as deadEndEntries are never cloned away from the\\n// worker-visible copy.\\n// ---------------------------------------------------------------------------\\nfunction getCompletedLabStateRef(state) {\\n return state ?? null\\n}\\nfunction setCompletedLabState(answer, state, serverName = \\\"\\\") {\\n labComplete = true\\n labCompleteAnswer = typeof answer === \\\"string\\\" ? answer : \\\"\\\"\\n labCompleteMap = state ? buildLabMapSnapshotRows(state).slice() : null\\n labCompleteServerName = serverName || state?.serverName || labState?.serverName || \\\"\\\"\\n}\\nfunction getLabCompleteState() {\\n return labComplete ? labState : null\\n}\\nfunction getLabCompleteAnswer() {\\n return labCompleteAnswer || \\\"\\\"\\n}\\nfunction getLabCompleteMap() {\\n return Array.isArray(labCompleteMap) ? labCompleteMap.slice() : null\\n}\\nfunction getLabCompleteServerName() {\\n return labCompleteServerName || labState?.serverName || \\\"\\\"\\n}\\nfunction applyLabCompletionMarker(server, completedState, fallbackX, fallbackY, result) {\\n const [finishX, finishY] = getLabCompletionCoords(server, fallbackX, fallbackY, result)\\n if (!Number.isInteger(finishX) || !Number.isInteger(finishY)) return [null, null]\\n if (completedState?.layout) {\\n completedState.layout.finishX = finishX\\n completedState.layout.finishY = finishY\\n }\\n if (completedState) completedState.finishKey = getLabKey(finishX, finishY)\\n return [finishX, finishY]\\n}\\nfunction getLabCompletionCoords(server, fallbackX, fallbackY, result) {\\n const rawCoords = getLabRawCoordsFromAuthResult(result?.authResults ?? result)\\n if (Array.isArray(rawCoords)) {\\n const state = (labState && labState.serverName === server) ? labState : null\\n const [actualX, actualY] = getLabActualCoords(rawCoords[0], rawCoords[1], { coords: rawCoords }, state)\\n if (Number.isInteger(actualX) && Number.isInteger(actualY)) return [actualX, actualY]\\n }\\n return [fallbackX, fallbackY]\\n}\\n// ---------------------------------------------------------------------------\\n// Path inference — the original solver did a BFS over recorded rooms to\\n// reconstruct the shortest known path from root to (x, y). We just read\\n// `room.path` (which is maintained incrementally by ensureLabRoom /\\n// recordLabRoom). Good enough for resync paths.\\n// ---------------------------------------------------------------------------\\nfunction getLabKnownOrInferredPath(state, x, y) {\\n const room = state?.rooms?.[getLabKey(x, y)]\\n return Array.isArray(room?.path) ? room.path.slice() : []\\n}\\n\\nconst labDecisionLog = false\\n\\n// ===========================================================================\\n// darktest.jsx fixes — adapters that bridge the legacy lab case body in\\n// the puzzle-dispatch switch onto labTest.jsx's pickGreedyStep / walkOneStep.\\n// Without these, the case body's `pickLabClaimAt` calls return null every\\n// iteration (signature mismatch) and the worker never moves.\\n// ===========================================================================\\n\\n// Bind labState to the global `inProgress` Map for the server we just\\n// touched, so legacy `inProgress.get(server)` reads in the case body see\\n// the right state object. No-op when inProgress is unavailable.\\nfunction syncLabToInProgress(server) {\\n if (typeof server !== \\\"string\\\" || !server) return\\n if (typeof inProgress?.set !== \\\"function\\\") return\\n if (labState && labState.serverName === server) {\\n syncLabSharedSections(labState)\\n inProgress.set(server, labState)\\n }\\n}\\n\\n// Legacy-form picker. Adapter around pickGreedyStep:\\n// * Accepts the (server, workerId, x, y, skipKeys) shape used by the\\n// case body's pickLabClaimAt closure.\\n// * Resolves `server` to the bound labState via ensureLabState.\\n// * Calls the underlying greedy picker.\\n// * Pads the return value with the fields the legacy walkLabToTarget\\n// and case-body post-arrival code reads (key, path, travelPath,\\n// routeRoomNext, fromX/fromY, influenceSignature).\\n//\\n// skipKeys is passed through so blocked/dead claims are not reselected.\\n// Back-direction candidates intentionally bypass it.\\nfunction pickGreedyStepLegacy(server, workerId, x, y, skipKeys) {\\n const state = ensureLabState(server)\\n syncLabToInProgress(server)\\n const pick = pickGreedyStep(state, workerId, x, y, { skipKeys })\\n syncLabToInProgress(server)\\n if (!pick) return null\\n const targetKey = getLabKey(pick.x, pick.y)\\n const targetRoom = state.rooms?.[targetKey]\\n return {\\n key: targetKey,\\n x: pick.x,\\n y: pick.y,\\n dir: pick.dir,\\n backstep: pick.backstep === true,\\n path: Array.isArray(targetRoom?.path) ? targetRoom.path.slice() : [],\\n travelPath: [pick.dir],\\n routeRoomNext: { [getLabKey(x, y)]: pick.dir },\\n fromX: x,\\n fromY: y,\\n influenceSignature: \\\"\\\"\\n }\\n}\\n\\n// Legacy-form walker. Bridges walkLabToTarget's contract onto walkOneStep.\\n// Per iteration, looks up the dir for the current cell from\\n// target.routeRoomNext (set by the picker for the from-cell only); if\\n// absent — because the worker has moved past the from-cell mid-walk —\\n// re-picks fresh from the current cell so a multi-step walk doesn't\\n// strand itself. Translates walkOneStep's compact result into the rich\\n// shape (arrived / blocked / desynced / finished / workerExited /\\n// stepLimit / noRoute, plus stepsTaken / currentX / currentY) the case\\n// body branches on.\\nasync function walkLabToTarget(ns, server, details, workerId, labWorker, target, options = {}) {\\n const result = { stepsTaken: 0, finished: false, arrived: false }\\n if (!target || !Number.isInteger(target.x) || !Number.isInteger(target.y)) {\\n result.missingTarget = true\\n return result\\n }\\n syncLabToInProgress(server)\\n const limit = Number.isFinite(options?.maxSteps) && options.maxSteps > 0\\n ? Math.floor(options.maxSteps)\\n : 1\\n const startPos = getLabWorkerPosition(server, workerId)\\n if (!startPos) {\\n result.missingPosition = true\\n return result\\n }\\n let [currentX, currentY] = startPos\\n let lastReport = false\\n while (result.stepsTaken < limit) {\\n if (currentX === target.x && currentY === target.y) {\\n result.arrived = true\\n result.currentX = currentX\\n result.currentY = currentY\\n result.report = lastReport\\n return result\\n }\\n let dir = target.routeRoomNext?.[getLabKey(currentX, currentY)]\\n if (!dir || !labDirections[dir]) {\\n const greedy = pickGreedyStep(labState, workerId, currentX, currentY)\\n if (!greedy) {\\n result.noRoute = true\\n result.currentX = currentX\\n result.currentY = currentY\\n return result\\n }\\n dir = greedy.dir\\n }\\n const moved = await walkOneStep(ns, server, details, workerId, labWorker, dir, currentX, currentY)\\n result.stepsTaken++\\n if (moved.workerExited) {\\n result.workerExited = true\\n return result\\n }\\n if (moved.lostServer) {\\n result.lostServer = true\\n result.currentX = moved.currentX\\n result.currentY = moved.currentY\\n return result\\n }\\n if (moved.finished) {\\n result.finished = true\\n result.authResults = moved.authResults\\n if (Number.isInteger(moved.exitX) && Number.isInteger(moved.exitY)) {\\n result.exitX = moved.exitX\\n result.exitY = moved.exitY\\n } else {\\n const [fx, fy] = getLabExitCoordsFromStep(labState, currentX, currentY, dir, moved.authResults)\\n result.exitX = fx\\n result.exitY = fy\\n }\\n return result\\n }\\n if (moved.blocked) {\\n result.blocked = true\\n result.currentX = moved.currentX\\n result.currentY = moved.currentY\\n return result\\n }\\n if (moved.desynced) {\\n result.desynced = true\\n result.currentX = moved.currentX\\n result.currentY = moved.currentY\\n return result\\n }\\n if (moved.moved) {\\n currentX = moved.currentX\\n currentY = moved.currentY\\n if (moved.quadrantCrossed) {\\n result.quadrantCrossed = true\\n result.currentX = currentX\\n result.currentY = currentY\\n return result\\n }\\n if (currentX === target.x && currentY === target.y) {\\n result.arrived = true\\n result.currentX = currentX\\n result.currentY = currentY\\n return result\\n }\\n }\\n }\\n result.stepLimit = true\\n result.currentX = currentX\\n result.currentY = currentY\\n return result\\n}\\n\""},{"filename":"SphyxOS/bins/dumpMoney.js","file":"\"import { getBestFavor, getBestRep, getPlay, getAugsFromFaction, getOwnedAugs, purchaseAug, upgHomeRam } from \\\"SphyxOS/util.js\\\"\\nimport { getReputationFromDonation, getGangFaction, getFactionFav, getFacRep, donateToFac, proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.atExit(() => ns.writePort(ns.pid, true))\\n const FAVOR = await proxy(ns, \\\"getFavorToDonate\\\")\\n const player = await getPlay(ns)\\n const factions = player.factions\\n let gangFaction = await getGangFaction(ns)\\n let bought = true\\n while (bought) {\\n bought = false\\n for (const faction of factions) {\\n const purchased = await getOwnedAugs(ns, true)\\n /**@type {String[]} purchasable */\\n let purchasable = await getAugsFromFaction(ns, faction)\\n purchasable = purchasable.filter((p) => !purchased.includes(p) && p !== \\\"NeuroFlux Governor\\\").sort((a, b) => ns.singularity.getAugmentationPrice(b) - ns.singularity.getAugmentationPrice(a))\\n for (const aug of purchasable) {\\n //If we cant buy it and we have enough favor to donate, donate enough to get it\\n let buy = await purchaseAug(ns, faction, aug)\\n if (buy) bought = true\\n if (!buy && await getFactionFav(ns, faction) >= FAVOR && faction !== gangFaction && faction !== \\\"Bladeburners\\\" && faction !== \\\"Church of the Machine God\\\" && faction !== \\\"Shadows of Anarchy\\\") {\\n if (ns.singularity.getAugmentationPrice(aug) > ns.getServerMoneyAvailable(\\\"home\\\")) break //If we can't afford the augment, stop donating\\n const donate = await getReputationFromDonation(ns, 1e6) //Rep for donating 1e6 dollars\\n const rep = await getFacRep(ns, faction)\\n const targetrep = ns.singularity.getAugmentationRepReq(aug)\\n if (!await donateToFac(ns, faction, Math.min(((targetrep - rep) / donate * 1e6) + 1000, ns.getServerMoneyAvailable(\\\"home\\\") - 1000000))) break\\n buy = await purchaseAug(ns, faction, aug)\\n if (buy) bought = true\\n }\\n } //End of pNoNFG\\n } //End of factions\\n }//End of While\\n \\n const bestRep = await getBestRep(ns)///Has faction ahd rep attributes\\n //First round of neuroflux - targetted at the best reputation place we have, filtering out gang and Bladeburners\\n if (bestRep.rep > 0) while (await purchaseAug(ns, bestRep.faction, \\\"NeuroFlux Governor\\\")) { }\\n //Donation round\\n const bestFavor = await getBestFavor(ns)//Has faction and favor attributes\\n if (bestFavor.favor >= FAVOR) {\\n while (true) {\\n await purchaseAug(ns, bestFavor.faction, \\\"NeuroFlux Governor\\\") //Buy it\\n const donate = await getReputationFromDonation(ns, 1e6) //Rep for donating 1e6 dollars\\n const rep = await getFacRep(ns, bestFavor.faction)\\n const targetRep = ns.singularity.getAugmentationRepReq(\\\"NeuroFlux Governor\\\")\\n if (ns.singularity.getAugmentationPrice(\\\"NeuroFlux Governor\\\") > ns.getServerMoneyAvailable(\\\"home\\\")) break\\n if (rep >= targetRep) continue //We have enough rep, continue\\n if (!await donateToFac(ns, bestFavor.faction, Math.min(((targetRep - rep) / donate * 1e6) + 1000, Math.max(0, ns.getServerMoneyAvailable(\\\"home\\\") - 1000000)))) {\\n await donateToFac(ns, bestFavor.faction, ns.getServerMoneyAvailable(\\\"home\\\") - 1000000)\\n break\\n }\\n }\\n }\\n //Ram Upgrading Round\\n while (await upgHomeRam(ns)) { }\\n}\""},{"filename":"SphyxOS/bins/gang.js","file":"\"import { gangRecruit, gangAscend, gangEquip, setWar, gangCreate, gangGetMembers, gangGetMembersFull, gangInGang } from \\\"SphyxOS/util.js\\\"\\nimport { gangGetGangInfo, gangGetOtherGangInfo, gangRespectForNext, getBNMults, hasBN, getFacRep, gangSetMemberTask } from \\\"SphyxOS/util.js\\\"\\nimport { joinFac, getPlay, travelCity, setGym, getMoneyAvail, doCrime } from \\\"SphyxOS/util.js\\\"\\nimport { hasSleeves, sleeveShockRecovery, sleeveSync } from \\\"SphyxOS/util.js\\\"\\nimport { sleeveTravel, sleeveSetToGym, sleeveSetToCrime, getSleeveObject, proxy, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\nconst WIDTH = 1055\\nconst HEIGHT = 660\\nconst STATS = 30\\nconst GANG_NAME = \\\"Slum Snakes\\\"\\nconst MAX_MEMBERS = 12\\nconst WIN_WAR_CHANCE = .55\\nconst WAR_CUTOFF = .9\\nconst MIN_TERRITORY_START_WAR = .99\\nconst COMBAT_STAT_TRAIN = 20\\nconst WORKERS = 9 / 12\\nlet MODE = \\\"Respect\\\" //Respect, Money, Auto\\nlet AUTOASCEND = true //Whether or not we automatically switch workers, turn on buying eq, ascend, etc.\\nlet AUTOEQ = true\\nlet SLEEVES = false\\nlet SLEEVEACCESS = false\\nlet WARFARE_TICK = -1\\nconst SLEEVESTATS = 30\\nconst SLEEVESHOCK = 97\\nlet HASBN4 = false\\nlet NOTRAIN = false\\nlet memberNames;\\nlet fullMembers;\\nlet gangInfo;\\nlet otherGangInfo;\\nlet respectForNext;\\nlet bitnodeMults;\\nlet win\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n ns.clearPort(6)\\n ns.writePort(6, ns.pid)\\n ns.atExit(() => {\\n ns.clearPort(6)\\n if (win) win.close()\\n })\\n\\n //Are we strong enough?\\n /** @type {Player} me */\\n let me = await getPlay(ns)\\n let skls = me.skills\\n HASBN4 = await hasBN(ns, 4, 2)\\n let wrk = HASBN4 ? await proxy(ns, \\\"singularity.getCurrentWork\\\") : false\\n let haveGang = await gangInGang(ns)\\n SLEEVEACCESS = await hasSleeves(ns)\\n WARFARE_TICK = -1\\n MODE = ns.args.includes(\\\"money\\\") ? \\\"Money\\\" : ns.args.includes(\\\"respect\\\") ? \\\"Respect\\\" : \\\"Training\\\"\\n getCommands(ns)\\n while (!haveGang && !NOTRAIN && (skls.agility < STATS || skls.defense < STATS || skls.dexterity < STATS || skls.strength < STATS)) {\\n me = await getPlay(ns)\\n skls = me.skills\\n wrk = HASBN4 ? await proxy(ns, \\\"singularity.getCurrentWork\\\") : false\\n if (SLEEVEACCESS && SLEEVES) await sleeveWork(ns)\\n\\n if (me.city !== \\\"Sector-12\\\") {\\n //Travel to our Gym\\n clearLogs(ns)\\n update(ns, \\\"Please go to Sector-12\\\")\\n if (HASBN4) await travelCity(ns, \\\"Sector-12\\\")\\n await ns.asleep(1000)\\n continue\\n }\\n if (skls.strength < STATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Str to 30\\\")\\n if (SLEEVEACCESS && SLEEVES) await displaySleeves(ns)\\n if (wrk === null || (wrk && wrk.classType !== \\\"str\\\")) {\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"str\\\")\\n }\\n await ns.asleep(1000)\\n continue\\n }\\n if (skls.defense < STATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Def to 30\\\")\\n if (SLEEVEACCESS && SLEEVES) await displaySleeves(ns)\\n if (wrk === null || (wrk && wrk.classType !== \\\"def\\\")) {\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"def\\\")\\n }\\n await ns.asleep(1000)\\n continue\\n }\\n if (skls.dexterity < STATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Dex to 30\\\")\\n if (SLEEVEACCESS && SLEEVES) await displaySleeves(ns)\\n if (wrk === null || (wrk && wrk.classType !== \\\"dex\\\")) {\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"dex\\\")\\n }\\n await ns.asleep(1000)\\n continue\\n }\\n if (skls.agility < STATS) {\\n clearLogs(ns)\\n update(ns, \\\"Train Agi to 30\\\")\\n if (SLEEVEACCESS && SLEEVES) await displaySleeves(ns)\\n if (wrk === null || (wrk && wrk.classType !== \\\"agi\\\")) {\\n await setGym(ns, \\\"Powerhouse Gym\\\", \\\"agi\\\")\\n }\\n await ns.asleep(1000)\\n continue\\n }\\n }\\n if (HASBN4 && !NOTRAIN) await doCrime(ns, \\\"Homicide\\\") //Automatic switch to homicide\\n //Do we have enough money, and are we bad enough yet?\\n let currentMoney = await getMoneyAvail(ns, \\\"home\\\")\\n while ((currentMoney < 1000000 || ns.heart.break() > -9) && !haveGang) {\\n if (SLEEVEACCESS && SLEEVES) await sleeveWork(ns)\\n currentMoney = await getMoneyAvail(ns, \\\"home\\\")\\n haveGang = await gangInGang(ns)\\n let wrk = HASBN4 ? await proxy(ns, \\\"singularity.getCurrentWork\\\") : false\\n clearLogs(ns)\\n update(ns, \\\"Do Homicide for Money and Karma\\\")\\n update(ns, \\\"Join Slum Snakes when you can\\\")\\n if (SLEEVEACCESS && SLEEVES) await displaySleeves(ns)\\n if (HASBN4 && !NOTRAIN && wrk && wrk.crimeType !== \\\"Homicide\\\") {\\n await doCrime(ns, \\\"Homicide\\\")\\n }\\n await ns.asleep(1000)\\n continue\\n }\\n let count = 0\\n let prev = 0\\n let buf = \\\"\\\"\\n //Are we in a gang yet?\\n await gangCreate(ns, GANG_NAME)\\n while (!haveGang) {\\n if (HASBN4) await joinFac(ns, GANG_NAME)\\n await gangCreate(ns, GANG_NAME)\\n count--\\n if (count < 0) {\\n count = 30\\n const karma = ns.heart.break()\\n let result = 0\\n if (prev === 0) {\\n result = 0\\n }\\n else {\\n result = ((-54000 - karma) / ((karma - prev) / 30)) * 1000\\n }\\n buf = ns.sprintf(\\\"Karma: %s / -54000 ETA: %s\\\", karma.toFixed(0), result === 0 ? \\\"n/a\\\" : fTime(ns, result))\\n prev = karma\\n }\\n haveGang = await gangInGang(ns)\\n clearLogs(ns)\\n update(ns, buf)\\n if (SLEEVEACCESS && SLEEVES) {\\n await sleeveWork(ns)\\n await displaySleeves(ns)\\n }\\n await ns.asleep(1000)\\n }\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n bitnodeMults = await getBNMults(ns)\\n gangInfo = await gangGetGangInfo(ns)\\n let oldPower = gangInfo.power\\n let time = 0\\n while (true) {\\n memberNames = await gangGetMembers(ns)\\n //if (MODE === \\\"Auto\\\" && memberNames.length === MAX_MEMBERS) MODE = \\\"Money\\\"\\n fullMembers = await gangGetMembersFull(ns)\\n gangInfo = await gangGetGangInfo(ns)\\n\\n\\n otherGangInfo = await gangGetOtherGangInfo(ns)\\n respectForNext = await gangRespectForNext(ns)\\n if (SLEEVEACCESS && SLEEVES) await sleeveWork(ns)\\n if (memberNames.length !== MAX_MEMBERS) await gangRecruit(ns)\\n if (AUTOASCEND)\\n await gangAscend(ns)\\n if (AUTOEQ && memberNames.length > 3)\\n await gangEquip(ns)\\n const territoryWinChance = await war(ns)\\n if (WARFARE_TICK === -1) {\\n if (oldPower < gangInfo.power) { //We have our tick! It was the last one\\n WARFARE_TICK = 20000 - time\\n }\\n }\\n else if (WARFARE_TICK === 0 && oldPower === gangInfo.power && territoryWinChance < WAR_CUTOFF) //Reovery! We may have run out of bonus time and things got messed up\\n WARFARE_TICK = -1\\n else {\\n WARFARE_TICK -= time\\n if (WARFARE_TICK < 0)\\n WARFARE_TICK = 20000 - time//+ WARFARE_TICK\\n }\\n\\n await assignMembers(ns, territoryWinChance)\\n\\n //Get sleeve work: if (SLEEVEACCESS && SLEEVES) sleeveWork(ns)\\n\\n await updateDisplay(ns)\\n oldPower = gangInfo.power\\n time = await ns.gang.nextUpdate()\\n\\n }\\n}\\n/** @param {NS} ns */\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printRaw(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"gang popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function sleeveWork(ns) {\\n //We should have access to sleeves now to get here\\n const sleeves = await getSleeveObject(ns)\\n for (const slv of sleeves) {\\n if (slv.me.shock > SLEEVESHOCK) {\\n //We need to ensure we are deshocking\\n await sleeveShockRecovery(ns, slv.num)\\n continue\\n }\\n if (slv.me.sync < 100) {\\n //We need to ensure we are Synced up. Shouldn't normally be an issue\\n await sleeveSync(ns, slv.num)\\n continue\\n }\\n //Make sure we are in Sector-12\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.me.skills.strength < SLEEVESTATS) {\\n if (slv.task === null || slv.task.classType !== \\\"str\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"str\\\")\\n }\\n continue\\n }\\n if (slv.me.skills.defense < SLEEVESTATS) {\\n if (slv.task === null || slv.task.classType !== \\\"def\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"def\\\")\\n }\\n continue\\n }\\n if (slv.me.skills.dexterity < SLEEVESTATS) {\\n if (slv.task === null || slv.task.classType !== \\\"dex\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"dex\\\")\\n }\\n continue\\n }\\n if (slv.me.skills.agility < SLEEVESTATS) {\\n if (slv.task === null || slv.task.classType !== \\\"agi\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"agi\\\")\\n }\\n continue\\n }\\n //Done training, do crime\\n if (slv.task === null || slv.task.crimeType !== \\\"Homicide\\\") {\\n await sleeveSetToCrime(ns, slv.num, \\\"Homicide\\\")\\n continue\\n }\\n }\\n}\\n\\nasync function war(ns) {\\n if (gangInfo.territory < MIN_TERRITORY_START_WAR) {\\n let lowestwinchance = 1\\n\\n for (const otherGang of combatGangs.concat(hackingGangs)) {\\n if (otherGang == gangInfo.faction) {\\n continue\\n }\\n else if (otherGangInfo[otherGang].territory <= 0) {\\n continue\\n }\\n else {\\n let othergangpower = otherGangInfo[otherGang].power\\n let winChance = gangInfo.power / (gangInfo.power + othergangpower)\\n lowestwinchance = Math.min(lowestwinchance, winChance)\\n }\\n }\\n if (lowestwinchance > WIN_WAR_CHANCE) {\\n if (!gangInfo.territoryWarfareEngaged) {\\n await setWar(ns, true)\\n }\\n }\\n else if (gangInfo.territoryWarfareEngaged) {\\n await setWar(ns, false)\\n }\\n return lowestwinchance\\n }\\n else if (gangInfo.territoryWarfareEngaged) {\\n await setWar(ns, false)\\n }\\n return 1\\n}\\n/** @param {NS} ns */\\nasync function assignMembers(ns, territoryWinChance) {\\n const sortedNames = fullMembers.toSorted((a, b) => memberCombatStats(b) - memberCombatStats(a))\\n let workJobs = Math.ceil((memberNames.length) * WORKERS)\\n let wantedLevelIncrease = 0\\n let testJob = false\\n for (let member of sortedNames) {\\n if (MODE === \\\"Training\\\") {\\n await gangSetMemberTask(ns, member.name, \\\"Train Combat\\\")\\n continue\\n }\\n let highestTaskValue = 0\\n let highestValueTask = \\\"Train Combat\\\"\\n const vigilanteDecrease = fWantedGain(member, await proxy(ns, \\\"gang.getTaskStats\\\", \\\"Vigilante Justice\\\"))\\n if (WARFARE_TICK === -1 && !testJob) {\\n workJobs--\\n testJob = true\\n highestValueTask = \\\"Territory Warfare\\\"\\n }\\n else if (workJobs > 0 && gangInfo.territory < 1 && WARFARE_TICK === 0 && territoryWinChance < WAR_CUTOFF && !gangInfo.territoryWarfareEngaged) {\\n // support territory warfare if max team size, not at max territory yet and win chance not high enough yet\\n workJobs--\\n highestValueTask = \\\"Territory Warfare\\\"\\n }\\n else if (workJobs > 0 && gangInfo.territory < 1 && WARFARE_TICK === 0 && territoryWinChance < WAR_CUTOFF && gangInfo.territoryWarfareEngaged && member.def > 300) {\\n // support territory warfare if max team size, not at max territory yet and win chance not high enough yet\\n workJobs--\\n highestValueTask = \\\"Territory Warfare\\\"\\n }\\n else if (memberCombatStats(member) < COMBAT_STAT_TRAIN) {\\n highestValueTask = \\\"Train Combat\\\"\\n }\\n else if (workJobs > 0 && (wantedLevelIncrease + gangInfo.wantedLevel - 1 > vigilanteDecrease * -1 * 5 || wantedLevelIncrease + gangInfo.wantedLevel > 20)) {\\n workJobs--\\n highestValueTask = \\\"Vigilante Justice\\\"\\n wantedLevelIncrease += vigilanteDecrease * 5\\n }\\n else if (workJobs > 0) {\\n workJobs--\\n for (const t of tasks) {\\n const task = await proxy(ns, \\\"gang.getTaskStats\\\", t)\\n if (await taskValue(ns, member, task) > highestTaskValue) {\\n highestTaskValue = await taskValue(ns, member, task)\\n highestValueTask = task\\n }\\n }\\n wantedLevelIncrease += fWantedGain(member, highestValueTask) * 5\\n highestValueTask = highestValueTask.name\\n }\\n if (member.task !== highestValueTask) {\\n await gangSetMemberTask(ns, member.name, highestValueTask)\\n }\\n }\\n}\\nfunction memberCombatStats(member) {\\n return (member.str + member.def + member.dex + member.agi) / 4\\n}\\n/** @param {NS} ns */\\nasync function taskValue(ns, member, task) {\\n // determine money and reputation gain for a task\\n let respect = fRespectGain(member, task)\\n let cash = fMoneyGain(member, task)\\n let wantedLevelIncrease = fWantedGain(member, task)\\n let vigilanteWantedDecrease = fWantedGain(member, await proxy(ns, \\\"gang.getTaskStats\\\", \\\"Vigilante Justice\\\"))\\n\\n if (wantedLevelIncrease + vigilanteWantedDecrease > 0) {\\n //avoid tasks where more than one vigilante justice is needed to compensate\\n return 0\\n }\\n //else if ((2 * wantedLevelIncrease) + vigilanteWantedDecrease > 0) {\\n // Simple compensation for wanted level since we need more vigilante then\\n // ToDo: Could be a more sophisticated formula here\\n //cash *= 0.75;\\n //}\\n let neededRep = 0\\n let hasRep = Infinity\\n if (HASBN4) {\\n neededRep = await maxRepNeeded(ns, GANG_NAME)\\n hasRep = await proxy(ns, \\\"singularity.getFactionRep\\\", GANG_NAME)\\n }\\n\\n\\n if (MODE === \\\"Auto\\\" && (memberNames.length < MAX_MEMBERS || hasRep < neededRep)) return respect\\n else if (MODE === \\\"Auto\\\") return cash\\n else\\n return MODE === \\\"Respect\\\" ? respect : cash\\n}\\n/** @param {NS} ns */\\nasync function updateDisplay(ns) {\\n clearLogs(ns)\\n update(ns, ns.sprintf(\\\"Name: %s\\\", gangInfo.faction))\\n update(ns, ns.sprintf(\\\"Respect: %s (%s/s)\\\", fNumber(ns, gangInfo.respect), fNumber(ns, gangInfo.respectGainRate * 5)))\\n update(ns, ns.sprintf(\\\"Next Recruit: %s\\\", respectForNext === Number.POSITIVE_INFINITY ? \\\"MAXED\\\" : fNumber(ns, respectForNext)))\\n update(ns, ns.sprintf(\\\"Mode: %s Auto-Ascend: %s Auto-EQ: %s\\\", MODE, AUTOASCEND, AUTOEQ))\\n update(ns, ns.sprintf(\\\"Wanted Level: %s (%s/s)\\\", fNumber(ns, gangInfo.wantedLevel, 3), fNumber(ns, gangInfo.wantedLevelGainRate * 5, 2)))\\n update(ns, ns.sprintf(\\\"Wanted Penalty: %s%s\\\", fNumber(ns, (gangInfo.wantedPenalty - 1) * 100), \\\"%\\\"))\\n update(ns, ns.sprintf(\\\"Money Gains: %s/s\\\", fNumber(ns, moneyIncrease(ns) * 5)))\\n if (HASBN4) update(ns, ns.sprintf(\\\"Reputation: %s\\\", fNumber(ns, await getFacRep(ns, gangInfo.faction))))\\n update(ns, ns.sprintf(\\\"Territory: %s%s\\\", fNumber(ns, gangInfo.territory * 100, 2), \\\"%\\\"))\\n update(ns, ns.sprintf(\\\"Power: %s\\\", fNumber(ns, gangInfo.power)))\\n update(ns, ns.sprintf(\\\"Clash Win Chance: %s%s\\\", fNumber(ns, clashwin() * 100, 2), \\\"%\\\"))\\n update(ns, ns.sprintf(\\\"Territory Warfare: %s\\\", gangInfo.territoryWarfareEngaged ? \\\"Engaged\\\" : gangInfo.territory == 1 ? \\\"Finished\\\" : \\\"Waiting\\\"))\\n update(ns, \\\"------------------------------------------------------------------------------------------------------------\\\")\\n update(ns, ns.sprintf(\\\"%10s %20s %6s %6s %6s %6s %6s %6s %6s %8s %8s %6s %2s\\\", \\\"Name\\\", \\\"Task\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"$/s\\\", \\\"R/s\\\", \\\"Wanted\\\", \\\"Respct\\\", \\\"EQ\\\"))\\n for (const me of fullMembers) {\\n update(ns, ns.sprintf(\\\"%10s %20s %6s %6s %6s %6s %6s %6s %6s %8s %8s %6s %2s\\\", me.name, me.task.substring(0, 19), fNumber(ns, me.hack, 1), fNumber(ns, me.str, 1), fNumber(ns, me.def, 1), fNumber(ns, me.dex, 1), fNumber(ns, me.agi, 1), fNumber(ns, me.cha, 1), fNumber(ns, me.moneyGain * 5, 1), fNumber(ns, me.respectGain * 5), fNumber(ns, me.wantedLevelGain * 5), fNumber(ns, me.earnedRespect, 1), geteq(ns, me)))\\n }\\n ns.ui.renderTail()\\n}\\n/** @param {NS} ns */\\nasync function displaySleeves(ns) {\\n update(ns, \\\"Sleeve Statistics:\\\")\\n update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %8s %s\\\", \\\"#\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Shock\\\", \\\"Action\\\", \\\"Name\\\"))\\n //num, me, task\\n const sleeves = await getSleeveObject(ns)\\n for (const slv of sleeves) {\\n update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %8s %s\\\", slv.num, fNumber(ns, slv.me.skills.hacking, 3), fNumber(ns, slv.me.skills.strength, 3), fNumber(ns, slv.me.skills.defense, 3), fNumber(ns, slv.me.skills.dexterity, 3), fNumber(ns, slv.me.skills.agility, 3), fNumber(ns, slv.me.skills.charisma, 3), fNumber(ns, slv.me.shock, 2), slv.task === null ? \\\"Shock Recovery\\\" : slv.task.type, slv.task.actionType || slv.task.classType || slv.task.crimeType || \\\"n/a\\\"))\\n }\\n}\\n\\n/** @param {NS} ns */\\nfunction moneyIncrease(ns) {\\n let moneygain = 0\\n for (const name of fullMembers) moneygain += name.moneyGain\\n return moneygain\\n}\\n\\n/** @param {NS} ns */\\nfunction geteq(ns, soldier) {\\n return soldier.augmentations.length + soldier.upgrades.length\\n}\\n\\n/** @param {NS} ns */\\nfunction clashwin() {\\n let lowestwinchance = 1\\n for (const otherGang of combatGangs.concat(hackingGangs)) {\\n if (otherGang === gangInfo.faction) continue\\n else if (otherGangInfo[otherGang].territory <= 0) continue\\n else {\\n let othergangpower = otherGangInfo[otherGang].power\\n let winChance = gangInfo.power / (gangInfo.power + othergangpower)\\n lowestwinchance = Math.min(lowestwinchance, winChance)\\n }\\n }\\n return lowestwinchance\\n}\\n/** @param {NS} ns */\\nfunction fWantedGain(member, task) {\\n if (task.baseWanted === 0) return 0\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha\\n statWeight -= 3.5 * task.difficulty\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.wanted) / 100);\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n if (task.baseWanted < 0) {\\n return 0.4 * task.baseWanted * statWeight * territoryMult;\\n }\\n const calc = (7 * task.baseWanted) / Math.pow(3 * statWeight * territoryMult, 0.8);\\n\\n // Put an arbitrary cap on this to prevent wanted level from rising too fast if the\\n // denominator is very small. Might want to rethink formula later\\n return Math.min(100, calc);\\n}\\n/** @param {NS} ns */\\nfunction fRespectGain(member, task) {\\n if (task.baseRespect === 0) return 0;\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha;\\n statWeight -= 4 * task.difficulty;\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.respect) / 100);\\n const territoryPenalty = bitnodeMults ? (0.2 * gangInfo.territory + 0.8) * bitnodeMults.GangSoftcap : (0.2 * gangInfo.territory + 0.8)\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n const respectMult = calculateWantedPenalty();\\n return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);\\n}\\n/** @param {NS} ns */\\nfunction fMoneyGain(member, task) {\\n if (task.baseMoney === 0) return 0;\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha;\\n\\n statWeight -= 3.2 * task.difficulty;\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.money) / 100);\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n const respectMult = calculateWantedPenalty();\\n let territoryPenalty = bitnodeMults ? (0.2 * gangInfo.territory + 0.8) * bitnodeMults.GangSoftcap : (0.2 * gangInfo.territory + 0.8)\\n return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);\\n}\\n\\nfunction calculateWantedPenalty() {\\n return gangInfo.respect / (gangInfo.respect + gangInfo.wantedLevel);\\n}\\n/** @param {NS} ns */\\nasync function maxRepNeeded(ns, faction) {\\n const allAugs = await proxy(ns, \\\"singularity.getAugmentationsFromFaction\\\", faction)\\n const myAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\", true)\\n const factionAugs = allAugs.filter(f => f !== \\\"NeuroFlux Governor\\\" && !myAugs.includes(f))\\n let repNeeded = 0\\n for (const aug of factionAugs)\\n if (await proxy(ns, \\\"singularity.getAugmentationRepReq\\\", aug) > repNeeded) repNeeded = await proxy(ns, \\\"singularity.getAugmentationRepReq\\\", aug)\\n return repNeeded\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(16) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(16)\\n switch (result) {\\n case \\\"popout\\\":\\n if (!silent) ns.tprintf(\\\"Gang: PopOut On!\\\")\\n win = await makeNewWindow(\\\"Gang\\\", ns.ui.getTheme())\\n break\\n case \\\"nopopout\\\":\\n if (!silent) ns.tprintf(\\\"Gang: PopOut Off!\\\")\\n if (win) win.close()\\n break\\n case \\\"AutoAscend On\\\":\\n if (!silent) ns.tprintf(\\\"Gang: AutoAscend On!\\\")\\n AUTOASCEND = true\\n break\\n case \\\"AutoAscend Off\\\":\\n if (!silent) ns.tprintf(\\\"Gang: AutoAscend Off!\\\")\\n AUTOASCEND = false\\n break\\n case \\\"AutoEQ On\\\":\\n if (!silent) ns.tprintf(\\\"Gang: AutoEQ On!\\\")\\n AUTOEQ = true\\n break\\n case \\\"AutoEQ Off\\\":\\n if (!silent) ns.tprintf(\\\"Gang: AutoEQ Off!\\\")\\n AUTOEQ = false\\n break\\n case \\\"Sleeves On\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Sleeves On!\\\")\\n SLEEVES = true\\n break\\n case \\\"Sleeves Off\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Sleeves Off!\\\")\\n SLEEVES = false\\n break\\n case \\\"Respect\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Respect Mode!\\\")\\n MODE = \\\"Respect\\\"\\n break\\n case \\\"Money\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Money Mode!\\\")\\n MODE = \\\"Money\\\"\\n break\\n case \\\"AutoMode\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Auto Mode!\\\")\\n MODE = \\\"Auto\\\"\\n break\\n case \\\"Training\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Training Mode!\\\")\\n MODE = \\\"Training\\\"\\n break\\n case \\\"Buy EQ\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Buy EQ for all!\\\")\\n await gangEquip(ns)\\n break\\n case \\\"Ascend\\\":\\n if (!silent) ns.tprintf(\\\"Gang: Ascend Forced\\\")\\n await gangAscend(ns, true)\\n break\\n case \\\"Silent\\\":\\n silent = true\\n break\\n case \\\"NoTrain\\\":\\n NOTRAIN = true\\n break\\n default:\\n ns.tprintf(\\\"Invalid command received in gang: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\\n\\n/*const names = [\\\"Rocko\\\", \\\"Mike\\\", \\\"Jack\\\", \\\"Rudo\\\", \\\"Charmichal\\\", \\\"Percy\\\", \\\"Gloria\\\", \\\"Jessica\\\", \\\"Kelly\\\", \\\"Sam\\\", \\\"Gloria\\\", \\\"Sarah\\\",\\n \\\"Jackson\\\", \\\"Adam\\\", \\\"Bob\\\", \\\"Carl\\\", \\\"Dominique\\\", \\\"Enrique\\\", \\\"Falcon\\\", \\\"Garry\\\", \\\"Helen\\\", \\\"Ivana\\\", \\\"Jeremy\\\", \\\"Kyle\\\", \\\"Lucca\\\",\\n \\\"Max\\\", \\\"Nordic\\\", \\\"Oscar\\\", \\\"Paul\\\", \\\"Q\\\", \\\"Rodric\\\", \\\"Steve\\\", \\\"Trevor\\\", \\\"Ulfric\\\", \\\"Volcof\\\", \\\"Wilson\\\", \\\"Xena\\\", \\\"Yoril\\\", \\\"Z\\\"]\\n*/\\nconst tasks = [\\\"Mug People\\\", \\\"Deal Drugs\\\", \\\"Strongarm Civilians\\\", \\\"Run a Con\\\", \\\"Armed Robbery\\\", \\\"Traffick Illegal Arms\\\", \\\"Threaten & Blackmail\\\", \\\"Human Trafficking\\\", \\\"Terrorism\\\"];\\nconst combatGangs = [\\\"Speakers for the Dead\\\", \\\"The Dark Army\\\", \\\"The Syndicate\\\", \\\"Tetrads\\\", \\\"Slum Snakes\\\"]\\nconst hackingGangs = [\\\"NiteSec\\\", \\\"The Black Hand\\\"]\""},{"filename":"SphyxOS/bins/go.js","file":"\"/**Author:\\n * Discord:\\n * - Sphyxis\\n * \\n * Additional Contributers:\\n * Discord:\\n * - Stoneware\\n * - gmcew\\n */\\nimport { getBState, getCEmptyNodes, getLibs, getValMoves, getChain, play2moves, destroyND, makeNewWindow, hasBN } from \\\"SphyxOS/util.js\\\"\\n\\n\\nlet CHEATS = true\\nlet HASBN14_2 = false\\nlet LOGTIME = false\\nlet LOGFILE = true\\nlet STYLE = 0\\nlet REPEAT = true\\nlet currentValidMovesTurn = 0 //The turn count that the currentValidMoves is valid for\\nlet currentValidMoves //All valid moves for this turn\\nlet currentValidContestedMoves //All valid moves that occupy a contested space\\nlet turn = 0\\nlet START = performance.now()\\nlet board;\\nlet contested;\\nlet validMove;\\nlet validLibMoves;\\nlet chains;\\nlet testBoard = []\\nconst opponent = []\\nconst opponent2 = []\\nlet oppNetburners = true\\nlet oppSlumSnakes = true\\nlet oppBlackHand = true\\nlet oppTetrads = true\\nlet oppDaedalus = true\\nlet oppIlluminati = true\\nlet oppRedPill = true\\nlet oppNoAi = false\\nlet playAsWhite = false\\nlet slowMode = false\\nlet me = \\\"X\\\"\\nlet you = \\\"O\\\"\\nlet win\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"disableLog\\\")\\n ns.disableLog(\\\"go.makeMove\\\")\\n ns.disableLog(\\\"go.passTurn\\\")\\n ns.disableLog(\\\"sleep\\\")\\n ns.disableLog(\\\"exec\\\")\\n LOGFILE = true\\n getCommands(ns)\\n await ns.asleep(4) //We need our commands. Let them get checked.\\n HASBN14_2 = await hasBN(ns, 14, 2)\\n if (LOGFILE) ns.ui.openTail()\\n me = playAsWhite ? \\\"O\\\" : \\\"X\\\"\\n you = me === \\\"X\\\" ? \\\"O\\\" : \\\"X\\\"\\n\\n ns.atExit(() => {\\n ns.clearPort(5)\\n if (win) win.close()\\n })\\n ns.clearPort(5)\\n ns.writePort(5, ns.pid) //We are running!\\n const startBoard = await getBState(ns)\\n let inProgress = false\\n turn = 0\\n START = performance.now()\\n //If we have already moved, jump the turn to 3 to get out of Opening Moves\\n for (let x = 0; x < startBoard[0].length; x++) {\\n for (let y = 0; y < startBoard[0].length; y++) {\\n if (startBoard[x][y] === me) {\\n inProgress = true\\n turn = 3\\n break\\n }\\n }\\n if (inProgress) break\\n }\\n getStyle(ns)\\n buildOpponents()\\n const currentGame = await ns.go.opponentNextTurn(false, playAsWhite)\\n checkNewGame(ns, currentGame, false)\\n while (true) {\\n if (slowMode) await ns.asleep(2000)\\n else await ns.asleep(4)\\n let passed = false\\n turn++\\n board = await getBState(ns)\\n contested = await getCEmptyNodes(ns)\\n validMove = await getValMoves(ns, playAsWhite)\\n validLibMoves = await getLibs(ns)\\n chains = await getChain(ns)\\n const size = board[0].length\\n //Build a test board with walls\\n testBoard = []\\n let testWall = \\\"\\\"\\n let results;\\n if (size === 13) testWall = \\\"WWWWWWWWWWWWWWW\\\"\\n else if (size === 9) testWall = \\\"WWWWWWWWWWW\\\"\\n else if (size === 7) testWall = \\\"WWWWWWWWW\\\"\\n else if (size === 19) testWall = \\\"WWWWWWWWWWWWWWWWWWWWW\\\"\\n else testWall = \\\"WWWWWWW\\\"\\n testBoard.push(testWall)\\n for (const b of board) testBoard.push(\\\"W\\\" + b + \\\"W\\\")\\n testBoard.push(testWall)\\n //We have our test board\\n if (turn <= 1)\\n results = await movePiece(ns, getOpeningMove(ns))\\n else {\\n switch (STYLE) {\\n case 0: //Netburners\\n case 1: //The Black Hand\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 3, 3, 1, 6))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, getAggroAttack(4, 7, 3, 1, 6))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getDefAttack(8, 20, 2))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n\\n case 2: //Mr. Mustacio - Slum Snakes\\t\\t\\t\\t\\t\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 3, 3, 1, 6))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, getDefAttack(4, 7, 3, 1, 6))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 3: //Daedalus\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 4, 3, 1, 6))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, getDefAttack(5, 7, 3, 2, 6))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 4: //Tetrads\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, getAggroAttack(5, 7, 3))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat(),)) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 5: //Illum\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 6: //??????\\n if (results = await movePiece(ns, getRandomCounterLib())) break\\n if (results = await movePiece(ns, getRandomLibAttack(88))) break\\n if (results = await movePiece(ns, getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(ns, getSnakeEyes(8))) break\\n if (results = await movePiece(ns, getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(ns, disruptEyes())) break\\n if (results = await movePiece(ns, getDefPattern())) break\\n if (results = await movePiece(ns, getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1))) break\\n if (results = await movePiece(ns, getDefAttack(5, 7, 3))) break\\n if (results = await movePiece(ns, attackGrowDragon(1))) break\\n if (results = await movePiece(ns, getRandomExpand())) break\\n if (results = await movePiece(ns, getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(ns, getRandomLibAttack())) break\\n if (results = await movePiece(ns, getRandomStrat())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker())) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(4))) break\\n if (results = await moveWallBreaker(ns, getWallBreaker(-1))) break\\n update(ns, \\\"Turn Passed\\\")\\n passed = true\\n ns.ui.renderTail()\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n } //End of style switch\\n } // end of turn >= 3\\n checkNewGame(ns, results, passed)\\n }\\n}\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printf(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"ipvgo popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nfunction getStyle(ns) {\\n const facing = ns.go.getOpponent()\\n switch (facing) {\\n case \\\"Netburners\\\":\\n STYLE = 0\\n break\\n case \\\"The Black Hand\\\":\\n STYLE = 1\\n break\\n case \\\"Slum Snakes\\\":\\n STYLE = 2\\n break\\n case \\\"Daedalus\\\":\\n STYLE = 3\\n break\\n case \\\"Tetrads\\\":\\n STYLE = 4\\n break\\n case \\\"Illuminati\\\":\\n STYLE = 5\\n break\\n default:\\n STYLE = 6\\n }\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let changed = false\\n let silent = false\\n while (ns.peek(15) !== \\\"NULL PORT DATA\\\") {\\n changed = true\\n switch (ns.readPort(15)) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Go\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"IPvGo: Popout On!\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n if (!silent) ns.tprintf(\\\"IPvGo: Popout Off!\\\")\\n break\\n case \\\"Cheats On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Cheats enabled!\\\")\\n CHEATS = true\\n break\\n case \\\"No Logfile\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Started without the LOG!\\\")\\n LOGFILE = false\\n break\\n case \\\"Cheats Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Cheats disabled!\\\")\\n CHEATS = false\\n break\\n case \\\"Repeat On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Repeat enabled!\\\")\\n REPEAT = true\\n break\\n case \\\"Repeat Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Repeat disabled!\\\")\\n REPEAT = false\\n break\\n case \\\"Logging On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Logging time enabled!\\\")\\n LOGTIME = true\\n break\\n case \\\"Logging Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Logging time disabled!\\\")\\n LOGTIME = false\\n break\\n case \\\"Net On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Netburners enabled!\\\")\\n oppNetburners = true\\n break\\n case \\\"Net Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Netburners disabled!\\\")\\n oppNetburners = false\\n break\\n case \\\"Slum On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Slum Snakes enabled!\\\")\\n oppSlumSnakes = true\\n break\\n case \\\"Slum Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Slum Snakes disabled!\\\")\\n oppSlumSnakes = false\\n break\\n case \\\"BH On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: The Black Hand enabled!\\\")\\n oppBlackHand = true\\n break\\n case \\\"BH Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: The Black Hand disabled!\\\")\\n oppBlackHand = false\\n break\\n case \\\"Tetrad On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Tetrads enabled!\\\")\\n oppTetrads = true\\n break\\n case \\\"Tetrad Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Tetrads disabled!\\\")\\n oppTetrads = false\\n break\\n case \\\"Daed On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Daedalus enabled!\\\")\\n oppDaedalus = true\\n break\\n case \\\"Daed Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Daedalus disabled!\\\")\\n oppDaedalus = false\\n break\\n case \\\"Illum On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Illuminati enabled!\\\")\\n oppIlluminati = true\\n break\\n case \\\"Illum Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Illuminati disabled!\\\")\\n oppIlluminati = false\\n break\\n case \\\"???? On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: ???????? enabled!\\\")\\n oppRedPill = true\\n break\\n case \\\"???? Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: ???????? disabled!\\\")\\n oppRedPill = false\\n break\\n case \\\"No AI On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: No AI enabled!\\\")\\n oppNoAi = true\\n break\\n case \\\"No AI Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: No AI disabled!\\\")\\n oppNoAi = false\\n break\\n case \\\"SlowMode On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: SlowMode enabled!\\\")\\n slowMode = true\\n break\\n case \\\"SlowMode Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: SlowMode disabled!\\\")\\n slowMode = false\\n break\\n case \\\"Play as White On\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Play as White enabled!\\\")\\n playAsWhite = true\\n me = playAsWhite ? \\\"O\\\" : \\\"X\\\"\\n you = me === \\\"X\\\" ? \\\"O\\\" : \\\"X\\\"\\n break\\n case \\\"Play as White Off\\\":\\n if (!silent) ns.tprintf(\\\"IPvGo: Play as White disabled!\\\")\\n playAsWhite = false\\n me = playAsWhite ? \\\"O\\\" : \\\"X\\\"\\n you = me === \\\"X\\\" ? \\\"O\\\" : \\\"X\\\"\\n break\\n case \\\"Silent\\\":\\n silent = true\\n break\\n }\\n }\\n if (changed) buildOpponents()\\n await ns.asleep(200)\\n }\\n}\\n/** @param {NS} ns */\\nfunction buildOpponents() {\\n opponent.length = 0\\n opponent2.length = 0\\n if (playAsWhite || oppNoAi) {\\n opponent.push(\\\"No AI\\\")\\n opponent2.push(\\\"No AI\\\")\\n return\\n }\\n else {\\n if (oppBlackHand) {\\n opponent.push(\\\"The Black Hand\\\")\\n opponent2.push(\\\"The Black Hand\\\")\\n }\\n if (oppDaedalus) {\\n opponent.push(\\\"Daedalus\\\")\\n opponent2.push(\\\"Daedalus\\\")\\n }\\n if (oppIlluminati) {\\n opponent.push(\\\"Illuminati\\\")\\n opponent2.push(\\\"Illuminati\\\")\\n }\\n if (oppNetburners) {\\n opponent.push(\\\"Netburners\\\")\\n opponent2.push(\\\"Netburners\\\")\\n }\\n if (oppRedPill) {\\n opponent2.push(\\\"????????????\\\")\\n }\\n if (oppSlumSnakes) {\\n opponent.push(\\\"Slum Snakes\\\")\\n opponent2.push(\\\"Slum Snakes\\\")\\n }\\n if (oppTetrads) {\\n opponent.push(\\\"Tetrads\\\")\\n opponent2.push(\\\"Tetrads\\\")\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction checkNewGame(ns, gameInfo, passed) {\\n if (gameInfo.type === \\\"gameOver\\\" || (gameInfo.type === \\\"pass\\\" && passed)) {\\n if (!REPEAT) ns.exit()\\n if (playAsWhite || ns.go.getOpponent() === \\\"No AI\\\") ns.go.resetBoardState(\\\"No AI\\\", 13)\\n else {\\n try { ns.go.resetBoardState(opponent2[Math.floor(Math.random() * opponent2.length)], 13) }\\n catch { ns.go.resetBoardState(opponent[Math.floor(Math.random() * opponent.length)], 13) }\\n }\\n turn = 0\\n clearLogs(ns)\\n getStyle(ns)\\n }\\n}\\n/** @param {NS} ns */\\nfunction isPattern(x, y, pattern) {\\n //Move the pattern around with x/y loops, check if pattern matches IF a move is placed\\n //We can assume that x and y are valid moves\\n\\n const size = testBoard[0].length\\n const patterns = getAllPatterns(pattern)\\n const patternSize = pattern.length\\n\\n for (const patternCheck of patterns) {\\n //cx and cy - the spots of the pattern we are checking against the test board\\n //For, say a 3x3 pattern, we do a grid of 0,0 -> 2, 2\\n for (let cx = ((patternSize - 1) * -1); cx <= 0; cx++) { // We've added a wall around everything, so 0 is a wall\\n if (cx + x + 1 < 0 || cx + x + 1 > size - 1) continue\\n for (let cy = ((patternSize - 1) * -1); cy <= 0; cy++) {\\n //We now have a cycle that will check each section of the grid against the pattern\\n //Safety checks: We know 0,0 is safe, we were sent it, but each other section could be bad \\n if (cy + y + 1 < 0 || cy + y + 1 > size - 1) continue\\n let count = 0\\n let abort = false\\n for (let px = 0; px < patternSize && !abort; px++) {\\n if (x + cx + px + 1 < 0 || x + cx + px + 1 >= size) { //Don't go off grid\\n abort = true\\n break\\n }\\n for (let py = 0; py < patternSize && !abort; py++) {\\n if (y + cy + py + 1 < 0 || y + cy + py + 1 >= size) { //Are we off the map?\\n abort = true\\n break\\n }\\n if (cx + px === 0 && cy + py === 0 && ![me, \\\"*\\\"].includes(patternCheck[px][py])) {\\n abort = true\\n break\\n }\\n if (cx + px === 0 && cy + py === 0 && [me].includes(contested[x][y]) && patternCheck[px][py] !== \\\"*\\\") {\\n abort = true\\n break\\n }\\n //We now have a cycles for each spot in the pattern\\n //0,0 -> 2,2 for a 3x3\\n switch (patternCheck[px][py]) {\\n case \\\"X\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === me || (cx + px === 0 && cy + py === 0 && testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\")) {\\n count++\\n }\\n else if (cx + px === 0 && cy + py === 0) {\\n count++ // Our placement piece\\n }\\n else abort = true\\n break\\n case \\\"*\\\": // Special case. We move here next or break the test\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\" && cx + px === 0 && cy + py === 0) {\\n count++\\n }\\n else abort = true\\n break\\n case \\\"O\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === you)\\n count++\\n else abort = true\\n break\\n case \\\"x\\\":\\n if ([me, \\\".\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"o\\\":\\n if ([you, \\\".\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"?\\\":\\n count++\\n break\\n case \\\".\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\")\\n count++\\n else abort = true\\n break\\n case \\\"W\\\":\\n if ([\\\"W\\\", \\\"#\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"B\\\":\\n if ([\\\"W\\\", \\\"#\\\", me].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"b\\\":\\n if ([\\\"W\\\", \\\"#\\\", you].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"A\\\":\\n if ([\\\"W\\\", \\\"#\\\", me, you].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n }\\n if (count === patternSize * patternSize) return true\\n }\\n }\\n }\\n }\\n }\\n return false\\n}\\n/** @param {NS} ns */\\nfunction getAllPatterns(pattern) {\\n const rotations = [\\n pattern,\\n rotate90Degrees(pattern),\\n rotate90Degrees(rotate90Degrees(pattern)),\\n rotate90Degrees(rotate90Degrees(rotate90Degrees(pattern))),\\n ]\\n return [...rotations, ...rotations.map(verticalMirror)]\\n}\\n\\n//Special thanks to @gmcew for the next 2 functions!\\n/** @param {NS} ns */\\nfunction rotate90Degrees(pattern) {\\n return pattern.map((val, index) => pattern.map(row => row[index]).reverse().join(\\\"\\\"))\\n}\\n/** @param {NS} ns */\\nfunction verticalMirror(pattern) {\\n return pattern.toReversed()\\n}\\n\\n/** @param {NS} ns */\\nfunction getSnakeEyes(minKilled = 6) {\\n if (!CHEATS || !HASBN14_2) return []\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n\\n const checked = new Set\\n\\n for (let x = 0; x < size - 1; x++)\\n for (let y = 0; y < size - 1; y++) {\\n if (contested[x][y] === me || board[x][y] !== you || validLibMoves[x][y] !== 2 || checked.has(JSON.stringify([x, y]))) continue\\n //Is it the enemy, with 2 libs (we can kill) and we have not checked this spot and the chain is large enough\\n const chain = getChainValue(x, y, you, true)\\n checked.add(JSON.stringify([x, y]))\\n if (chain < minKilled) continue\\n //We have a winner! Check all it's spots and find the 2 killing blows. Add the checked spots to the checked list so we don't recheck\\n const enemySearch = new Set\\n const move1 = []\\n const move2 = []\\n enemySearch.add(JSON.stringify([x, y]))\\n for (const explore of enemySearch) {\\n const [fx, fy] = JSON.parse(explore)\\n //Find your eyes\\n if (board[fx][fy] === \\\".\\\") {\\n move1.length ? move2.push([fx, fy]) : move1.push([fx, fy])\\n checked.add(JSON.stringify([fx, fy]))\\n continue\\n }\\n\\n //Find more of yourself to search...\\n if (fx < size - 1 && [you, \\\".\\\"].includes(board[fx + 1][fy])) {\\n enemySearch.add(JSON.stringify([fx + 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fx > 0 && [you, \\\".\\\"].includes(board[fx - 1][fy])) {\\n enemySearch.add(JSON.stringify([fx - 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy > 0 && [you, \\\".\\\"].includes(board[fx][fy - 1])) {\\n enemySearch.add(JSON.stringify([fx, fy - 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy < size - 1 && [you, \\\".\\\"].includes(board[fx][fy + 1])) {\\n enemySearch.add(JSON.stringify([fx, fy + 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n } // End of searching the enemy\\n\\n if (chain > highValue) {\\n highValue = chain\\n moveOptions.length = 0\\n const mv1 = move1.pop()\\n const mv2 = move2.pop()\\n moveOptions.push([mv1[0], mv1[1], mv2[0], mv2[1]])\\n }\\n else if (chain === highValue) {\\n const mv1 = move1.pop()\\n const mv2 = move2.pop()\\n moveOptions.push([mv1[0], mv1[1], mv2[0], mv2[1]])\\n }\\n } // Search whole board\\n\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"SnakeEyes Cheat\\\"\\n } : []\\n}\\n\\n/** @param {NS} ns */\\nfunction getWallBreaker(eyesToBreak = 3) {\\n if (!CHEATS || !HASBN14_2) return []\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n\\n const checked = new Set\\n\\n for (let x = 0; x < size - 1; x++)\\n for (let y = 0; y < size - 1; y++) {\\n if (contested[x][y] === me || board[x][y] !== you || (validLibMoves[x][y] !== eyesToBreak && eyesToBreak > 0) || checked.has(JSON.stringify([x, y]))) continue\\n //Is it the enemy, with 2 libs (we can kill) and we have not checked this spot and the chain is large enough\\n const chain = getChainValue(x, y, you, true)\\n checked.add(JSON.stringify([x, y]))\\n //We have a winner! Check all it's spots and find the 2 killing blows. Add the checked spots to the checked list so we don't recheck\\n const enemySearch = new Set\\n const moves = []\\n enemySearch.add(JSON.stringify([x, y]))\\n for (const explore of enemySearch) {\\n const [fx, fy] = JSON.parse(explore)\\n //Find your eyes\\n if (board[fx][fy] === \\\".\\\") {\\n moves.push([fx, fy])\\n checked.add(JSON.stringify([fx, fy]))\\n continue\\n }\\n\\n //Find more of yourself to search...\\n if (fx < size - 1 && [you, \\\".\\\"].includes(board[fx + 1][fy])) {\\n enemySearch.add(JSON.stringify([fx + 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fx > 0 && [you, \\\".\\\"].includes(board[fx - 1][fy])) {\\n enemySearch.add(JSON.stringify([fx - 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy > 0 && [you, \\\".\\\"].includes(board[fx][fy - 1])) {\\n enemySearch.add(JSON.stringify([fx, fy - 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy < size - 1 && [you, \\\".\\\"].includes(board[fx][fy + 1])) {\\n enemySearch.add(JSON.stringify([fx, fy + 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n } // End of searching the enemy\\n\\n if (chain > highValue) {\\n highValue = chain\\n moveOptions.length = 0\\n moveOptions.push(...moves)\\n }\\n else if (chain === highValue) {\\n moveOptions.push(...moves)\\n }\\n } // Search whole board\\n\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"WallBreaker Cheat\\\"\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getRandomLibAttack(minKilled = 1) {\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (contested[x][y] === me || validLibMoves[x][y] !== -1) continue\\n\\n let count = 0\\n let chains = 0\\n\\n //We are only checking up, down, left and right\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] === 1) {\\n count++\\n chains += getChainValue(x - 1, y, you)\\n }\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] === 1) {\\n count++\\n chains += getChainValue(x + 1, y, you)\\n }\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] === 1) {\\n count++\\n chains += getChainValue(x, y - 1, you)\\n }\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] === 1) {\\n count++\\n chains += getChainValue(x, y + 1, you)\\n }\\n const enemyLibs = getSurroundLibs(x, y, you)\\n if (count === 0 || (chains < minKilled && enemyLibs <= 1)) continue\\n\\n const result = count * chains\\n if (result > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = result\\n }\\n else if (result === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Lib Attack\\\"\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getRandomLibDefend(savedMin = 1) {\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n const surround = getSurroundLibs(x, y, me)\\n const myEyes = getEyeValue(x, y, me)\\n if (surround + myEyes < 2 || createsLib(x, y, me)) continue //Abort. Let it go, let it go...\\n\\n if (validLibMoves[x][y] === -1) {\\n let count = 0\\n //We are only checking up, down, left and right\\n if (x > 0 && validLibMoves[x - 1][y] === 1 && board[x - 1][y] === me) count += getChainValue(x - 1, y, me)\\n if (x < size - 1 && validLibMoves[x + 1][y] === 1 && board[x + 1][y] === me) count += getChainValue(x + 1, y, me)\\n if (y > 0 && validLibMoves[x][y - 1] === 1 && board[x][y - 1] === me) count += getChainValue(x, y - 1, me)\\n if (y < size - 1 && validLibMoves[x][y + 1] === 1 && board[x][y + 1] === me) count += getChainValue(x, y + 1, me)\\n if (count === 0 || count < savedMin) continue\\n //Just HOW effective will this move be? Counter attack if we can.\\n count *= surround\\n\\n if (count > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = count\\n }\\n else if (count === highValue) moveOptions.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Lib Defend\\\"\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getRandomCounterLib(ns) {\\n //Advanced strategy\\n //If we have a chain that's going to die, and a hanging lib attached to it\\n //Find that hanging lib and kill it to save the chain\\n const size = board[0].length\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n const movesAvailable = new Set //Contains the empty squares that we are looking to see if we should take\\n const friendlyToCheckForOpp = new Set\\n for (const [x, y] of moves) {\\n //We are checking up, down, left and right first\\n\\n if (x > 0 && validLibMoves[x - 1][y] === 1 && board[x - 1][y] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x - 1, y]))\\n }\\n if (x < size - 1 && validLibMoves[x + 1][y] === 1 && board[x + 1][y] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x + 1, y]))\\n }\\n if (y > 0 && validLibMoves[x][y - 1] === 1 && board[x][y - 1] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x, y - 1]))\\n }\\n if (y < size - 1 && validLibMoves[x][y + 1] === 1 && board[x][y + 1] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x, y + 1]))\\n }\\n }\\n //Shortcut. While there's 1, is it THE one?\\n //We know that 1 side of this is a friendly with 1 lib at risk. Is another side the enemy?\\n for (const explore of movesAvailable) {\\n const [fx, fy] = JSON.parse(explore)\\n if (!validMove[fx][fy]) continue\\n if (fx < size - 1 && board[fx + 1][fy] === you && validLibMoves[fx + 1][fy] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the east\\\"\\n }\\n }\\n if (fx > 0 && board[fx - 1][fy] === you && validLibMoves[fx - 1][fy] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the west\\\"\\n }\\n }\\n if (fy > 0 && board[fx][fy - 1] === you && validLibMoves[fx][fy - 1] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the south\\\"\\n }\\n }\\n if (fy < size - 1 && board[fx][fy + 1] === you && validLibMoves[fx][fy + 1] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the north\\\"\\n }\\n }\\n }\\n const enemiesToSearch = new Set\\n //We have our empty chain. Look through him to find adjoining O's that can be killed and other friendies\\n for (const explore of friendlyToCheckForOpp) {\\n const [fx, fy] = JSON.parse(explore)\\n if (fx < size - 1 && board[fx + 1][fy] === you && validLibMoves[fx + 1][fy] === 1) enemiesToSearch.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && board[fx - 1][fy] === you && validLibMoves[fx - 1][fy] === 1) enemiesToSearch.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && board[fx][fy - 1] === you && validLibMoves[fx][fy - 1] === 1) enemiesToSearch.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && board[fx][fy + 1] === you && validLibMoves[fx][fy + 1] === 1) enemiesToSearch.add(JSON.stringify([fx, fy + 1]))\\n\\n if (fx < size - 1 && [me].includes(board[fx + 1][fy])) friendlyToCheckForOpp.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && [me].includes(board[fx - 1][fy])) friendlyToCheckForOpp.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && [me].includes(board[fx][fy - 1])) friendlyToCheckForOpp.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && [me].includes(board[fx][fy + 1])) friendlyToCheckForOpp.add(JSON.stringify([fx, fy + 1]))\\n }\\n\\n for (const explore of enemiesToSearch) {\\n const [fx, fy] = JSON.parse(explore)\\n if (fx < size - 1 && board[fx + 1][fy] === you) enemiesToSearch.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && board[fx - 1][fy] === you) enemiesToSearch.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && board[fx][fy - 1] === you) enemiesToSearch.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && board[fx][fy + 1] === you) enemiesToSearch.add(JSON.stringify([fx, fy + 1]))\\n\\n if (fx < size - 1 && board[fx + 1][fy] === \\\".\\\" && validMove[fx + 1][fy]) {\\n return {\\n coords: [fx + 1, fy],\\n msg: \\\"Counter Lib Attack - The wind blows\\\"\\n }\\n }\\n if (fx > 0 && board[fx - 1][fy] === \\\".\\\" && validMove[fx - 1][fy]) {\\n return {\\n coords: [fx - 1, fy],\\n msg: \\\"Counter Lib Attack - The earth grows\\\"\\n }\\n }\\n if (fy > 0 && board[fx][fy - 1] === \\\".\\\" && validMove[fx][fy - 1]) {\\n return {\\n coords: [fx, fy - 1],\\n msg: \\\"Counter Lib Attack - The fire burns\\\"\\n }\\n }\\n if (fy < size - 1 && board[fx][fy + 1] === \\\".\\\" && validMove[fx][fy + 1]) {\\n return {\\n coords: [fx, fy + 1],\\n msg: \\\"Counter Lib Attack - The water flows\\\"\\n }\\n }\\n }\\n return []\\n}\\n/** @param {NS} ns */\\nfunction getRandomExpand() {\\n const moveOptions = []\\n const size = board[0].length;\\n let highValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n const surroundLibs = getSurroundLibs(x, y, me)\\n const enemySurroundLibs = getSurroundLibs(x, y, you)\\n if (contested[x][y] !== \\\"?\\\" || surroundLibs <= 2 || createsLib(x, y, me) || enemySurroundLibs <= 1) continue\\n let count = 0\\n //We are only checking up, down, left and right. Don't expand if you're surrounded by friendlies\\n if (x > 0 && board[x - 1][y] === me) count++\\n if (x < size - 1 && board[x + 1][y] === me) count++\\n if (y > 0 && board[x][y - 1] === me) count++\\n if (y < size - 1 && board[x][y + 1] === me) count++\\n if (count >= 3 || count <= 0) continue\\n\\n const surroundSpace = getSurroundSpaceFull(x, y) + 1\\n const enemySurroundChains = getChainAttack(x, y) + 1\\n const myEyes = getEyeValueFull(x, y, me) + 1\\n const enemies = getSurroundEnemiesFull(x, y) + 1\\n const freeSpace = getFreeSpace(x, y)\\n const rank = myEyes * enemySurroundLibs * enemies * enemySurroundChains * freeSpace * surroundSpace\\n\\n if (rank > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = rank\\n }\\n else if (rank === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Expansion\\\"\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getRandomBolster(libRequired, savedNodesMin, onlyContested = true) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highValue = 1\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n if ((onlyContested && contested[x][y] !== \\\"?\\\")) continue\\n if (createsLib(x, y, me)) continue\\n let right = 0\\n let left = 0\\n let up = 0\\n let down = 0\\n\\n //We are only checking up, down, left and right\\n //We are checking for linking chains of friendlies, filtering out those already checked\\n let checkedChains = []\\n if (x < size - 1 && board[x + 1][y] === me && validLibMoves[x + 1][y] === libRequired) {\\n right = getChainValue(x + 1, y, me)\\n checkedChains.push(chains[x + 1][y])\\n }\\n if (x > 0 && board[x - 1][y] === me && !checkedChains.includes(chains[x - 1][y]) && validLibMoves[x - 1][y] === libRequired) {\\n left = getChainValue(x - 1, y, me)\\n checkedChains.push(chains[x - 1][y])\\n }\\n if (y < size - 1 && board[x][y + 1] === me && !checkedChains.includes(chains[x][y + 1]) && validLibMoves[x][y + 1] === libRequired) {\\n up = getChainValue(x, y + 1, me)\\n checkedChains.push(chains[x][y + 1])\\n }\\n if (y > 0 && board[x][y - 1] === me && !checkedChains.includes(chains[x][y - 1]) && validLibMoves[x][y - 1] === libRequired)\\n down = getChainValue(x, y - 1, me)\\n\\n let count = 0\\n let total = 0\\n if (right >= savedNodesMin) {\\n count++\\n total += right\\n }\\n if (left >= savedNodesMin) {\\n count++\\n total += left\\n }\\n if (up >= savedNodesMin) {\\n count++\\n total += up\\n }\\n if (down >= savedNodesMin) {\\n count++\\n total += down\\n }\\n if (count <= 0) continue\\n const surroundMulti = getSurroundLibSpread(x, y, me)\\n const rank = total * count * surroundMulti\\n if (rank > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = rank\\n }\\n else if (rank === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Bolster - Libs: \\\" + libRequired + \\\" Nodes: \\\" + savedNodesMin + \\\" OnlyContested: \\\" + onlyContested\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getChainValue(checkx, checky, player, isolated = false) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (contested[checkx][checky] === \\\"?\\\" || contested[checkx][checky] === \\\"#\\\" || board[checkx][checky] === otherPlayer) return 0\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 1\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer || (isolated && board[x][y] === \\\".\\\")) continue\\n count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getEyeValue(checkx, checky, player) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 0\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer) continue\\n if (contested[x][y] === player) count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getFreeSpace(checkx, checky) {\\n const size = board[0].length\\n if (contested[checkx][checky] !== \\\"?\\\") return 0\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 1\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if ([\\\"#\\\", me, you].includes(contested[x][y])) continue\\n if (contested[x][y] === \\\"?\\\") count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getEyeValueFull(checkx, checky, player) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n if (checkx < size - 1 && checky < size - 1) explored.add(JSON.stringify([checkx + 1, checky + 1]))\\n if (checkx > 0 && checky < size - 1) explored.add(JSON.stringify([checkx - 1, checky + 1]))\\n if (checkx < size - 1 && checky > 0) explored.add(JSON.stringify([checkx + 1, checky - 1]))\\n if (checkx > 0 && checky > 0) explored.add(JSON.stringify([checkx - 1, checky - 1]))\\n let count = 0\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer) continue\\n if (contested[x][y] === player) count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getChainAttack(x, y) {\\n const size = board[0].length\\n let count = 0\\n if (x > 0 && board[x - 1][y] === you) count += getChainValue(x - 1, y, you)\\n if (x < size - 1 && board[x + 1][y] === you) count += getChainValue(x + 1, y, you)\\n if (y > 0 && board[x][y - 1] === you) count += getChainValue(x, y - 1, you)\\n if (y < size - 1 && board[x][y + 1] === you) count += getChainValue(x, y + 1, you)\\n\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getChainAttackFull(x, y) {\\n const size = board[0].length\\n let count = 0\\n if (x < size - 1) count += getChainValue(x + 1, y, you)\\n if (x > 0) count += getChainValue(x - 1, y, you)\\n if (y > 0) count += getChainValue(x, y - 1, you)\\n if (y < size - 1) count += getChainValue(x, y + 1, you)\\n if (x < size - 1 && y < size - 1) count += getChainValue(x + 1, y + 1, you)\\n if (x > 0 && y < size - 1) count += getChainValue(x - 1, y + 1, you)\\n if (x < size - 1 && y > 0) count += getChainValue(x + 1, y - 1, you)\\n if (x > 0 && y > 0) count += getChainValue(x - 1, y - 1, you)\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getSurroundSpace(x, y) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && board[x - 1][y] === \\\".\\\") surround++\\n if (x < size - 1 && board[x + 1][y] === \\\".\\\") surround++\\n if (y > 0 && board[x][y - 1] === \\\".\\\") surround++\\n if (y < size - 1 && board[x][y + 1] === \\\".\\\") surround++\\n return surround\\n}\\n/** @param {NS} ns */\\nfunction getSurroundSpaceFull(startx, starty, player = me, depth = 1) {\\n const size = board[0].length\\n let surround = 0\\n for (let x = startx - depth; x <= startx + depth; x++)\\n for (let y = starty - depth; y <= starty + depth; y++)\\n if (x >= 0 && x <= size - 1 && y >= 0 && y <= size - 1 && [\\\".\\\", player].includes(board[x][y])) surround++\\n return surround\\n}\\n/** @param {NS} ns */\\nfunction getHeatMap(startx, starty, player = me, depth = 2) {\\n const size = board[0].length\\n let count = 1\\n for (let x = startx - depth; x <= startx + depth; x++)\\n for (let y = starty - depth; y <= starty + depth; y++)\\n if (x >= 0 && x <= size - 1 && y >= 0 && y <= size - 1 && [\\\".\\\", player].includes(board[x][y])) count += board[x][y] === player ? 1.5 : board[x][y] === \\\".\\\" ? 1 : 0\\n return count\\n}\\n/** @param {NS} ns */\\nfunction getSurroundLibs(x, y, player) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && (board[x - 1][y] === \\\".\\\" || board[x - 1][y] === player)) surround += board[x - 1][y] === \\\".\\\" ? 1 : validLibMoves[x - 1][y] - 1\\n if (x < size - 1 && (board[x + 1][y] === \\\".\\\" || board[x + 1][y] === player)) surround += board[x + 1][y] === \\\".\\\" ? 1 : validLibMoves[x + 1][y] - 1\\n if (y > 0 && (board[x][y - 1] === \\\".\\\" || board[x][y - 1] === player)) surround += board[x][y - 1] === \\\".\\\" ? 1 : validLibMoves[x][y - 1] - 1\\n if (y < size - 1 && (board[x][y + 1] === \\\".\\\" || board[x][y + 1] === player)) surround += board[x][y + 1] === \\\".\\\" ? 1 : validLibMoves[x][y + 1] - 1\\n return surround\\n}\\n/** @param {NS} ns */\\nfunction getSurroundLibSpread(x, y, player) {\\n const size = board[0].length\\n let surround = 0\\n const checks = new Set\\n if (board[x][y] === \\\".\\\") checks.add(JSON.stringify([x, y]))\\n else return 0\\n if (x > 0 && board[x - 1][y] === \\\".\\\") checks.add(JSON.stringify([x - 1, y]))\\n if (x < size - 1 && board[x + 1][y] === \\\".\\\") checks.add(JSON.stringify([x + 1, y]))\\n if (y > 0 && board[x][y - 1] === \\\".\\\") checks.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1 && board[x][y + 1] === \\\".\\\") checks.add(JSON.stringify([x, y + 1]))\\n //Now, check the liberty values of all the checks\\n for (const check of checks) {\\n const [x, y] = JSON.parse(check)\\n surround += getSurroundLibs(x, y, player)\\n }\\n return surround\\n}\\n/** @param {NS} ns */\\nfunction getSurroundEnemiesFull(x, y) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && board[x - 1][y] === you) surround += getChainValue(x - 1, y, you)\\n if (x < size - 1 && board[x + 1][y] === you) surround += getChainValue(x + 1, y, you)\\n if (y > 0 && board[x][y - 1] === you) surround += getChainValue(x, y - 1, you)\\n if (y < size - 1 && board[x][y + 1] === you) surround += getChainValue(x, y + 1, you)\\n\\n if (x > 0 && y > 0 && board[x - 1][y - 1] === you) surround += getChainValue(x - 1, y - 1, you)\\n if (x < size - 1 && y > 0 && board[x + 1][y - 1] === you) surround += getChainValue(x + 1, y - 1, you)\\n if (y < size - 1 && x > 0 && board[x - 1][y + 1] === you) surround += getChainValue(x - 1, y - 1, you)\\n if (y < size - 1 && x < size - 1 && board[x + 1][y + 1] === you) surround += getChainValue(x + 1, y + 1, you)\\n\\n return surround\\n}\\n/** @param {NS} ns */\\nfunction getRandomStrat() {\\n const moveOptions = []\\n const moveOptions2 = []\\n const size = board[0].length\\n\\n // Look through all the points on the board\\n let bestRank = 0\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (![\\\"?\\\", you].includes(contested[x][y]) || createsLib(x, y, me)) continue\\n let isSupport = ((x > 0 && board[x - 1][y] === me && validLibMoves[x - 1][y] >= 1) || (x < size - 1 && board[x + 1][y] === me && validLibMoves[x + 1][y] >= 1) || (y > 0 && board[x][y - 1] === me && validLibMoves[x][y - 1] >= 1) || (y < size - 1 && board[x][y + 1] === me && validLibMoves[x][y + 1] >= 1)) ? true : false\\n let isAttack = ((x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= 2) || (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= 2) || (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= 2) || (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= 2)) ? true : false\\n\\n const surround = getSurroundSpace(x, y)\\n if (isSupport || isAttack) {\\n if (surround > bestRank) {\\n moveOptions.length = 0\\n bestRank = surround\\n moveOptions.push([x, y]);\\n }\\n else if (surround === bestRank) {\\n moveOptions.push([x, y])\\n }\\n }\\n else {\\n moveOptions2.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length);\\n const randomIndex2 = Math.floor(Math.random() * moveOptions2.length);\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Random Safe\\\"\\n } : moveOptions2[randomIndex2] ? {\\n coords: moveOptions2[randomIndex2],\\n msg: \\\"Random Unsafe\\\"\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getAggroAttack(libsMin, libsMax, minSurround = 3, minChain = 1, minFreeSpace = 0) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (createsLib(x, y, me)) continue\\n const isAttack = (\\n (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= libsMin && validLibMoves[x - 1][y] <= libsMax) ||\\n (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= libsMin && validLibMoves[x + 1][y] <= libsMax) ||\\n (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= libsMin && validLibMoves[x][y - 1] <= libsMax) ||\\n (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= libsMin && validLibMoves[x][y + 1] <= libsMax)) ? true : false\\n const surround = getSurroundLibs(x, y, me)\\n const freeSpace = getFreeSpace(x, y)\\n if (freeSpace < minFreeSpace) continue\\n if (!isAttack || surround < minSurround) continue\\n const chainAtk = getChainAttack(x, y)\\n if (chainAtk < minChain) continue\\n let lowestLibs = 999\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] < lowestLibs) lowestLibs = validLibMoves[x - 1][y]\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] < lowestLibs) lowestLibs = validLibMoves[x + 1][y]\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] < lowestLibs) lowestLibs = validLibMoves[x][y - 1]\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] < lowestLibs) lowestLibs = validLibMoves[x][y + 1]\\n\\n const enemyLibs = getSurroundLibSpread(x, y, you)\\n const startEyeValue = getEyeValue(x, y, you)\\n const eyeValue = startEyeValue > 1 ? startEyeValue : 1\\n const atk = enemyLibs * chainAtk / eyeValue / lowestLibs\\n if (atk > highestValue) {\\n highestValue = atk\\n moveOptions.length = 0\\n moveOptions.push([x, y]);\\n }\\n else if (atk === highestValue) {\\n highestValue = atk\\n moveOptions.push([x, y]);\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Aggro Attack: \\\" + libsMin + \\\"/\\\" + libsMax + \\\" Surround: \\\" + minSurround\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getDefAttack(libsMin, libsMax, minSurround = 3, minChain = 1, minFreeSpace = 0) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (createsLib(x, y, me)) continue\\n const isAttack = (\\n (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= libsMin && validLibMoves[x - 1][y] <= libsMax) ||\\n (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= libsMin && validLibMoves[x + 1][y] <= libsMax) ||\\n (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= libsMin && validLibMoves[x][y - 1] <= libsMax) ||\\n (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= libsMin && validLibMoves[x][y + 1] <= libsMax)) ? true : false\\n const surround = getSurroundLibs(x, y, me)\\n const freeSpace = getFreeSpace(x, y)\\n if (freeSpace < minFreeSpace) continue\\n if (!isAttack || surround < minSurround) continue\\n const chainAtk = getChainAttack(x, y)\\n if (chainAtk < minChain) continue\\n let lowestLibs = 999\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] < lowestLibs) lowestLibs = validLibMoves[x - 1][y]\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] < lowestLibs) lowestLibs = validLibMoves[x + 1][y]\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] < lowestLibs) lowestLibs = validLibMoves[x][y - 1]\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] < lowestLibs) lowestLibs = validLibMoves[x][y + 1]\\n\\n const friendlyLibs = getSurroundLibs(x, y, me)\\n const startEyeValue = getEyeValue(x, y, you)\\n const eyeValue = startEyeValue > 1 ? startEyeValue : 1\\n\\n const atk = friendlyLibs * chainAtk / eyeValue * getHeatMap(x, y, me) / lowestLibs * (getEyeValue(x, y, me) + 1)\\n\\n if (atk > highestValue) {\\n highestValue = atk\\n moveOptions.length = 0\\n moveOptions.push([x, y]);\\n }\\n else if (atk === highestValue) {\\n highestValue = atk\\n moveOptions.push([x, y]);\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Defensive Attack: \\\" + libsMin + \\\"/\\\" + libsMax + \\\" Surround: \\\" + minSurround\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction attackGrowDragon(requiredEyes, killLib = false) {\\n const moveOptions = [];\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (contested[x][y] !== \\\"?\\\" || createsLib(x, y, me)) continue\\n const surround = getSurroundEnemiesFull(x, y)\\n const myLibs = getSurroundLibs(x, y, me)\\n if (surround < 1 || myLibs < 3) continue\\n const enemyLibs = getSurroundLibs(x, y, you)\\n if (enemyLibs === 1 && !killLib) continue\\n const enemyChains = getChainAttackFull(x, y)\\n const myEyes = getEyeValueFull(x, y, me)\\n if (myEyes < requiredEyes) continue // || count === 3) continue\\n const result = enemyLibs * enemyChains // surround * enemyLibs * myChains * /*freeSpace * */ enemyEyes * enemyChains\\n\\n if (result > highestValue) {\\n highestValue = result\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n }\\n else if (result === highestValue) {\\n highestValue = result\\n moveOptions.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Attack/Grow Dragon: \\\" + requiredEyes\\n } : []\\n}\\n/** @param {NS} ns */\\nfunction getDefPattern() {\\n let def = []\\n def.push(...def5)\\n\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n for (const pattern of def)\\n if (isPattern(x, y, pattern)) {\\n const msg = sprintf(\\\"Def Pattern: %s\\\\n%s\\\\n%s\\\", pattern.length, pattern.join(\\\"\\\\n\\\"), \\\"---------------\\\")\\n return {\\n coords: [x, y],\\n msg: msg\\n }\\n }\\n }\\n return []\\n}\\n/** @param {NS} ns */\\nfunction disruptEyes() {\\n let disrupt = []\\n disrupt.push(...disrupt4)\\n disrupt.push(...disrupt5)\\n\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n for (const pattern of disrupt)\\n if (isPattern(x, y, pattern)) {\\n const msg = sprintf(\\\"Eye Disruption: %s\\\\n%s\\\\n%s\\\", pattern.length, pattern.join(\\\"\\\\n\\\"), \\\"---------------\\\")\\n return {\\n coords: [x, y],\\n msg: msg\\n }\\n }\\n }\\n return []\\n}\\n/** @param {NS} ns */\\nasync function movePiece(ns, attack) {\\n if (attack.coords === undefined) return false\\n const [x, y] = attack.coords\\n if (x === undefined) return false\\n let mid = performance.now()\\n update(ns, ns.sprintf(\\\"%s\\\", attack.msg))\\n const results = await ns.go.makeMove(x, y, playAsWhite)\\n let END = performance.now()\\n if (LOGTIME) {\\n update(ns, ns.sprintf(\\\"Time: Me: %s Them: %s\\\", fTime(ns, mid - START, true), fTime(ns, END - mid, true)))\\n }\\n START = performance.now()\\n ns.ui.renderTail()\\n return results\\n}\\n/** @param {NS} ns */\\nasync function moveWallBreaker(ns, attack) {\\n if (attack.coords === undefined || !CHEATS || !HASBN14_2) return false\\n const [s1x, s1y] = attack.coords\\n if (s1x === undefined) return false\\n try {\\n const chance = ns.go.cheat.getCheatSuccessChance(undefined, playAsWhite)\\n if (chance < .7) return false\\n let mid = performance.now()\\n const results = await destroyND(ns, s1x, s1y, playAsWhite)\\n update(ns, ns.sprintf(\\\"%s\\\", attack.msg))\\n let END = performance.now()\\n if (LOGTIME) {\\n update(ns, ns.sprintf(\\\"Time: Me: %s Them: %s\\\", fTime(ns, mid - START, true), fTime(ns, END - mid, true)))\\n }\\n START = performance.now()\\n ns.ui.renderTail()\\n return results\\n }\\n catch { return false }\\n}\\n/** @param {NS} ns */\\nasync function moveSnakeEyes(ns, attack) {\\n if (attack.coords === undefined || !CHEATS || !HASBN14_2) return false\\n const [s1x, s1y, s2x, s2y] = attack.coords\\n if (s1x === undefined) return false\\n try {\\n const chance = ns.go.cheat.getCheatSuccessChance(undefined, playAsWhite)\\n if (chance < .7) return false\\n let mid = performance.now()\\n const results = await play2moves(ns, s1x, s1y, s2x, s2y, playAsWhite)\\n update(ns, ns.sprintf(\\\"%s\\\", attack.msg))\\n let END = performance.now()\\n if (LOGTIME) {\\n update(ns, ns.sprintf(\\\"Time: Me: %s Them: %s\\\", fTime(ns, mid - START, true), fTime(ns, END - mid, true)))\\n }\\n START = performance.now()\\n ns.ui.renderTail()\\n return results\\n }\\n catch { return false }\\n}\\nfunction getAllValidMoves(notMine = false) {\\n if (currentValidMovesTurn === turn) return notMine ? currentValidContestedMoves : currentValidMoves\\n let moves = []\\n let contestedMoves = []\\n for (let x = 0; x < board[0].length; x++)\\n for (let y = 0; y < board[0].length; y++) {\\n if (validMove[x][y]) {\\n if ([you, \\\"?\\\"].includes(contested[x][y])) contestedMoves.push([x, y])\\n moves.push([x, y])\\n }\\n }\\n\\n //Moves contains a randomized array of x,y\\n moves = moves.sort(() => Math.random() - Math.random())\\n contestedMoves = contestedMoves.sort(() => Math.random() - Math.random())\\n currentValidMoves = moves\\n currentValidContestedMoves = contestedMoves\\n currentValidMovesTurn = turn\\n return notMine ? currentValidContestedMoves : currentValidMoves\\n}\\nfunction createsLib(x, y, player) {\\n const size = board[0].length\\n\\n if (x > 0 && board[x - 1][y] === player && validLibMoves[x - 1][y] > 2) return false\\n if (x < size - 1 && board[x + 1][y] === player && validLibMoves[x + 1][y] > 2) return false\\n if (y > 0 && board[x][y - 1] === player && validLibMoves[x][y - 1] > 2) return false\\n if (y < size - 1 && board[x][y + 1] === player && validLibMoves[x][y + 1] > 2) return false\\n\\n if (x > 0 && board[x - 1][y] === player && validLibMoves[x - 1][y] === 2 && getSurroundLibs(x - 1, y, player) === 1) return true\\n if (x < size - 1 && board[x + 1][y] === player && validLibMoves[x + 1][y] === 2 && getSurroundLibs(x + 1, y, player) === 1) return true\\n if (y > 0 && board[x][y - 1] === player && validLibMoves[x][y - 1] === 2 && getSurroundLibs(x, y - 1, player) === 1) return true\\n if (y < size - 1 && board[x][y + 1] === player && validLibMoves[x][y + 1] === 2 && getSurroundLibs(x, y + 1, player) === 1) return true\\n\\n return false\\n}\\nfunction getOpeningMove() {\\n const size = board[0].length\\n switch (size) {\\n case 13:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 10) === 4 && validMove[2][10]) return ({\\n coords: [2, 10],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(10, 10) === 4 && validMove[10][10]) return ({\\n coords: [10, 10],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(10, 2) === 4 && validMove[10][2]) return ({\\n coords: [10, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 9) === 4 && validMove[3][9]) return ({\\n coords: [3, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(9, 9) === 4 && validMove[9][9]) return ({\\n coords: [9, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(9, 3) === 4 && validMove[9][3]) return ({\\n coords: [9, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 8) === 4 && validMove[4][8]) return ({\\n coords: [4, 8],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(8, 8) === 4 && validMove[8][8]) return ({\\n coords: [8, 8],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(8, 4) === 4 && validMove[8][4]) return ({\\n coords: [8, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 9:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 6) === 4 && validMove[2][6]) return ({\\n coords: [2, 6],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(6, 6) === 4 && validMove[6][6]) return ({\\n coords: [6, 6],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(6, 2) === 4 && validMove[6][2]) return ({\\n coords: [6, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 5) === 4 && validMove[3][5]) return ({\\n coords: [3, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 5) === 4 && validMove[5][5]) return ({\\n coords: [5, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 3) === 4 && validMove[5][3]) return ({\\n coords: [5, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 7:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 4) === 4 && validMove[2][4]) return ({\\n coords: [2, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 2) === 4 && validMove[4][2]) return ({\\n coords: [4, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 1) === 4 && validMove[1][1]) return ({\\n coords: [1, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 1) === 4 && validMove[5][1]) return ({\\n coords: [5, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 5) === 4 && validMove[5][5]) return ({\\n coords: [5, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 5) === 4 && validMove[1][5]) return ({\\n coords: [1, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 5:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 1) === 4 && validMove[3][1]) return ({\\n coords: [3, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 3) === 4 && validMove[1][3]) return ({\\n coords: [1, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 1) === 4 && validMove[1][1]) return ({\\n coords: [1, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 19:\\n if (getSurroundSpace(9, 9) === 4 && validMove[9][9]) return ({\\n coords: [9, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(16, 2) === 4 && validMove[16][2]) return ({\\n coords: [16, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 16) === 4 && validMove[2][16]) return ({\\n coords: [2, 16],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(16, 16) === 4 && validMove[16][16]) return ({\\n coords: [16, 16],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 15) === 4 && validMove[3][15]) return ({\\n coords: [3, 15],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(15, 15) === 4 && validMove[15][15]) return ({\\n coords: [15, 15],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(15, 3) === 4 && validMove[15][3]) return ({\\n coords: [15, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 14) === 4 && validMove[4][14]) return ({\\n coords: [4, 14],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(14, 14) === 4 && validMove[14][14]) return ({\\n coords: [14, 14],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(14, 4) === 4 && validMove[14][4]) return ({\\n coords: [14, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\n\\n\\n//X,O = Me, You x, o = Anything but the other person or a blocking, \\\"W\\\" space is off the board, ? is anything goes\\n//B is blocking(Wall or you, not empty or enemy), b is blocking but could be enemy, A is All but . (Wall, Me, You, Blank)\\n//* is move here next if you can - no safeties\\n\\nconst disrupt4 = [\\n [\\\"??b?\\\", \\\"?b.b\\\", \\\"b.*b\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"?bb?\\\", \\\"b..b\\\", \\\"b*Xb\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"?bb?\\\", \\\"b..b\\\", \\\"b.*b\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"??b?\\\", \\\"?b.b\\\", \\\"?b*b\\\", \\\"??O?\\\"], //Pattern# Sphyxis - Sacrifice to kill an eye\\n [\\\"?bbb\\\", \\\"bb.b\\\", \\\"W.*b\\\", \\\"?oO?\\\"], //Pattern# Sphyxis - 2x2 nook breatk\\n [\\\"?bbb\\\", \\\"bb.b\\\", \\\"W.*b\\\", \\\"?Oo?\\\"], //Pattern# Sphyxis - 2x2 nook break\\n [\\\".bbb\\\", \\\"o*.b\\\", \\\".bbb\\\", \\\"????\\\"], //Pattern# Sphyxis - Dangling 2 break\\n]\\nconst disrupt5 = [\\n [\\\"?bbb?\\\", \\\"b.*.b\\\", \\\"?bbb?\\\", \\\"?????\\\", \\\"?????\\\"], //Pattern# Sphyxis - Convert to 1 eye\\n [\\\"??OO?\\\", \\\"?b*.b\\\", \\\"?b..b\\\", \\\"??bb?\\\", \\\"?????\\\"], //Pattern# Sphyxis - Buy time\\n [\\\"?????\\\", \\\"??bb?\\\", \\\"?b*Xb\\\", \\\"?boob\\\", \\\"??bb?\\\"], //Pattern# Sphyxis - Buy time\\n [\\\"WWW??\\\", \\\"WWob?\\\", \\\"Wo*b?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 attack corner if possible\\n [\\\"??b??\\\", \\\"?b.b?\\\", \\\"?b*b?\\\", \\\"?b.A?\\\", \\\"??b??\\\"], //Pattern# Sphyxis - Break two eyes into 1, buy a turn\\n [\\\"??b??\\\", \\\"?b.b?\\\", \\\"??*.b\\\", \\\"?b?b?\\\", \\\"?????\\\"], //Pattern# Sphyxis - Break eyes, buy time\\n [\\\"?WWW?\\\", \\\"WoOoW\\\", \\\"WOO*W\\\", \\\"W???W\\\", \\\"?????\\\"], //Block 3x3 corner\\n [\\\"?WWW?\\\", \\\"Wo*oW\\\", \\\"WOOOW\\\", \\\"W???W\\\", \\\"?????\\\"], //Block 3x3 corner\\n]\\n\\nconst def5 = [\\n [\\\"?WW??\\\", \\\"WW.X?\\\", \\\"W.XX?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - Eyes in a nook\\n [\\\"WWW??\\\", \\\"WW.X?\\\", \\\"W.*X?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 corner contain #GREAT\\n [\\\"BBB??\\\", \\\"BB.X?\\\", \\\"B..X?\\\", \\\"BBB??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 corner contain #GREAT\\n [\\\"?WWW?\\\", \\\"W.*.W\\\", \\\"WXXXW\\\", \\\"?????\\\", \\\"?????\\\"], //Take the 3x3 back corner\\n]\\n\\n// Testing\\n//const opponent = [\\\"Slum Snakes\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\"]\\n//const opponent2 = [\\\"????????????\\\"]\\n// Original\\n//const opponent = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\"]\\n//const opponent2 = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\", \\\"????????????\\\"]\""},{"filename":"SphyxOS/bins/graftingAdv.js","file":"\"import { proxy, proxyTry, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\nlet win\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.atExit(() => {\\n ns.clearPort(20)\\n if (win) win.close()\\n })\\n ns.clearPort(20)\\n ns.writePort(20, ns.pid)\\n win = false\\n let graftable = await getGraftable(ns)\\n const specificQueue = []\\n let MODE = await ns.prompt(\\\"Select Priority:\\\", { type: \\\"select\\\", choices: priorities })\\n let SPECIFIC;\\n let FOCUS = graftable.includes(\\\"Neuroreceptor Management Implant\\\")\\n if (MODE === \\\"Specific\\\") SPECIFIC = await ns.prompt(\\\"Select Augment:\\\", { type: \\\"select\\\", choices: graftable })\\n if (MODE === \\\"\\\" || (MODE === \\\"Specific\\\" && SPECIFIC === \\\"\\\")) {\\n ns.tprint(\\\"No selection made in grafter. Exiting\\\")\\n ns.exit()\\n }\\n else if (MODE === \\\"Specific\\\") specificQueue.push(SPECIFIC)\\n\\n while (MODE === \\\"Specific\\\" && SPECIFIC !== \\\"\\\" && SPECIFIC !== \\\"Done\\\") {\\n graftable = await getGraftable(ns, specificQueue)\\n SPECIFIC = await ns.prompt(\\\"Select Next Queued Augment:\\\", { type: \\\"select\\\", choices: [\\\"Done\\\"].concat(graftable) })\\n if (SPECIFIC !== \\\"\\\" && SPECIFIC !== \\\"Done\\\") {\\n specificQueue.push(SPECIFIC)\\n }\\n }\\n ns.ui.openTail()\\n getCommands(ns)\\n await ns.asleep(4)\\n let player = await proxy(ns, \\\"getPlayer\\\")\\n let city = player.city\\n if (city !== \\\"New Tokyo\\\") {\\n while (city !== \\\"New Tokyo\\\") {\\n await ns.asleep(100)\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"Trying to travel to New Tokyo! In %s\\\", city))\\n await proxy(ns, \\\"singularity.travelToCity\\\", \\\"New Tokyo\\\")\\n player = await proxy(ns, \\\"getPlayer\\\")\\n city = player.city\\n\\n }\\n }//Get to New Tokyo\\n let temp = []\\n if (MODE !== \\\"Specific\\\") {\\n graftable = await proxy(ns, \\\"grafting.getGraftableAugmentations\\\")\\n\\n for (const graft of graftable) {\\n const record = {\\n \\\"name\\\": graft,\\n \\\"price\\\": await proxy(ns, \\\"grafting.getAugmentationGraftPrice\\\", graft),\\n \\\"stats\\\": await proxy(ns, \\\"singularity.getAugmentationStats\\\", graft),\\n \\\"time\\\": await proxy(ns, \\\"grafting.getAugmentationGraftTime\\\", graft)\\n }\\n temp.push(record)\\n }\\n }\\n if (MODE !== \\\"Specific\\\") {\\n switch (MODE) {\\n case \\\"None\\\":\\n graftable = temp\\n break\\n case \\\"Price Highest\\\":\\n graftable = temp.toSorted((a, b) => { return b.price - a.price })\\n break\\n case \\\"Price Lowest\\\":\\n graftable = temp.toSorted((a, b) => { return a.price - b.price })\\n break\\n case \\\"Fastest\\\":\\n graftable = temp.toSorted((a, b) => { return a.time - b.time })\\n break\\n case \\\"Special\\\":\\n break\\n case \\\"H/G/W Speed\\\":\\n graftable = temp.toSorted((a, b) => { return b.stats?.hacking_speed - a.stats?.hacking_speed })\\n break\\n case \\\"Hack Power\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacking_money - a.stats?.hacking_money) })\\n break\\n case \\\"Grow Power\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacking_grow - a.stats?.hacking_grow) })\\n break\\n case \\\"Hack Success\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacking_chance - a.stats?.hacking_chance) })\\n break\\n case \\\"Hacking\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacking_exp - a.stats?.hacking_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacking - a.stats?.hacking) })\\n break\\n case \\\"Strength\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.strength_exp - a.stats?.strength_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.strength - a.stats?.strength) })\\n break\\n case \\\"Defence\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.defense_exp - a.stats?.defense_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.defense - a.stats?.defense) })\\n break\\n case \\\"Dexterity\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.dexterity_exp - a.stats?.dexterity_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.dexterity - a.stats?.dexterity) })\\n break\\n case \\\"Agility\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.agility_exp - a.stats?.agility_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.agility - a.stats?.agility) })\\n break\\n case \\\"Charisma\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.charisma_exp - a.stats?.charisma_exp) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.charisma - a.stats?.charisma) })\\n break\\n case \\\"Reputation\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.company_rep - a.stats?.company_rep) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.faction_rep - a.stats?.faction_rep) })\\n break\\n case \\\"Work Money\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.work_money - a.stats?.work_money) })\\n break\\n case \\\"Crime Money\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.crime_success - a.stats?.crime_success) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.crime_money - a.stats?.crime_money) })\\n break\\n case \\\"Crime Chance\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.crime_money - a.stats?.crime_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.crime_success - a.stats?.crime_success) })\\n break\\n case \\\"HackNet Production\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_ram_cost - a.stats?.hacknet_node_ram_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_core_cost - a.stats?.hacknet_node_core_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_level_cost - a.stats?.hacknet_node_level_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n break\\n case \\\"Hacknet Level Costs\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_ram_cost - a.stats?.hacknet_node_ram_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_core_cost - a.stats?.hacknet_node_core_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_level_cost - a.stats?.hacknet_node_level_cost) })\\n break\\n case \\\"Hacknet RAM Costs\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_core_cost - a.stats?.hacknet_node_core_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_level_cost - a.stats?.hacknet_node_level_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_ram_cost - a.stats?.hacknet_node_ram_cost) })\\n break\\n case \\\"HackNet Core Cost\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_ram_cost - a.stats?.hacknet_node_ram_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_level_cost - a.stats?.hacknet_node_level_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_core_cost - a.stats?.hacknet_node_core_cost) })\\n break\\n case \\\"HackNet Money\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_ram_cost - a.stats?.hacknet_node_ram_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_core_cost - a.stats?.hacknet_node_core_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_level_cost - a.stats?.hacknet_node_level_cost) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.hacknet_node_money - a.stats?.hacknet_node_money) })\\n break\\n case \\\"BB Analysis\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_analysis - a.stats?.bladeburner_analysis) })\\n break\\n case \\\"BB Stamina\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_stamina_gain - a.stats?.bladeburner_stamina_gain) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_max_stamina - a.stats?.bladeburner_max_stamina) })\\n break\\n case \\\"BB Stamina Gain\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_max_stamina - a.stats?.bladeburner_max_stamina) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_stamina_gain - a.stats?.bladeburner_stamina_gain) })\\n break\\n case \\\"BB Success Chance\\\":\\n graftable = temp.toSorted((a, b) => { return (b.stats?.agility - a.stats?.agility) })\\n graftable = temp.toSorted((a, b) => { return (b.stats?.bladeburner_success_chance - a.stats?.bladeburner_success_chance) })\\n break\\n default:\\n ns.tprintf(\\\"Invalid Mode received in grafter: %s\\\", MODE)\\n ns.exit()\\n }\\n graftable = graftable.map(g => g.name)\\n }\\n if (MODE === \\\"Special\\\") graftable = special\\n //New while loop here with a queue\\n //graftable is now sorted, or I have my specificQueue\\n const augments = MODE !== \\\"Specific\\\" ? graftable : specificQueue\\n const bench = []\\n while (augments.length > 0) { //Expand this while loop\\n const aug = augments.shift()\\n if (!await proxyTry(ns, \\\"grafting.getAugmentationGraftPrice\\\", aug)) continue\\n player = await proxy(ns, \\\"getPlayer\\\")\\n city = player.city\\n if (city !== \\\"New Tokyo\\\") {\\n while (city !== \\\"New Tokyo\\\") {\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"Trying to travel to New Tokyo! Currently in %s\\\", city))\\n await proxy(ns, \\\"singularity.travelToCity\\\", \\\"New Tokyo\\\")\\n player = await proxy(ns, \\\"getPlayer\\\")\\n city = player.city\\n await ns.asleep(100)\\n }\\n }//Get to New Tokyo\\n clearAll(ns)\\n update(ns, \\\"Waiting on a graft to start.\\\")\\n graftable = await getGraftable(ns)\\n FOCUS = graftable.includes(\\\"Neuroreceptor Management Implant\\\")\\n let wrk = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n if (wrk == null || wrk.type !== \\\"GRAFTING\\\") {\\n if (!await proxy(ns, \\\"grafting.graftAugmentation\\\", aug, FOCUS)) {\\n bench.push(aug) //Keep track of what we've skipped\\n if (augments.length === 0)\\n while (bench.length > 0)\\n augments.unshift(bench.pop())\\n await ns.asleep(100)\\n continue\\n }\\n }\\n wrk = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n while (wrk && wrk.type === \\\"GRAFTING\\\") {\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"Mode: %s\\\", MODE))\\n update(ns, ns.sprintf(\\\"Neuroreceptor Management Implant: %s\\\", !FOCUS))\\n update(ns, ns.sprintf(\\\"Grafting: %s\\\", wrk.augmentation))\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) update(ns, ns.sprintf(\\\"Will take roughly %s\\\", fTime(ns, await proxy(ns, \\\"grafting.getAugmentationGraftTime\\\", wrk.augmentation) - (wrk.cyclesWorked * 200))))\\n else update(ns, ns.sprintf(\\\"Will take roughly %s\\\", fTime(ns, await proxy(ns, \\\"grafting.getAugmentationGraftTime\\\", wrk.augmentation) - (wrk.cyclesWorked * 200))))\\n const augStats = await proxy(ns, \\\"singularity.getAugmentationStats\\\", wrk.augmentation)\\n for (const [name, stat] of Object.entries(augStats)) if (stat !== 1) update(ns, ns.sprintf(\\\"%s - %s\\\", name, stat))\\n if (FOCUS) update(ns, \\\"Can be off if you unfocus\\\")\\n else update(ns, \\\"You can do something else now.\\\")\\n await ns.asleep(500)\\n wrk = await proxy(ns, \\\"singularity.getCurrentWork\\\")\\n }\\n await ns.asleep(100)\\n while (bench.length > 0)\\n augments.unshift(bench.pop())\\n }\\n update(ns, \\\"No augments left in list, finishing up.\\\")\\n await ns.asleep(1000)\\n}\\n/** @param {NS} ns */\\nasync function getGraftable(ns, willOwnAugs = []) {\\n const ownedAugs = await proxy(ns, \\\"singularity.getOwnedAugmentations\\\")\\n ownedAugs.push(...willOwnAugs)\\n const graftableAugs = await proxy(ns, \\\"grafting.getGraftableAugmentations\\\")\\n const graftable = graftableAugs.filter((aug) => {\\n if (ownedAugs.includes(aug)) return false\\n const preReq = ns.singularity.getAugmentationPrereq(aug)\\n if (preReq.length === 0) return true\\n const ownedPreReq = preReq.filter((pre) => ownedAugs.includes(pre))\\n if (ownedPreReq.length === preReq.length) return true\\n return false\\n })\\n return graftable\\n}\\n/** @param {NS} ns */\\nfunction clearAll(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\n/** @param {NS} ns */\\nfunction update(ns, text) {\\n ns.printf(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"grafting popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(23) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(23)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Grafting\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Grafting will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n win = false\\n if (!silent) ns.tprintf(\\\"Grafting will not use a popout\\\")\\n break\\n case \\\"silent\\\":\\n silent = true\\n break;\\n default:\\n ns.tprintf(\\\"Invalid command received in GraftingBasic: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nconst special = [\\\"violet Congruity Implant\\\", \\\"Neuroreceptor Management Implant\\\", \\\"PCMatrix\\\", \\\"BitRunners Neurolink\\\"]\\nconst priorities = [\\\"None\\\", \\\"Specific\\\", \\\"Price Highest\\\", \\\"Price Lowest\\\", \\\"Fastest\\\", \\\"Special\\\", \\\"H/G/W Speed\\\", \\\"Hack Power\\\", \\\"Grow Power\\\", \\\"Hack Success\\\", \\\"Hacking\\\", \\\"Strength\\\", \\\"Defence\\\", \\\"Dexterity\\\", \\\"Agility\\\", \\\"Charisma\\\", \\\"Reputation\\\", \\\"Work Money\\\", \\\"Crime Money\\\", \\\"Crime Chance\\\", \\\"HackNet Production\\\", \\\"Hacknet Level Costs\\\", \\\"HackNet RAM Cost\\\", \\\"HackNet Core Cost\\\", \\\"HackNet Money\\\", \\\"BB Analysis\\\", \\\"BB Stamina\\\", \\\"BB Stamina Gain\\\", \\\"BB Success Chance\\\"]\""},{"filename":"SphyxOS/bins/graftingBasic.js","file":"\"import { proxy, proxyTry, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\nlet win;\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n let g = ns.grafting\\n ns.atExit(() => {\\n ns.clearPort(20)\\n if (win) win.close()\\n })\\n ns.clearPort(20)\\n ns.writePort(20, ns.pid)\\n win = false\\n let graftable = await proxy(ns, \\\"grafting.getGraftableAugmentations\\\")\\n let queue = []\\n graftable.unshift(\\\"Done\\\")\\n let FOCUS = graftable.includes(\\\"Neuroreceptor Management Implant\\\")\\n let SPECIFIC = await ns.prompt(\\\"Select Augment:\\\", { type: \\\"select\\\", choices: graftable })\\n\\n if (SPECIFIC === \\\"\\\" || SPECIFIC === \\\"Done\\\")\\n ns.exit()\\n queue.push(SPECIFIC)\\n while (SPECIFIC !== \\\"\\\" && SPECIFIC !== \\\"Done\\\") {\\n SPECIFIC = await ns.prompt(\\\"Select Next Queued Augment:\\\", { type: \\\"select\\\", choices: graftable.filter(f => !queue.includes(f)) })\\n if (SPECIFIC !== \\\"\\\" && SPECIFIC !== \\\"Done\\\") {\\n queue.push(SPECIFIC)\\n }\\n }\\n clearAll(ns)\\n getCommands(ns)\\n await ns.asleep(4)\\n ns.ui.openTail()\\n update(ns, ns.sprintf(\\\"Neuroreceptor Management Implant: %s\\\", !FOCUS))\\n if (FOCUS) update(ns, \\\"Please remain focused or your time will increase.\\\")\\n else update(ns, \\\"You can unfocus and do other things without penalty now.\\\")\\n update(ns, \\\"Grafting: Unknown\\\")\\n update(ns, \\\"Will take a min of Unknown.\\\")\\n update(ns, \\\"Script will continue once this graft is finished.\\\")\\n let ready = false\\n try {\\n g.waitForOngoingGrafting().then(() => {\\n ready = true\\n })\\n }\\n catch { ready = true }\\n while (!ready) {\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"Neuroreceptor Management Implant: %s\\\", !FOCUS))\\n if (FOCUS) update(ns, \\\"Please remain focused or your time will increase.\\\")\\n else update(ns, \\\"You can unfocus and do other things without penalty now.\\\")\\n update(ns, \\\"Grafting: Unknown\\\")\\n update(ns, \\\"Will take a min of Unknown.\\\")\\n update(ns, \\\"Script will continue once this graft is finished.\\\")\\n await ns.asleep(200)\\n }\\n while (queue.length > 0) {\\n graftable = await proxy(ns, \\\"grafting.getGraftableAugmentations\\\")\\n FOCUS = graftable.includes(\\\"Neuroreceptor Management Implant\\\")\\n let player = await proxy(ns, \\\"getPlayer\\\")\\n let city = player.city\\n if (city !== \\\"New Tokyo\\\") {\\n while (city !== \\\"New Tokyo\\\") {\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"You need to travel to New Tokyo! Currently in %s\\\", city))\\n player = await proxy(ns, \\\"getPlayer\\\")\\n city = player.city\\n await ns.asleep(100)\\n }\\n }//Get to New Tokyo\\n clearAll(ns)\\n SPECIFIC = queue.shift()\\n graftable = await proxy(ns, \\\"grafting.getGraftableAugmentations\\\")\\n FOCUS = graftable.includes(\\\"Neuroreceptor Management Implant\\\")\\n await proxyTry(ns, \\\"grafting.graftAugmentation\\\", SPECIFIC, FOCUS)\\n update(ns, ns.sprintf(\\\"Neuroreceptor Management Implant: %s\\\", !FOCUS))\\n if (FOCUS) update(ns, ns.sprintf(\\\"Please remain focused or your time will increase.\\\"))\\n else update(ns, ns.sprintf(\\\"You can unfocus and do other things without penalty now.\\\"))\\n update(ns, ns.sprintf(\\\"Grafting: %s\\\", SPECIFIC))\\n const graftTime = await proxyTry(ns, \\\"grafting.getAugmentationGraftTime\\\", SPECIFIC)\\n if (graftTime) {\\n update(ns, ns.sprintf(\\\"Will take a min of %s\\\", fTime(ns, graftTime)))\\n }\\n if (queue.length > 0) {\\n const price = await proxyTry(ns, \\\"grafting.getAugmentationGraftPrice\\\", queue[0])\\n if (price) {\\n update(ns, ns.sprintf(\\\"Queued: %s for $%s\\\", queue[0], fNumber(ns, price, 3)))\\n }\\n else update(ns, \\\"Queued: Invalid and will be skipped.\\\")\\n update(ns, ns.sprintf(\\\"#Queued After above: %s\\\", queue.length - 1))\\n }\\n const time = performance.now()\\n ready = false\\n try {\\n g.waitForOngoingGrafting().then(() => {\\n ready = true\\n })\\n }\\n catch { ready = true }\\n while (!ready) {\\n clearAll(ns)\\n update(ns, ns.sprintf(\\\"Neuroreceptor Management Implant: %s\\\", !FOCUS))\\n if (FOCUS) update(ns, ns.sprintf(\\\"Please remain focused or your time will increase.\\\"))\\n else update(ns, ns.sprintf(\\\"You can unfocus and do other things without penalty now.\\\"))\\n update(ns, ns.sprintf(\\\"Grafting: %s\\\", SPECIFIC))\\n const graftTime = await proxyTry(ns, \\\"grafting.getAugmentationGraftTime\\\", SPECIFIC)\\n if (graftTime) {\\n update(ns, ns.sprintf(\\\"Will take a min of %s\\\", fTime(ns, graftTime)))\\n }\\n if (queue.length > 0) {\\n const price = await proxyTry(ns, \\\"grafting.getAugmentationGraftPrice\\\", queue[0])\\n if (price) {\\n update(ns, ns.sprintf(\\\"Queued: %s for $%s\\\", queue[0], fNumber(ns, price, 3)))\\n }\\n else update(ns, \\\"Queued: Invalid and will be skipped.\\\")\\n update(ns, ns.sprintf(\\\"#Queued After above: %s\\\", queue.length - 1))\\n }\\n await ns.asleep(200)\\n }\\n if (performance.now() - time < 1000) {\\n const augPrice = await proxyTry(ns, \\\"grafting.getAugmentationGraftPrice\\\", SPECIFIC)\\n if (!augPrice)\\n update(ns, \\\"You have already installed this.\\\")\\n else if (ns.getServerMoneyAvailable(\\\"home\\\") < augPrice)\\n update(ns, \\\"You need more money for this augment\\\")\\n else\\n update(ns, ns.sprintf(\\\"Need to install a pre-req for %s first\\\", SPECIFIC))\\n }\\n\\n if (queue.length === 0) {\\n update(ns, \\\"No augments left in queue. Finishing up.\\\")\\n break\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction clearAll(ns) {\\n clearAll(ns)\\n if (win) win.clear()\\n}\\n/** @param {NS} ns */\\nfunction update(ns, text) {\\n ns.printf(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"grafting popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(23) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(23)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Grafting\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Grafting will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n win = false\\n if (!silent) ns.tprintf(\\\"Grafting will not use a popout\\\")\\n break\\n case \\\"silent\\\":\\n silent = true\\n break;\\n default:\\n ns.tprintf(\\\"Invalid command received in GraftingBasic: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\""},{"filename":"SphyxOS/bins/hacknetPurchaser.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let upgradeCost = -1\\n ns.atExit(() => {\\n ns.writePort(ns.pid, upgradeCost)\\n })\\n let count = 0\\n while (true) {\\n let upgradeType = 0\\n let upgradeItem = -1\\n upgradeCost = -1\\n if (ns.hacknet.numNodes() < ns.hacknet.maxNumNodes()) {\\n upgradeCost = ns.hacknet.getPurchaseNodeCost()\\n upgradeType = 5\\n }\\n for (let i = 0; i < ns.hacknet.numNodes(); i++) {\\n\\n if (upgradeCost == -1) { //Might be first one if we've purchased them all. We need to set the cost of something. Do so then move on\\n upgradeCost = ns.hacknet.getLevelUpgradeCost(i, 1)\\n upgradeType = 1\\n upgradeItem = i\\n }\\n if (ns.hacknet.getLevelUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getLevelUpgradeCost(i, 1)\\n upgradeType = 1\\n upgradeItem = i\\n }\\n if (ns.hacknet.getRamUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getRamUpgradeCost(i, 1)\\n upgradeType = 2\\n upgradeItem = i\\n }\\n if (ns.hacknet.getCoreUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getCoreUpgradeCost(i, 1)\\n upgradeType = 3\\n upgradeItem = i\\n }\\n if (ns.hacknet.getCacheUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getCacheUpgradeCost(i, 1)\\n upgradeType = 4\\n upgradeItem = i\\n }\\n }\\n\\n if (upgradeCost === Number.POSITIVE_INFINITY) {\\n upgradeCost = 0\\n return\\n } //We have no upgrade\\n else if (ns.getServerMoneyAvailable(\\\"home\\\") < upgradeCost) return //We don't have enough money to purchase\\n switch (upgradeType) {\\n case 1:\\n ns.hacknet.upgradeLevel(upgradeItem, 1)\\n break\\n case 2:\\n ns.hacknet.upgradeRam(upgradeItem, 1)\\n break\\n case 3:\\n ns.hacknet.upgradeCore(upgradeItem, 1)\\n break\\n case 4:\\n ns.hacknet.upgradeCache(upgradeItem, 1)\\n break\\n case 5:\\n const num = ns.hacknet.purchaseNode()\\n if (num >= 0) {\\n const hnetNode = \\\"hacknet-server-\\\" + num\\n try {\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", hnetNode, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", hnetNode, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", hnetNode, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", hnetNode, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", hnetNode, \\\"home\\\")\\n }\\n catch { }\\n }\\n break\\n default:\\n return\\n }\\n count++\\n if (count % 200 === 0) await ns.sleep(0)\\n }\\n}\""},{"filename":"SphyxOS/bins/puppetMini.js","file":"\"//Puppet2 by Sphyxis\\nimport { getServers, getSrvr, getOptimalTarget, getHackP, weakenStr, getGrowThreads, doGetScriptRam } from \\\"SphyxOS/util.js\\\"\\nimport { getHckTimeBasic, getIsRunning, getPlay, profitPerSecond, doGetServerCurSec, doGetServerMinSec } from \\\"SphyxOS/util.js\\\"\\nimport { virus, serverPurchaser, serverRun, getPortOpeners, getServersLight, getServerAvailRam, maxRun, proxy } from \\\"SphyxOS/util.js\\\"\\nimport { hashIt, getPortOpenersSing, hasBN, hacknetPurchaser, upgHomeRam, reservedRam, getHckTime, getBNMults, runIt, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\nimport { hackReady } from \\\"SphyxOS/basic/hack.js\\\"\\nimport { growReady } from \\\"SphyxOS/basic/grow.js\\\"\\nimport { weakenReady } from \\\"SphyxOS/basic/weaken.js\\\"\\n/** @type {Server[]} baseServers */\\nlet baseServers;\\n\\n//For the tail logs:\\n/** @type {Server} TARGET */\\nlet TARGET = \\\"\\\" //Who you are hacking\\n/** @type {Server} NEXTTARGET */\\nlet NEXTTARGET = \\\"\\\" //Whos next up\\nlet TARGETUPDATE = false\\nlet ZERGSTATUS = false\\nlet ZERGSENT = 0\\nlet ZERGREQUIRED = -1\\nlet RECALC_GOOD = false\\nlet RECALC_BAD = false\\nlet PORTS_OPEN = 0\\nlet BMODE = \\\"B\\\" //Batch mode: b is not batching, B is batching\\nlet THREADSLEFT = 0 //Total threads used\\nlet THREADSMAX = 0 //Total threads available\\nlet BATCHESTOTAL = 0 //Total batches done\\nlet BATCHESRUN = 0 //Actual batches run\\nlet PREPW1 = 0 //Prep wave\\nlet PREPG1 = 0\\nlet PREPW2 = 0\\nlet PREPH1 = 1\\nlet PREPW3 = 0\\nlet PREPG2 = 0\\nlet PREPW4 = 0\\nlet BATCHINFO;\\nlet STARTTIME = 0\\nlet ENDTIME = 0\\nlet BETWEENSTART = 0\\nlet BETWEENEND = 0\\nlet HACKTIME = 0\\nlet WEAKENTIME = 0\\nlet USEHACKNET = false\\nlet PURCHASE = true\\nlet AUTOHASH = false\\nlet AUTOBUYHACKNET = false\\nlet MONEYMODE = true\\nlet XPMODE = true\\nlet STANEKMODE = false\\nlet LOGMODE = false\\nlet PADMODE = false\\nconst WIDTH = 540\\nconst HEIGHT = 300\\nlet win\\n//Configuration\\nlet lastpid = 0\\nlet weakenStrength = 1\\nlet mults;\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n win = false\\n ns.clearPort(2)\\n ns.writePort(2, ns.pid)\\n ns.atExit(() => {\\n ns.clearPort(2)\\n ns.clearPort(3)\\n if (win) win.close()\\n })\\n if (!hackReady || !growReady || !weakenReady) {\\n ns.tprintf(\\\"Error with importing workers\\\")\\n ns.exit()\\n }\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n mults = await getBNMults(ns)\\n USEHACKNET = ns.args.includes(\\\"usehacknet\\\")\\n PURCHASE = !ns.args.includes(\\\"nopurchase\\\")\\n AUTOHASH = ns.args.includes(\\\"autohash\\\")\\n AUTOBUYHACKNET = ns.args.includes(\\\"autobuyhacknet\\\")\\n MONEYMODE = !ns.args.includes(\\\"nomoney\\\")\\n XPMODE = !ns.args.includes(\\\"noxp\\\")\\n STANEKMODE = ns.args.includes(\\\"stanek\\\")\\n LOGMODE = ns.args.includes(\\\"logging\\\")\\n PADMODE = ns.args.includes(\\\"pad\\\")\\n await virus(ns)\\n await init(ns)\\n weakenStrength = await weakenStr(ns)\\n /**@type {Player} player */\\n let player = await getPlay(ns)\\n //Is argument not null and is it a server? We target it, otherwise find the best\\n /*Arguments\\n * ns.args[0] is target - if one is to be specified. If no valid target is listed, it will get the best one.\\n * nohacknet\\n * nopurchase\\n */\\n const basicservers = await getServersLight(ns)\\n if (ns.args[0] && basicservers.includes(ns.args[0]))\\n TARGET = await getSrvr(ns, ns.args[0])\\n else if (player.skills.hacking < 10) TARGET = await getSrvr(ns, \\\"n00dles\\\")\\n else TARGET = await getOptimalTarget(ns, true)\\n NEXTTARGET = TARGET\\n\\n //Get the batch info. Contains: H1 W1 G1 W2 Type Take HackP\\n BATCHINFO = await getHackP(ns, TARGET.hostname, -1, -1, 1)\\n ns.clearPort(3)\\n ns.writePort(3, TARGET.hostname) //emit our target/next target for Hash targets\\n let spending = true\\n let new_ports_open = 0\\n PORTS_OPEN = 0\\n let overflowed = false\\n const SING = await hasBN(ns, 4, 2)\\n const PORTOPENERRAM = await doGetScriptRam(ns, \\\"SphyxOS/extras/getPortOpenersSing.js\\\")\\n const UPGRAM = await doGetScriptRam(ns, \\\"SphyxOS/singularity/upgradeHomeRam.js\\\")\\n getCommands(ns) //200ms refresh\\n update_hud(ns) //200ms refresh\\n while (true) {\\n await ns.asleep(4) //Let things catch up.\\n TARGET = await getSrvr(ns, TARGET.hostname)\\n //Calc wave\\n const wavew1 = Math.ceil((TARGET.hackDifficulty - TARGET.minDifficulty) / weakenStrength)\\n const waveg1 = Math.ceil(await getGrowThreads(ns, TARGET.hostname, TARGET.moneyAvailable, TARGET.minDifficulty))\\n\\n //Refresh times. Hack Time is the constant for that. 3.2x for Grow, 4x for Weaken\\n HACKTIME = await getHckTimeBasic(ns, TARGET.hostname)\\n WEAKENTIME = HACKTIME * 4\\n //Refresh base servers\\n baseServers = await getServers(ns)\\n //Get thread information\\n THREADSLEFT = 0\\n let emergencyReserve = await getServerAvailRam(ns, \\\"home\\\") <= 16 ? true : false\\n const max = emergencyReserve ? await maxRun(ns, false, USEHACKNET) : 0\\n const resRam = !emergencyReserve ? 0 : max >= 256 ? 256 : max >= 128 ? 128 : max >= 64 ? 64 : max >= 32 ? 32 : 16\\n for (const server of baseServers) {\\n if (server.hostname.startsWith(\\\"hacknet\\\") && !USEHACKNET) continue\\n if (server.hasAdminRights && server.maxRam > 0) {\\n let tmpramavailable = await getServerAvailRam(ns, server.hostname)\\n if (emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n } //Reserve if home ram is 16GB or less\\n if (server.hostname === \\\"home\\\") tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n let tmpthreads = Math.floor(tmpramavailable / 1.75)\\n THREADSLEFT += tmpthreads\\n }\\n }\\n THREADSMAX = THREADSLEFT\\n\\n //Figure out how many threads to assign to the wave, and where they will go for best usage.\\n //First weaken\\n if (MONEYMODE) {\\n if (wavew1 > THREADSLEFT) { //We need too many!\\n PREPW1 = THREADSLEFT\\n THREADSLEFT = 0\\n }\\n else { //Enough to fit\\n PREPW1 = wavew1\\n THREADSLEFT -= PREPW1 //Could be as low as 0 now\\n }\\n\\n // If we have threads left, move on to Grow/Weaken\\n if (waveg1 > THREADSLEFT) { //We need more grow than we can handle\\n PREPW2 = Math.ceil((THREADSLEFT * .004) / weakenStrength) //Figure out how many weaken threads we need to accomodate the highest\\n PREPG1 = THREADSLEFT - PREPW2 //Fill in as many grows as can fit now\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total grow threads, but can we handle it with weaken?\\n PREPW2 = Math.ceil((waveg1 * .004) / weakenStrength) //total weakens we need for a full grow\\n if (PREPW2 + waveg1 <= THREADSLEFT) {//We have enough for both grow and weaken!\\n PREPG1 = waveg1\\n THREADSLEFT -= PREPG1 + PREPW2 //Could be as low as 0 now\\n }\\n else { //We don't have enough. Calculate optimal\\n const growP = .004 / weakenStrength\\n const remainder = waveg1 + PREPW2 - THREADSLEFT\\n const weakremove = Math.floor(remainder * growP)\\n const growremove = remainder - weakremove\\n PREPG1 = waveg1 - growremove\\n PREPW2 -= weakremove\\n THREADSLEFT = 0\\n }\\n }\\n\\n //If we have threads left, move on to Hack/Weaken\\n if (BATCHINFO.H1 > THREADSLEFT) { //We don't have enough to fully hack!\\n PREPW3 = Math.ceil((THREADSLEFT * .002) / weakenStrength)\\n PREPH1 = THREADSLEFT - PREPW3\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total hack threads, but what about the weakens it produces?\\n PREPW3 = Math.ceil((BATCHINFO.H1 * .002) / weakenStrength)\\n if (PREPW3 + BATCHINFO.H1 <= THREADSLEFT) { //We have enough for both hack and weaken\\n PREPH1 = BATCHINFO.H1\\n THREADSLEFT -= PREPH1 + PREPW3\\n }\\n else { //We don'thave enough. Calculate optimal\\n const hackP = .002 / weakenStrength\\n const remainder = BATCHINFO.H1 + PREPW3 - THREADSLEFT\\n const weakenremove = Math.ceil(remainder * hackP)\\n const hackremove = remainder - weakenremove\\n PREPH1 = BATCHINFO.H1 - hackremove\\n PREPW3 -= weakenremove\\n THREADSLEFT = 0\\n }\\n }\\n\\n // If we have threads left, move on to Grow/Weaken\\n if (BATCHINFO.G1 > THREADSLEFT) { //We need more grow than we can handle\\n PREPW4 = Math.ceil((THREADSLEFT * .004) / weakenStrength) //Figure out how many weaken threads we need to accomodate the highest\\n PREPG2 = THREADSLEFT - PREPW4 //Fill in as many grows as can fit now\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total grow threads, but can we handle it with weaken?\\n PREPW4 = Math.ceil((BATCHINFO.G1 * .004) / weakenStrength) //total weakens we need for a full grow\\n if (PREPW4 + BATCHINFO.G1 <= THREADSLEFT) {//We have enough for both grow and weaken!\\n PREPG2 = BATCHINFO.G1\\n THREADSLEFT -= PREPG2 + PREPW4 //Could be as low as 0 now\\n }\\n else { //We don't have enough. Calculate optimal\\n const growP = .004 / weakenStrength\\n const remainder = BATCHINFO.G1 + PREPW4 - THREADSLEFT\\n const weakremove = Math.floor(remainder * growP)\\n const growremove = remainder - weakremove\\n PREPG2 = BATCHINFO.G1 - growremove\\n PREPW4 -= weakremove\\n THREADSLEFT = 0\\n }\\n }\\n BATCHESTOTAL = Math.floor(THREADSLEFT / (BATCHINFO.H1 + BATCHINFO.W1 + BATCHINFO.G1 + BATCHINFO.W2))\\n if (ZERGSTATUS && ZERGREQUIRED !== ZERGSENT && BATCHESTOTAL > 3) BATCHESTOTAL = Math.max(Math.max(Math.floor(BATCHESTOTAL * 4 / 5), BATCHESTOTAL - 50), 0) //Reserve a few batches to send as zerglings\\n }\\n BETWEENEND = performance.now()\\n STARTTIME = performance.now()\\n //Start it all and get the results\\n let results\\n if (MONEYMODE) {\\n await ns.asleep(4)\\n results = await serverRun(ns, LOGMODE, TARGET.hostname, PREPW1, PREPG1, PREPW2, PREPH1, PREPW3, PREPG2, PREPW4, BATCHINFO.H1, BATCHINFO.W1, BATCHINFO.G1, BATCHINFO.W2, BATCHESTOTAL, USEHACKNET)\\n THREADSLEFT -= ((BATCHINFO.H1 + BATCHINFO.W1 + BATCHINFO.G1 + BATCHINFO.W2) * results.batches)\\n }\\n\\n if (MONEYMODE && ZERGSTATUS && THREADSLEFT > 0 && ZERGREQUIRED !== ZERGSENT && BATCHESTOTAL > 2) {\\n await ns.asleep(4)\\n await zerglings(ns, THREADSLEFT) //If zerg is on, send the lings!\\n }\\n let xpResults;\\n if (XPMODE) {\\n await ns.asleep(4)\\n xpResults = await generateXP(ns, THREADSLEFT, player)\\n THREADSLEFT = 0\\n }\\n ENDTIME = performance.now()\\n if (MONEYMODE) {\\n lastpid = results.lastpid\\n RECALC_BAD = results.recalc\\n BATCHESRUN = results.batches\\n BMODE = results.batching ? \\\"B\\\" : \\\"b\\\"\\n }\\n else {\\n lastpid = xpResults[0].lastpid\\n RECALC_BAD = false\\n BATCHESRUN = 1\\n BMODE = \\\"B\\\"\\n WEAKENTIME = xpResults[1]\\n BMODE = \\\"XP\\\"\\n }\\n //Now that we have the next batch ready, we wait...\\n if (!lastpid) {\\n BMODE = \\\"WAITING FOR RAM\\\"\\n await ns.asleep(1000)\\n }\\n else {\\n while (await getIsRunning(ns, lastpid)) {\\n await ns.asleep(20)\\n }\\n }\\n await ns.asleep(4)\\n\\n //If our hacking has gone up, recalculate\\n const maxRam = await maxRun(ns, false)\\n const homeRam = await getServerAvailRam(ns, \\\"home\\\")\\n if (SING && homeRam < reservedRam && maxRam > UPGRAM) await upgHomeRam(ns)\\n if (PORTS_OPEN < 5) new_ports_open = SING && PORTOPENERRAM <= maxRam ? await getPortOpenersSing(ns) : await getPortOpeners(ns)\\n if (PURCHASE && spending) if (!await serverPurchaser(ns)) spending = false\\n if (AUTOHASH) {\\n await hashIt(ns, \\\"max\\\")\\n await hashIt(ns, \\\"min\\\")\\n }\\n if (AUTOBUYHACKNET) {\\n if (!await hacknetPurchaser(ns)) {\\n AUTOBUYHACKNET = false\\n ns.writePort(1, \\\"puppet hacknet off\\\")\\n }\\n\\n }\\n //Charge Stanek here\\n if (STANEKMODE && lastpid) {\\n const stanekPid = await runIt(ns, \\\"SphyxOS/stanek/startCharge.js\\\", true, [\\\"quiet\\\"])\\n BMODE = \\\"Stanek\\\"\\n const frags = await proxy(ns, \\\"stanek.activeFragments\\\")\\n const numFrags = frags.reduce((val, a) => a.id < 100 ? val += 1 : val = val, 0)\\n BATCHINFO.Type = \\\"Charging \\\" + numFrags + \\\" Stanek pieces\\\"\\n WEAKENTIME += (numFrags + 1) * 1000\\n while (await getIsRunning(ns, stanekPid)) {\\n await ns.asleep(20)\\n }\\n }\\n BETWEENSTART = performance.now()\\n let portsChanged = false\\n if (PORTS_OPEN !== new_ports_open) {\\n PORTS_OPEN = new_ports_open\\n await virus(ns)\\n portsChanged = true\\n }\\n /**@type {Player} player2 */\\n const player2 = await getPlay(ns)\\n if ((player2.skills.hacking > player.skills.hacking + 10 && BATCHESTOTAL >= 2 && MONEYMODE) || (BATCHESTOTAL >= 2 && portsChanged && MONEYMODE)) {\\n player = player2\\n RECALC_GOOD = true\\n TARGETUPDATE = true\\n }\\n\\n if (NEXTTARGET.hostname === TARGET.hostname && TARGETUPDATE) { //Nexttarget is target. We are open for a new target \\n /**@type {Server} upcoming */\\n const upcoming = await getOptimalTarget(ns)\\n if (upcoming && upcoming.hostname !== TARGET.hostname) { //We have an up and commer that's better. Start zerglings\\n NEXTTARGET = upcoming\\n ZERGSTATUS = true\\n }\\n TARGETUPDATE = false\\n }\\n else if (NEXTTARGET.hostname !== TARGET.hostname && await doGetServerCurSec(ns, NEXTTARGET.hostname) === await doGetServerMinSec(ns, NEXTTARGET.hostname)) { //Ready for the change over\\n TARGET = NEXTTARGET\\n ZERGSTATUS = false\\n ZERGSENT = 0\\n ZERGREQUIRED = -1\\n RECALC_BAD = false\\n RECALC_GOOD = false\\n overflowed = false\\n //Get the batch info. Contains: H1 W1 G1 W2 Type Take HackP\\n BATCHINFO = await getHackP(ns, TARGET.hostname, -1, -1, 1)\\n TARGETUPDATE = true\\n }\\n ns.clearPort(3)\\n ns.writePort(3, TARGET.hostname) //emit our target/next target for Hash targets\\n\\n if (RECALC_BAD) {\\n BATCHINFO = await getHackP(ns, TARGET.hostname, BATCHESRUN, THREADSMAX, BATCHINFO.H1)\\n RECALC_BAD = false\\n overflowed = true\\n }\\n else if (RECALC_GOOD && !overflowed) {\\n BATCHINFO = await getHackP(ns, TARGET.hostname, -1, -1, 1)\\n RECALC_GOOD = false\\n }\\n else BATCHINFO = await getHackP(ns, TARGET.hostname, -1, -1, Math.max(BATCHINFO.H1 - 1, 1))\\n if (PADMODE) {\\n BATCHINFO.G1 += Math.ceil(BATCHINFO.G1 * .15)\\n BATCHINFO.W2 = Math.ceil(((BATCHINFO.G1 * 0.004) + Math.max(((BATCHINFO.H1 * 0.002) / weakenStrength) - (BATCHINFO.W1 * weakenStrength), 0)) / weakenStrength)\\n }\\n }//while (true) loop\\n}\\n\\n/** @param {NS} ns */\\nasync function update_hud(ns) {\\n while (true) {\\n clearLogs(ns)\\n update(ns, ns.sprintf(\\\"%s[%s] - (%s)\\\", TARGET.hostname, BMODE, BATCHINFO.Type))\\n update(ns, ns.sprintf(\\\"%s%s%s%s%s%s%s\\\", MONEYMODE ? \\\"Money \\\" : \\\"\\\", XPMODE ? \\\"XP \\\" : \\\"\\\", PURCHASE ? \\\"BuyServers \\\" : \\\"\\\", STANEKMODE ? \\\"Stanek \\\" : \\\"\\\", USEHACKNET ? \\\"UseHacknet \\\" : \\\"\\\", AUTOBUYHACKNET ? \\\"BuyHacknet \\\" : \\\"\\\", AUTOHASH ? \\\"AutoHash \\\" : \\\"\\\", PADMODE ? \\\"Padding \\\" : \\\"\\\", LOGMODE ? \\\"Logging \\\" : \\\"\\\"))\\n if (TARGET.hostname !== NEXTTARGET.hostname) update(ns, ns.sprintf(\\\"Next: %s Zerglings: %s/%s\\\", NEXTTARGET.hostname, ZERGSENT, ZERGREQUIRED === -1 ? \\\"Waiting\\\" : ZERGREQUIRED))\\n update(ns, ns.sprintf(\\\"%s/%s(%s) Batches: %s Take: $%s\\\", THREADSMAX - THREADSLEFT, THREADSMAX, THREADSLEFT, BATCHESRUN + 1, fNumber(ns, BATCHINFO.Take * (BATCHESRUN + 1) * PREPH1 / BATCHINFO.H1)))\\n update(ns, ns.sprintf(\\\"HackP: %s%s ($%s/each) Chance: %s%s\\\", Math.round(BATCHINFO.HackP * 10000 * PREPH1) / 100, \\\"%\\\", fNumber(ns, BATCHINFO.Take * PREPH1 / BATCHINFO.H1), fNumber(ns, BATCHINFO.Chance * 100, 2), \\\"%\\\"))\\n update(ns, ns.sprintf(\\\"Prep Wave: W:%s G:%s W:%s H:%s W:%s G:%s W:%s\\\", PREPW1, PREPG1, PREPW2, PREPH1, PREPW3, PREPG2, PREPW4))\\n update(ns, ns.sprintf(\\\"Batching Composition: H:%s W:%s G:%s W:%s\\\", BATCHINFO.H1, BATCHINFO.W1, BATCHINFO.G1, BATCHINFO.W2))\\n update(ns, ns.sprintf(\\\"%s Countdown: %s\\\", \\\"$\\\" + profitPerSecond(ns, WEAKENTIME, BATCHINFO.Take * BATCHINFO.H1 / PREPH1, BATCHESRUN + 1), fTime(ns, (WEAKENTIME + ENDTIME) - performance.now())))\\n update(ns, ns.sprintf(\\\"Preptime : %s\\\", fTime(ns, BETWEENEND - BETWEENSTART, true)))\\n update(ns, ns.sprintf(\\\"Loadtime : %s\\\", fTime(ns, ENDTIME - STARTTIME, true)))\\n update(ns, ns.sprintf(\\\"Batchtime: %s\\\", fTime(ns, WEAKENTIME, true)))\\n ns.ui.renderTail()\\n await ns.asleep(200)\\n }\\n}\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printRaw(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"puppet popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\\n\\n/** @param {NS} ns */\\nasync function zerglings(ns, threads) {\\n if (ZERGREQUIRED <= 0) ZERGREQUIRED = Math.ceil((NEXTTARGET.hackDifficulty - NEXTTARGET.minDifficulty) / weakenStrength) + 1\\n if (ZERGSENT >= ZERGREQUIRED || threads === 0) return\\n const weakthreadsneeded = Math.ceil((NEXTTARGET.hackDifficulty - NEXTTARGET.minDifficulty) / weakenStrength) + 1 - ZERGSENT\\n const threadsthisround = weakthreadsneeded >= threads ? threads : weakthreadsneeded\\n\\n if (threadsthisround > 0) { //We are sending zerglings\\n ZERGSENT += threadsthisround\\n THREADSLEFT -= threadsthisround\\n await serverRun(ns, LOGMODE, NEXTTARGET.hostname, threadsthisround, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, USEHACKNET)\\n }\\n}\\n/** @param {NS} ns */\\nasync function generateXP(ns, threads, player) {\\n if (threads === 0) return [false, 0]\\n const servers = await getServersLight(ns)\\n let bestServer = \\\"\\\"\\n let bestTime = Infinity\\n let bestXPRatio = 0\\n for (const server of servers) {\\n const sObj = await getSrvr(ns, server)\\n if (!sObj.hasAdminRights || sObj.hostname === \\\"home\\\" || sObj.moneyMax === 0 || sObj.purchasedByPlayer || sObj.minDifficulty <= 1) continue\\n const time = await getHckTime(ns, server, sObj.minDifficulty)\\n if (xpGain(player, sObj) / time > bestXPRatio) {\\n bestServer = server\\n bestTime = time\\n bestXPRatio = xpGain(player, sObj) / time\\n }\\n }\\n const sObj = await getSrvr(ns, bestServer)\\n bestTime = await getHckTimeBasic(ns, bestServer)\\n let wavew1 = Math.ceil((sObj.hackDifficulty - sObj.minDifficulty) / weakenStrength)\\n let waveg1 = Math.ceil(await getGrowThreads(ns, bestServer, sObj.moneyAvailable, sObj.minDifficulty))\\n let wavew2 = 0\\n if (wavew1 > threads) { //We need too many!\\n wavew1 = threads\\n threads = 0\\n }\\n else { //Enough to fit\\n threads -= wavew1 //Could be as low as 0 now\\n }\\n\\n // If we have threads left, move on to Grow/Weaken\\n if (waveg1 > threads) { //We need more grow than we can handle\\n wavew2 = Math.ceil((threads * .004) / weakenStrength) //Figure out how many weaken threads we need to accomodate the highest\\n waveg1 = threads - wavew2 //Fill in as many grows as can fit now\\n threads = 0\\n }\\n else { //We can handle the total grow threads, but can we handle it with weaken?\\n wavew2 = Math.ceil((waveg1 * .004) / weakenStrength) //total weakens we need for a full grow\\n if (wavew2 + waveg1 <= threads) {//We have enough for both grow and weaken!\\n threads -= waveg1 + wavew2 //Could be as low as 0 now\\n }\\n else { //We don't have enough. Calculate optimal\\n const growP = .004 / weakenStrength\\n\\n //const remainder = waveg1 + wavew2 - threads //Threads left after \\n const weakremove = Math.ceil(threads * growP) //Weakens needed\\n const growremove = threads - weakremove\\n waveg1 = growremove\\n wavew2 = weakremove\\n threads = 0\\n }\\n }\\n const result = await serverRun(ns, LOGMODE, bestServer, wavew1, waveg1, wavew2, 0, 0, threads, 0, 0, 0, 0, 0, 0, USEHACKNET)\\n THREADSLEFT = 0\\n const time = wavew1 + wavew2 > 0 ? bestTime * 4 : bestTime * 3.2\\n return [result, time]\\n}\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(12) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(12)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Batcher\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n win = false\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not use a popout\\\")\\n break\\n case \\\"silent\\\":\\n silent = true\\n break;\\n case \\\"nohacknet\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not use Hacknet nodes now\\\")\\n USEHACKNET = false\\n break;\\n case \\\"hacknet\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will use Hacknet nodes now\\\")\\n USEHACKNET = true\\n break;\\n case \\\"purchaseservers\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will purchase servers\\\")\\n PURCHASE = true\\n break;\\n case \\\"nopurchaseservers\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not purchase servers\\\")\\n PURCHASE = false\\n break;\\n case \\\"autohash\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will automatically spend hashes\\\")\\n AUTOHASH = true\\n break;\\n case \\\"autobuyhacknet\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will automatically buy hacknet servers\\\")\\n AUTOBUYHACKNET = true\\n break;\\n case \\\"noautobuyhacknet\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not buy hacknet servers\\\")\\n AUTOBUYHACKNET = false\\n break;\\n case \\\"noautohash\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not automatically spend hashes\\\")\\n AUTOHASH = false\\n break;\\n case \\\"money\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will generate money\\\")\\n MONEYMODE = true\\n break;\\n case \\\"nomoney\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not generate money\\\")\\n MONEYMODE = false\\n break;\\n case \\\"xp\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will generate xp\\\")\\n XPMODE = true\\n break;\\n case \\\"noxp\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not generate xp\\\")\\n XPMODE = false\\n break;\\n case \\\"stanek\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will charge Stanek\\\")\\n STANEKMODE = true\\n break;\\n case \\\"nostanek\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not charge Stanek\\\")\\n STANEKMODE = false\\n break;\\n case \\\"log\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will generate error logs\\\")\\n LOGMODE = true\\n break;\\n case \\\"nolog\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not generate error logs\\\")\\n LOGMODE = false\\n break;\\n case \\\"pad\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will pad grows\\\")\\n PADMODE = true\\n break;\\n case \\\"nopad\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Puppet will not pad grows\\\")\\n PADMODE = false\\n break;\\n default:\\n ns.tprintf(\\\"Invalid command received in puppetMini: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\n\\n/** @param {NS} ns */\\nasync function init(ns) {\\n baseServers = await getServers(ns)\\n TARGET = \\\"\\\" //Who you are hacking\\n NEXTTARGET = \\\"\\\" //Whos next up\\n TARGETUPDATE = false\\n ZERGSTATUS = false\\n ZERGSENT = 0\\n ZERGREQUIRED = -1\\n RECALC_GOOD = false\\n RECALC_BAD = false\\n PORTS_OPEN = await getPortOpeners(ns)\\n BMODE = \\\"B\\\" //Batching style. b is not batching, B is batching\\n THREADSMAX = 0 //Total threads available\\n BATCHESTOTAL = 0 //Total batches done\\n BATCHESRUN = 0 //Total batches actually run\\n PREPW1 = 0 //Prep wave\\n PREPG1 = 0\\n PREPW2 = 0\\n PREPH1 = 1\\n PREPW3 = 0\\n PREPG2 = 0\\n PREPW4 = 0\\n STARTTIME = 0\\n ENDTIME = 0\\n BETWEENSTART = performance.now()\\n BETWEENEND = 0\\n WEAKENTIME = 0\\n}\\nfunction xpGain(person, server) {\\n const baseDifficulty = server.baseDifficulty;\\n if (!baseDifficulty) return 0;\\n const baseExpGain = 3;\\n const diffFactor = 0.3;\\n let expGain = baseExpGain;\\n expGain += baseDifficulty * diffFactor;\\n return expGain * person.mults.hacking_exp * mults.HackExpGain\\n}\""},{"filename":"SphyxOS/bins/singularityBackdoor.js","file":"\"import { getServersLight, runIt } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.clearLog()\\n ns.atExit(() => ns.writePort(ns.pid, true))\\n if (!ns.args.includes(\\\"quiet\\\")) ns.ui.openTail()\\n const all = ns.args.includes(\\\"all\\\")\\n const allServers = await getServersLight(ns)\\n const purchasedServers = getNames(ns)\\n const hackingLevel = ns.getHackingLevel()\\n const servers = all ? allServers.filter((s) => s !== \\\"home\\\" && !s.startsWith(\\\"hacknet\\\") && !purchasedServers.includes(s) && hackingLevel >= ns.getServerRequiredHackingLevel(s) && ns.getServer(s).hasAdminRights && !ns.getServer(s).backdoorInstalled)\\n : ns.args.includes(\\\"autopilot\\\") ? targetsAutoPilot.filter((s) => ns.getHackingLevel() >= ns.getServerRequiredHackingLevel(s) && ns.getServer(s).hasAdminRights && !ns.getServer(s).backdoorInstalled)\\n : targets.filter((s) => ns.getHackingLevel() >= ns.getServerRequiredHackingLevel(s) && ns.getServer(s).hasAdminRights && !ns.getServer(s).backdoorInstalled)\\n servers.sort()\\n const startTime = performance.now()\\n ns.printf(\\\"Servers: %s\\\", servers.length)\\n let eta = 0\\n servers.forEach(s => eta += (ns.getHackTime(s) / 4))\\n ns.printf(\\\"Max ETA: %s\\\", fTime(ns, eta), 3)\\n let runningScripts = 0\\n for (let point of servers) {\\n let target = point\\n const path = [target]\\n while ((target = ns.scan(target)[0]) !== \\\"home\\\") path.unshift(target)\\n path.unshift(\\\"home\\\")\\n for (const server of path)\\n ns.singularity.connect(server)\\n const runningPid = await runIt(ns, \\\"SphyxOS/singularity/backdoor.js\\\", true, [], 0, true)\\n if (runningPid === 0) {\\n ns.printf(\\\"Server(Local): %s - %s\\\", point, fTime(ns, ns.getHackTime(point) / 4))\\n await ns.singularity.installBackdoor()\\n ns.printf(\\\"Installed backdoor on %s\\\", point)\\n }\\n else {\\n runningScripts++\\n ns.printf(\\\"Server(Remote): %s - %s\\\", point, fTime(ns, ns.getHackTime(point) / 4))\\n ns.nextPortWrite(runningPid).then(() => {\\n ns.printf(\\\"Installed backdoor on %s\\\", point)\\n runningScripts--\\n })\\n await ns.asleep(100) //Let the backdoor script run\\n }\\n }\\n if (servers.length > 0) ns.singularity.connect(\\\"home\\\")\\n while (runningScripts > 0) await ns.asleep(1000)\\n ns.printf(\\\"Finished %s servers in %s\\\", servers.length, fTime(ns, performance.now() - startTime))\\n}\\n/** @param {NS} ns */\\nfunction getNames(ns) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.getServerNames()\\n else return ns.getPurchasedServers()\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nconst targets = [\\n \\\"CSEC\\\",\\n \\\"I.I.I.I\\\",\\n \\\"avmnite-02h\\\",\\n \\\"run4theh111z\\\",\\n \\\"powerhouse-fitness\\\",\\n \\\"fulcrumassets\\\"\\n]\\nconst targetsAutoPilot = [\\n \\\"CSEC\\\",\\n \\\"I.I.I.I\\\",\\n \\\"avmnite-02h\\\",\\n \\\"run4theh111z\\\"\\n]\""},{"filename":"SphyxOS/bins/startShare.js","file":"\"import { getServersLight, doScriptKill } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n const servers = await getServersLight(ns)\\n\\n for (const server of servers) {\\n if (!ns.args.includes(\\\"stop\\\")) {\\n const reserved = server === \\\"home\\\" ? 32 : 0\\n const threads = Math.floor((ns.getServerMaxRam(server) - ns.getServerUsedRam(server) - reserved) / 4)\\n\\n if (ns.hasRootAccess(server) && threads > 0) {\\n ns.scp(\\\"SphyxOS/basic/share.js\\\", server, \\\"home\\\")\\n ns.exec(\\\"SphyxOS/basic/share.js\\\", server, threads)\\n }\\n }\\n else {\\n await doScriptKill(ns, \\\"SphyxOS/basic/share.js\\\", server)\\n }\\n }\\n}\""},{"filename":"SphyxOS/bins/tSleeves.js","file":"\"import { hasBN } from \\\"SphyxOS/util.js\\\"\\nimport { sleeveSetToCrime, sleeveSetToGym, sleeveSetToUniversity, sleeveGetAugs, sleeveIdle } from \\\"SphyxOS/util.js\\\"\\nimport { getSleeveObject, sleeveTravel, sleeveShockRecovery, sleeveSync, sleeveInstallAugs, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\n\\nlet MODE = \\\"Recovery\\\" //Training, Money, Recovery, Sync, Karma, Int, Idle\\nlet IMODE = false // Install Mode\\nlet HASBN5 = 0\\nconst WIDTH = 1000\\nconst HEIGHT = 300\\nlet win\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.clearPort(7)\\n ns.writePort(7, ns.pid)\\n ns.atExit(() => {\\n ns.clearPort(7)\\n if (win) win.close()\\n })\\n win = false\\n HASBN5 = await hasBN(ns, 5, 1)\\n ns.ui.openTail()\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n getCommands(ns)\\n while (true) {\\n await ns.asleep(1000)\\n //me, num, task\\n const sleeves = await getSleeveObject(ns)\\n if (IMODE) await sleeveInstallAugs(ns)\\n await displaySleeves(ns, sleeves)\\n for (const slv of sleeves) {\\n\\n if (MODE === \\\"Recovery\\\") {\\n await sleeveShockRecovery(ns, slv.num)\\n continue\\n }\\n else if (MODE === \\\"Sync\\\") {\\n await sleeveSync(ns, slv.num)\\n continue\\n }\\n else if (MODE === \\\"Idle\\\") {\\n await sleeveIdle(ns, slv.num)\\n continue\\n }\\n else if (MODE === \\\"All\\\") {\\n const skls = slv.me.skills\\n //Make sure we are in Sector-12\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (skls.hacking === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"Computer Science\\\") {\\n await sleeveSetToUniversity(ns, slv.num, \\\"Rothman University\\\", \\\"Computer Science\\\")\\n }\\n continue\\n }\\n if (skls.strength === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"str\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"str\\\")\\n }\\n continue\\n }\\n if (skls.defense === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"def\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"def\\\")\\n }\\n continue\\n }\\n if (skls.dexterity === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"dex\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"dex\\\")\\n }\\n continue\\n }\\n if (skls.agility === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"agi\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"agi\\\")\\n }\\n continue\\n }\\n if (skls.charisma === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"Leadership\\\") {\\n await sleeveSetToUniversity(ns, slv.num, \\\"Rothman University\\\", \\\"Leadership\\\")\\n }\\n continue\\n }\\n ns.tprintf(\\\"Error! Failed to train.\\\")\\n continue\\n }//End All Training\\n else if (MODE === \\\"Hack\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"Computer Science\\\") {\\n await sleeveSetToUniversity(ns, slv.num, \\\"Rothman University\\\", \\\"Computer Science\\\")\\n }\\n continue\\n }\\n else if (MODE === \\\"Str\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"str\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"str\\\")\\n }\\n continue\\n }\\n else if (MODE === \\\"Def\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"def\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"def\\\")\\n }\\n continue\\n }\\n else if (MODE === \\\"Dex\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"dex\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"dex\\\")\\n }\\n continue\\n }\\n else if (MODE === \\\"Agi\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"agi\\\") {\\n await sleeveSetToGym(ns, slv.num, \\\"Powerhouse Gym\\\", \\\"agi\\\")\\n }\\n continue\\n }\\n else if (MODE === \\\"Cha\\\") {\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!await sleeveTravel(ns, slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (slv.task === null || slv.task.classType !== \\\"Leadership\\\") {\\n await sleeveSetToUniversity(ns, slv.num, \\\"Rothman University\\\", \\\"Leadership\\\")\\n }\\n continue\\n }\\n else if ([\\\"Money\\\", \\\"Karma\\\", \\\"Int\\\"].includes(MODE)) {\\n //Cycle our crimes and find the best for our mode.\\n let bestRatio = 0\\n let bestCrime = \\\"Mug\\\"\\n for (const crime of crimes) {\\n const chance = getChance(ns, crime, slv.me)\\n const gain = MODE === \\\"Money\\\" ? crime.money : IMODE ? crime.money : MODE === \\\"Karma\\\" ? crime.karma : crime.intelligence_exp\\n const ratio = gain * chance / crime.time\\n if (ratio > bestRatio) {\\n bestRatio = ratio\\n bestCrime = crime.name\\n }\\n }\\n if (slv.task === null || (slv.task && slv.task.crimeType !== bestCrime)) await sleeveSetToCrime(ns, slv.num, bestCrime)\\n continue\\n }\\n ns.tprintRaw(\\\"Sleeves failed to select a valid mode: \\\" + MODE)\\n }//End of sleeves\\n }//End While True\\n}\\n/** @param {NS} ns */\\nasync function displaySleeves(ns, sleeves) {\\n clearAll(ns)\\n update(ns, \\\"Sleeve Statistics:\\\")\\n update(ns, ns.sprintf(\\\"Mode: %s Install: %s\\\", MODE, IMODE))\\n if (HASBN5) update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s\\\", \\\"#\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Int\\\", \\\"Aug\\\", \\\"Shock\\\", \\\"Action\\\", \\\"Name\\\"))\\n else update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s\\\", \\\"#\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Aug\\\", \\\"Shock\\\", \\\"Action\\\", \\\"Name\\\"))\\n //num, me, task\\n for (const slv of sleeves) {\\n const augs = await sleeveGetAugs(ns, slv.num)\\n if (HASBN5) update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s %s\\\", slv.num, fNumber(ns, slv.me.skills.hacking, 3), fNumber(ns, slv.me.skills.strength, 3), fNumber(ns, slv.me.skills.defense, 3), fNumber(ns, slv.me.skills.dexterity, 3), fNumber(ns, slv.me.skills.agility, 3), fNumber(ns, slv.me.skills.charisma, 3), fNumber(ns, slv.me.skills.intelligence), augs, fNumber(ns, slv.me.shock, 2), slv.task === null ? \\\"Shock Recovery\\\" : slv.task?.type, slv.task?.actionType || slv.task?.classType || slv.task?.crimeType || \\\"n/a\\\"))\\n else update(ns, ns.sprintf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s %s\\\", slv.num, fNumber(ns, slv.me.skills.hacking, 3), fNumber(ns, slv.me.skills.strength, 3), fNumber(ns, slv.me.skills.defense, 3), fNumber(ns, slv.me.skills.dexterity, 3), fNumber(ns, slv.me.skills.agility, 3), fNumber(ns, slv.me.skills.charisma, 3), augs, fNumber(ns, slv.me.shock, 2), slv.task === null ? \\\"Shock Recovery\\\" : slv.task?.type, slv.task?.actionType || slv.task?.classType || slv.task?.crimeType || \\\"n/a\\\"))\\n }\\n ns.ui.renderTail()\\n}\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(17) !== \\\"NULL PORT DATA\\\") {\\n let result = ns.readPort(17)\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Sleeves\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Sleeves: Will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n win = false\\n if (!silent) ns.tprintf(\\\"Sleeves: Will not use a popout\\\")\\n break\\n case \\\"All\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Multi Training Mode!\\\")\\n MODE = \\\"All\\\"\\n break\\n case \\\"Hack\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Hack now!\\\")\\n MODE = \\\"Hack\\\"\\n break\\n case \\\"Str\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Str now!\\\")\\n MODE = \\\"Str\\\"\\n break\\n case \\\"Def\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Def now!\\\")\\n MODE = \\\"Def\\\"\\n break\\n case \\\"Dex\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Dex now!\\\")\\n MODE = \\\"Dex\\\"\\n break\\n case \\\"Agi\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Agi now!\\\")\\n MODE = \\\"Agi\\\"\\n break\\n case \\\"Cha\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Cha now!\\\")\\n MODE = \\\"Cha\\\"\\n break\\n case \\\"Int\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Training Int now!\\\")\\n MODE = \\\"Int\\\"\\n break\\n case \\\"Idle\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Idle Mode!\\\")\\n MODE = \\\"Idle\\\"\\n break\\n case \\\"Money\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Money Mode!\\\")\\n MODE = \\\"Money\\\"\\n break\\n case \\\"Recovery\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Recovery Mode!\\\")\\n MODE = \\\"Recovery\\\"\\n break\\n case \\\"Sync\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Sync Mode!\\\")\\n MODE = \\\"Sync\\\"\\n break\\n case \\\"Karma\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Karma Mode!\\\")\\n MODE = \\\"Karma\\\"\\n break\\n case \\\"Install On\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched to Install Mode!\\\")\\n IMODE = true\\n break\\n case \\\"Install Off\\\":\\n if (!silent) ns.tprintf(\\\"Sleeves: Switched off Install Mode!\\\")\\n IMODE = false\\n break\\n case \\\"Silent\\\":\\n silent = true\\n break\\n default:\\n ns.tprintf(\\\"Invalid command received in tSleeves: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction getChance(ns, crimestats, wsleeve) {\\n let hackweight = crimestats.hacking_success_weight * wsleeve.skills.hacking\\n let strweight = crimestats.strength_success_weight * wsleeve.skills.strength\\n let defweight = crimestats.defense_success_weight * wsleeve.skills.defense\\n let dexweight = crimestats.dexterity_success_weight * wsleeve.skills.dexterity\\n let agiweight = crimestats.agility_success_weight * wsleeve.skills.agility\\n let chaweight = crimestats.charisma_success_weight * wsleeve.skills.charisma\\n let intweight = HASBN5 ? 0.025 * wsleeve.skills.intelligence : 0\\n let chance = hackweight + strweight + defweight + dexweight + agiweight + chaweight + intweight\\n chance /= 975\\n chance /= crimestats.difficulty\\n chance *= wsleeve.mults.crime_success\\n if (HASBN5) chance *= 1 + (1 * Math.pow(wsleeve.skills.intelligence, 0.8)) / 600\\n chance *= 100\\n return Math.min(chance, 100)\\n}\\n/** @param {NS} ns */\\nfunction clearAll(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\n/** @param {NS} ns */\\nfunction update(ns, text) {\\n ns.printf(text)\\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"sleeves popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\\nconst crimes = [\\n {\\n \\\"name\\\": \\\"Shoplift\\\",\\n \\\"time\\\": 2e3,\\n \\\"money\\\": 15e3,\\n \\\"difficulty\\\": 1 / 20,\\n \\\"karma\\\": 0.1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Rob Store\\\",\\n \\\"time\\\": 60e3,\\n \\\"money\\\": 400e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.5,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 7.5 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Mug\\\",\\n \\\"time\\\": 4e3,\\n \\\"money\\\": 36e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.25,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1.5,\\n \\\"defense_success_weight\\\": 0.5,\\n \\\"dexterity_success_weight\\\": 1.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Larceny\\\",\\n \\\"time\\\": 90e3,\\n \\\"money\\\": 800e3,\\n \\\"difficulty\\\": 1 / 3,\\n \\\"karma\\\": 1.5,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 15 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Deal Drugs\\\",\\n \\\"time\\\": 10e3,\\n \\\"money\\\": 120e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 0.5,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 3,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Bond Forgery\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 4.5e6,\\n \\\"difficulty\\\": 1 / 2,\\n \\\"karma\\\": 0.1,\\n \\\"hacking_success_weight\\\": 0.05,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1.25,\\n \\\"agility_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 60 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Traffick Arms\\\",\\n \\\"time\\\": 40e3,\\n \\\"money\\\": 600e3,\\n \\\"difficulty\\\": 2,\\n \\\"karma\\\": 1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Homicide\\\",\\n \\\"time\\\": 3e3,\\n \\\"money\\\": 45e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 3,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 2,\\n \\\"defense_success_weight\\\": 2,\\n \\\"dexterity_success_weight\\\": 0.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Grand Theft Auto\\\",\\n \\\"time\\\": 80e3,\\n \\\"money\\\": 1.6e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 5,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 4,\\n \\\"agility_success_weight\\\": 2,\\n \\\"charisma_success_weight\\\": 2,\\n \\\"intelligence_exp\\\": 16 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Kidnap\\\",\\n \\\"time\\\": 120e3,\\n \\\"money\\\": 3.6e6,\\n \\\"difficulty\\\": 5,\\n \\\"karma\\\": 6,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 26 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Assassination\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 12e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 10,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 65 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Heist\\\",\\n \\\"time\\\": 600e3,\\n \\\"money\\\": 120e6,\\n \\\"difficulty\\\": 18,\\n \\\"karma\\\": 15,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 130 * 0.05\\n }\\n]\""},{"filename":"SphyxOS/bins/tStocks.js","file":"\"import { hasWSEAcct, hasTIXAPIAccs, getSyms, getSalesGain, shortEnabled, has4SAPI, getmaxshares } from \\\"SphyxOS/util.js\\\"\\nimport { getBidP, getAskP, getPosi, sellstock, sellshort, makeNewWindow } from \\\"SphyxOS/util.js\\\"\\nimport { buyshort, buystock, getfv, getSnap, getWorth } from \\\"SphyxOS/util.js\\\"\\nimport { getMoneyAvail } from \\\"SphyxOS/util.js\\\"\\n\\nconst SLEEPTM = 6000 // Default time of cycles\\nconst MSGTICKS = 3 // How many tics will messages stay in the logs for?\\nconst MSGTICKTM = SLEEPTM * MSGTICKS\\nlet SHORTS = false\\nlet S4DATA = false\\nconst SNAPS = 16\\nconst BUY_THREASH = 60\\nconst SELL_THREASH = 52\\nlet AUTOBUY = false\\nlet RESERVE = 0\\nconst TRANSACTION_COST = 100000 // Cost per transaction is 100k\\nconst MIN_TRANSACTION = 10000000 // 10m\\nconst MIN_STOCKS = 100\\nconst REPORT = 1000 * 60 * 60 // Every hour\\nlet STARTWORTH = 0\\nlet RUNNINGTOTAL = 0\\nlet RUNNINGCOST = 0\\nlet RUNNINGBANKED = 0\\nlet WORKINGMONEY = 0\\nlet starttime = performance.now()\\nconst HEIGHT = 400//970\\nconst WIDTH = 830\\nlet syms\\n\\nconst stocks = []\\nconst printmsgs = []\\nlet win\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.atExit(() => {\\n UpdateHud()\\n ns.clearPort(4)\\n if (win) win.close()\\n })\\n ns.writePort(4, ns.pid)\\n win = false\\n RESERVE = Number.isInteger(ns.args[0]) ? Number(ns.args[0]) : 0\\n getCommands(ns) //200ms refresh\\n\\n if (!await hasWSEAcct(ns) || !await hasTIXAPIAccs(ns)) {\\n ns.tprintf(\\\"WSE and TIX API Access are required to run this.\\\")\\n return\\n }\\n //Initialize our master lists\\n stocks.length = 0\\n printmsgs.length = 0\\n\\n syms = await getSyms(ns)\\n for (const sym of syms) {\\n let record = {\\n \\\"sym\\\": sym,\\n \\\"snaps\\\": [],\\n \\\"s4forcast\\\": 50,\\n \\\"s4adjfcast\\\": 50,\\n \\\"forcast\\\": 50,\\n \\\"adjfcast\\\": 50,\\n \\\"regforcast\\\": 50,\\n \\\"regadjfcast\\\": 50,\\n \\\"posi\\\": await getPosi(ns, sym),\\n \\\"maxshares\\\": await getmaxshares(ns, sym),\\n \\\"s4volitile\\\": 0,\\n \\\"regvolitile\\\": 0,\\n \\\"volitile\\\": 0,\\n \\\"time\\\": Date.now()\\n }\\n stocks.push(record)\\n }\\n newMsg(ns, \\\"Just Initialized\\\")\\n\\n SHORTS = await shortEnabled(ns) === 1\\n AUTOBUY = ns.args.includes(\\\"autobuy\\\")\\n S4DATA = await has4SAPI(ns)\\n STARTWORTH = 0\\n RUNNINGTOTAL = 0\\n RUNNINGCOST = 0\\n RUNNINGBANKED = 0\\n WORKINGMONEY = 0\\n await printLogs(ns, stocks)\\n UpdateHud(fNumber(ns, await getWorth(ns), 3))\\n let count = 0\\n starttime = performance.now()\\n\\n ns.ui.openTail()\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n if (S4DATA) count = SNAPS //Jump right in if we have 4s data\\n let INITIALCHECKREQUIRED = true\\n while (true) {\\n\\n\\n if (count === SNAPS) {\\n printmsgs.length = 0\\n newMsg(ns, \\\"Ready!\\\")\\n count++\\n }\\n\\n //Report!\\n if (performance.now() >= starttime + REPORT) {\\n starttime = performance.now()\\n let endworth = await getWorth(ns)\\n const combinedWorth = endworth + RUNNINGBANKED\\n if (combinedWorth > STARTWORTH) {\\n ns.tprintf(\\\"INFO: Success! After 1 hour %s turned into %s (%s%%)\\\", fNumber(ns, STARTWORTH, 2), fNumber(ns, combinedWorth, 2), fNumber(ns, combinedWorth / STARTWORTH * 100, 2))\\n newMsg(ns, \\\"INFO: Success! After 1 hour %s turned into %s (%s%%)\\\", fNumber(ns, STARTWORTH, 2), fNumber(ns, combinedWorth, 2), fNumber(ns, combinedWorth / STARTWORTH * 100, 2))\\n }\\n else {\\n ns.tprintf(\\\"INFO: Fail! After 1 hour %s turned into %s (%s%%)\\\", fNumber(ns, STARTWORTH, 2), fNumber(ns, combinedWorth, 2), fNumber(ns, combinedWorth / STARTWORTH * 100, 2))\\n newMsg(ns, \\\"INFO: Fail! After 1 hour %s turned into %s (%s%%)\\\", fNumber(ns, STARTWORTH, 2), fNumber(ns, combinedWorth, 2), fNumber(ns, combinedWorth / STARTWORTH * 100, 2))\\n }\\n STARTWORTH = endworth\\n RUNNINGTOTAL = 0\\n RUNNINGBANKED = 0\\n }\\n\\n //Switch to 4S if we can\\n if (!S4DATA && await has4SAPI(ns)) {\\n S4DATA = true\\n newMsg(ns, \\\"4S Data has been enabled!\\\")\\n count = SNAPS\\n }\\n\\n //Snapshot\\n for (const stck of stocks) {\\n const snap = await getSnap(ns, stck.sym)\\n let record = {\\n \\\"bidprice\\\": snap.bidp,\\n \\\"askprice\\\": snap.askp,\\n \\\"price\\\": snap.price,\\n \\\"spread\\\": snap.askp - snap.bidp,\\n \\\"time\\\": performance.now()\\n }\\n stck.snaps.push(record)\\n stck.snaps.length > SNAPS ? stck.snaps.shift() : null\\n }\\n //Update Forcast\\n await updateForcast(ns, stocks)\\n\\n if (count >= SNAPS) {\\n //Sell\\n await sellItems(ns, stocks, \\\"none\\\")\\n //Buy\\n await buyItems(ns, stocks)\\n if (INITIALCHECKREQUIRED) {\\n STARTWORTH = await getWorth(ns) //Get our start worth after we have gone through the first buy/sell cycle.\\n INITIALCHECKREQUIRED = false\\n }\\n }\\n\\n if (count < SNAPS) {\\n let msg = ns.sprintf(\\\"Pre-total snaps %s/%s\\\", count, SNAPS)\\n newMsg(ns, msg)\\n count++\\n }\\n await printLogs(ns, stocks)\\n\\n UpdateHud(fNumber(ns, await getWorth(ns)))\\n await ns.stock.nextUpdate()\\n }//Main while loop\\n}\\n\\n/** @param {NS} ns */\\nfunction newMsg(ns, msg) {\\n let record = {\\n \\\"msg\\\": msg,\\n \\\"time\\\": performance.now() + MSGTICKTM\\n }\\n printmsgs.push(record)\\n}\\n\\n/** @param {NS} ns */\\nfunction UpdateHud(totalWorth) {\\n const doc = eval('document');\\n const hook0 = doc.getElementById('overview-extra-hook-0');\\n const hook1 = doc.getElementById('overview-extra-hook-1');\\n\\n try {\\n const headers = []\\n const values = [];\\n\\n if (totalWorth === undefined) {\\n hook0.innerText = '';\\n hook1.innerText = '';\\n return;\\n }\\n\\n headers.push('Investments: ');\\n values.push(totalWorth);\\n\\n hook0.innerText = headers.join(\\\" \\\\n\\\");\\n hook1.innerText = values.join(\\\"\\\\n\\\");\\n\\n } catch (err) {\\n }\\n}\\n\\nfunction clearLogs(ns) {\\n ns.clearLog()\\n if (win) win.clear()\\n}\\nfunction update(ns, text) {\\n ns.printRaw(text) \\n if (win && win.closed) {\\n win = false\\n ns.writePort(1, \\\"stocks popout off\\\")\\n }\\n if (win) win.update(text)\\n}\\n\\n/** @param {NS} ns */\\nasync function printLogs(ns, stocks) {\\n clearLogs(ns)\\n //Clear the printmsgs queue so we just have fresh messages\\n while (printmsgs.length > 0 && printmsgs[0].time <= performance.now()) printmsgs.shift()\\n\\n for (const msg of printmsgs) {\\n update(ns, msg.msg)\\n }\\n\\n let totalpaid = 0\\n let totalvalue = 0\\n let totalshares = 0\\n let totalprofit = 0\\n //ns.printf(\\\"-----------------------------------------------------------------------\\\")\\n update(ns, ns.sprintf(\\\"┌───────┬───────┬─────────┬─────────┬─────────┬──────────┬─────────┬────────┬──────┐\\\"))\\n update(ns, ns.sprintf(\\\"│ SYM │ TYPE │ SHARES │ PAID │ VALUE │ PROFIT │ %% Change│ FCAST │ VOLI │\\\"))\\n update(ns, ns.sprintf(\\\"├───────┼───────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┼──────┤\\\"))\\n\\n for (const stk of stocks) {\\n let paid = 0\\n let value = 0\\n let shares = 0\\n let profit = 0\\n let percentchange = 0\\n let type = \\\"-----\\\"\\n if (stk.posi[0] > 0) { // Long position\\n paid = stk.posi[0] * stk.posi[1]\\n value = ns.ui.getGameInfo()?.versionNumber >= 44 ? await getSalesGain(ns, stk.sym, stk.posi[0], \\\"L\\\") : await getSalesGain(ns, stk.sym, stk.posi[0], \\\"long\\\")\\n shares = stk.posi[0]\\n profit = value - paid\\n percentchange = (profit > 0) ? (100 - value / paid * 100) * -1 : (100 - (value / paid * 100)) * -1\\n type = \\\"Long \\\"\\n }\\n else if (stk.posi[2] > 0) { // Short position\\n paid = stk.posi[2] * stk.posi[3]\\n value = ns.ui.getGameInfo()?.versionNumber >= 44 ? await getSalesGain(ns, stk.sym, stk.posi[2], \\\"S\\\") : await getSalesGain(ns, stk.sym, stk.posi[2], \\\"short\\\")\\n shares = stk.posi[2]\\n profit = value - paid\\n percentchange = (profit > 0) ? (100 - value / paid * 100) * -1 : (100 - (value / paid * 100)) * -1\\n type = \\\"Short\\\"\\n }\\n totalpaid += paid\\n totalvalue += value\\n totalshares += shares\\n totalprofit += profit\\n\\n update(ns, ns.sprintf(\\\"│ %5s │ %4s │ %7s │ %7s │ %7s │ %8s │ %7s │ %6s │ %4s │\\\", stk.sym, type, (shares > 0) ? fNumber(ns, shares, 2) : \\\"-------\\\", (paid > 0) ? fNumber(ns, paid, 2) : \\\"-------\\\", (value > 0) ? fNumber(ns, value, 2) : \\\"-------\\\", (profit != 0) ? fNumber(ns, profit, 2) : \\\"--------\\\", (percentchange != 0) ? fNumber(ns, percentchange, 2) : \\\"-------\\\", fNumber(ns, stk.forcast, 2), fNumber(ns, stk.volitile, 2)))\\n }\\n let totalpercentchange = (totalpaid > 0) ? (100 - (totalvalue + RUNNINGBANKED) / totalpaid * 100) * -1 : 0\\n let worth = await getWorth(ns) + RUNNINGBANKED\\n update(ns, ns.sprintf(\\\"├───────┴───────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┴──────┤\\\"))\\n update(ns, ns.sprintf(\\\"│Start: %8s│ %7s │ %7s │ %7s │ %8s │ %7s │Gain: %7s%% │\\\", \\\"$\\\" + fNumber(ns, STARTWORTH, 2), fNumber(ns, totalshares, 2), fNumber(ns, totalpaid, 2), fNumber(ns, totalvalue, 2), fNumber(ns, totalprofit, 2), fNumber(ns, totalpercentchange, 2), STARTWORTH === 0 ? 0 : fNumber(ns, ((worth / STARTWORTH) - 1) * 100, 2)))\\n update(ns, ns.sprintf(\\\"├───────────────┴─────────┼─────────┴─────────┼──────────┴─────────┼───────────────┘\\\"))\\n update(ns, ns.sprintf(\\\"│Sales: %18s│Fees: %13s│Banked: %12s│\\\", \\\"$\\\" + fNumber(ns, RUNNINGTOTAL, 2), \\\"$\\\" + fNumber(ns, RUNNINGCOST, 2), \\\"$\\\" + fNumber(ns, RUNNINGBANKED, 2)))\\n const tm = fTime(ns, starttime + REPORT - performance.now())\\n update(ns, ns.sprintf(\\\"└─────────────────────────┴───────────────────┴────────────────────┘\\\"))\\n update(ns, ns.sprintf(\\\"Update in: \\\" + tm))\\n ns.ui.renderTail()\\n}\\n\\n/** @param {NS} ns */\\nasync function updateForcast(ns, stocks) {\\n // Cycle through our stocks and update the forcast\\n for (let stk of stocks) {\\n //With the darknet addition, we can get stocks randomly. Update our position\\n stk.posi = await getPosi(ns, stk.sym)\\n //Update 4S forcast\\n if (S4DATA) {\\n const fv = await getfv(ns, stk.sym)\\n stk.s4forcast = fv.forcast * 100//await getFCast(ns, stk.sym) * 100\\n stk.s4adjfcast = (stk.s4forcast >= 50) ? stk.s4forcast : 100 - stk.s4forcast\\n stk.s4volitile = fv.vol * 100//await getVol(ns, stk.sym) * 100\\n }\\n //Process the snapshot\\n //We are going to track 3 values and average them out. Price, AskPrice, BidPrice\\n let price = 0\\n let totalprice = 0\\n //-----------------\\n let ask = 0\\n let totalask = 0\\n //-----------------\\n let bid = 0\\n let totalbid = 0\\n //-----------------\\n let vol = 0\\n let bestvol = 0\\n //-----------------\\n for (let i = 0; i < stk.snaps.length - 1; i++) {\\n price += stk.snaps[i + 1].price - stk.snaps[i].price\\n totalprice += Math.abs(stk.snaps[i + 1].price - stk.snaps[i].price)\\n ask += stk.snaps[i + 1].askprice - stk.snaps[i].askprice\\n totalask += Math.abs(stk.snaps[i + 1].askprice - stk.snaps[i].askprice)\\n bid += stk.snaps[i + 1].bidprice - stk.snaps[i].bidprice\\n totalbid += Math.abs(stk.snaps[i + 1].bidprice - stk.snaps[i].bidprice)\\n vol = (stk.snaps[i + 1].price > stk.snaps[i].price) ? (stk.snaps[i + 1].price / stk.snaps[i].price) - 1 : (stk.snaps[i].price / stk.snaps[i + 1].price) - 1\\n vol *= 100\\n if (vol > bestvol) bestvol = vol\\n }\\n if (totalprice == 0) {\\n stk.regforcast = 50\\n stk.regadjfcast = 50\\n stk.regvolitile = 0\\n }\\n else {\\n let pfcast = (price / totalprice * 50) + 50\\n let afcast = (ask / totalask * 50) + 50\\n let bfcast = (bid / totalbid * 50) + 50\\n\\n stk.regforcast = (pfcast + afcast + bfcast) / 3\\n stk.regadjfcast = (stk.regforcast >= 50) ? stk.regforcast : 100 - stk.regforcast\\n stk.regvolitile = bestvol\\n }\\n\\n if (S4DATA) {\\n stk.forcast = stk.s4forcast\\n stk.adjfcast = stk.s4adjfcast\\n stk.volitile = stk.s4volitile\\n }\\n else {\\n stk.forcast = stk.regforcast\\n stk.adjfcast = stk.regadjfcast\\n stk.volitile = stk.regvolitile\\n }\\n }\\n stocks.sort((a, b) => { return a.forcast - b.forcast })\\n}\\n\\n/** @param {NS} ns */\\nasync function sellItems(ns, stocks, arg) {\\n //Send the arg of 'sell' to sell everything\\n for (const stk of stocks) {\\n if ((stk.posi[0] > 0 && stk.forcast <= SELL_THREASH) || (stk.posi[0] > 0 && arg && arg == \\\"sell\\\")) { // We have Longs to sell\\n const sellprice = await sellstock(ns, stk.sym, stk.posi[0])\\n WORKINGMONEY += (sellprice * stk.posi[0]) - TRANSACTION_COST\\n RUNNINGCOST -= TRANSACTION_COST\\n RUNNINGTOTAL += (sellprice * stk.posi[0]) - (stk.posi[0] * stk.posi[1])\\n if (sellprice >= stk.posi[1]) { // Profit\\n const profit = (sellprice * stk.posi[0]) - (stk.posi[0] * stk.posi[1])\\n const msg = ns.sprintf(\\\"WARN: Selling %s long for $%s ($%s profit)\\\", stk.sym, fNumber(ns, sellprice * stk.posi[0], 2), fNumber(ns, profit, 2))\\n newMsg(ns, msg)\\n }\\n else {// Loss\\n const loss = (sellprice * stk.posi[0]) - (stk.posi[0] * stk.posi[1])\\n const msg = ns.sprintf(\\\"WARN: Selling %s long for $%s ($%s loss)\\\", stk.sym, fNumber(ns, sellprice * stk.posi[0], 2), fNumber(ns, loss, 2))\\n newMsg(ns, msg)\\n }\\n stk.posi[0] = 0\\n stk.posi[1] = 0\\n }\\n if (stk.posi[2] > 0 && stk.forcast >= 100 - SELL_THREASH || (stk.posi[2] > 0 && arg && arg == \\\"sell\\\")) { // We have shorts to sell\\n const shortsales = ns.ui.getGameInfo()?.versionNumber >= 44 ? await getSalesGain(ns, stk.sym, stk.posi[2], \\\"S\\\") : await getSalesGain(ns, stk.sym, stk.posi[2], \\\"short\\\")\\n WORKINGMONEY += shortsales - TRANSACTION_COST\\n RUNNINGCOST -= TRANSACTION_COST\\n const paidshort = stk.posi[2] * stk.posi[3]\\n RUNNINGTOTAL += shortsales - paidshort\\n await sellshort(ns, stk.sym, stk.posi[2])\\n if (shortsales >= paidshort) { // Profit\\n const profit = shortsales - paidshort// - (sellprice * posi[2])\\n const msg = ns.sprintf(\\\"WARN: Selling %s short for $%s ($%s profit)\\\", stk.sym, fNumber(ns, shortsales, 2), fNumber(ns, profit, 2))\\n newMsg(ns, msg)\\n }\\n else {// Loss\\n const loss = shortsales - paidshort// - (sellprice * posi[2])\\n const msg = ns.sprintf(\\\"WARN: Selling %s short for $%s ($%s loss)\\\", stk.sym, fNumber(ns, shortsales, 2), fNumber(ns, loss, 2))\\n newMsg(ns, msg)\\n }\\n stk.posi[2] = 0\\n stk.posi[3] = 0\\n }\\n }//End of Stocks\\n if (arg && arg === \\\"sell\\\") {\\n if (WORKINGMONEY < 0) { //Less than 0 means we spent money that we did not just take in from sales.\\n const remainder = RUNNINGBANKED + WORKINGMONEY\\n if (RUNNINGBANKED > 0) {\\n if (remainder > 0) { //We still have money left over in banked\\n RUNNINGBANKED += WORKINGMONEY\\n }\\n }\\n else { //We've used up all our banked and need to split things up\\n STARTWORTH -= remainder\\n RUNNINGBANKED = 0\\n }\\n }\\n else if (WORKINGMONEY > 0)\\n RUNNINGBANKED += WORKINGMONEY\\n WORKINGMONEY = 0\\n }\\n}\\n\\n/** @param {NS} ns */\\nasync function buyItems(ns, stocks, arg) {\\n //start off our buying spree\\n let topl = stocks.length - 1\\n let botl = 0\\n let top = stocks[topl]\\n let bot = stocks[botl]\\n\\n let running = true\\n while (running) { // Purchase loop\\n let cash = 0\\n if (AUTOBUY || arg === \\\"force\\\") cash = await getMoneyAvail(ns, \\\"home\\\")\\n else cash = WORKINGMONEY\\n let budget = cash - TRANSACTION_COST - RESERVE\\n\\n top = stocks[topl]\\n bot = stocks[botl]\\n\\n //Get the max shares of the stock and our position on the stock. Do we have all the shares? If so, skip it\\n let topposi = top.posi//await getPosi(ns, top.sym)\\n let botposi = bot.posi//await getPosi(ns, bot.sym)\\n\\n while (topposi[0] >= top.maxshares || topposi[2] >= top.maxshares) {\\n if (topl <= 0) break\\n topl--\\n top = stocks[topl]\\n topposi = top.posi//await getPosi(ns, top.sym)\\n }\\n while (botposi[0] >= bot.maxshares || botposi[2] >= bot.maxshares) {\\n if (botl >= stocks.length - 1) break\\n botl++\\n bot = stocks[botl]\\n botposi = bot.posi//await getPosi(ns, bot.sym)\\n }\\n top = stocks[topl]\\n bot = stocks[botl]\\n let max = false\\n if (SHORTS) {\\n if (bot.adjfcast >= top.forcast && bot.adjfcast >= BUY_THREASH) { //Bottom is the way to go right now\\n //buy shorts of bottom, get the next bottom\\n const price = await getBidP(ns, bot.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + botposi[0] + botposi[2] > bot.maxshares) {\\n buying = bot.maxshares - botposi[0] - botposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Shorting: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n const bought = await buyshort(ns, bot.sym, buying)\\n if (bought > 0) {\\n WORKINGMONEY -= (bought * buying) + TRANSACTION_COST\\n RUNNINGCOST -= TRANSACTION_COST\\n const msg = ns.sprintf(\\\"Buying %s short of %s for $%s\\\", buying, bot.sym, fNumber(ns, bought * buying, 2))\\n newMsg(ns, msg)\\n botl++\\n bot.posi = await getPosi(ns, bot.sym)\\n }\\n else {\\n const msg = ns.sprintf(\\\"Failed to buy %s Short of %s\\\", buying, bot.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n else if (top.forcast >= BUY_THREASH) { // Top is the way to go\\n // Buy long of top, get the next top\\n const price = await getAskP(ns, top.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + topposi[0] + topposi[2] > top.maxshares) {\\n buying = top.maxshares - topposi[0] - topposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Long within short: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n const bought = await buystock(ns, top.sym, buying)\\n if (bought > 0) {\\n WORKINGMONEY -= (bought * buying) + TRANSACTION_COST\\n RUNNINGCOST -= TRANSACTION_COST\\n const msg = ns.sprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, fNumber(ns, bought * buying, 2))\\n newMsg(ns, msg)\\n topl--\\n top.posi = await getPosi(ns, top.sym)\\n }\\n else {\\n const msg = ns.sprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n }\\n else if (top.forcast >= BUY_THREASH) { //check for long buy\\n const price = await getAskP(ns, top.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + topposi[0] + topposi[2] > top.maxshares) {\\n buying = top.maxshares - topposi[0] - topposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Long: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n const bought = await buystock(ns, top.sym, buying)\\n if (bought > 0) {\\n WORKINGMONEY -= (bought * buying) + TRANSACTION_COST\\n RUNNINGCOST -= TRANSACTION_COST\\n const msg = ns.sprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, fNumber(ns, bought * buying, 2))\\n newMsg(ns, msg)\\n topl--\\n top.posi = await getPosi(ns, top.sym)\\n }\\n else {\\n const msg = ns.sprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n if (!max) {\\n running = false\\n }\\n }\\n if (WORKINGMONEY < 0) { //Less than 0 means we spent money that we did not just take in from sales.\\n const remainder = RUNNINGBANKED + WORKINGMONEY\\n if (RUNNINGBANKED > 0) {\\n if (remainder > 0) { //We still have money left over in banked\\n RUNNINGBANKED += WORKINGMONEY\\n }\\n else {\\n STARTWORTH -= remainder\\n RUNNINGBANKED = 0\\n }\\n }\\n else { //We've used up all our banked and need to split things up\\n STARTWORTH -= remainder\\n RUNNINGBANKED = 0\\n }\\n }\\n else if (WORKINGMONEY > 0)\\n RUNNINGBANKED += WORKINGMONEY\\n WORKINGMONEY = 0 //We shave off the remainder so we don't have to worry about it not being there later\\n}\\n\\n/** @param {NS} ns */\\nasync function getCommands(ns) {\\n while (true) {\\n let silent = false\\n while (ns.peek(13) !== \\\"NULL PORT DATA\\\") { //1-4 1: noHacknet, 2: !noHacknet, 3: buyServers, 4: !buyServers\\n const result = ns.readPort(13)\\n if (Number.isInteger(result)) {\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will use a reserve of \\\" + result)\\n RESERVE = result\\n continue\\n }\\n switch (result) {\\n case \\\"popout\\\":\\n win = await makeNewWindow(\\\"Stocks\\\", ns.ui.getTheme())\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will use a popout\\\")\\n break\\n case \\\"nopopout\\\":\\n if (win) win.close()\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will not use a popout\\\")\\n break\\n case \\\"silent\\\":\\n silent = true\\n break;\\n case \\\"buy\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Stocks is purchasing now\\\")\\n await buyItems(ns, stocks, \\\"force\\\")\\n printLogs(ns, stocks)\\n break;\\n case \\\"sell\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Stocks is selling now\\\")\\n await sellItems(ns, stocks, \\\"sell\\\")\\n WORKINGMONEY = 0\\n printLogs(ns, stocks)\\n break;\\n case \\\"autobuy\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will auto purchase now\\\")\\n AUTOBUY = true\\n break;\\n case \\\"autobuyoff\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will no longer auto purchase\\\")\\n AUTOBUY = false\\n break;\\n case \\\"reset\\\":\\n if (!silent) ns.tprintf(\\\"Command received. Stocks will reset stats data\\\")\\n RUNNINGBANKED = 0\\n RUNNINGTOTAL = 0\\n STARTWORTH = await getWorth(ns)\\n starttime = performance.now()\\n break\\n default:\\n ns.tprintf(\\\"Invalid command received in Stocks: %s\\\", result)\\n break;\\n }\\n }\\n await ns.asleep(200)\\n }\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nfunction fNumber(ns, num, fraction = 3, suffix = 1000, isInt = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.number(num, fraction, suffix, isInt)\\n else return ns.formatNumber(num, fraction, suffix, isInt)\\n}\""},{"filename":"SphyxOS/bins/themeEditor.jsx","file":"\"/**Author:\\n * Discord: Sphyxis\\n */\\nconst SAVE_DIR = \\\"SphyxOSUserData/themes/\\\"\\nconst DEFAULT_WIDTH = 640\\nconst DEFAULT_HEIGHT = 840\\n\\nfunction getReactLib() {\\n return globalThis[\\\"React\\\"] ?? globalThis[\\\"window\\\"]?.React\\n}\\nfunction isPlainObject(value) {\\n return !!value && typeof value === \\\"object\\\" && !Array.isArray(value)\\n}\\nfunction cloneEditableObject(source) {\\n const clone = {}\\n for (const [key, value] of Object.entries(source ?? {})) {\\n clone[key] = value\\n }\\n return clone\\n}\\nfunction clamp(value, min, max) {\\n return Math.min(max, Math.max(min, value))\\n}\\nfunction toHexByte(value) {\\n return clamp(Math.round(value), 0, 255).toString(16).padStart(2, \\\"0\\\")\\n}\\nfunction normalizeHexString(value) {\\n const raw = String(value ?? \\\"\\\").trim().replace(/^#/, \\\"\\\")\\n if (!raw) return null\\n if (/^[0-9a-fA-F]{3}$/.test(raw)) {\\n return \\\"#\\\" + raw.split(\\\"\\\").map((part) => part + part).join(\\\"\\\").toLowerCase() + \\\"ff\\\"\\n }\\n if (/^[0-9a-fA-F]{4}$/.test(raw)) {\\n return \\\"#\\\" + raw.split(\\\"\\\").map((part) => part + part).join(\\\"\\\").toLowerCase()\\n }\\n if (/^[0-9a-fA-F]{6}$/.test(raw)) return \\\"#\\\" + raw.toLowerCase() + \\\"ff\\\"\\n if (/^[0-9a-fA-F]{8}$/.test(raw)) return \\\"#\\\" + raw.toLowerCase()\\n return null\\n}\\nfunction isColorLike(value) {\\n if (typeof value !== \\\"string\\\") return false\\n if (!String(value).trim().startsWith(\\\"#\\\")) return false\\n return normalizeHexString(value) !== null\\n}\\nfunction splitHexColor(value) {\\n const normalized = normalizeHexString(value) ?? \\\"#000000ff\\\"\\n return {\\n hex: normalized,\\n rgb: normalized.slice(0, 7),\\n alphaByte: parseInt(normalized.slice(7, 9), 16),\\n alphaPercent: Math.round((parseInt(normalized.slice(7, 9), 16) / 255) * 100),\\n }\\n}\\nfunction composeHexColor(rgb, alphaPercent) {\\n const cleanRgb = normalizeHexString(rgb)?.slice(0, 7) ?? \\\"#000000\\\"\\n const alphaByte = Math.round((clamp(Number(alphaPercent) || 0, 0, 100) / 100) * 255)\\n return cleanRgb + toHexByte(alphaByte)\\n}\\nfunction asNumberString(value) {\\n if (typeof value !== \\\"number\\\" || Number.isNaN(value)) return \\\"\\\"\\n return Number.isInteger(value) ? String(value) : String(value)\\n}\\nfunction getNumberStep(value, key) {\\n if (typeof value !== \\\"number\\\") return \\\"1\\\"\\n if (String(key).toLowerCase().includes(\\\"opacity\\\")) return \\\"0.01\\\"\\n return Number.isInteger(value) ? \\\"1\\\" : \\\"0.1\\\"\\n}\\nfunction safeStringify(value) {\\n return JSON.stringify(value, null, 2)\\n}\\nfunction formatObjectForCode(name, value) {\\n return `const ${name} = ${safeStringify(value)}\\\\n`\\n}\\nfunction statusMessage(text, tone = \\\"info\\\") {\\n return { text, tone, ts: Date.now() }\\n}\\nfunction ColorControl({ label, value, onChange, registerRecent, editorInputProps }) {\\n const React = getReactLib()\\n const parsed = splitHexColor(value)\\n const [textValue, setTextValue] = React.useState(parsed.hex)\\n\\n React.useEffect(() => {\\n setTextValue(parsed.hex)\\n }, [parsed.hex])\\n\\n const applyHex = (nextHex, shouldTrack = true) => {\\n const normalized = normalizeHexString(nextHex)\\n setTextValue(nextHex)\\n if (!normalized) return\\n onChange(normalized)\\n if (shouldTrack) registerRecent(normalized)\\n }\\n\\n return (\\n \\n
\\n
\\n
{label}
\\n
{parsed.hex}
\\n
\\n
\\n
\\n
\\n {\\n const next = composeHexColor(event.target.value, parsed.alphaPercent)\\n applyHex(next)\\n }}\\n {...editorInputProps}\\n style={styles.nativeColorInput}\\n />\\n setTextValue(event.target.value)}\\n onBlur={() => applyHex(textValue, false)}\\n placeholder=\\\"#rrggbb or #rrggbbaa\\\"\\n {...editorInputProps}\\n style={styles.textInput}\\n />\\n
\\n
\\n
\\n Opacity \\n {parsed.alphaPercent}% \\n
\\n
{\\n const next = composeHexColor(parsed.rgb, Number(event.target.value))\\n applyHex(next)\\n }}\\n {...editorInputProps}\\n style={styles.rangeInput}\\n />\\n
\\n
\\n )\\n}\\nfunction GenericControl({ label, value, onChange, editorInputProps }) {\\n const React = getReactLib()\\n\\n if (typeof value === \\\"boolean\\\") {\\n return (\\n \\n \\n
{label}
\\n
{String(value)}
\\n
\\n onChange(event.target.checked)}\\n {...editorInputProps}\\n style={styles.checkbox}\\n />\\n \\n )\\n }\\n\\n if (typeof value === \\\"number\\\") {\\n const [textValue, setTextValue] = React.useState(asNumberString(value))\\n\\n React.useEffect(() => {\\n setTextValue(asNumberString(value))\\n }, [value])\\n\\n const commitNumber = (rawValue) => {\\n const trimmed = String(rawValue ?? \\\"\\\").trim()\\n if (trimmed === \\\"\\\") return\\n const nextValue = Number(trimmed)\\n if (!Number.isNaN(nextValue)) onChange(nextValue)\\n }\\n\\n return (\\n \\n
\\n
setTextValue(event.target.value)}\\n onBlur={() => commitNumber(textValue)}\\n {...editorInputProps}\\n style={styles.textInput}\\n />\\n
\\n )\\n }\\n\\n return (\\n \\n
\\n
\\n
{label}
\\n
{typeof value}
\\n
\\n
\\n
onChange(event.target.value)}\\n {...editorInputProps}\\n style={styles.textInput}\\n />\\n
\\n )\\n}\\nfunction SettingsSection({\\n title,\\n subtitle,\\n data,\\n onValueChange,\\n onApply,\\n onReset,\\n registerRecent,\\n editorInputProps,\\n showFilter = false,\\n filterText = \\\"\\\",\\n onFilterChange = () => { },\\n}) {\\n const entries = Object.entries(data ?? {}).filter(([key]) => key.toLowerCase().includes(filterText.toLowerCase())).sort(([a], [b]) => a.localeCompare(b))\\n\\n return (\\n \\n \\n
\\n
{title} \\n
{subtitle}
\\n
\\n
\\n Apply \\n Reset \\n
\\n
\\n {showFilter ? (\\n onFilterChange(event.target.value)}\\n placeholder={`Filter ${title.toLowerCase()} keys`}\\n {...editorInputProps}\\n style={{ ...styles.textInput, marginBottom: 10 }}\\n />\\n ) : null}\\n \\n {entries.length} visible \\n {Object.keys(data ?? {}).length} total \\n
\\n \\n {entries.map(([key, value]) =>\\n isColorLike(value) ? (\\n onValueChange(key, next)}\\n registerRecent={registerRecent}\\n editorInputProps={editorInputProps}\\n />\\n ) : (\\n onValueChange(key, next)}\\n editorInputProps={editorInputProps}\\n />\\n ),\\n )}\\n
\\n \\n )\\n}\\nfunction RecentColors({ colors }) {\\n if (!colors.length) return null\\n return (\\n \\n Recent Colors
\\n Reference swatches from your latest edits.
\\n \\n {colors.map((color) => {\\n const parts = splitHexColor(color)\\n return (\\n
\\n {color} \\n
\\n )\\n })}\\n
\\n \\n )\\n}\\nfunction ModalShell({ title, children, onClose, cardRef, onBlurCapture, onPointerDownCapture, onKeyDownCapture, onKeyUpCapture }) {\\n return (\\n \\n )\\n}\\nfunction PreviewPane({ theme, stylesDraft, onApplyAll, onResetAll, onRefresh, onLoad, onSave, onManage, status }) {\\n const accent = theme?.primary ?? theme?.button ?? \\\"#00f5d4ff\\\"\\n const accentAlt = theme?.secondary ?? theme?.button ?? \\\"#3a86ffff\\\"\\n const fg = theme?.primarylight ?? theme?.secondary ?? theme?.text ?? \\\"#d5dde5ff\\\"\\n const muted = theme?.primarydark ?? theme?.disabled ?? \\\"#8896a3ff\\\"\\n const bg = theme?.backgroundprimary ?? theme?.background ?? \\\"#101820ff\\\"\\n const bgAlt = theme?.backgroundsecondary ?? theme?.well ?? \\\"#18232fff\\\"\\n const warning = theme?.warning ?? \\\"#ffb703ff\\\"\\n const err = theme?.error ?? \\\"#ff5d73ff\\\"\\n const success = theme?.success ?? \\\"#39ff14ff\\\"\\n const info = theme?.info ?? \\\"#00d1ffff\\\"\\n const fontFamily = typeof stylesDraft?.fontFamily === \\\"string\\\" ? stylesDraft.fontFamily : \\\"monospace\\\"\\n const fontSize = typeof stylesDraft?.fontSize === \\\"number\\\" ? stylesDraft.fontSize : 14\\n\\n return (\\n \\n \\n
\\n
Live Preview
\\n
Uses your current draft values before you apply them.
\\n
\\n
\\n Apply All \\n Reset All \\n Refresh \\n Load \\n Save \\n Manage \\n
\\n
\\n \\n
\\n
Primary
\\n
Secondary
\\n
Info
\\n
\\n
Theme sampling
\\n
Buttons, labels, status chips, backgrounds, and every exposed theme color below.
\\n
\\n Primary \\n Success \\n Info \\n Warning \\n Error \\n
\\n
\\n
\\n
Terminal
\\n
$ run grow.js n00dles
\\n
threads: 120
\\n
completed successfully
\\n
\\n
\\n
UI States
\\n
\\n Action \\n Danger \\n
\\n
\\n link color \\n warning text \\n
\\n
\\n
\\n
\\n \\n {status?.text ?? \\\"Ready.\\\"}\\n
\\n \\n )\\n}\\nfunction ThemeEditorApp({ ns, initialTheme, initialStyles }) {\\n const React = getReactLib()\\n const appRef = React.useRef(null)\\n const modalCardRef = React.useRef(null)\\n const saveInputRef = React.useRef(null)\\n const loadSelectRef = React.useRef(null)\\n const manageSelectRef = React.useRef(null)\\n const [themeDraft, setThemeDraft] = React.useState(() => cloneEditableObject(initialTheme))\\n const [styleDraft, setStyleDraft] = React.useState(() => cloneEditableObject(initialStyles))\\n const [themeFilter, setThemeFilter] = React.useState(\\\"\\\")\\n const [recentColors, setRecentColors] = React.useState([])\\n const [savedLayouts, setSavedLayouts] = React.useState([])\\n const [selectedLayoutName, setSelectedLayoutName] = React.useState(\\\"\\\")\\n const [managedLayoutName, setManagedLayoutName] = React.useState(\\\"\\\")\\n const [saveName, setSaveName] = React.useState(\\\"\\\")\\n const [activeDialog, setActiveDialog] = React.useState(\\\"\\\")\\n const [status, setStatus] = React.useState(statusMessage(\\\"Loaded current theme and styles.\\\"))\\n\\n const focusEditorSoon = () => {\\n const focusTarget = () => appRef.current?.focus?.({ preventScroll: true })\\n focusTarget()\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 0)\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 50)\\n }\\n\\n const focusDialogControlSoon = () => {\\n const focusTarget = () => {\\n if (activeDialog === \\\"save\\\") {\\n saveInputRef.current?.focus?.({ preventScroll: true })\\n saveInputRef.current?.select?.()\\n return\\n }\\n if (activeDialog === \\\"load\\\") {\\n loadSelectRef.current?.focus?.({ preventScroll: true })\\n return\\n }\\n if (activeDialog === \\\"manage\\\") {\\n manageSelectRef.current?.focus?.({ preventScroll: true })\\n }\\n }\\n focusTarget()\\n //If we are losing focus to the terminal still, start enabling these.\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 0)\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 50)\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 150)\\n //globalThis[\\\"setTimeout\\\"]?.(focusTarget, 350)\\n }\\n\\n React.useEffect(() => {\\n focusEditorSoon()\\n }, [])\\n\\n React.useEffect(() => {\\n if (activeDialog) {\\n focusDialogControlSoon()\\n return\\n }\\n focusEditorSoon()\\n }, [activeDialog, savedLayouts.length])\\n\\n const handleDialogBlurCapture = (event) => {\\n const dialogNode = modalCardRef.current\\n if (!dialogNode || !activeDialog) return\\n const nextFocusTarget = event.relatedTarget\\n if (nextFocusTarget && dialogNode.contains(nextFocusTarget)) return\\n globalThis[\\\"setTimeout\\\"]?.(() => {\\n const activeElement = globalThis[\\\"document\\\"]?.activeElement\\n if (activeElement && dialogNode.contains(activeElement)) return\\n focusDialogControlSoon()\\n }, 0)\\n }\\n\\n const handleModalPointerDownCapture = () => {\\n if (!activeDialog) return\\n globalThis[\\\"setTimeout\\\"]?.(() => {\\n focusDialogControlSoon()\\n }, 0)\\n }\\n\\n const handleModalKeyCapture = (event) => {\\n if (!activeDialog) return\\n event.stopPropagation()\\n }\\n\\n const handleEditorInputPointerDownCapture = (event) => {\\n event.stopPropagation()\\n }\\n\\n const handleEditorInputKeyCapture = (event) => {\\n event.stopPropagation()\\n }\\n\\n const handleEditorInputFocus = (event) => {\\n event.stopPropagation()\\n }\\n\\n const editorInputProps = {\\n onPointerDownCapture: handleEditorInputPointerDownCapture,\\n onKeyDownCapture: handleEditorInputKeyCapture,\\n onKeyUpCapture: handleEditorInputKeyCapture,\\n onFocus: handleEditorInputFocus,\\n }\\n\\n const refreshFromGame = () => {\\n try {\\n const nextTheme = cloneEditableObject(ns.ui.getTheme())\\n const nextStyles = cloneEditableObject(ns.ui.getStyles())\\n setThemeDraft(nextTheme)\\n setStyleDraft(nextStyles)\\n setStatus(statusMessage(\\\"Reloaded values from the live game session.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Unable to refresh from game: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const rememberColor = (hex) => {\\n setRecentColors((current) => [hex, ...current.filter((item) => item !== hex)].slice(0, 10))\\n }\\n\\n const applyTheme = () => {\\n try {\\n ns.ui.setTheme(themeDraft)\\n setStatus(statusMessage(\\\"Theme applied.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Theme apply failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const applyStyles = () => {\\n try {\\n ns.ui.setStyles(styleDraft)\\n setStatus(statusMessage(\\\"Styles applied.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Style apply failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const applyAll = () => {\\n try {\\n ns.ui.setTheme(themeDraft)\\n ns.ui.setStyles(styleDraft)\\n setStatus(statusMessage(\\\"Theme and styles applied.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Apply all failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const resetAll = () => {\\n try {\\n ns.ui.resetTheme()\\n ns.ui.resetStyles()\\n const nextTheme = cloneEditableObject(ns.ui.getTheme())\\n const nextStyles = cloneEditableObject(ns.ui.getStyles())\\n setThemeDraft(nextTheme)\\n setStyleDraft(nextStyles)\\n setStatus(statusMessage(\\\"Theme and styles reset.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Reset all failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const handleLoad = () => {\\n try {\\n const layouts = getSavedLayouts()\\n setSavedLayouts(layouts)\\n setSelectedLayoutName(layouts[0]?.name ?? \\\"\\\")\\n setActiveDialog(\\\"load\\\")\\n setStatus(statusMessage(\\\"Choose a saved layout to load.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Load failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const handleSave = () => {\\n try {\\n setSaveName(\\\"\\\")\\n setActiveDialog(\\\"save\\\")\\n setStatus(statusMessage(\\\"Enter a name for the layout you want to save.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Save failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const handleManage = () => {\\n try {\\n const layouts = getSavedLayouts()\\n setSavedLayouts(layouts)\\n setManagedLayoutName(layouts[0]?.name ?? \\\"\\\")\\n setActiveDialog(\\\"manage\\\")\\n setStatus(statusMessage(\\\"Select a saved layout to delete.\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Manage failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const getSavedLayouts = () => {\\n const files = ns.ls(\\\"home\\\", SAVE_DIR)//.map(f => f.substring(SAVE_DIR.length))\\n const layouts = []\\n for (const file of files) {\\n ns.scp(file, ns.self().server, \\\"home\\\")\\n layouts.push(JSON.parse(ns.read(file)))\\n }\\n return layouts.sort((a, b) => a.name > b.name)\\n }\\n\\n const confirmLoad = () => {\\n try {\\n const chosen = savedLayouts.find((layout) => layout.name === selectedLayoutName)\\n if (!chosen) {\\n setStatus(statusMessage(\\\"Select a saved layout first.\\\", \\\"error\\\"))\\n return\\n }\\n if (isPlainObject(chosen.theme)) setThemeDraft(cloneEditableObject(chosen.theme))\\n if (isPlainObject(chosen.styles)) setStyleDraft(cloneEditableObject(chosen.styles))\\n setActiveDialog(\\\"\\\")\\n setStatus(statusMessage(`Loaded layout \\\"${chosen.name}\\\" into the editor.`))\\n focusEditorSoon()\\n } catch (error) {\\n setStatus(statusMessage(`Load failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const confirmDelete = () => {\\n try {\\n const trimmedName = managedLayoutName.trim()\\n if (!trimmedName) {\\n setStatus(statusMessage(\\\"Select a saved layout first.\\\", \\\"error\\\"))\\n return\\n }\\n const fileName = `${SAVE_DIR}${trimmedName}.txt`\\n if (!ns.fileExists(fileName, \\\"home\\\")) {\\n setStatus(statusMessage(`Could not find \\\"${trimmedName}\\\" to delete.`, \\\"error\\\"))\\n return\\n }\\n ns.rm(fileName, \\\"home\\\")\\n const nextLayouts = getSavedLayouts()\\n setSavedLayouts(nextLayouts)\\n setManagedLayoutName(nextLayouts[0]?.name ?? \\\"\\\")\\n setStatus(statusMessage(`Deleted \\\"${trimmedName}\\\".`))\\n if (!nextLayouts.length) {\\n setActiveDialog(\\\"\\\")\\n focusEditorSoon()\\n }\\n } catch (error) {\\n setStatus(statusMessage(`Delete failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const confirmSave = () => {\\n try {\\n const trimmedName = saveName.trim()\\n if (!trimmedName) {\\n setStatus(statusMessage(\\\"Enter a layout name before saving.\\\", \\\"error\\\"))\\n return\\n }\\n const files = ns.ls(\\\"home\\\", SAVE_DIR).map(f => f.substring(SAVE_DIR.length))\\n if (files.includes(trimmedName + \\\".txt\\\")) {\\n setStatus(statusMessage(\\\"A theme by this name already exists.\\\", \\\"error\\\"))\\n return\\n }\\n const payload = {\\n name: trimmedName,\\n theme: cloneEditableObject(themeDraft),\\n styles: cloneEditableObject(styleDraft),\\n }\\n const serialized = JSON.stringify(payload, null, 2)\\n const fileName = SAVE_DIR + trimmedName + \\\".txt\\\"\\n ns.write(fileName, serialized, \\\"w\\\")\\n ns.scp(fileName, \\\"home\\\", ns.self().server)\\n void serialized\\n setActiveDialog(\\\"\\\")\\n setStatus(statusMessage(`${trimmedName} has been saved.`))\\n focusEditorSoon()\\n } catch (error) {\\n setStatus(statusMessage(`Save failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const resetTheme = () => {\\n try {\\n ns.ui.resetTheme()\\n const nextTheme = cloneEditableObject(ns.ui.getTheme())\\n setThemeDraft(nextTheme)\\n setStatus(statusMessage(\\\"Theme reset, then reloaded from ns.ui.getTheme().\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Theme reset failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n const resetStyles = () => {\\n try {\\n ns.ui.resetStyles()\\n const nextStyles = cloneEditableObject(ns.ui.getStyles())\\n setStyleDraft(nextStyles)\\n setStatus(statusMessage(\\\"Styles reset, then reloaded from ns.ui.getStyles().\\\"))\\n } catch (error) {\\n setStatus(statusMessage(`Style reset failed: ${String(error?.message ?? error)}`, \\\"error\\\"))\\n }\\n }\\n\\n return (\\n {\\n const targetTag = String(event.target?.tagName ?? \\\"\\\").toLowerCase()\\n if (targetTag === \\\"input\\\" || targetTag === \\\"textarea\\\" || targetTag === \\\"select\\\") return\\n focusEditorSoon()\\n }}\\n >\\n
\\n
\\n setStyleDraft((current) => ({ ...current, [key]: nextValue }))}\\n onApply={applyStyles}\\n onReset={resetStyles}\\n registerRecent={rememberColor}\\n editorInputProps={editorInputProps}\\n showFilter={false}\\n />\\n \\n setThemeDraft((current) => ({ ...current, [key]: nextValue }))}\\n onApply={applyTheme}\\n onReset={resetTheme}\\n registerRecent={rememberColor}\\n editorInputProps={editorInputProps}\\n showFilter={true}\\n />\\n
\\n {activeDialog === \\\"load\\\" ? (\\n
setActiveDialog(\\\"\\\")}\\n cardRef={modalCardRef}\\n onBlurCapture={handleDialogBlurCapture}\\n onPointerDownCapture={handleModalPointerDownCapture}\\n onKeyDownCapture={handleModalKeyCapture}\\n onKeyUpCapture={handleModalKeyCapture}\\n >\\n \\n {savedLayouts.length ? (\\n
setSelectedLayoutName(event.target.value)}\\n style={styles.textInput}\\n >\\n {savedLayouts.map((layout) => (\\n {layout.name} \\n ))}\\n \\n ) : (\\n
No saved layouts were returned.
\\n )}\\n
\\n setActiveDialog(\\\"\\\")} style={styles.secondaryButton}>Cancel \\n Load Selected \\n
\\n
\\n \\n ) : null}\\n {activeDialog === \\\"manage\\\" ? (\\n
setActiveDialog(\\\"\\\")}\\n cardRef={modalCardRef}\\n onBlurCapture={handleDialogBlurCapture}\\n onPointerDownCapture={handleModalPointerDownCapture}\\n onKeyDownCapture={handleModalKeyCapture}\\n onKeyUpCapture={handleModalKeyCapture}\\n >\\n \\n {savedLayouts.length ? (\\n
setManagedLayoutName(event.target.value)}\\n style={styles.textInput}\\n >\\n {savedLayouts.map((layout) => (\\n {layout.name} \\n ))}\\n \\n ) : (\\n
No saved layouts are available to manage.
\\n )}\\n
\\n setActiveDialog(\\\"\\\")} style={styles.secondaryButton}>Close \\n Delete Selected \\n
\\n
\\n \\n ) : null}\\n {activeDialog === \\\"save\\\" ? (\\n
setActiveDialog(\\\"\\\")}\\n cardRef={modalCardRef}\\n onBlurCapture={handleDialogBlurCapture}\\n onPointerDownCapture={handleModalPointerDownCapture}\\n onKeyDownCapture={handleModalKeyCapture}\\n onKeyUpCapture={handleModalKeyCapture}\\n >\\n \\n
setSaveName(event.target.value)}\\n placeholder=\\\"Enter layout name\\\"\\n style={styles.textInput}\\n />\\n
\\n setActiveDialog(\\\"\\\")} style={styles.secondaryButton}>Cancel \\n Save Layout \\n
\\n
\\n \\n ) : null}\\n
\\n )\\n}\\nconst styles = {\\n appShell: {\\n color: \\\"#d5dde5\\\",\\n background: \\\"linear-gradient(180deg, #0b1220 0%, #091018 100%)\\\",\\n minHeight: \\\"100%\\\",\\n padding: 12,\\n fontFamily: \\\"Consolas, Monaco, monospace\\\",\\n },\\n stack: {\\n display: \\\"grid\\\",\\n gap: 12,\\n },\\n panel: {\\n border: \\\"1px solid #1d3140\\\",\\n borderRadius: 12,\\n background: \\\"rgba(9, 16, 24, 0.94)\\\",\\n boxShadow: \\\"0 8px 24px rgba(0, 0, 0, 0.25)\\\",\\n padding: 12,\\n },\\n compactPanel: {\\n border: \\\"1px solid #1d3140\\\",\\n borderRadius: 12,\\n background: \\\"rgba(9, 16, 24, 0.94)\\\",\\n boxShadow: \\\"0 8px 24px rgba(0, 0, 0, 0.25)\\\",\\n padding: 12,\\n marginBottom: 12,\\n },\\n panelHeader: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n alignItems: \\\"center\\\",\\n gap: 8,\\n marginBottom: 10,\\n },\\n previewHeader: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n alignItems: \\\"flex-start\\\",\\n gap: 8,\\n marginBottom: 10,\\n },\\n panelTitle: {\\n margin: 0,\\n fontSize: 18,\\n color: \\\"#f4f7fb\\\",\\n },\\n panelSubtitle: {\\n marginTop: 3,\\n fontSize: 11,\\n color: \\\"#89a0b4\\\",\\n },\\n panelActions: {\\n display: \\\"flex\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n },\\n primaryButton: {\\n border: \\\"1px solid #00d1ff\\\",\\n background: \\\"linear-gradient(180deg, #00d1ff 0%, #009ec2 100%)\\\",\\n color: \\\"#071013\\\",\\n padding: \\\"7px 12px\\\",\\n borderRadius: 8,\\n cursor: \\\"pointer\\\",\\n fontWeight: 700,\\n fontSize: 12,\\n },\\n secondaryButton: {\\n border: \\\"1px solid #2a455a\\\",\\n background: \\\"#111c28\\\",\\n color: \\\"#d5dde5\\\",\\n padding: \\\"7px 12px\\\",\\n borderRadius: 8,\\n cursor: \\\"pointer\\\",\\n fontWeight: 700,\\n fontSize: 12,\\n },\\n dangerButton: {\\n border: \\\"1px solid #8b2f3b\\\",\\n background: \\\"linear-gradient(180deg, #b63b4d 0%, #8e2738 100%)\\\",\\n color: \\\"#fff5f6\\\",\\n padding: \\\"7px 12px\\\",\\n borderRadius: 8,\\n cursor: \\\"pointer\\\",\\n fontWeight: 700,\\n fontSize: 12,\\n },\\n statsRow: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n fontSize: 11,\\n color: \\\"#7891a6\\\",\\n marginBottom: 10,\\n },\\n settingsGrid: {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"repeat(auto-fit, minmax(250px, 1fr))\\\",\\n gap: 10,\\n },\\n settingCard: {\\n border: \\\"1px solid #1b2d3c\\\",\\n borderRadius: 10,\\n background: \\\"#0f1822\\\",\\n padding: 10,\\n },\\n checkboxCard: {\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"space-between\\\",\\n gap: 10,\\n },\\n settingHead: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n alignItems: \\\"flex-start\\\",\\n gap: 8,\\n marginBottom: 8,\\n },\\n settingLabel: {\\n fontSize: 13,\\n fontWeight: 700,\\n color: \\\"#f4f7fb\\\",\\n },\\n settingMeta: {\\n fontSize: 11,\\n color: \\\"#84a0b5\\\",\\n marginTop: 2,\\n },\\n textInput: {\\n width: \\\"100%\\\",\\n boxSizing: \\\"border-box\\\",\\n borderRadius: 8,\\n border: \\\"1px solid #274155\\\",\\n background: \\\"#091018\\\",\\n color: \\\"#e6edf3\\\",\\n padding: \\\"8px 10px\\\",\\n fontSize: 12,\\n fontFamily: \\\"Consolas, Monaco, monospace\\\",\\n },\\n checkbox: {\\n width: 18,\\n height: 18,\\n },\\n colorChip: {\\n width: 28,\\n height: 28,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.18)\\\",\\n boxShadow: \\\"inset 0 0 0 1px rgba(0,0,0,0.25)\\\",\\n },\\n colorRow: {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"46px 1fr\\\",\\n gap: 8,\\n marginBottom: 8,\\n },\\n nativeColorInput: {\\n width: 46,\\n height: 36,\\n padding: 3,\\n borderRadius: 8,\\n border: \\\"1px solid #274155\\\",\\n background: \\\"#091018\\\",\\n cursor: \\\"pointer\\\",\\n },\\n sliderBlock: {\\n marginBottom: 8,\\n },\\n sliderLabel: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n fontSize: 11,\\n color: \\\"#84a0b5\\\",\\n marginBottom: 4,\\n },\\n rangeInput: {\\n width: \\\"100%\\\",\\n },\\n previewCard: {\\n borderRadius: 12,\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n padding: 14,\\n },\\n previewBar: {\\n display: \\\"flex\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 8,\\n },\\n previewBadge: {\\n display: \\\"inline-block\\\",\\n padding: \\\"4px 8px\\\",\\n borderRadius: 999,\\n fontSize: 11,\\n fontWeight: 800,\\n },\\n previewTitle: {\\n fontSize: 20,\\n fontWeight: 800,\\n marginBottom: 6,\\n },\\n previewText: {\\n fontSize: 13,\\n lineHeight: 1.5,\\n opacity: 0.88,\\n },\\n previewPills: {\\n display: \\\"flex\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n marginTop: 10,\\n marginBottom: 12,\\n },\\n previewPill: {\\n display: \\\"inline-block\\\",\\n padding: \\\"5px 9px\\\",\\n borderRadius: 999,\\n fontSize: 11,\\n fontWeight: 800,\\n },\\n statusBar: {\\n marginTop: 10,\\n borderRadius: 8,\\n padding: \\\"8px 10px\\\",\\n fontSize: 12,\\n },\\n statusInfo: {\\n background: \\\"rgba(0, 209, 255, 0.12)\\\",\\n border: \\\"1px solid rgba(0, 209, 255, 0.35)\\\",\\n color: \\\"#b8efff\\\",\\n },\\n statusError: {\\n background: \\\"rgba(255, 93, 115, 0.12)\\\",\\n border: \\\"1px solid rgba(255, 93, 115, 0.35)\\\",\\n color: \\\"#ffd3d9\\\",\\n },\\n miniTitle: {\\n fontSize: 13,\\n fontWeight: 800,\\n color: \\\"#f4f7fb\\\",\\n marginBottom: 8,\\n },\\n recentRow: {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"repeat(auto-fit, minmax(110px, 1fr))\\\",\\n gap: 8,\\n },\\n recentColor: {\\n minHeight: 40,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n cursor: \\\"pointer\\\",\\n position: \\\"relative\\\",\\n overflow: \\\"hidden\\\",\\n },\\n recentColorLabel: {\\n position: \\\"absolute\\\",\\n inset: \\\"auto 0 0 0\\\",\\n fontSize: 10,\\n background: \\\"rgba(0, 0, 0, 0.55)\\\",\\n color: \\\"#f7fbff\\\",\\n padding: \\\"3px 4px\\\",\\n textAlign: \\\"center\\\",\\n },\\n modalOverlay: {\\n position: \\\"fixed\\\",\\n inset: 0,\\n background: \\\"rgba(3, 8, 14, 0.76)\\\",\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"center\\\",\\n padding: 18,\\n zIndex: 9999,\\n },\\n modalCard: {\\n width: \\\"min(560px, 100%)\\\",\\n maxHeight: \\\"80vh\\\",\\n overflow: \\\"auto\\\",\\n borderRadius: 14,\\n border: \\\"1px solid #294357\\\",\\n background: \\\"#0b1320\\\",\\n boxShadow: \\\"0 24px 56px rgba(0, 0, 0, 0.45)\\\",\\n padding: 14,\\n },\\n modalHeader: {\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"space-between\\\",\\n gap: 12,\\n marginBottom: 12,\\n },\\n modalTitle: {\\n fontSize: 18,\\n fontWeight: 800,\\n color: \\\"#f4f7fb\\\",\\n },\\n modalCloseButton: {\\n border: \\\"1px solid #2a455a\\\",\\n background: \\\"#111c28\\\",\\n color: \\\"#d5dde5\\\",\\n padding: \\\"6px 10px\\\",\\n borderRadius: 8,\\n cursor: \\\"pointer\\\",\\n fontSize: 12,\\n fontWeight: 700,\\n },\\n modalBody: {\\n display: \\\"grid\\\",\\n gap: 12,\\n },\\n layoutList: {\\n display: \\\"grid\\\",\\n gap: 8,\\n },\\n layoutOption: {\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n gap: 10,\\n padding: \\\"10px 12px\\\",\\n borderRadius: 10,\\n border: \\\"1px solid #213649\\\",\\n background: \\\"#0f1822\\\",\\n cursor: \\\"pointer\\\",\\n },\\n emptyState: {\\n borderRadius: 10,\\n border: \\\"1px dashed #2a455a\\\",\\n background: \\\"#0f1822\\\",\\n padding: 12,\\n color: \\\"#9db0c1\\\",\\n fontSize: 12,\\n },\\n modalActions: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"flex-end\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n },\\n previewMockGrid: {\\n display: \\\"grid\\\",\\n gridTemplateColumns: \\\"1fr 1fr\\\",\\n gap: 12,\\n marginBottom: 12,\\n },\\n previewMockPanel: {\\n borderRadius: 10,\\n border: \\\"1px solid\\\",\\n padding: 10,\\n },\\n previewMockHeading: {\\n fontSize: 12,\\n fontWeight: 800,\\n marginBottom: 8,\\n },\\n previewCodeLine: {\\n fontSize: 12,\\n lineHeight: 1.5,\\n },\\n previewActionRow: {\\n display: \\\"flex\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 8,\\n },\\n previewButton: {\\n border: \\\"none\\\",\\n borderRadius: 10,\\n padding: \\\"7px 12px\\\",\\n fontSize: 12,\\n fontWeight: 800,\\n cursor: \\\"default\\\",\\n },\\n previewLinkRow: {\\n display: \\\"flex\\\",\\n gap: 12,\\n flexWrap: \\\"wrap\\\",\\n fontSize: 12,\\n },\\n}\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n if (!ns.ui?.getTheme || !ns.ui?.getStyles || !ns.ui?.setTheme || !ns.ui?.setStyles) {\\n ns.tprint(\\\"This script requires the BitBurner 3.0.0 dev UI theme/style APIs.\\\")\\n return\\n }\\n\\n const React = getReactLib()\\n if (!React) {\\n ns.tprint(\\\"React runtime is unavailable in this BitBurner session.\\\")\\n return\\n }\\n ns.atExit(() => { ns.clearPort(28) })\\n ns.clearPort(28)\\n ns.writePort(28, ns.pid)\\n\\n const initialTheme = cloneEditableObject(ns.ui.getTheme())\\n const initialStyles = cloneEditableObject(ns.ui.getStyles())\\n\\n ns.ui.openTail()\\n ns.ui.resizeTail(DEFAULT_WIDTH, DEFAULT_HEIGHT)\\n ns.clearLog()\\n ns.printRaw( )\\n await new Promise(() => { })\\n}\\n\""},{"filename":"SphyxOS/bladeBurner/getActionCountRemain.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getActionCountRemaining(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionCurLevel.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let result;\\n try { result = ns.bladeburner.getActionCurrentLevel(ns.args[0], ns.args[1]) } catch { result = -1 }\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionCurrentTime.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getActionCurrentTime()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionEstSuccessChance.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.args[2] !== undefined ? ns.bladeburner.getActionEstimatedSuccessChance(ns.args[0], ns.args[1], ns.args[2]) :\\n ns.bladeburner.getActionEstimatedSuccessChance(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionMaxLevel.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getActionMaxLevel(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionRepGain.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getActionRepGain(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getActionTime.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getActionTime(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getBlackOpRank.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getBlackOpRank(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getCity.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getCity()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getCityChaos.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getCityChaos(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getCityComms.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getCityCommunities(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getCityEstPop.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getCityEstimatedPopulation(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getCurrentAction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getCurrentAction()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getRank.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getRank()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getSkillLevel.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getSkillLevel(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getSkillPoints.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getSkillPoints()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getSkillUpgradeCost.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getSkillUpgradeCost(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/getStam.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.getStamina()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/joinBBFac.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.joinBladeburnerFaction()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/joinBBdiv.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.joinBladeburnerDivision()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/restart.js","file":"\"import { runIt } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n virus(ns)\\n await runIt(ns, \\\"SphyxOS/bins/LoaderSphyxOS.jsx\\\", true, [\\\"BBRestart\\\"])\\n}\\n\\n/** @param {NS} ns **/\\nfunction virus(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try {\\n ns.nuke(server)\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n }\\n catch { }\\n }\\n}\\n\\n/** @param {NS} ns */\\nexport function getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n const serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(server)\\n }\\n return serverDetails\\n}\""},{"filename":"SphyxOS/bladeBurner/setActionAutoLevel.js","file":"\"export async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.setActionAutolevel(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/setActionLevel.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n try { ns.bladeburner.setActionLevel(ns.args[0], ns.args[1], ns.args[2]) } catch {}\\n ns.atExit(() => port.write(true))\\n}\""},{"filename":"SphyxOS/bladeBurner/startAction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.startAction(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/switchCity.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.switchCity(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/bladeBurner/upgradeSkill.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.bladeburner.upgradeSkill(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/changeLog.txt","file":"\"v2.3\\r\\n-Added the Change Log\\r\\n2.3.1\\r\\n-Fixed Backdoor All script bug\\r\\n-Fixed batcher bug for use hacknet option\\r\\n2.3.2\\r\\n-Attempted to fix out fo threads issue with batcher\\r\\n-Added recovery to targeting for batcher. The first target needs to be at min security now\\r\\n2.3.3\\r\\n-Looked into another fix for batcher RAM issues\\r\\n2.3.4\\r\\n-Decreased the starting hight of the stocks script\\r\\n2.3.5\\r\\n-Fixed a bug in batcher targetting (first target), where if no servers were at min security it would fail\\r\\n2.3.6\\r\\n-Revised first target selection\\r\\n2.3.7\\r\\n-Revised first target selection again\\r\\n2.3.8\\r\\n-Fixed starting IPvGo being stuck on enabled if it failed to launch\\r\\n2.3.9\\r\\n-Fixed crash when batcher starts with no RAM avaialble on the network\\r\\n2.3.10\\r\\n-Fixed an end game interaction with the batcher when there is no RAM available on the network\\r\\n2.4\\r\\n-Added autoPilot v1\\r\\n-Added check in corps to kill the script if a corp cannot be created\\r\\n-Fixed a bug in backdoor that could cause it to think you were backdooring home\\r\\n-Fixed a bug in dumpmoney where it did not factor in the favor change of BN 12\\r\\n2.5\\r\\n-Added Stanek support to autoPilot\\r\\n-Added IPvGo support to autoPilot\\r\\n-Added BN 2 customized support to autoPilot\\r\\n-Changed up Gangs.\\r\\n--Will now autobuy EQ when it reaches 4 or more members. Changed training stats down to 20 from 60\\r\\n--When the mode is set to Auto, will do respect until you can purchase all augments, then it switches to money\\r\\n-IPvGo will now cheat at a size of 7 from 5\\r\\n-IPvGo will now require a contiguous chain of 7 to use snake eyes\\r\\n-Fixed an error in sleeves regarding a error when sending an unstripped promise over ports\\r\\n-Added 3.0.0 support, along side of 2.8.1 support.\\r\\n-Added info on current game version at the top of the main loader script\\r\\n2.5.1\\r\\n-Fixed backdoor all's compatability between 2.8.1 and 3.0.0\\r\\n2.5.2\\r\\n-Fixed corps backward compatability\\r\\n2.5.3\\r\\n-Fixed Casino slowdown issues in 3.0\\r\\n-Fixed Stocks backwards compatability issue\\r\\n-Fixed issue with DumpMoney where NFG would not be purchased if you were a high ranking member of \\\"Church of the Machine Gods\\\"\\r\\n-Added BN 3, 4, 5 and 10 to the autoPilot list - Requires more testing\\r\\n2.5.4\\r\\n-Added a slowdown to Casino in the prep stage to allow the page to refresh. Needed to get accurate results\\r\\n-Added a loop to buying augments in DumpMoney, where it stops trying if it fails to buy anything during the loop to account for pre-reqs\\r\\n-Added a new cheat move to IPvGo. WallBreaker. Will try to destroy empty nodes if a group only has 3-4 near the end to use up cheats\\r\\n-Updated logic in IPvGo for agro attack and def attack, thanks to Dusky (Discord)\\r\\n-Fixed an issue in Stocks regarding an unexpected placeholder error\\r\\n-Fixed an issue in Stocks regarding incorrect typing of short(S) and long(L) between versions\\r\\n-Updated backdoor timings to help prevent backdooring \\\"home\\\" error\\r\\n-Widened the batcher log window so the Take line doesn't wrap\\r\\n-Added new achievements to Unlock All Achievements\\r\\n-Changed batcher timings to pause after 200ms instead of 2000 batches\\r\\n-Added modes to batcher display\\r\\n-Tested autoPilot1 for BN's 1, 4 - OK BN10 should be OK too but needs further testing\\r\\n2.5.5\\r\\n-Tested autoPilot1 for BN's 2. Current tested autoPilot stages are BN's 1, 2, 4\\r\\n-Fixed a missing mode display in the batcher\\r\\n-Increased backdoor timings to avoid backdooring home. Down to 10 servers a second.\\r\\n2.5.6\\r\\n-Added more delay to casino starting to allow other scripts to wait for it to be ready\\r\\n-Fixed autoBuyHacknet for batcher\\r\\n-Lowered the revenue needed to trigger going public in corps - along with the dividends payout\\r\\n-Tested autopilot1 in BN 3, 5, 9, 10\\r\\n -autopilot1 can now do BN's 1, 2, 3, 4, 5, 9, 10 with no supports\\r\\n-Casino will now bet $0 when calculating the sequence and will recover if you click out of it\\r\\n2.5.7\\r\\n-Fixed a few bugs in autpilot for BN 9\\r\\n-Added a delay to make sure coding contracts finish before moving on in autopilot\\r\\n-Testing BN 14 in autopilot\\r\\n-Removed \\\"fulcrumassets\\\" server from autopilot backdoor to save time\\r\\n-Added a larger minimum rep purchase to Dump Money to avoid a potential loop\\r\\n-Added a popout option to the batcher for the log\\r\\n2.5.8\\r\\n-Removed powerhouse-fitness from autopilot backdoor to save time\\r\\n-Fixed auto infiltrate status when resetting with it enabled\\r\\n-Confirmed autopilot for BN 14 works without supports\\r\\n-Fixed an issue in autopilot for BN 10 where it would kill the script if you were not in new tokyo when it tries to move there\\r\\n-Added a toggle to autopilot, that will either move to the next node or leave you at the node selection screen when done\\r\\n-Added popout to autopilot, stocks, IPvGo\\r\\n-Fixed error when turning off autohashing for batcher\\r\\n-Prevented autopilot from ending the node when calling it's backdoor script\\r\\n2.5.9\\r\\n-Added popout to BB, Gang\\r\\n-Added BN 6 and 7 to autopilot\\r\\n-Allowed autopilot to remember if it had gone through an upgrade cycle if stopped and restarted\\r\\n-Modified BB Analysis algorithm. 2 modes, with and without sleeves\\r\\n-Fixed BB bug that crashed script sometime when doing a Black Op\\r\\n-Added Charisma to BB training\\r\\n-Fixed Grafting Standard option, renamed to None\\r\\n-Added \\\"Fastest\\\" to Grafting options\\r\\n2.5.10\\r\\n-Added popout to Grafting, Sleeves\\r\\n-Stopped backdoor basic from spoiling the truth\\r\\n-Fixed BB finisher crash\\r\\n-Fixed crash in batcher when no good \\\"next target\\\" is found\\r\\n2.5.11\\r\\n-Lowered dump money ram cost back to 8gb\\r\\n-dumpmoney will now reserver 1m in cash\\r\\n-autoinfil will now autoselect a faction for rep if you only have 1 available\\r\\n-Testing autopilot for BN 13\\r\\n2.5.12\\r\\n-Ram dodged the autoinfil change from above\\r\\n2.5.13\\r\\n-Modified the faction option for autoinfil slightly and removed bug introduced\\r\\n2.5.14\\r\\n-Fixed a bug in autopilot in regards to a city error\\r\\n2.5.15\\r\\n-Fixed a second bug in autopilot in regards to city error\\r\\n2.6\\r\\n-Changed option in batcher from displaying \\\"BuyHashes\\\" to \\\"AutoHash\\\"\\r\\n-Added platform to the loaders display\\r\\n-Added step information to autopilot\\r\\n-autopilot good for BN 13 now. Leaves 8, 11 and 12 to do\\r\\n-Changed Stocks money tracking to better track money gained\\r\\n-Added more info to Stocks\\r\\n-Added reset button to Stocks that resets the time before the next report, sales fees and banked\\r\\n-Fixed Stocks display of shorts information\\r\\n2.6.1\\r\\n-autopilot good for BN 11 now\\r\\n-Added a slowmode to IPvGo. This will add a delay of 2 seconds between moves\\r\\n-Removed the displaying of cheat error if you do not have the unlock while having it turned on\\r\\n--This hopefully fixes a rare crash after cheating when not able to\\r\\n-Added button to enable/disable error loggin in Batcher - default is disabled\\r\\n-Added padding button to Batcher, will pad grows 15% and add enough weakens to offset the addition. Default is disabled\\r\\n-Improved dump money a bit, added filter for SoA faction and a min of 0 to donations.\\r\\n2.6.2\\r\\n-Completely revamped the innerds of autopilot. Please report any errors\\r\\n-Fixed a bug in autopilot that caused it to constantly buy ram if able\\r\\n-Stopped autopilot from resetting you to buy ram on game restart if your money on hand supported it\\r\\n-autopilot now supports BN 8\\r\\n-Updated a syntax error in changelog.js\\r\\n-Fixed an issue in runit regarding scriptOverride costs\\r\\n-Updated dump money. It will now purchase home RAM as the last thing it does\\r\\n-Added next update time to Stocks\\r\\n-Added a Keep Tab Alive button to Misc. This will play an inaudible audio signal to keep a webbrowser tab alive when backgrouned\\r\\n2.6.3\\r\\n-Fixed autopilot for BN 8 and added compatability between version 2.8.1stable and 3.0dev\\r\\n2.6.4\\r\\n-Fixed a small bug in autopilot BN 8 that prevent stocks from opening automatically in 2.8.1\\r\\n2.6.5\\r\\n-Stopped autopilot from starting corps in the background in BN 12\\r\\n-Reduced the size of the Blade Burner script by 4gb\\r\\n-Added \\\"Total Number of Primes\\\" to the coding contracts solver\\r\\n-Fixed an issue in Stocks that prevented it from buying stocks\\r\\n2.6.6\\r\\n-Added better memory handling to the coding contracts webworker management\\r\\n-Fixed an error in autopilot for BN 10\\r\\n2.6.7\\r\\n-Fixed another error in autopilot for BN 10 where it did not show info on 14/15\\r\\n2.6.8\\r\\n-Updated autopilot for BN 10. It will not correctly select the Covenant faction if you are a member of multiple\\r\\n2.6.9\\r\\n-Fixed autopilot's tracking for BN 6 and 7\\r\\n2.6.10\\r\\n-Fixed some autopilot errors in BN 9\\r\\n2.6.11\\r\\n-Reduced the RAM cost of the Gang script to 4gb\\r\\n-Disabled all logs in hack/grow/weaken to improve performance\\r\\n-Upgraded scripts that purchased servers to support the new .cloud namespace\\r\\n-Ram dodged the attempt call in coding contacts\\r\\n-Added ramOverride to all exec calls for proxy.\\r\\n-Removed ramOverride from all proxy files\\r\\n-Changes buttons and backgrounds to match your current theme. If you change your theme you will need to refresh or click something for the Loader to update\\r\\n2.6.12\\r\\n-Fixed the server purchaser script\\r\\n2.6.13\\r\\n-Fixed a ram dodging command to use ramOverride\\r\\n2.6.14\\r\\n-Fixed a compatability issue in sleeves and gangs\\r\\n2.6.15\\r\\n-Added backwards compatability for a gang change\\r\\n2.6.16\\r\\n-Added new coding contract for Largest Rectangle in Matrix\\r\\n2.6.17\\r\\n-Trying to get new github repo to download the proper information.\\r\\n2.6.18\\r\\n-Changed over update button link to the new link\\r\\n3.0.0\\r\\n-Updated main Loader script to use React. Should be much snappier now\\r\\n-Buttons/Backgrounds now use themes inline color to auto refresh when changed\\r\\n-Changed how options are displayed in the batcher (added spacing between all of them)\\r\\n-Updated proxy command to remove promises and enclose the attempt within a try/catch and remove all promises\\r\\n--proxy command should now be able to replace the majority of all previous ram dodged calls. Will slowly phase out the old ones\\r\\n-Added a Games section. Current games are Minesweeper and DOOM (network connection required for DOOM)\\r\\n-Added the new Dark Net mechanic\\r\\n-Switched all programs that receive updates to be on a 200ms async timer to look for those updates\\r\\n-Added popout to Corp\\r\\n-Added a Theme Editor, that can edit all your style info, theme colors, reset, save and load your themes+styles\\r\\n-Loader now has a persistent state, which saves across closes and restarts\\r\\n-Reorganized top buttons into an \\\"Actions\\\" dropdown menu\\r\\n-Added a \\\"Join Discord!!\\\" button to the loader's actions\\r\\n-Added a \\\"Create GitHub Issue\\\" button to the loader's actions\\r\\n-Added a new \\\"Mini\\\" view. Toggle between views by pressing the view button\\r\\n-Added the ability to hide rows from view\\r\\n-Added delete option for Stanek layouts\\r\\n-Add a new Dev Menu - the NOT the Dev Menu is a recreation of the dev menu, in a tail window\\r\\n-The \\\"Unlock All Achievements\\\" button now requires you confirm a prompt\\r\\n3.0.1\\r\\n-Fixed autoinfiltration\\r\\n-Fix some darknet issues\\r\\n3.0.2\\r\\n-Fixed autopilot issues\\r\\n3.0.3\\r\\n-Trying to fix autopilot again\\r\\n-Fixes to darknet\\r\\n3.0.4\\r\\n-Fixed darknet again\\r\\n3.0.5\\r\\n-Added a limiter to AutoInfil. It requires 80% market demand\\r\\n-Reverted lab solver to the diagnostics version\\r\\n-Added the game \\\"Timberman\\\"\\r\\n-Added a guard against darknet giving more stocks than you should be able to get\\r\\n3.0.5.1\\r\\n-Added forced move when lab solver runs out\\r\\n-Fixed stocks interactions with darknet causing a freeze\\r\\n3.0.5.2\\r\\n-Fixed darknet more\\r\\n3.0.5.3\\r\\n-Let darknet show all the time. It will alert you if it cannot be started\\r\\n-Updated darknet again\\r\\n3.0.5.4\\r\\n-Still workin on darknet\\r\\n-Fixed a few issues in autopilot\\r\\n-Fixed a display issue in loader\\r\\n3.0.5.5\\r\\n-Darknet Fixes\\r\\n3.0.5.6\\r\\n-Added webstorms to the darknet controller\\r\\n-Added stock manipulation to the darknet controller\\r\\n-Fixed a corp display bug (Thank you Discord user @Jake DeZure )\\r\\n-Fixed network virus issues from removing try/catch\\r\\n3.0.5.7\\r\\n-Moved some proxie calls from darknet that were run on home run locally instead\\r\\n-Added a Hash AutoSpend button.\\r\\n-Closing the lab map will turn Show Lab Map off\\r\\n-Added a training section to Sleeves\\r\\n-Added a training option for Gangs\\r\\n-Fixed BN display in Loader\\r\\n-Added a crash guard for Corps. It will no longer start if you run it manually and don't have its pre-reqs\""},{"filename":"SphyxOS/cheats/achievements.js","file":"\"export async function main(ns) {\\n globalThis.webpack_require ?? webpackChunkbitburner.push([[-1], {}, w => globalThis.webpack_require = w]);\\n const skippedModuleIds = new Set(Object.keys(webpackChunkbitburner[0][1]));\\n let p;\\n Object.keys(webpack_require.m).filter(id => !skippedModuleIds.has(id)).forEach(k => Object.values(webpack_require(k)).find(f => { if (typeof f?.giveExploit === \\\"function\\\") p = f }))\\n \\n //We now have p - the active player. Do what you will with it.\\n //Exploits\\n p.giveExploit(\\\"Bypass\\\")\\n p.giveExploit(\\\"EditSaveFile\\\")\\n p.giveExploit(\\\"PrototypeTampering\\\")\\n p.giveExploit(\\\"Unclickable\\\")\\n p.giveExploit(\\\"TimeCompression\\\")\\n p.giveExploit(\\\"UndocumentedFunctionCall\\\")\\n p.giveExploit(\\\"RealityAlteration\\\")\\n p.giveExploit(\\\"N00dles\\\")\\n p.giveExploit(\\\"YoureNotMeantToAccessThis\\\")\\n p.giveExploit(\\\"TrueRecursion\\\")\\n p.giveExploit(\\\"INeedARainbow\\\")\\n\\n //Achievements\\n p.giveAchievement(\\\"CYBERSEC\\\")\\n p.giveAchievement(\\\"NITESEC\\\")\\n p.giveAchievement(\\\"THE_BLACK_HAND\\\")\\n p.giveAchievement(\\\"BITRUNNERS\\\")\\n p.giveAchievement(\\\"THE_COVENANT\\\")\\n p.giveAchievement(\\\"DAEDALUS\\\")\\n p.giveAchievement(\\\"ILLUMINATI\\\")\\n p.giveAchievement(\\\"BRUTESSH.EXE\\\")\\n p.giveAchievement(\\\"FTPCRACK.EXE\\\")\\n p.giveAchievement(\\\"RELAYSMTP.EXE\\\")\\n p.giveAchievement(\\\"HTTPWORM.EXE\\\")\\n p.giveAchievement(\\\"SQLINJECT.EXE\\\")\\n p.giveAchievement(\\\"FORMULAS.EXE\\\")\\n p.giveAchievement(\\\"MONEY_1Q\\\")\\n p.giveAchievement(\\\"MONEY_M1B\\\")\\n p.giveAchievement(\\\"INSTALL_1\\\")\\n p.giveAchievement(\\\"INSTALL_100\\\")\\n p.giveAchievement(\\\"QUEUE_40\\\")\\n p.giveAchievement(\\\"HACKING_100000\\\")\\n p.giveAchievement(\\\"COMBAT_3000\\\")\\n p.giveAchievement(\\\"NEUROFLUX_255\\\")\\n p.giveAchievement(\\\"NS2\\\")\\n p.giveAchievement(\\\"FROZE\\\")\\n p.giveAchievement(\\\"RUNNING_SCRIPTS_1000\\\")\\n p.giveAchievement(\\\"DRAIN_SERVER\\\")\\n p.giveAchievement(\\\"MAX_RAM\\\")\\n p.giveAchievement(\\\"MAX_CORES\\\")\\n p.giveAchievement(\\\"SCRIPTS_30\\\")\\n p.giveAchievement(\\\"KARMA_1000000\\\")\\n p.giveAchievement(\\\"STOCK_1q\\\")\\n p.giveAchievement(\\\"DISCOUNT\\\")\\n p.giveAchievement(\\\"SCRIPT_32GB\\\")\\n p.giveAchievement(\\\"FIRST_HACKNET_NODE\\\")\\n p.giveAchievement(\\\"30_HACKNET_NODE\\\")\\n p.giveAchievement(\\\"MAX_HACKNET_NODE\\\")\\n p.giveAchievement(\\\"HACKNET_NODE_10M\\\")\\n p.giveAchievement(\\\"REPUTATION_10M\\\")\\n p.giveAchievement(\\\"DONATION\\\")\\n p.giveAchievement(\\\"TRAVEL\\\")\\n p.giveAchievement(\\\"WORKOUT\\\")\\n p.giveAchievement(\\\"TOR\\\")\\n p.giveAchievement(\\\"HOSPITALIZED\\\")\\n p.giveAchievement(\\\"GANG\\\")\\n p.giveAchievement(\\\"FULL_GANG\\\")\\n p.giveAchievement(\\\"GANG_TERRITORY\\\")\\n p.giveAchievement(\\\"GANG_MEMBER_POWER\\\")\\n p.giveAchievement(\\\"CORPORATION\\\")\\n p.giveAchievement(\\\"CORPORATION_BRIBE\\\")\\n p.giveAchievement(\\\"CORPORATION_PROD_1000\\\")\\n p.giveAchievement(\\\"CORPORATION_EMPLOYEE_3000\\\")\\n p.giveAchievement(\\\"CORPORATION_REAL_ESTATE\\\")\\n p.giveAchievement(\\\"INTELLIGENCE_255\\\")\\n p.giveAchievement(\\\"BLADEBURNER_DIVISION\\\")\\n p.giveAchievement(\\\"BLADEBURNER_OVERCLOCK\\\")\\n p.giveAchievement(\\\"BLADEBURNER_UNSPENT_100000\\\")\\n p.giveAchievement(\\\"4S\\\")\\n p.giveAchievement(\\\"FIRST_HACKNET_SERVER\\\")\\n p.giveAchievement(\\\"ALL_HACKNET_SERVER\\\")\\n p.giveAchievement(\\\"MAX_HACKNET_SERVER\\\")\\n p.giveAchievement(\\\"HACKNET_SERVER_1B\\\")\\n p.giveAchievement(\\\"MAX_CACHE\\\")\\n p.giveAchievement(\\\"SLEEVE_8\\\")\\n p.giveAchievement(\\\"SF1.1\\\")\\n p.giveAchievement(\\\"SF2.1\\\")\\n p.giveAchievement(\\\"SF3.1\\\")\\n p.giveAchievement(\\\"SF4.1\\\")\\n p.giveAchievement(\\\"SF5.1\\\")\\n p.giveAchievement(\\\"SF6.1\\\")\\n p.giveAchievement(\\\"SF7.1\\\")\\n p.giveAchievement(\\\"SF8.1\\\")\\n p.giveAchievement(\\\"SF9.1\\\")\\n p.giveAchievement(\\\"SF10.1\\\")\\n p.giveAchievement(\\\"SF11.1\\\")\\n p.giveAchievement(\\\"SF12.1\\\")\\n p.giveAchievement(\\\"FAST_BN\\\")\\n p.giveAchievement(\\\"INDECISIVE\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN1\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN2\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN3\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN6\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN7\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN8\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN9\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN10\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN12\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN13\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN13\\\")\\n p.giveAchievement(\\\"CHALLENGE_BN15\\\")\\n p.giveAchievement(\\\"UNACHIEVABLE\\\")\\n p.giveAchievement(\\\"IPVGO_WINNING_STREAK\\\")\\n p.giveAchievement(\\\"IPVGO_ANTICHEAT\\\")\\n p.giveAchievement(\\\"DARKNET_DEPTHS\\\")\\n p.giveAchievement(\\\"DARKNET_BACKDOOR\\\")\\n}\""},{"filename":"SphyxOS/cheats/autoInfil.js","file":"\"/*\\nMaintainer:\\nDiscord: Sphyxis\\n\\nContributer:\\nDiscord: Dihelvid\\n--Props for the simple \\\"I Win\\\" exploit\\n--Added args to allow for auto auto infiltrate ;)\\n\\n*/\\n\\nconst argsSchema = [\\n [\\\"single\\\", false],\\n [\\\"stop\\\", false],\\n [\\\"status\\\", false],\\n [\\\"quiet\\\", false],\\n [\\\"auto\\\", false],\\n [\\\"faction\\\", ''],\\n [\\\"update\\\", false],\\n [\\\"company\\\", ''],\\n ['time', 60000]\\n]\\n\\nexport function autocomplete(data, args) {\\n data.flags(argsSchema);\\n return [];\\n}\\n\\n//important parameters: \\\"--auto\\\" for auto replay, \\\"--faction BitRunners\\\" for auto-accepting reputation for named faction\\n\\nconst state = {\\n // Name of the company that's infiltrated.\\n company: \\\"\\\",\\n\\n // A copy of company, used for auto-restart so it doesn't get reset at end\\n lastCompany: \\\"\\\",\\n\\n // Whether infiltration started. False means, we're\\n // waiting to arrive on the infiltration screen.\\n started: false,\\n\\n // Details/state of the current mini game.\\n // Is reset after every game.\\n game: {},\\n};\\n\\n// automatically accept reward and re-run for the same company\\nlet auto = false\\n\\n\\n// auto-accept reputation for faction instead of money\\nlet repFaction = ''\\n\\n\\n// Speed of game actions, in milliseconds.\\nconst speed = 50;\\n\\n// Time infiltration(s)\\nlet infiltrationStart = 0\\n\\n// Small hack to save RAM.\\n// This will work smoothly, because the script does not use\\n// any \\\"ns\\\" functions, it's a pure browser automation tool.\\nconst wnd = eval(\\\"window\\\");\\nconst doc = wnd[\\\"document\\\"];\\n\\n// List of all games and an automated solver.\\nconst infiltrationGames = [\\n { name: \\\"type it backward\\\" },\\n { name: \\\"type it\\\" },\\n { name: \\\"enter the code\\\" },\\n { name: \\\"close the brackets\\\" },\\n { name: 'attack after the sentinel drops his guard and is distracted' },\\n { name: \\\"say something nice about the guard\\\" },\\n { name: \\\"remember all the mines\\\" },\\n { name: \\\"mark all the mines\\\" },\\n { name: \\\"match the symbols\\\" },\\n { name: \\\"cut the wires with the following properties\\\" },\\n];\\n\\nlet postTimeout = null\\n\\n/** @param {NS} ns **/\\nexport async function main(ns) {\\n const args = ns.flags(argsSchema);\\n auto = args.auto\\n repFaction = args.faction\\n\\n function print(msg) {\\n if (!args.quiet) {\\n ns.tprint(`\\\\n${msg}\\\\n`);\\n }\\n }\\n\\n if (args.status) {\\n if (wnd.tmrAutoInf) {\\n print(\\\"Automated infiltration is active\\\");\\n } else {\\n print(\\\"Automated infiltration is inactive\\\");\\n }\\n return;\\n }\\n\\n if (wnd.tmrAutoInf) {\\n print(\\\"Stopping automated infiltration...\\\");\\n clearInterval(wnd.tmrAutoInf);\\n delete wnd.tmrAutoInf;\\n delete globalThis[\\\"infil\\\"]\\n if (!args.update) return;\\n }\\n\\n if (args.stop) {\\n setTimeout(() => {\\n var btn = Array.from(doc.querySelectorAll('button')).find(x => x.innerText.includes('Cancel'))\\n if (btn) btn[Object.keys(btn)[1]].onClick({ isTrusted: true })\\n }, 1000)\\n return;\\n }\\n\\n auto = args.auto\\n\\n repFaction = args.faction && args.faction.length && args.faction\\n\\n print(\\n \\\"Automated infiltration is enabled...\\\\nWhen you visit the infiltration screen of any company, all tasks are completed automatically. \\\" +\\n `Auto? ${auto} ` +\\n `Faction or Money? ${repFaction || 'MONEY'}`\\n );\\n endInfiltration();\\n\\n // Monitor the current screen and start infiltration once a\\n // valid screen is detected.\\n wnd.tmrAutoInf = setInterval(infLoop, speed);\\n\\n // If company is set goto company and start infiltration\\n if (args.company) {\\n state.lastCompany = args.company\\n postTimeout = setTimeout(() => {\\n postTimeout = null\\n var btn = Array.from(doc.querySelectorAll('button')).find(x => x.innerText.indexOf('Infiltrate Company') >= 0)\\n if (btn) btn[Object.keys(btn)[1]].onClick({ isTrusted: true })\\n }, 1000)\\n }\\n}\\n\\n\\n\\n/**\\n * The infiltration loop, which is called at a rapid interval\\n */\\nasync function infLoop() {\\n if (!state.started) {\\n await waitForStart();\\n } else {\\n playGame();\\n }\\n}\\n\\n/**\\n * Returns a list of DOM elements from the main game\\n * container.\\n */\\nfunction getEl(parent, selector) {\\n let prefix = \\\":scope\\\";\\n\\n if (\\\"string\\\" === typeof parent) {\\n selector = parent;\\n parent = doc;\\n\\n prefix = \\\".MuiBox-root>.MuiBox-root>.MuiBox-root\\\";\\n\\n if (!doc.querySelectorAll(prefix).length) {\\n prefix = \\\".MuiBox-root>.MuiBox-root>.MuiGrid-root\\\";\\n }\\n if (!doc.querySelectorAll(prefix).length) {\\n prefix = \\\".MuiContainer-root>.MuiPaper-root\\\";\\n }\\n if (!doc.querySelectorAll(prefix).length) {\\n return [];\\n }\\n }\\n\\n selector = selector.split(\\\",\\\");\\n selector = selector.map((item) => `${prefix} ${item}`);\\n selector = selector.join(\\\",\\\");\\n\\n return parent.querySelectorAll(selector);\\n}\\n\\n/**\\n * Returns the first element with matching text content.\\n */\\nfunction filterByText(elements, text) {\\n text = text.toLowerCase();\\n\\n for (let i = 0; i < elements.length; i++) {\\n const content = elements[i].textContent.toLowerCase();\\n\\n if (-1 !== content.indexOf(text)) {\\n return elements[i];\\n }\\n }\\n\\n return null;\\n}\\n\\n/**\\n * Reset the state after infiltration is done.\\n */\\nfunction endInfiltration() {\\n state.company = \\\"\\\";\\n state.started = false;\\n // cancelMyTimeout()\\n // acceptMoney() // TODO: needed?\\n}\\n\\n/**\\n * Simulate wining a minigame. Tells the minigame you won. (Exploit)\\n */\\nfunction winGame() {\\n if (globalThis[\\\"infil\\\"]) globalThis[\\\"infil\\\"].onSuccess()\\n const doc = globalThis['document'];\\n const rootFiber = findReactRoot(doc);\\n const anyOnSuccess = deepFind(v => typeof v.onSuccess === 'function', rootFiber);\\n const infilLike = deepFind(v => 'level' in v && 'maxLevel' in v && 'stage' in v, rootFiber);\\n const hits = deepFind(v => typeof v.onSuccess === 'function' && typeof v.onFailure === 'function', rootFiber);\\n const test = hits[0]?.val ?? infilLike[0]?.val ?? anyOnSuccess[0]?.val;\\n globalThis['infil'] = test;\\n globalThis['infil'].onSuccess()\\n}\\n\\n/**\\n * Infiltration monitor to start automatic infiltration.\\n *\\n * This function runs asynchronously, after the \\\"main\\\" function ended,\\n * so we cannot use any \\\"ns\\\" function here!\\n */\\nconst slp = ms => new Promise(r => setTimeout(r, ms))\\nasync function waitForStart() {\\n if (state.started) {\\n return;\\n }\\n\\n const h4 = getEl(\\\"h4\\\");\\n\\n if (!h4.length) {\\n return;\\n }\\n const title = h4[0].textContent;\\n if (0 !== title.indexOf(\\\"Infiltrating\\\")) {\\n return;\\n }\\n\\n const btnStart = filterByText(getEl(\\\"button\\\"), \\\"Start\\\");\\n if (!btnStart) {\\n return;\\n }\\n const marketShare = extractMarketDemandPercentage()\\n\\n if (marketShare < 80) {\\n await slp(200)\\n return\\n }\\n\\n state.company = title.substr(13);\\n state.lastCompany = title.substr(13);\\n state.started = true;\\n\\n var datetime = new Date().today() + \\\" @ \\\" + new Date().timeNow();\\n //console.log(datetime, \\\" Start automatic infiltration of\\\", state.company);\\n btnStart.click();\\n}\\n\\n/**\\n * Identify the current infiltration game and win it.\\n */\\nfunction playGame() {\\n const screens = doc.querySelectorAll(\\\".MuiContainer-root\\\");\\n wnd.info = { screens }\\n\\n if (!screens.length) {\\n wnd.info = { screens, messge: 'no screens.length, calling endInfiltration()' }\\n endInfiltration();\\n //refillhealth();\\n selectCompany();\\n return;\\n }\\n if (screens[0].children.length < 3) {\\n wnd.info = { screens, message: 'screens.children.length < 3, calling endInfiltration()' }\\n if (!postTimeout && screens[0].children[1].children[0].innerText === 'Infiltration successful!') {\\n acceptMoney('spam') // I think this is spamming, yes, need to check for infiltration complete, but where\\n }\\n return;\\n }\\n\\n const screen = screens[0].children[2];\\n const h4 = screen.children//getEl(screen, \\\"h4\\\");\\n\\n if (!h4.length) {\\n wnd.info = { screens, message: 'no h4.length, calling endInfiltration()' }\\n endInfiltration();\\n return;\\n }\\n\\n cancelMyTimeout()\\n\\n const title = h4[0].textContent.trim().toLowerCase().split(/[!.(]/)[0];\\n wnd.info = { screens, message: 'searching for something', title }\\n\\n if (\\\"infiltration successful\\\" === title) {\\n // NOTE: I get screens.length < 3 on success, not this...\\n wnd.info = { screens, message: 'infiltration successful!' }\\n endInfiltration();\\n return;\\n } else {\\n wnd.last_title = title\\n }\\n\\n if (\\\"get ready\\\" === title) {\\n if (!infiltrationStart) infiltrationStart = new Date().valueOf()\\n return;\\n }\\n\\n const game = infiltrationGames.find((game) => game.name === title);\\n wnd.STATE = { game, screen, h4, title }\\n\\n if (game) {\\n winGame() // Tells screen you won\\n } else {\\n console.error(\\\"Unknown game:\\\", title);\\n }\\n}\\n\\n/*================================================================================\\n = Auto Mode\\n ================================================================================*/\\n\\n/**\\n * Select a company and begin infiltration for auto mode\\n */\\nfunction selectCompany() {\\n if (!auto) return\\n cancelMyTimeout()\\n\\n postTimeout = setTimeout(() => {\\n postTimeout = null\\n\\n var selector = 'span[aria-label=\\\"' + state.lastCompany + '\\\"]'\\n var companyEle = doc.querySelector(selector)\\n if (companyEle) {\\n if (infiltrationStart) {\\n console.info(`FAILED INFILTRATION - ${((new Date().valueOf() - infiltrationStart) / 1000).toFixed(1)} sec, last was ${last_title}`);\\n infiltrationStart = 0\\n }\\n companyEle.click()\\n postTimeout = setTimeout(() => {\\n postTimeout = null\\n var btn = Array.from(doc.querySelectorAll('button')).find(x => x.innerText.indexOf('Infiltrate Company') >= 0)\\n if (btn) btn[Object.keys(btn)[1]].onClick({ isTrusted: true })\\n }, 1000)\\n }\\n }, 1000)\\n}\\n\\n// accept money bonus, hand off to acceptReputation() if repFaction is set\\nfunction acceptMoney(msg) {\\n if (!auto) return\\n if (postTimeout) return\\n\\n //console.log('acceptMoney:', msg)\\n cancelMyTimeout()\\n\\n if (repFaction && repFaction.length) {\\n //console.log(\\\"starting function accept reputation\\\");\\n acceptReputation()\\n return\\n }\\n\\n postTimeout = setTimeout(() => {\\n //console.log('acceptMoney()', msg)\\n cancelMyTimeout()\\n var btn = Array.from(doc.querySelectorAll('button')).find(x => x.innerText.indexOf('Sell for') >= 0)\\n if (btn) {\\n if (infiltrationStart) {\\n //console.info(`SUCCESSFUL INFILTRATION - ${((new Date().valueOf() - infiltrationStart) / 1000).toFixed(1)} sec: ${btn.innerText}`);\\n infiltrationStart = 0\\n }\\n btn[Object.keys(btn)[1]].onClick({ isTrusted: true })\\n } else {\\n //console.log(`Failure! ${ms}`)\\n }\\n //refillhealth();\\n selectCompany();\\n }, 1000)\\n}\\n\\n// accept reputation bonus\\nfunction acceptReputation() {\\n cancelMyTimeout()\\n\\n postTimeout = setTimeout(() => {\\n postTimeout = null\\n\\n // var e = Array.from(doc.querySelectorAll('[role=\\\"button\\\"]')).find(x => x.innerText.indexOf('None') >= 0);\\n var e = Array.from(doc.querySelectorAll('[role=\\\"combobox\\\"]')).find(x => x.innerText.indexOf('none') >= 0);\\n if (typeof (e) == 'undefined') {\\n var e = Array.from(doc.querySelectorAll('[role=\\\"combobox\\\"]')).find(x => x.innerText.indexOf(repFaction) >= 0);\\n }\\n // var datetime = new Date().today() + \\\" @ \\\" + new Date().timeNow();\\n // console.log(datetime, \\\" function acceptReputation: e \\\",e);\\n // console.log(datetime, \\\" function acceptReputation: repFaction \\\", repFaction);\\n if (e) {\\n e[Object.keys(e)[1]].onKeyDown(new KeyboardEvent('keydown', { 'key': ' ' }));\\n postTimeout = setTimeout(() => {\\n var e2 = Array.from(doc.querySelectorAll('li[role=\\\"option\\\"]')).find(x => x.innerText.indexOf(repFaction) >= 0)\\n // console.log(\\\"function acceptReputation: e2 \\\", e2);\\n e2.click()\\n postTimeout = setTimeout(() => {\\n var btn = Array.from(doc.querySelectorAll('button')).find(x => x.innerText.indexOf('Trade for') >= 0)\\n // console.log(\\\"function acceptReputation: btn \\\",btn);\\n if (btn) {\\n btn[Object.keys(btn)[1]].onClick({ isTrusted: true })\\n if (infiltrationStart) {\\n //console.info(`SUCCESSFUL INFILTRATION - ${((new Date().valueOf() - infiltrationStart) / 1000).toFixed(1)} sec - ${btn.innerText}`, repFaction);\\n infiltrationStart = 0\\n }\\n }\\n })\\n }, 1000)\\n }\\n }, 1000)\\n}\\n\\n\\n// For todays date;\\nDate.prototype.today = function () {\\n return ((this.getDate() < 10) ? \\\"0\\\" : \\\"\\\") + this.getDate() + \\\"/\\\" + (((this.getMonth() + 1) < 10) ? \\\"0\\\" : \\\"\\\") + (this.getMonth() + 1) + \\\"/\\\" + this.getFullYear();\\n}\\n\\n// For the time now\\nDate.prototype.timeNow = function () {\\n return ((this.getHours() < 10) ? \\\"0\\\" : \\\"\\\") + this.getHours() + \\\":\\\" + ((this.getMinutes() < 10) ? \\\"0\\\" : \\\"\\\") + this.getMinutes() + \\\":\\\" + ((this.getSeconds() < 10) ? \\\"0\\\" : \\\"\\\") + this.getSeconds();\\n}\\n\\nfunction cancelMyTimeout() {\\n if (postTimeout) {\\n clearTimeout(postTimeout)\\n postTimeout = null\\n }\\n}\\n\\nfunction findReactRoot(doc) {\\n const all = doc.querySelectorAll('*');\\n for (const el of all) {\\n for (const k of Object.keys(el)) {\\n if (k.startsWith('__reactContainer$')) return el[k].stateNode.current;\\n if (k.startsWith('__reactFiber$')) return el[k];\\n }\\n }\\n return null;\\n}\\nfunction* fiberStates(f) {\\n yield f.memoizedProps;\\n yield f.pendingProps;\\n yield f.stateNode && f.stateNode.state;\\n let h = f.memoizedState;\\n let guard = 0;\\n while (h && guard++ < 200) {\\n yield h.memoizedState;\\n if (h.memoizedState && typeof h.memoizedState === 'object') {\\n yield h.memoizedState.current;\\n }\\n h = h.next;\\n }\\n}\\nfunction deepFind(predicate, rootFiber, maxDepth = 4) {\\n const seenFibers = new Set();\\n const seenObjs = new WeakSet();\\n const hits = [];\\n const stack = [rootFiber];\\n\\n function probe(val, path, depth, fiber) {\\n if (!val || typeof val !== 'object' || seenObjs.has(val) || depth > maxDepth) return;\\n seenObjs.add(val);\\n try { if (predicate(val)) hits.push({ path, val, fiber }); } catch { }\\n for (const k of Object.keys(val)) {\\n try { probe(val[k], path + '.' + k, depth + 1, fiber); } catch { }\\n }\\n }\\n\\n while (stack.length) {\\n const f = stack.pop();\\n if (!f || seenFibers.has(f)) continue;\\n seenFibers.add(f);\\n const name = f.type?.displayName || f.type?.name ||\\n (typeof f.type === 'string' ? f.type : '?');\\n let i = 0;\\n for (const bag of fiberStates(f)) probe(bag, `${name}#${i++}`, 0, f);\\n if (f.child) stack.push(f.child);\\n if (f.sibling) stack.push(f.sibling);\\n }\\n return hits;\\n}\\nfunction extractMarketDemandPercentage() {\\n const iterator = doc.evaluate(\\n \\\"//*[contains(text(), 'Market demand:')]\\\", \\n doc, // Context node: The whole page\\n null, // Namespace resolver (usually null)\\n XPathResult.ORDERED_NODE_ITERATOR_TYPE,\\n null\\n )\\n\\n let foundElement = null\\n let currentNode = iterator.iterateNext()\\n // Iterate through results (there should only be one relevant element)\\n while (currentNode !== null) {\\n foundElement = currentNode\\n currentNode = iterator.iterateNext()\\n }\\n if (!foundElement) {\\n console.error(\\\"Market demand: line could not be located using XPath.\\\")\\n return 100\\n }\\n const textContent = foundElement.lastChild.data\\n return Number(textContent.replace(\\\"%\\\", \\\"\\\"))\\n}\\n/* \\n----------------------------------------------\\nIn memory of a script gone, but not forgotten:\\n----------------------------------------------\\n\\n {\\n name: \\\"type it\\\",\\n init: function (screen) {\\n const lines = getLines(getEl(screen, \\\"p\\\"));\\n state.game.data = lines[0].split(\\\"\\\");\\n },\\n play: function (screen) {\\n if (!state.game.data || !state.game.data.length) {\\n delete state.game.data;\\n return;\\n }\\n\\n pressKey(state.game.data.shift());\\n },\\n },\\n {\\n name: \\\"enter the code\\\",\\n init: function (screen) { state.game.position = 0 },\\n play: function (screen) {\\n const h4 = getEl(screen, \\\"h4\\\");\\n const code = h4[1].textContent;\\n\\n switch (code[state.game.position]) {\\n case \\\"↑\\\":\\n pressKey(\\\"w\\\");\\n break;\\n case \\\"↓\\\":\\n pressKey(\\\"s\\\");\\n break;\\n case \\\"←\\\":\\n pressKey(\\\"a\\\");\\n break;\\n case \\\"→\\\":\\n pressKey(\\\"d\\\");\\n break;\\n }\\n state.game.position++;\\n },\\n },\\n {\\n name: \\\"close the brackets\\\",\\n init: function (screen) {\\n const data = getLines(getEl(screen, \\\"p\\\"));\\n const brackets = data.join(\\\"\\\").split(\\\"\\\");\\n state.game.data = [];\\n\\n for (let i = brackets.length - 1; i >= 0; i--) {\\n const char = brackets[i];\\n\\n if (\\\"<\\\" == char) {\\n state.game.data.push(\\\">\\\");\\n } else if (\\\"(\\\" == char) {\\n state.game.data.push(\\\")\\\");\\n } else if (\\\"{\\\" == char) {\\n state.game.data.push(\\\"}\\\");\\n } else if (\\\"[\\\" == char) {\\n state.game.data.push(\\\"]\\\");\\n }\\n }\\n },\\n play: function (screen) {\\n if (!state.game.data || !state.game.data.length) {\\n delete state.game.data;\\n return;\\n }\\n\\n pressKey(state.game.data.shift());\\n },\\n },\\n {\\n name: \\\"attack after the sentinel drops his guard and is distracted\\\",\\n init: function (screen) {\\n state.game.data = \\\"wait\\\";\\n },\\n play: function (screen) {\\n const data = getLines(getEl(screen, \\\"h4\\\"));\\n\\n if (\\\"attack\\\" === state.game.data) {\\n pressKey(\\\" \\\");\\n state.game.data = \\\"done\\\";\\n\\n }\\n\\n // Attack in next frame - instant attack sometimes\\n // ends in failure.\\n if ('wait' === state.game.data && -1 !== data.indexOf(\\\"Distracted!\\\")) {\\n state.game.data = \\\"attack\\\";\\n\\n }\\n },\\n },\\n {\\n name: \\\"say something nice about the guard\\\",\\n init: function (screen) { },\\n play: function (screen) {\\n const correct = [\\n \\\"affectionate\\\",\\n \\\"agreeable\\\",\\n \\\"bright\\\",\\n \\\"charming\\\",\\n \\\"creative\\\",\\n \\\"determined\\\",\\n \\\"energetic\\\",\\n \\\"friendly\\\",\\n \\\"funny\\\",\\n \\\"generous\\\",\\n \\\"polite\\\",\\n \\\"likable\\\",\\n \\\"diplomatic\\\",\\n \\\"helpful\\\",\\n \\\"giving\\\",\\n \\\"kind\\\",\\n \\\"hardworking\\\",\\n \\\"patient\\\",\\n \\\"dynamic\\\",\\n \\\"loyal\\\",\\n \\\"based\\\",\\n \\\"straightforward\\\",\\n ];\\n const word = getLines(getEl(screen, \\\"h5\\\"))[1];\\n\\n if (-1 !== correct.indexOf(word)) {\\n pressKey(\\\" \\\");\\n } else {\\n pressKey(\\\"w\\\");\\n }\\n },\\n },\\n {\\n name: \\\"remember all the mines\\\",\\n init: function (screen) {\\n const rows = getEl(screen, \\\"p\\\");\\n let gridSize = null;\\n switch (rows.length) {\\n case 9:\\n gridSize = [3, 3];\\n break;\\n case 12:\\n gridSize = [3, 4];\\n break;\\n case 16:\\n gridSize = [4, 4];\\n break;\\n case 20:\\n gridSize = [4, 5];\\n break;\\n case 25:\\n gridSize = [5, 5];\\n break;\\n case 30:\\n gridSize = [5, 6];\\n break;\\n case 36:\\n gridSize = [6, 6];\\n break;\\n }\\n if (gridSize == null) {\\n return;\\n }\\n //12 20 30 42\\n state.game.data = [];\\n let index = 0;\\n //for each row\\n for (let y = 0; y < gridSize[1]; y++) {\\n //initialize array data\\n state.game.data[y] = [];\\n for (let x = 0; x < gridSize[0]; x++) {\\n //for each column in the row add to state data if it has a child\\n if (rows[index].children.length > 0) {\\n state.game.data[y].push(true);\\n } else state.game.data[y].push(false);\\n index += 1;\\n }\\n }\\n },\\n play: function (screen) { },\\n },\\n {\\n name: \\\"mark all the mines\\\",\\n init: function (screen) {\\n state.game.x = 0;\\n state.game.y = 0;\\n state.game.cols = state.game.data[0].length;\\n state.game.dir = 1;\\n },\\n play: function (screen) {\\n let { data, x, y, cols, dir } = state.game;\\n\\n if (data[y][x]) {\\n pressKey(\\\" \\\");\\n data[y][x] = false;\\n }\\n\\n x += dir;\\n\\n if (x < 0 || x >= cols) {\\n x = Math.max(0, Math.min(cols - 1, x));\\n y++;\\n dir *= -1;\\n pressKey(\\\"s\\\");\\n } else {\\n pressKey(dir > 0 ? \\\"d\\\" : \\\"a\\\");\\n }\\n\\n state.game.data = data;\\n state.game.x = x;\\n state.game.y = y;\\n state.game.dir = dir;\\n },\\n },\\n {\\n name: \\\"match the symbols\\\",\\n init: function (screen) {\\n const data = getLines(getEl(screen, \\\"h5 span\\\"));\\n const rows = getLines(getEl(screen, \\\"p\\\"));\\n const keypad = [];\\n const targets = [];\\n let gridSize = null;\\n switch (rows.length) {\\n case 9:\\n gridSize = [3, 3];\\n break;\\n case 12:\\n gridSize = [3, 4];\\n break;\\n case 16:\\n gridSize = [4, 4];\\n break;\\n case 20:\\n gridSize = [4, 5];\\n break;\\n case 25:\\n gridSize = [5, 5];\\n break;\\n case 30:\\n gridSize = [5, 6];\\n break;\\n case 36:\\n gridSize = [6, 6];\\n break;\\n }\\n if (gridSize == null) {\\n return;\\n }\\n //build the keypad grid.\\n let index = 0;\\n for (let i = 0; i < gridSize[1]; i++) {\\n keypad[i] = [];\\n for (let y = 0; y < gridSize[0]; y++) {\\n\\n keypad[i].push(rows[index]);\\n index += 1;\\n }\\n }\\n //foreach data get coords of keypad entry\\n for (let i = 0; i < data.length; i++) {\\n const symbol = data[i].trim();\\n //for each keypad entry\\n for (let j = 0; j < keypad.length; j++) {\\n const k = keypad[j].indexOf(symbol);\\n\\n if (-1 !== k) {\\n targets.push([j, k]);\\n break;\\n }\\n }\\n }\\n state.game.data = targets;\\n state.game.x = 0;\\n state.game.y = 0;\\n },\\n play: function (screen) {\\n const target = state.game.data[0];\\n let { x, y } = state.game;\\n\\n if (!target) {\\n return;\\n }\\n\\n const to_y = target[0];\\n const to_x = target[1];\\n\\n if (to_y < y) {\\n y--;\\n pressKey(\\\"w\\\");\\n } else if (to_y > y) {\\n y++;\\n pressKey(\\\"s\\\");\\n } else if (to_x < x) {\\n x--;\\n pressKey(\\\"a\\\");\\n } else if (to_x > x) {\\n x++;\\n pressKey(\\\"d\\\");\\n } else {\\n pressKey(\\\" \\\");\\n state.game.data.shift();\\n }\\n\\n state.game.x = x;\\n state.game.y = y;\\n },\\n },\\n {\\n name: \\\"cut the wires with the following properties\\\",\\n init: function (screen) {\\n let numberHack = [\\\"1\\\", \\\"2\\\", \\\"3\\\", \\\"4\\\", \\\"5\\\", \\\"6\\\", \\\"7\\\", \\\"8\\\", \\\"9\\\"];\\n const colors = {\\n red: \\\"red\\\",\\n white: \\\"white\\\",\\n blue: \\\"blue\\\",\\n \\\"rgb(255, 193, 7)\\\": \\\"yellow\\\",\\n };\\n const wireColor = {\\n red: [],\\n white: [],\\n blue: [],\\n yellow: [],\\n };\\n //gather the instructions\\n var instructions = []\\n for (let child of screen.children) instructions.push(child);\\n var wiresData = instructions.pop();\\n instructions.shift();\\n instructions = getLines(instructions);\\n //get the wire information\\n const samples = getEl(wiresData, \\\"p\\\");\\n const wires = [];\\n //get the amount of wires\\n let wireCount = 0;\\n for (let i = wireCount; i < samples.length; i++) {\\n if (numberHack.includes(samples[i].innerText)) wireCount += 1;\\n else break;\\n }\\n let index = 0;\\n //get just the first 3 rows of wires.\\n for (let i = 0; i < 3; i++) {\\n //for each row\\n for (let j = 0; j < wireCount; j++) {\\n const node = samples[index];\\n const color = colors[node.style.color];\\n if (!color) {\\n index += 1;\\n continue;\\n }\\n wireColor[color].push(j + 1);\\n index += 1;\\n }\\n }\\n\\n for (let i = 0; i < instructions.length; i++) {\\n const line = instructions[i].trim().toLowerCase();\\n\\n if (!line || line.length < 10) {\\n continue;\\n }\\n if (-1 !== line.indexOf(\\\"cut wires number\\\")) {\\n const parts = line.split(/(number\\\\s*|\\\\.)/);\\n wires.push(parseInt(parts[2]));\\n }\\n if (-1 !== line.indexOf(\\\"cut all wires colored\\\")) {\\n const parts = line.split(/(colored\\\\s*|\\\\.)/);\\n const color = parts[2];\\n\\n if (!wireColor[color]) {\\n // should never happen.\\n continue;\\n }\\n\\n wireColor[color].forEach((num) => wires.push(num));\\n }\\n }\\n\\n // new Set() removes duplicate elements.\\n state.game.data = [...new Set(wires)];\\n },\\n play: function (screen) {\\n const wire = state.game.data;\\n //state.game.data.shift();\\n if (!wire) {\\n return;\\n }\\n for (let i = 0; i < wire.length; i++) {\\n pressKey(wire[i].toString());\\n }\\n },\\n },\\n];\\n\\n\\nfunction pressKey(keyOrCode) {\\n let keyCode = 0;\\n let key = \\\"\\\";\\n\\n if (\\\"string\\\" === typeof keyOrCode && keyOrCode.length > 0) {\\n key = keyOrCode.toLowerCase().slice(0, 1)//.substr(0, 1);\\n keyCode = key.charCodeAt(0);\\n } else if (\\\"number\\\" === typeof keyOrCode) {\\n keyCode = keyOrCode;\\n key = String.fromCharCode(keyCode);\\n }\\n\\n if (!keyCode || key.length !== 1) {\\n return;\\n }\\n\\n function sendEvent(event) {\\n const keyboardEvent = new KeyboardEvent(event, {\\n key,\\n keyCode,\\n });\\n doc.dispatchEvent(keyboardEvent)\\n }\\n\\n sendEvent(\\\"keydown\\\");\\n}\\n\\nfunction playGame() {\\n const screens = doc.querySelectorAll(\\\".MuiContainer-root\\\");\\n\\n if (!screens.length) {\\n endInfiltration();\\n return;\\n }\\n if (screens[0].children.length < 3) {\\n return;\\n }\\n\\n const screen = screens[0].children[2];\\n const h4 = screen.children//getEl(screen, \\\"h4\\\");\\n\\n if (!h4.length) {\\n endInfiltration();\\n return;\\n }\\n\\n const title = h4[0].textContent.trim().toLowerCase().split(/[!.(]/)[0];\\n\\n if (\\\"infiltration successful\\\" === title) {\\n endInfiltration();\\n return;\\n }\\n\\n if (\\\"get ready\\\" === title) {\\n return;\\n }\\n\\n const game = infiltrationGames.find((game) => game.name === title);\\n\\n if (game) {\\n if (state.game.current !== title) {\\n state.game.current = title;\\n game.init(screen);\\n }\\n\\n game.play(screen);\\n } else {\\n console.error(\\\"Unknown game:\\\", title);\\n }\\n}\\n\\nfunction wrapEventListeners() {\\n if (!doc._addEventListener) {\\n doc._addEventListener = doc.addEventListener;\\n doc.addEventListener = function (type, callback, options) {\\n if (\\\"undefined\\\" === typeof options) {\\n options = false;\\n }\\n let handler = false;\\n\\n // For this script, we only want to modify \\\"keydown\\\" events.\\n if (\\\"keydown\\\" === type) {\\n handler = function (...args) {\\n if (!args[0].isTrusted) {\\n let hackedEv = {}\\n\\n for (const key in args[0]) {\\n if (\\\"isTrusted\\\" === key) {\\n hackedEv.isTrusted = true;\\n } else if (\\\"function\\\" === typeof args[0][key]) {\\n hackedEv[key] = args[0][key].bind(args[0]);\\n } else {\\n hackedEv[key] = args[0][key];\\n }\\n }\\n Object.setPrototypeOf(hackedEv, KeyboardEvent.prototype)\\n args[0] = hackedEv;\\n }\\n return callback.apply(callback, args);\\n };\\n\\n for (const prop in callback) {\\n if (\\\"function\\\" === typeof callback[prop]) {\\n handler[prop] = callback[prop].bind(callback);\\n } else {\\n handler[prop] = callback[prop];\\n }\\n }\\n }\\n\\n if (!this.eventListeners) {\\n this.eventListeners = {};\\n }\\n if (!this.eventListeners[type]) {\\n this.eventListeners[type] = [];\\n }\\n\\n this.eventListeners[type].push({\\n listener: callback,\\n useCapture: options,\\n wrapped: handler,\\n });\\n\\n return this._addEventListener(\\n type,\\n handler ? handler : callback,\\n options\\n )\\n };\\n }\\n\\n if (!doc._removeEventListener) {\\n doc._removeEventListener = doc.removeEventListener;\\n\\n doc.removeEventListener = function (type, callback, options) {\\n if (\\\"undefined\\\" === typeof options) {\\n options = false;\\n }\\n\\n if (!this.eventListeners) {\\n this.eventListeners = {};\\n }\\n if (!this.eventListeners[type]) {\\n this.eventListeners[type] = [];\\n }\\n\\n for (let i = 0; i < this.eventListeners[type].length; i++) {\\n if (\\n this.eventListeners[type][i].listener === callback &&\\n this.eventListeners[type][i].useCapture === options\\n ) {\\n if (this.eventListeners[type][i].wrapped) {\\n callback = this.eventListeners[type][i].wrapped;\\n }\\n\\n this.eventListeners[type].splice(i, 1);\\n break;\\n }\\n }\\n\\n if (this.eventListeners[type].length == 0) {\\n delete this.eventListeners[type];\\n }\\n\\n return this._removeEventListener(type, callback, options);\\n };\\n }\\n}\\n\\nfunction unwrapEventListeners() {\\n if (doc._addEventListener) {\\n doc.addEventListener = doc._addEventListener;\\n delete doc._addEventListener;\\n }\\n if (doc._removeEventListener) {\\n doc.removeEventListener = doc._removeEventListener;\\n delete doc._removeEventListener;\\n }\\n delete doc.eventListeners;\\n}\\n*/\""},{"filename":"SphyxOS/cheats/casino.js","file":"\"import { getPlay, hasBN, travelCity, goToLoc } from \\\"SphyxOS/util.js\\\"\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog('ALL')\\n await ns.sleep(100)\\n ns.atExit(() => { ns.clearPort(10), ns.ui.closeTail() })\\n const HASBN4 = await hasBN(ns, 4, 2)\\n\\n if (ns.getMoneySources().sinceInstall?.casino >= 10e9) {\\n ns.tprintf('ERROR: Already banned from the casino!')\\n return\\n }\\n let player = await getPlay(ns)\\n // Go to Aevum if we aren't already there\\n if (player.city !== 'Aevum' && player.money < 2e5) {\\n ns.tprintf('ERROR: Sorry, you need at least 200k to travel to Aevum.');\\n return;\\n }\\n\\n if (player.city !== 'Aevum' && HASBN4 && !await travelCity(ns, \\\"Aevum\\\")) {\\n ns.tprintf('ERROR: Failed to travel to Aevum.')\\n return\\n }\\n else if (!HASBN4 && player.city !== 'Aevum') {\\n ns.tprintf('INFO: Travel to Aevum for the casino.');\\n return\\n }\\n\\n //Are we in Aevum?\\n if (HASBN4) await goToLoc(ns, \\\"Iker Molina Casino\\\")\\n player = await getPlay(ns)\\n /*if (player.location !== \\\"Iker Molina Casino\\\" && player.location !== \\\"Travel Agency\\\") {\\n\\n ns.printf(\\\"You are here: %s\\\", player.location)\\n return\\n }*/\\n\\n let doc = eval(\\\"document\\\");\\n\\n // Step 2 Try to start the coin flip game\\n const coinflip = find(doc, \\\"//button[contains(text(), 'coin flip')]\\\");\\n if (!coinflip) {\\n ns.tprintf(\\\"ERROR: Go to the casino and rerun the script\\\")\\n ns.tprintf(\\\"ERROR: The script must click on entering coinflip\\\")\\n return;\\n }\\n //We have officially started!\\n ns.writePort(10, ns.pid)\\n ns.ui.openTail()\\n ns.printf(\\\"Started. Hold on! Calulating sequence\\\")\\n click(coinflip);\\n // Step 3 Find the buttons\\n const tails = find(doc, \\\"//button[contains(text(), 'Tail!')]\\\");\\n const heads = find(doc, \\\"//button[contains(text(), 'Head!')]\\\");\\n const input = find(doc, \\\"//input[@type='number']\\\");\\n if (!input) {\\n ns.printf('FAIL: Could not get a hold of the bet amount input!');\\n return;\\n }\\n\\n\\n const log = [];\\n input.value = 0;\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) {\\n const event1 = { target: { value: 0 } }\\n const tmp = Object.getOwnPropertyNames(input).filter(p => p.includes(\\\"__reactProps\\\")).pop()\\n const prop = input[tmp]\\n prop.onChange(event1)\\n }\\n\\n // Step 4: Click one of the buttons\\n for (let i = 0; i < 1024; i++) {\\n\\n click(tails);\\n let isTails\\n let isHeads\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) {\\n isTails = find(doc, \\\"//span[text() = 'Tail']\\\");\\n isHeads = find(doc, \\\"//span[text() = 'Head']\\\");\\n }\\n else {\\n isTails = find(doc, \\\"//p[text() = 'T']\\\");\\n isHeads = find(doc, \\\"//p[text() = 'H']\\\");\\n }\\n\\n if (isTails) log.push('T');\\n else if (isHeads) log.push('H');\\n else {\\n ns.printf('FAIL: Something went wrong, aborting sequence!');\\n return;\\n }\\n //if (i % 200 === 0) await ns.sleep(0);\\n await ns.sleep(0)\\n }\\n\\n let loops = 0;\\n input.value = 10000;\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) {\\n const event2 = { target: { value: 10000 } }\\n const tmp = Object.getOwnPropertyNames(input).filter(p => p.includes(\\\"__reactProps\\\")).pop()\\n const prop = input[tmp]\\n prop.onChange(event2)\\n }\\n ns.printf(\\\"You can do something else now.\\\")\\n ns.writePort(ns.pid, 1)\\n await ns.sleep(4)\\n const terminal = [...globalThis[\\\"document\\\"].querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n terminal.filter(e => e.textContent === \\\"Terminal\\\")[0]?.click()\\n //globalThis[\\\"document\\\"].dispatchEvent(new KeyboardEvent(\\\"keydown\\\", { key: \\\"t\\\", altKey: true}))\\n await ns.sleep(4)\\n // Step 5: Execute sequence\\n while (true) {\\n try {\\n if (log[loops % 1024] == 'T') {\\n click(tails);\\n }\\n else if (log[loops % 1024] == 'H') {\\n click(heads);\\n }\\n\\n if (loops % 2000 == 0) {\\n await ns.sleep(4)\\n }\\n loops++;\\n if (ns.getMoneySources().sinceInstall?.casino >= 10_000_000_000) return;\\n }\\n catch (e) {\\n ns.tprint('FAIL: ' + e);\\n return;\\n }\\n }\\n}\\n\\nfunction find(doc, xpath) { return doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; }\\n\\nfunction click(elem) {\\n elem[Object.keys(elem)[1]].onClick({ isTrusted: true });\\n}\""},{"filename":"SphyxOS/cheats/devMenu.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n globalThis.webpackRequire ?? webpackChunkbitburner.push([[-1], {}, w => globalThis.webpackRequire = w]);\\n const skippedModuleIds = new Set(Object.keys(webpackChunkbitburner[0][1]));\\n Object.keys(webpackRequire.m).filter(id => !skippedModuleIds.has(id)).forEach(k => Object.values(webpackRequire(k)).forEach(p => p?.toPage?.('Dev')));\\n}\\n\\n/** @param {NS} ns */\\n/*\\nexport async function main(ns) {\\n globalThis.webpack_require ?? webpackChunkbitburner.push([[-1], {}, w => globalThis.webpack_require = w]);\\n Object.keys(webpack_require.m).forEach(k => Object.values(webpack_require(k)).forEach(p => p?.toPage?.('Dev')));\\n}*/\""},{"filename":"SphyxOS/cheats/notTheDevMenu.jsx","file":"\"/** Dev menu tail UI for Bitburner.\\n * Drop this on home and run it as a JSX script. It uses webpack discovery to\\n * reach the same internal game objects used by the native development menu.\\n */\\n\\nconst BIG = 1e27;\\nconst MAX_FAVOR = 35331;\\nconst VALID_BITNODES = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];\\nconst DEFAULT_PROGRAMS = [\\n \\\"NUKE.exe\\\",\\n \\\"BruteSSH.exe\\\",\\n \\\"FTPCrack.exe\\\",\\n \\\"relaySMTP.exe\\\",\\n \\\"HTTPWorm.exe\\\",\\n \\\"SQLInject.exe\\\",\\n \\\"DeepscanV1.exe\\\",\\n \\\"DeepscanV2.exe\\\",\\n \\\"ServerProfiler.exe\\\",\\n \\\"AutoLink.exe\\\",\\n \\\"Formulas.exe\\\",\\n \\\"b1t_flum3.exe\\\",\\n \\\"fl1ght.exe\\\",\\n \\\"DarkscapeNavigator.exe\\\",\\n \\\"STORM_SEED.exe\\\",\\n];\\nconst DEFAULT_CONTRACT_TYPES = [\\n \\\"Find Largest Prime Factor\\\",\\n \\\"Subarray with Maximum Sum\\\",\\n \\\"Total Ways to Sum\\\",\\n \\\"Total Ways to Sum II\\\",\\n \\\"Spiralize Matrix\\\",\\n \\\"Array Jumping Game\\\",\\n \\\"Array Jumping Game II\\\",\\n \\\"Merge Overlapping Intervals\\\",\\n \\\"Generate IP Addresses\\\",\\n \\\"Algorithmic Stock Trader I\\\",\\n \\\"Algorithmic Stock Trader II\\\",\\n \\\"Algorithmic Stock Trader III\\\",\\n \\\"Algorithmic Stock Trader IV\\\",\\n \\\"Minimum Path Sum in a Triangle\\\",\\n \\\"Unique Paths in a Grid I\\\",\\n \\\"Unique Paths in a Grid II\\\",\\n \\\"Shortest Path in a Grid\\\",\\n \\\"Sanitize Parentheses in Expression\\\",\\n \\\"Find All Valid Math Expressions\\\",\\n \\\"HammingCodes: Integer to Encoded Binary\\\",\\n \\\"HammingCodes: Encoded Binary to Integer\\\",\\n \\\"Proper 2-Coloring of a Graph\\\",\\n \\\"Compression I: RLE Compression\\\",\\n \\\"Compression II: LZ Decompression\\\",\\n \\\"Compression III: LZ Compression\\\",\\n \\\"Encryption I: Caesar Cipher\\\",\\n \\\"Encryption II: Vigenere Cipher\\\",\\n \\\"Square Root\\\",\\n \\\"Total Number of Primes\\\",\\n \\\"Largest Rectangle in a Matrix\\\",\\n];\\nconst DEFAULT_BLADE_SKILLS = [\\n \\\"Blade's Intuition\\\",\\n \\\"Cloak\\\",\\n \\\"Short-Circuit\\\",\\n \\\"Digital Observer\\\",\\n \\\"Tracer\\\",\\n \\\"Overclock\\\",\\n \\\"Reaper\\\",\\n \\\"Evasive System\\\",\\n \\\"Datamancer\\\",\\n \\\"Cyber's Edge\\\",\\n \\\"Hands of Midas\\\",\\n \\\"Hyperdrive\\\",\\n];\\nconst DEFAULT_GANG_FACTIONS = [\\n \\\"Slum Snakes\\\",\\n \\\"Tetrads\\\",\\n \\\"The Syndicate\\\",\\n \\\"The Dark Army\\\",\\n \\\"Speakers for the Dead\\\",\\n \\\"NiteSec\\\",\\n \\\"The Black Hand\\\",\\n];\\nconst DARKNET_SERVER_TYPES = [\\n \\\"RANDOM\\\",\\n \\\"110100100\\\",\\n \\\"2G_cellular\\\",\\n \\\"AccountsManager_4.2\\\",\\n \\\"BellaCuore\\\",\\n \\\"BigMo%od\\\",\\n \\\"CloudBlare(tm)\\\",\\n \\\"DeepGreen\\\",\\n \\\"DeskMemo_3.1\\\",\\n \\\"EuroZone Free\\\",\\n \\\"Factori-Os\\\",\\n \\\"FreshInstall_1.0\\\",\\n \\\"KingOfTheHill\\\",\\n \\\"Laika4\\\",\\n \\\"MathML\\\",\\n \\\"NIL\\\",\\n \\\"OctantVoxel\\\",\\n \\\"OpenWebAccessPoint\\\",\\n \\\"OrdoXenos\\\",\\n \\\"PHP 5.4\\\",\\n \\\"Pr0verFl0\\\",\\n \\\"PrimeTime 2\\\",\\n \\\"RateMyPix.Auth\\\",\\n \\\"TopPass\\\",\\n \\\"ZeroLogon\\\",\\n];\\nconst DARKNET_CONFIG_BY_EXPORT = {\\n getNoPasswordConfig: \\\"ZeroLogon\\\",\\n getDefaultPasswordConfig: \\\"FreshInstall_1.0\\\",\\n getEchoVulnConfig: \\\"DeskMemo_3.1\\\",\\n getSortedEchoVulnConfig: \\\"PHP 5.4\\\",\\n getCaptchaConfig: \\\"CloudBlare(tm)\\\",\\n getDogNameConfig: \\\"Laika4\\\",\\n getGuessNumberConfig: \\\"AccountsManager_4.2\\\",\\n getLargeDictionaryConfig: \\\"TopPass\\\",\\n getEuCountryDictionaryConfig: \\\"EuroZone Free\\\",\\n getYesn_tConfig: \\\"NIL\\\",\\n getRomanNumeralConfig: \\\"BellaCuore\\\",\\n getBufferOverflowConfig: \\\"Pr0verFl0\\\",\\n getMastermindHintConfig: \\\"DeepGreen\\\",\\n getTimingAttackConfig: \\\"2G_cellular\\\",\\n getLargestPrimeFactorConfig: \\\"PrimeTime 2\\\",\\n getBinaryEncodedConfig: \\\"110100100\\\",\\n getSpiceLevelConfig: \\\"RateMyPix.Auth\\\",\\n getConvertToBase10Config: \\\"OctantVoxel\\\",\\n getParseArithmeticExpressionConfig: \\\"MathML\\\",\\n getDivisibilityTestConfig: \\\"Factori-Os\\\",\\n getTripleModuloConfig: \\\"BigMo%od\\\",\\n getKingOfTheHillConfig: \\\"KingOfTheHill\\\",\\n getPacketSnifferConfig: \\\"OpenWebAccessPoint\\\",\\n getXorMaskEncryptedPasswordConfig: \\\"OrdoXenos\\\",\\n};\\nconst DARKNET_FUNC_BY_EXPORT = {\\n serverFactory: \\\"serverFactory\\\",\\n moveDarknetServer: \\\"moveDarknetServer\\\",\\n createDarknetServer: \\\"createDarknetServer\\\",\\n addRandomDarknetServers: \\\"addRandomDarknetServers\\\",\\n moveRandomDarknetServers: \\\"moveRandomDarknetServers\\\",\\n deleteRandomDarknetServers: \\\"deleteRandomDarknetServers\\\",\\n restartAllDarknetServers: \\\"restartAllDarknetServers\\\",\\n balanceDarknetServers: \\\"balanceDarknetServers\\\",\\n validateDarknetNetwork: \\\"validateDarknetNetwork\\\",\\n clearDarknet: \\\"clearDarknet\\\",\\n populateDarknet: \\\"populateDarknet\\\",\\n launchWebstorm: \\\"launchWebstorm\\\",\\n};\\nconst DARKNET_SERVER_GENERATOR_EXPORTS = {\\n K0: \\\"serverFactory\\\",\\n bW: \\\"createDarknetServer\\\",\\n};\\nconst DARKNET_MOVEMENT_EXPORTS = {\\n Sw: \\\"moveDarknetServer\\\",\\n G3: \\\"addRandomDarknetServers\\\",\\n oY: \\\"moveRandomDarknetServers\\\",\\n AP: \\\"deleteRandomDarknetServers\\\",\\n w4: \\\"restartAllDarknetServers\\\",\\n _H: \\\"balanceDarknetServers\\\",\\n wL: \\\"validateDarknetNetwork\\\",\\n};\\nconst DARKNET_NETWORK_GENERATOR_EXPORTS = {\\n vv: \\\"clearDarknet\\\",\\n u9: \\\"populateDarknet\\\",\\n};\\nconst DARKNET_WEBSTORM_EXPORTS = {\\n P: \\\"launchWebstorm\\\",\\n};\\nconst CODING_CONTRACT_GENERATOR_EXPORTS = {\\n generateDummyContract: \\\"generateDummyContract\\\",\\n es: \\\"generateDummyContract\\\",\\n};\\nconst DEFAULT_AUGS = [\\n \\\"NeuroFlux Governor\\\",\\n \\\"The Red Pill\\\",\\n \\\"Stanek's Gift - Genesis\\\",\\n \\\"Stanek's Gift - Awakening\\\",\\n \\\"Stanek's Gift - Serenity\\\",\\n \\\"The Blade's Simulacrum\\\",\\n \\\"The Shadow's Simulacrum\\\",\\n \\\"CashRoot Starter Kit\\\",\\n \\\"SoA - Might of Ares\\\",\\n \\\"The B1ade of Solomonoff\\\",\\n];\\nconst STATS = [\\n [\\\"Hacking\\\", \\\"hacking\\\", \\\"gainHackingExp\\\", \\\"HackingLevelMultiplier\\\"],\\n [\\\"Strength\\\", \\\"strength\\\", \\\"gainStrengthExp\\\", \\\"StrengthLevelMultiplier\\\"],\\n [\\\"Defense\\\", \\\"defense\\\", \\\"gainDefenseExp\\\", \\\"DefenseLevelMultiplier\\\"],\\n [\\\"Dexterity\\\", \\\"dexterity\\\", \\\"gainDexterityExp\\\", \\\"DexterityLevelMultiplier\\\"],\\n [\\\"Agility\\\", \\\"agility\\\", \\\"gainAgilityExp\\\", \\\"AgilityLevelMultiplier\\\"],\\n [\\\"Charisma\\\", \\\"charisma\\\", \\\"gainCharismaExp\\\", \\\"CharismaLevelMultiplier\\\"],\\n [\\\"Intelligence\\\", \\\"intelligence\\\", \\\"gainIntelligenceExp\\\", \\\"IntelligenceLevelMultiplier\\\"],\\n];\\n\\nconst openDB = new Set();\\nconst defaultMenuState = {\\n viewMode: \\\"Mini\\\",\\n selectedRows: [\\\"General\\\"],\\n hiddenRows: [],\\n};\\nconst menuState = {\\n viewMode: defaultMenuState.viewMode,\\n selectedRows: [...defaultMenuState.selectedRows],\\n hiddenRows: [...defaultMenuState.hiddenRows],\\n};\\n\\n/** @param {NS} api */\\nexport async function main(api) {\\n let startup = cacheStartupApi(api);\\n startup.disableLog(\\\"ALL\\\");\\n startup.clearLog();\\n startup.openTail();\\n startup.setTailTitle(\\\"SphyxOS Dev Menu\\\");\\n startup.resizeTail(860, 720);\\n\\n const React = getReactLib();\\n if (!React) {\\n startup.print(\\\"React runtime was not available. Open a tail and run this after the game UI has loaded.\\\");\\n startup = null;\\n return;\\n }\\n exposeInternalGameObjects();\\n startup.printRaw( );\\n startup = null;\\n}\\n\\nfunction cacheStartupApi(api) {\\n const noop = () => undefined;\\n const bind = (target, name) => typeof target?.[name] === \\\"function\\\" ? target[name].bind(target) : noop;\\n const ui = api?.ui;\\n return {\\n disableLog: bind(api, \\\"disableLog\\\"),\\n clearLog: bind(api, \\\"clearLog\\\"),\\n openTail: bind(ui, \\\"openTail\\\"),\\n setTailTitle: bind(ui, \\\"setTailTitle\\\"),\\n resizeTail: bind(ui, \\\"resizeTail\\\"),\\n print: bind(api, \\\"print\\\"),\\n printRaw: bind(api, \\\"printRaw\\\"),\\n };\\n}\\n\\nfunction getReactLib() {\\n return globalThis.React ?? globalThis[\\\"window\\\"]?.React;\\n}\\n\\nfunction safeFunctionSource(value) {\\n if (typeof value !== \\\"function\\\") return \\\"\\\";\\n try {\\n return Function.prototype.toString.call(value);\\n } catch { }\\n try {\\n return String(value);\\n } catch {\\n return \\\"\\\";\\n }\\n}\\n\\nfunction exposeWebpackRequire() {\\n if (globalThis.webpackRequire) return;\\n if (!globalThis.webpackChunkbitburner?.push) return;\\n globalThis.webpackChunkbitburner.push([[-1], {}, (webpackRequire) => (globalThis.webpackRequire = webpackRequire)]);\\n}\\n\\nfunction getSkippedWebpackModuleIds() {\\n try {\\n return new Set(Object.keys(globalThis.webpackChunkbitburner?.[0]?.[1] ?? {}));\\n } catch {\\n return new Set();\\n }\\n}\\n\\nfunction looksLikeUnmaskedFunction(value, text) {\\n return safeFunctionSource(value).includes(text);\\n}\\n\\nfunction exposeInternalGameObjects(force = false) {\\n if (!globalThis.webpackChunkbitburner) return;\\n exposeWebpackRequire();\\n if (!globalThis.webpackRequire?.m) return;\\n if (globalThis.__devMenuTestBridge && !force) return;\\n globalThis.__devMenuTestBridge = discoverGameObjects(force);\\n}\\n\\nfunction discoverGameObjects(force = false) {\\n if (globalThis.__devMenuTestBridge && !force) return globalThis.__devMenuTestBridge;\\n exposeWebpackRequire();\\n const bridge = {\\n modules: [],\\n Player: globalThis.Bitburner?.Player,\\n Factions: globalThis.Bitburner?.Factions,\\n Companies: globalThis.Bitburner?.Companies,\\n Router: globalThis.Router,\\n GetServer: globalThis.GetServer,\\n GetAllServers: globalThis.Bitburner?.GetAllServers,\\n Engine: undefined,\\n currentNodeMults: undefined,\\n achievements: undefined,\\n Augmentations: undefined,\\n StockMarket: undefined,\\n staneksGift: undefined,\\n DarknetState: undefined,\\n DarknetEvents: undefined,\\n SnackbarEvents: undefined,\\n funcs: {},\\n enums: {},\\n darknetConfigBuilders: {},\\n errors: [],\\n };\\n const req = globalThis.webpackRequire;\\n if (!req?.m) {\\n globalThis.__devMenuTestBridge = bridge;\\n return bridge;\\n }\\n\\n const skippedModuleIds = getSkippedWebpackModuleIds();\\n for (const moduleId of Object.keys(req.m).filter((id) => !skippedModuleIds.has(id))) {\\n let module;\\n try {\\n module = req(moduleId);\\n } catch (error) {\\n bridge.errors.push(String(error?.message ?? error));\\n continue;\\n }\\n if (!module) continue;\\n bridge.modules.push(module);\\n const exportedEntries = [[\\\"__module\\\", module], ...objectEntries(module)];\\n\\n for (const [exportName, value] of exportedEntries) {\\n try {\\n if (!value) continue;\\n if (!bridge.Router && value.page && value.toPage) bridge.Router = value;\\n if (!bridge.Player && isPlayerObject(value)) bridge.Player = value;\\n if (!bridge.Factions && isFactionsObject(value)) bridge.Factions = value;\\n if (!bridge.Companies && isCompaniesObject(value)) bridge.Companies = value;\\n if (!bridge.Engine && isEngineObject(value)) bridge.Engine = value;\\n if (!bridge.currentNodeMults && isNodeMultObject(value)) bridge.currentNodeMults = value;\\n if (!bridge.achievements && isAchievementsObject(value)) bridge.achievements = value;\\n if (!bridge.Augmentations && (exportName === \\\"Augmentations\\\" || isAugmentationsObject(value))) bridge.Augmentations = value;\\n if (!bridge.StockMarket && isStockMarketObject(value)) bridge.StockMarket = value;\\n if (!bridge.staneksGift && isStanekObject(value)) bridge.staneksGift = value;\\n if (!bridge.DarknetState && isDarknetState(value)) bridge.DarknetState = value;\\n if (!bridge.DarknetEvents && value?.emit && value?.subscribe && value?.unsubscribe) bridge.DarknetEvents = value;\\n if (!bridge.SnackbarEvents && exportName === \\\"SnackbarEvents\\\" && isEventEmitterObject(value)) bridge.SnackbarEvents = value;\\n\\n if (typeof value === \\\"object\\\") {\\n if (!bridge.enums.AugmentationName && enumHas(value, [\\\"NeuroFlux Governor\\\", \\\"The Red Pill\\\"])) bridge.enums.AugmentationName = value;\\n if (!bridge.enums.CompletedProgramName && enumHas(value, [\\\"NUKE.exe\\\", \\\"BruteSSH.exe\\\", \\\"Formulas.exe\\\"])) bridge.enums.CompletedProgramName = value;\\n if (!bridge.enums.CodingContractName && enumHas(value, [\\\"Find Largest Prime Factor\\\", \\\"Total Ways to Sum\\\"])) bridge.enums.CodingContractName = value;\\n if (!bridge.enums.BladeburnerSkillName && enumHas(value, [\\\"Blade's Intuition\\\", \\\"Hyperdrive\\\"])) bridge.enums.BladeburnerSkillName = value;\\n }\\n\\n if (looksLikeUnmaskedFunction(value, \\\"Trying to add a server with an existing\\\")) {\\n for (const [innerName, inner] of objectEntries(module)) {\\n if (looksLikeUnmaskedFunction(inner, \\\"?? null\\\") || looksLikeUnmaskedFunction(inner, \\\"??null\\\")) {\\n bridge.GetServer = inner;\\n globalThis.GetServer = inner;\\n }\\n if (innerName === \\\"GetAllServers\\\" || innerName === \\\"US\\\" || isLikelyGetAllServers(inner)) {\\n bridge.GetAllServers = inner;\\n }\\n }\\n }\\n if (typeof value === \\\"function\\\") classifyFunction(bridge, value, exportName);\\n } catch (error) {\\n bridge.errors.push(\\\"Skipped webpack export \\\" + moduleId + \\\": \\\" + String(error?.message ?? error));\\n }\\n }\\n classifyDarknetModule(bridge, module);\\n classifyCodingContractModule(bridge, module);\\n classifySnackbarModule(bridge, module);\\n }\\n if (bridge.Router) globalThis.Router = bridge.Router;\\n globalThis.__devMenuTestBridge = bridge;\\n return bridge;\\n}\\n\\nfunction classifyFunction(bridge, fn, exportName = \\\"\\\") {\\n const code = safeFunctionSource(fn);\\n if (!code) return;\\n const add = (name) => {\\n setBridgeFunc(bridge, name, fn);\\n };\\n const mappedFunc = DARKNET_FUNC_BY_EXPORT[exportName];\\n if (mappedFunc) add(mappedFunc);\\n if ([\\n \\\"serverFactory\\\",\\n \\\"moveDarknetServer\\\",\\n \\\"createDarknetServer\\\",\\n \\\"addRandomDarknetServers\\\",\\n \\\"moveRandomDarknetServers\\\",\\n \\\"deleteRandomDarknetServers\\\",\\n \\\"restartAllDarknetServers\\\",\\n \\\"balanceDarknetServers\\\",\\n \\\"validateDarknetNetwork\\\",\\n \\\"clearDarknet\\\",\\n \\\"populateDarknet\\\",\\n \\\"launchWebstorm\\\",\\n ].includes(exportName)) add(exportName);\\n const exportMappedType = DARKNET_CONFIG_BY_EXPORT[exportName];\\n if (exportMappedType) bridge.darknetConfigBuilders[exportMappedType] = fn;\\n if (!bridge.funcs.serverFactory && isLikelyDarknetServerFactory(fn)) add(\\\"serverFactory\\\");\\n if (!bridge.funcs.createDarknetServer && isLikelyCreateDarknetServer(fn, code)) add(\\\"createDarknetServer\\\");\\n if (!bridge.funcs.addRandomDarknetServers && isLikelyAddRandomDarknetServers(fn)) add(\\\"addRandomDarknetServers\\\");\\n if (!bridge.funcs.clearDarknet && isLikelyClearDarknet(fn)) add(\\\"clearDarknet\\\");\\n if (!bridge.funcs.populateDarknet && isLikelyPopulateDarknet(fn)) add(\\\"populateDarknet\\\");\\n for (const type of DARKNET_SERVER_TYPES) {\\n if (type !== \\\"RANDOM\\\" && isCallableHelper(fn) && code.includes(type) && (code.includes(\\\"staticPasswordHint\\\") || code.includes(\\\"passwordHintData\\\") || code.includes(\\\"modelId\\\"))) {\\n bridge.darknetConfigBuilders[type] = fn;\\n }\\n }\\n if (code.includes(\\\"Congruity Implant\\\") || (code.includes(\\\"staticAugmentation\\\") && code.includes(\\\"mergeMultipliers\\\"))) add(\\\"applyAugmentation\\\");\\n if (code.includes(\\\"sourceFileLvl(10)\\\") && code.includes(\\\"sleevesFromCovenant\\\") && code.includes(\\\"new \\\")) add(\\\"recalculateSleeves\\\");\\n if (code.includes(\\\"checkForMessagesToSend\\\") || (code.includes(\\\"Message\\\") && code.includes(\\\"Red Pill\\\"))) add(\\\"checkMessages\\\");\\n if (code.includes(\\\"DarkscapeNavigator.exe\\\") && code.includes(\\\"populateDarknet\\\")) add(\\\"getDarkscapeNavigator\\\");\\n if (isLikelyClearDarknet(fn)) add(\\\"clearDarknet\\\");\\n if (isLikelyPopulateDarknet(fn)) add(\\\"populateDarknet\\\");\\n if (code.includes(\\\"leftOffset\\\") && code.includes(\\\"difficulty\\\") && code.includes(\\\"depth\\\") && code.includes(\\\"DnetServerBuilder\\\")) add(\\\"serverFactory\\\");\\n if (code.includes(\\\"Something is trying to move darkweb\\\") && code.includes(\\\"getAllOpenPositions\\\")) add(\\\"moveDarknetServer\\\");\\n if (code.includes(\\\"MAX_PASSWORD_LENGTH\\\") && code.includes(\\\"serverFactory\\\")) add(\\\"createDarknetServer\\\");\\n if (code.includes(\\\"getAllMovableDarknetServers\\\") && code.includes(\\\"moveDarknetServer\\\") && code.includes(\\\"Math.random\\\")) add(\\\"moveRandomDarknetServers\\\");\\n if (code.includes(\\\"createDarknetServer\\\") && code.includes(\\\"moveDarknetServer\\\") && code.includes(\\\"getNetDepth\\\")) add(\\\"addRandomDarknetServers\\\");\\n if (code.includes(\\\"gainCharismaExp\\\") && code.includes(\\\"addSessionToServer\\\") && code.includes(\\\"hasAdminRights\\\")) add(\\\"handleSuccessfulAuth\\\");\\n if (code.includes(\\\"Created\\\") && code.includes(\\\"darknet\\\") && code.includes(\\\"moveDarknetServer\\\")) add(\\\"createDarknetServer\\\");\\n if (code.includes(\\\"Server restarted.\\\") && code.includes(\\\"authenticatedPIDs\\\")) add(\\\"restartDarknetServer\\\");\\n if (code.includes(\\\"violent\\\") && code.includes(\\\"webstorm\\\")) add(\\\"launchWebstorm\\\");\\n if (code.includes(\\\"DARKNET WEBSTORM APPROACHING\\\")) add(\\\"launchWebstorm\\\");\\n if (exportName === \\\"generateDummyContract\\\") add(\\\"generateDummyContract\\\");\\n if (isLikelyGenerateDummyContract(fn)) add(\\\"generateDummyContract\\\");\\n}\\n\\nfunction classifyDarknetModule(bridge, module) {\\n const entries = objectEntries(module).filter(([, value]) => typeof value === \\\"function\\\");\\n if (!entries.length) return;\\n const moduleCode = entries.map(([, fn]) => safeFunctionSource(fn)).join(\\\"\\\\n\\\");\\n\\n if (moduleCode.includes(\\\"staticPasswordHint\\\") && (moduleCode.includes(\\\"The password is\\\") || moduleCode.includes(\\\"passwordHintData\\\"))) {\\n for (const [exportName, fn] of entries) {\\n const mapped = DARKNET_SERVER_GENERATOR_EXPORTS[exportName];\\n if (mapped) setBridgeFunc(bridge, mapped, fn);\\n if (!bridge.funcs.serverFactory && isLikelyDarknetServerFactory(fn)) setBridgeFunc(bridge, \\\"serverFactory\\\", fn);\\n if (!bridge.funcs.createDarknetServer && isLikelyCreateDarknetServer(fn, moduleCode)) setBridgeFunc(bridge, \\\"createDarknetServer\\\", fn);\\n const config = previewDarknetConfig(fn);\\n if (config?.modelId && isCallableHelper(fn) && DARKNET_SERVER_TYPES.includes(config.modelId)) bridge.darknetConfigBuilders[config.modelId] = fn;\\n }\\n }\\n\\n if (moduleCode.includes(\\\"Something is trying to move darkweb\\\")) {\\n for (const [exportName, fn] of entries) {\\n const code = safeFunctionSource(fn);\\n const mapped = DARKNET_MOVEMENT_EXPORTS[exportName];\\n if (mapped) setBridgeFunc(bridge, mapped, fn);\\n if (!bridge.funcs.moveDarknetServer && code.includes(\\\"Something is trying to move darkweb\\\")) setBridgeFunc(bridge, \\\"moveDarknetServer\\\", fn);\\n if (!bridge.funcs.addRandomDarknetServers && isLikelyAddRandomDarknetServers(fn)) setBridgeFunc(bridge, \\\"addRandomDarknetServers\\\", fn);\\n if (!bridge.funcs.restartDarknetServer && code.includes(\\\"Server restarted.\\\")) setBridgeFunc(bridge, \\\"restartDarknetServer\\\", fn);\\n }\\n }\\n\\n if (moduleCode.includes(\\\"migrationInductionServers\\\") || moduleCode.includes(\\\"Invalid darknet server instance detected\\\")) {\\n for (const [exportName, fn] of entries) {\\n const mapped = DARKNET_NETWORK_GENERATOR_EXPORTS[exportName];\\n if (mapped) setBridgeFunc(bridge, mapped, fn);\\n if (!bridge.funcs.clearDarknet && isLikelyClearDarknet(fn)) setBridgeFunc(bridge, \\\"clearDarknet\\\", fn);\\n if (!bridge.funcs.populateDarknet && isLikelyPopulateDarknet(fn)) setBridgeFunc(bridge, \\\"populateDarknet\\\", fn);\\n }\\n }\\n\\n if (moduleCode.includes(\\\"DARKNET WEBSTORM APPROACHING\\\")) {\\n for (const [exportName, fn] of entries) {\\n const code = safeFunctionSource(fn);\\n const mapped = DARKNET_WEBSTORM_EXPORTS[exportName];\\n if (mapped) setBridgeFunc(bridge, mapped, fn);\\n if (!bridge.funcs.launchWebstorm && code.includes(\\\"DARKNET WEBSTORM APPROACHING\\\")) setBridgeFunc(bridge, \\\"launchWebstorm\\\", fn);\\n }\\n }\\n}\\n\\nfunction classifyCodingContractModule(bridge, module) {\\n const entries = objectEntries(module).filter(([, value]) => typeof value === \\\"function\\\");\\n if (!entries.length) return;\\n const moduleCode = entries.map(([, fn]) => safeFunctionSource(fn)).join(\\\"\\\\n\\\");\\n if (!moduleCode.includes(\\\"Invalid problem type\\\") || !moduleCode.includes(\\\"contract-\\\") || !moduleCode.includes(\\\"rewardScaling\\\")) return;\\n for (const [exportName, fn] of entries) {\\n const mapped = CODING_CONTRACT_GENERATOR_EXPORTS[exportName];\\n if (mapped) setBridgeFunc(bridge, mapped, fn);\\n if (!bridge.funcs.generateDummyContract && isLikelyGenerateDummyContract(fn)) setBridgeFunc(bridge, \\\"generateDummyContract\\\", fn);\\n }\\n}\\n\\nfunction classifySnackbarModule(bridge, module) {\\n if (bridge.SnackbarEvents) return;\\n const entries = objectEntries(module);\\n const moduleCode = entries\\n .filter(([, value]) => typeof value === \\\"function\\\")\\n .map(([, fn]) => safeFunctionSource(fn))\\n .join(\\\"\\\\n\\\");\\n if (!moduleCode.includes(\\\"enqueueSnackbar\\\") || !moduleCode.includes(\\\"autoHideDuration\\\")) return;\\n for (const [, value] of entries) {\\n if (isEventEmitterObject(value)) {\\n bridge.SnackbarEvents = value;\\n return;\\n }\\n }\\n}\\n\\nfunction setBridgeFunc(bridge, name, fn) {\\n if (!bridge.funcs[name] && isCallableHelper(fn)) bridge.funcs[name] = fn;\\n}\\n\\nfunction isCallableHelper(fn) {\\n if (typeof fn !== \\\"function\\\") return false;\\n return !safeFunctionSource(fn).trimStart().startsWith(\\\"class \\\");\\n}\\n\\nfunction isEventEmitterObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.emit === \\\"function\\\"\\n && typeof value.subscribe === \\\"function\\\";\\n}\\n\\nfunction compactSource(source) {\\n return String(source ?? \\\"\\\").replace(/\\\\s+/g, \\\"\\\");\\n}\\n\\nfunction isLikelyDarknetServerFactory(fn) {\\n const code = safeFunctionSource(fn);\\n return isCallableHelper(fn)\\n && fn.length >= 4\\n && code.includes(\\\"difficulty\\\")\\n && code.includes(\\\"depth\\\")\\n && code.includes(\\\"leftOffset\\\");\\n}\\n\\nfunction isLikelyCreateDarknetServer(fn, moduleCode) {\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n const compactModule = compactSource(moduleCode);\\n return isCallableHelper(fn)\\n && fn.length === 3\\n && (moduleCode.includes(\\\"staticPasswordHint\\\") || compactModule.includes(\\\"staticPasswordHint\\\") || compactCode.includes(\\\"-1,-1\\\"))\\n && (code.includes(\\\"Math.random\\\") || compactCode.includes(\\\"-1,-1\\\"))\\n && !code.includes(\\\"Something is trying to move darkweb\\\");\\n}\\n\\nfunction isLikelyAddRandomDarknetServers(fn) {\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n return isCallableHelper(fn)\\n && compactCode.includes(\\\"-1,-1\\\")\\n && code.includes(\\\"Math.random\\\")\\n && !code.includes(\\\"Something is trying to move darkweb\\\");\\n}\\n\\nfunction isLikelyClearDarknet(fn) {\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n return isCallableHelper(fn)\\n && (\\n (code.includes(\\\"stockPromotions\\\") && code.includes(\\\"migrationInductionServers\\\"))\\n || (compactCode.includes(\\\"zoomIndex=7\\\") && compactCode.includes(\\\"netViewLeftScroll=0\\\") && compactCode.includes(\\\"netViewTopScroll=0\\\"))\\n );\\n}\\n\\nfunction isLikelyPopulateDarknet(fn) {\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n return isCallableHelper(fn)\\n && compactCode.includes(\\\"Network[0].length\\\")\\n && compactCode.includes(\\\"Network[1].length\\\")\\n && (code.includes(\\\"Math.random\\\") || compactCode.includes(\\\"Math.random\\\"));\\n}\\n\\nfunction isLikelyGetAllServers(fn) {\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n return isCallableHelper(fn)\\n && compactCode.includes(\\\".entries())\\\")\\n && compactCode.includes(\\\"push(\\\")\\n && compactCode.includes(\\\"instanceof\\\");\\n}\\n\\nfunction isLikelyGenerateDummyContract(fn) {\\n const code = safeFunctionSource(fn);\\n return isCallableHelper(fn)\\n && code.includes(\\\"Invalid problem type\\\")\\n && code.includes(\\\"addContract\\\")\\n && code.includes(\\\"null\\\");\\n}\\n\\nfunction previewDarknetConfig(fn) {\\n if (!isCallableHelper(fn) || fn.length > 1) return null;\\n const code = safeFunctionSource(fn);\\n const compactCode = compactSource(code);\\n if (!isLikelyDarknetConfigBuilderSource(code, compactCode)) return null;\\n try {\\n const result = fn(3);\\n if (!result || typeof result !== \\\"object\\\") return null;\\n if (typeof result.modelId !== \\\"string\\\" || typeof result.password !== \\\"string\\\" || typeof result.staticPasswordHint !== \\\"string\\\") return null;\\n return result;\\n } catch {\\n return null;\\n }\\n}\\n\\nfunction isLikelyDarknetConfigBuilderSource(code, compactCode = compactSource(code)) {\\n return compactCode.includes(\\\"return{\\\")\\n && compactCode.includes(\\\"modelId:\\\")\\n && compactCode.includes(\\\"password:\\\")\\n && compactCode.includes(\\\"staticPasswordHint:\\\")\\n && !compactCode.includes(\\\"-1,-1\\\")\\n && !code.includes(\\\"PasswordResponse\\\")\\n && !code.includes(\\\"console.error\\\")\\n && !code.includes(\\\"TypeAssertion\\\")\\n && !code.includes(\\\"AddToAllServers\\\")\\n && !code.includes(\\\"Something is trying\\\");\\n}\\n\\nfunction enumHas(object, values) {\\n const all = Object.values(object);\\n return values.every((value) => all.includes(value));\\n}\\n\\nfunction isPlayerObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.gainMoney === \\\"function\\\"\\n && typeof value.getHomeComputer === \\\"function\\\"\\n && typeof value.updateSkillLevels === \\\"function\\\"\\n && \\\"queuedAugmentations\\\" in value\\n && \\\"sourceFiles\\\" in value;\\n}\\n\\nfunction isFactionsObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && isFactionRecordObject(value.Illuminati);\\n}\\n\\nfunction isCompaniesObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && isCompanyRecordObject(value.ECorp);\\n}\\n\\nfunction isFactionRecordObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.name === \\\"string\\\"\\n && typeof value.setFavor === \\\"function\\\"\\n && Array.isArray(value.augmentations)\\n && \\\"playerReputation\\\" in value\\n && \\\"discovery\\\" in value\\n && \\\"alreadyInvited\\\" in value\\n && !(\\\"companyPositions\\\" in value);\\n}\\n\\nfunction isCompanyRecordObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.name === \\\"string\\\"\\n && typeof value.setFavor === \\\"function\\\"\\n && \\\"playerReputation\\\" in value\\n && \\\"companyPositions\\\" in value\\n && typeof value.hasPosition === \\\"function\\\"\\n && \\\"salaryMultiplier\\\" in value\\n && \\\"expMultiplier\\\" in value\\n && \\\"jobStatReqOffset\\\" in value;\\n}\\n\\nfunction isEngineObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.updateGame === \\\"function\\\"\\n && value.Counters\\n && \\\"achievementsCounter\\\" in value.Counters\\n && \\\"_lastUpdate\\\" in value;\\n}\\n\\nfunction isNodeMultObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && \\\"HackingLevelMultiplier\\\" in value\\n && \\\"StrengthLevelMultiplier\\\" in value\\n && \\\"WorldDaemonDifficulty\\\" in value;\\n}\\n\\nfunction isAchievementsObject(value) {\\n if (!value || typeof value !== \\\"object\\\") return false;\\n const items = Object.values(value);\\n return items.length > 25 && items.some((item) => item?.ID && item?.Name && item?.Description);\\n}\\n\\nfunction isAugmentationsObject(value) {\\n if (!value || typeof value !== \\\"object\\\") return false;\\n const items = objectValues(value).filter(isAugmentationObject);\\n return items.length > 50 && items.some((item) => item.name === \\\"Wired Reflexes\\\") && items.some((item) => item.name === \\\"NeuroFlux Governor\\\");\\n}\\n\\nfunction isAugmentationObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && typeof value.name === \\\"string\\\"\\n && value.mults\\n && typeof value.mults === \\\"object\\\"\\n && Array.isArray(value.prereqs)\\n && \\\"isSpecial\\\" in value\\n && \\\"baseCost\\\" in value;\\n}\\n\\nfunction isStockMarketObject(value) {\\n if (!value || typeof value !== \\\"object\\\") return false;\\n const stocks = Object.values(value).filter((stock) => stock && typeof stock === \\\"object\\\" && \\\"symbol\\\" in stock && \\\"price\\\" in stock && \\\"cap\\\" in stock);\\n return stocks.length > 10;\\n}\\n\\nfunction isStanekObject(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && \\\"storedCycles\\\" in value\\n && value.fragments\\n && typeof value.fragments.forEach === \\\"function\\\";\\n}\\n\\nfunction isDarknetState(value) {\\n return !!value\\n && typeof value === \\\"object\\\"\\n && Array.isArray(value.Network)\\n && \\\"showFullNetwork\\\" in value\\n && \\\"storedCycles\\\" in value;\\n}\\n\\nfunction safeNumber(value, fallback = 0) {\\n const number = Number(value);\\n return Number.isFinite(number) ? number : fallback;\\n}\\n\\nfunction formatNumber(value, digits = 2) {\\n if (value === Infinity) return \\\"Infinity\\\";\\n if (value === -Infinity) return \\\"-Infinity\\\";\\n if (!Number.isFinite(Number(value))) return String(value);\\n const abs = Math.abs(value);\\n if (abs >= 1e15) return (value / 1e15).toFixed(digits) + \\\"q\\\";\\n if (abs >= 1e12) return (value / 1e12).toFixed(digits) + \\\"t\\\";\\n if (abs >= 1e9) return (value / 1e9).toFixed(digits) + \\\"b\\\";\\n if (abs >= 1e6) return (value / 1e6).toFixed(digits) + \\\"m\\\";\\n if (abs >= 1e3) return (value / 1e3).toFixed(digits) + \\\"k\\\";\\n return Number(value).toFixed(abs >= 10 ? 0 : digits);\\n}\\n\\nfunction formatMoney(value) {\\n return \\\"$\\\" + formatNumber(value);\\n}\\n\\nfunction formatRam(gb) {\\n if (!Number.isFinite(gb)) return String(gb);\\n if (gb >= 1073741824) return formatNumber(gb / 1073741824) + \\\"EB\\\";\\n if (gb >= 1048576) return formatNumber(gb / 1048576) + \\\"PB\\\";\\n if (gb >= 1024) return formatNumber(gb / 1024) + \\\"TB\\\";\\n return formatNumber(gb) + \\\"GB\\\";\\n}\\n\\nfunction notify(text, variant = \\\"info\\\") {\\n try {\\n let bridge = globalThis.__devMenuTestBridge ?? discoverGameObjects();\\n if (!bridge?.SnackbarEvents) bridge = discoverGameObjects(true);\\n bridge?.SnackbarEvents?.emit?.(String(text), variant, 2500);\\n } catch { }\\n}\\n\\nfunction getHome(player) {\\n try {\\n return player?.getHomeComputer?.();\\n } catch {\\n return undefined;\\n }\\n}\\nfunction normalizeSourceFiles(resetInfo) {\\n const ownedSF = resetInfo?.ownedSF;\\n if (ownedSF instanceof Map) return [...ownedSF.entries()].map(([n, lvl]) => ({ n, lvl }));\\n return [];\\n}\\n\\nfunction getResetInfoFromPlayer(player) {\\n const bitNodeOptions = player?.bitNodeOptions ?? {};\\n const activeSourceFiles = player?.activeSourceFiles instanceof Map\\n ? player.activeSourceFiles\\n : player?.sourceFiles instanceof Map ? player.sourceFiles : new Map();\\n return {\\n lastAugReset: player?.lastAugReset ?? 0,\\n lastNodeReset: player?.lastNodeReset ?? 0,\\n currentNode: player?.bitNodeN ?? 1,\\n ownedAugs: new Map((player?.augmentations ?? []).map((aug) => [aug.name, aug.level])),\\n ownedSF: new Map([...activeSourceFiles].filter(([, activeLevel]) => activeLevel > 0)),\\n bitNodeOptions: {\\n ...bitNodeOptions,\\n sourceFileOverrides: new Map(bitNodeOptions.sourceFileOverrides ?? []),\\n },\\n };\\n}\\nfunction hasBN(resetInfo, sourceFiles, bn, sfLvl = 1) {\\n if (bn === true && sfLvl === true) return true;\\n if (bn === false && sfLvl === false) return false;\\n if (resetInfo?.currentNode === bn) return true;\\n for (const sf of sourceFiles ?? []) if (sf.n === bn && sf.lvl >= sfLvl) return true;\\n return false;\\n}\\n\\nfunction sourceFileLevel(player, sourceFiles, n) {\\n if (typeof player?.sourceFileLvl === \\\"function\\\") return player.sourceFileLvl(n);\\n const sf = (sourceFiles ?? []).find((item) => item.n === n);\\n return sf?.lvl ?? 0;\\n}\\n\\nfunction rowUnlocked(row, snapshot) {\\n if (typeof row.gate === \\\"function\\\") return !!row.gate(snapshot);\\n if (row.bn === true && row.lvl === true) return true;\\n if (row.bn === 6) return hasBN(snapshot.resetInfo, snapshot.sourceFiles, 6, row.lvl) || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 7, row.lvl);\\n return hasBN(snapshot.resetInfo, snapshot.sourceFiles, row.bn, row.lvl);\\n}\\n\\nfunction getAllServers(game) {\\n if (typeof game.GetAllServers === \\\"function\\\") {\\n const all = game.GetAllServers(true);\\n if (Array.isArray(all) && all.length) return all;\\n }\\n const getSvr = game.GetServer;\\n if (typeof getSvr !== \\\"function\\\") return [];\\n const seen = new Set();\\n const servers = [];\\n const queue = [\\\"home\\\", \\\"darkweb\\\", \\\"w0r1d_d43m0n\\\"];\\n while (queue.length) {\\n const hostname = queue.shift();\\n if (!hostname || seen.has(hostname)) continue;\\n seen.add(hostname);\\n let server;\\n try {\\n server = getSvr(hostname);\\n } catch {\\n server = null;\\n }\\n if (!server) continue;\\n servers.push(server);\\n for (const next of server.serversOnNetwork ?? []) if (!seen.has(next)) queue.push(next);\\n }\\n return servers;\\n}\\n\\nfunction objectValues(record) {\\n try {\\n return record && (typeof record === \\\"object\\\" || typeof record === \\\"function\\\") ? Object.values(record) : [];\\n } catch {\\n return [];\\n }\\n}\\n\\nfunction objectEntries(record) {\\n try {\\n return record && (typeof record === \\\"object\\\" || typeof record === \\\"function\\\") ? Object.entries(record) : [];\\n } catch {\\n return [];\\n }\\n}\\n\\nfunction pushProgram(home, name) {\\n if (!home || !name) return;\\n if (home.pushProgram) {\\n home.pushProgram(name);\\n return;\\n }\\n home.programs ??= [];\\n if (!home.programs.includes(name)) home.programs.push(name);\\n}\\n\\nfunction uniqueSorted(values) {\\n return [...new Set(values.filter((value) => value !== undefined && value !== null && value !== \\\"\\\"))].sort((a, b) => String(a).localeCompare(String(b)));\\n}\\n\\nfunction getAugmentations(game) {\\n const enumAugs = objectValues(game.enums?.AugmentationName);\\n const factionAugs = getFactionObjects(game).flatMap((faction) => faction?.augmentations ?? []);\\n const augObjects = getAugmentationObjects(game).map((aug) => aug.name);\\n return uniqueSorted([...enumAugs, ...factionAugs, ...augObjects, ...DEFAULT_AUGS]);\\n}\\n\\nfunction getPrograms(game) {\\n return uniqueSorted([...objectValues(game.enums?.CompletedProgramName), ...DEFAULT_PROGRAMS]);\\n}\\n\\nfunction getContractTypes(game) {\\n return uniqueSorted([...objectValues(game.enums?.CodingContractName), ...DEFAULT_CONTRACT_TYPES]);\\n}\\n\\nfunction getBladeSkills(game) {\\n return uniqueSorted([...objectValues(game.enums?.BladeburnerSkillName), ...DEFAULT_BLADE_SKILLS]);\\n}\\n\\nfunction getAugmentationObjects(game) {\\n return objectValues(game.Augmentations).filter(isAugmentationObject);\\n}\\n\\nfunction getStocks(game) {\\n return objectValues(game.StockMarket).filter((stock) => stock && typeof stock === \\\"object\\\" && \\\"symbol\\\" in stock && \\\"price\\\" in stock);\\n}\\n\\nfunction getFactionObjects(game) {\\n return objectValues(game.Factions).filter(isFactionRecordObject);\\n}\\n\\nfunction getCompanyObjects(game) {\\n return objectValues(game.Companies).filter(isCompanyRecordObject);\\n}\\n\\nfunction currentBN(resetInfo, sourceFiles) {\\n const n = resetInfo?.currentNode ?? \\\"?\\\";\\n const level = sourceFiles?.find((sf) => sf.n === n)?.lvl ?? 0;\\n return \\\"BN\\\" + n + (level ? \\\" / SF\\\" + n + \\\".\\\" + level : \\\"\\\");\\n}\\n\\nasync function buildSnapshot() {\\n exposeInternalGameObjects();\\n const game = discoverGameObjects();\\n const player = game.Player;\\n const resetInfo = getResetInfoFromPlayer(player);\\n const sourceFiles = normalizeSourceFiles(resetInfo);\\n const servers = getAllServers(game);\\n const home = getHome(player);\\n const factionObjects = getFactionObjects(game);\\n const companyObjects = getCompanyObjects(game);\\n const factions = uniqueSorted(factionObjects.map((faction) => faction?.name));\\n const companies = uniqueSorted(companyObjects.map((company) => company?.name));\\n const stockSymbols = getStocks(game).map((stock) => stock.symbol).sort();\\n return {\\n game,\\n player,\\n home,\\n resetInfo,\\n sourceFiles,\\n servers,\\n factionObjects,\\n companyObjects,\\n serverNames: servers.map((server) => server.hostname).sort(),\\n factions,\\n companies,\\n programs: getPrograms(game),\\n augmentations: getAugmentations(game),\\n contractTypes: getContractTypes(game),\\n bladeSkills: getBladeSkills(game),\\n stockSymbols,\\n hasBridge: !!player,\\n bnLabel: currentBN(resetInfo, sourceFiles),\\n hasStockMarket: !!player[\\\"hasWseAccount\\\"] || !!player[\\\"hasTixApiAccess\\\"] || !!player[\\\"has4SData\\\"] || !!player[\\\"has4SDataTixApi\\\"] || resetInfo?.currentNode === 8 || hasBN(resetInfo, sourceFiles, 8),\\n hasStanek: hasOwnedOrQueuedAug(player, \\\"Stanek's Gift - Genesis\\\") || hasOwnedOrQueuedAug(player, \\\"Stanek's Gift - Awakening\\\") || hasOwnedOrQueuedAug(player, \\\"Stanek's Gift - Serenity\\\"),\\n hasDarknet: home?.programs?.includes(\\\"DarkscapeNavigator.exe\\\") || resetInfo?.currentNode === 15 || hasBN(resetInfo, sourceFiles, 15),\\n };\\n}\\n\\nfunction hasOwnedOrQueuedAug(player, name) {\\n return !!player?.augmentations?.some((aug) => aug.name === name)\\n || !!player?.queuedAugmentations?.some((aug) => aug.name === name);\\n}\\n\\nfunction loadSettings() {\\n return {\\n viewMode: menuState.viewMode,\\n selectedRows: [...menuState.selectedRows],\\n hiddenRows: [...menuState.hiddenRows],\\n };\\n}\\n\\nfunction saveSettings(settings) {\\n menuState.viewMode = settings.viewMode ?? defaultMenuState.viewMode;\\n menuState.selectedRows = [...(settings.selectedRows ?? defaultMenuState.selectedRows)];\\n menuState.hiddenRows = [...(settings.hiddenRows ?? defaultMenuState.hiddenRows)];\\n}\\n\\nfunction resetSettings() {\\n menuState.viewMode = defaultMenuState.viewMode;\\n menuState.selectedRows = [...defaultMenuState.selectedRows];\\n menuState.hiddenRows = [...defaultMenuState.hiddenRows];\\n openDB.clear();\\n return loadSettings();\\n}\\n\\nfunction DevMenuApp() {\\n const React = getReactLib();\\n const saved = loadSettings();\\n const [snapshot, setSnapshot] = React.useState(null);\\n const [viewMode, setViewMode] = React.useState(saved.viewMode ?? \\\"Mini\\\");\\n const [selectedRows, setSelectedRows] = React.useState(saved.selectedRows ?? [\\\"General\\\", \\\"Servers\\\", \\\"Source-Files\\\"]);\\n const [hiddenRows, setHiddenRows] = React.useState(saved.hiddenRows ?? []);\\n const [status, setStatus] = React.useState(\\\"\\\");\\n const [toolbarOpen, setToolbarOpen] = React.useState(\\\"\\\");\\n const [rowVersion, setRowVersion] = React.useState(0);\\n\\n React.useEffect(() => {\\n let cancelled = false;\\n let timer;\\n const tick = async () => {\\n const next = await buildSnapshot();\\n if (!cancelled) setSnapshot(next);\\n if (!cancelled) timer = setTimeout(tick, 400);\\n };\\n timer = setTimeout(tick, 80);\\n return () => {\\n cancelled = true;\\n if (timer) clearTimeout(timer);\\n };\\n }, []);\\n\\n React.useEffect(() => {\\n saveSettings({ viewMode, selectedRows, hiddenRows });\\n }, [viewMode, selectedRows, hiddenRows]);\\n\\n const runAction = async (action, label = \\\"Action\\\") => {\\n try {\\n const result = await action();\\n const text = result ? String(result) : label + \\\" complete\\\";\\n setStatus(text);\\n notify(text, \\\"success\\\");\\n } catch (error) {\\n const text = label + \\\" failed: \\\" + String(error?.message ?? error);\\n setStatus(text);\\n notify(text, \\\"error\\\");\\n }\\n setSnapshot(await buildSnapshot());\\n };\\n\\n if (!snapshot) return {\\\"Loading Dev Menu Test...\\\"}
;\\n if (!snapshot.hasBridge) {\\n return (\\n \\n
{\\\"SphyxOS Dev Menu\\\"}
\\n
{\\\"The webpack bridge did not find Player. Try closing and rerunning after the game has fully loaded.\\\"}
\\n
runAction(() => {\\n exposeInternalGameObjects(true);\\n return \\\"Webpack bridge rescanned\\\";\\n }, \\\"Rescan\\\")}>{\\\"Rescan Webpack\\\"} \\n
\\n );\\n }\\n\\n const rows = buildRows(snapshot, runAction, setStatus);\\n const availableRows = rows.filter((row) => rowUnlocked(row, snapshot) && !hiddenRows.includes(row.title));\\n const hasCorpAccess = !!snapshot.player.corporation || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 3, 3);\\n const hasGangAccess = !!snapshot.player.gang || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 2);\\n const hasBladeburnerAccess = !!snapshot.player.bladeburner || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 6) || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 7);\\n const hasSleeveAccess = (snapshot.player.sleeves?.length ?? 0) > 0 || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 10);\\n const toggleSelected = (title) => setSelectedRows((current) => current.includes(title) ? current.filter((row) => row !== title) : [...current, title]);\\n const hideRow = (title) => {\\n setHiddenRows((current) => current.includes(title) ? current : [...current, title]);\\n setSelectedRows((current) => current.filter((row) => row !== title));\\n setRowVersion((value) => value + 1);\\n };\\n const unhideAll = () => {\\n setHiddenRows([]);\\n setRowVersion((value) => value + 1);\\n };\\n\\n return (\\n {\\n if (!toolbarOpen) return;\\n if (!event.target.closest?.(\\\"[data-toolbar-menu='true']\\\")) setToolbarOpen(\\\"\\\");\\n }}>\\n
\\n
\\n
\\n
{\\\"SphyxOS Dev Menu\\\"}
\\n
{snapshot.bnLabel + \\\" | Money \\\" + formatMoney(snapshot.player.money ?? 0) + \\\" | Home RAM \\\" + formatRam(snapshot.home?.maxRam ?? 0)}
\\n
{\\\"Internal bridge: \\\" + Object.keys(snapshot.game.funcs ?? {}).length + \\\" helper functions found\\\"}
\\n
\\n
\\n {hasCorpAccess ? {snapshot.player.corporation ? \\\"Corp\\\" : \\\"No Corp\\\"} : null}\\n {hasGangAccess ? {snapshot.player.gang ? \\\"Gang\\\" : \\\"No Gang\\\"} : null}\\n {hasBladeburnerAccess ? {snapshot.player.bladeburner ? \\\"Bladeburner\\\" : \\\"No Bladeburner\\\"} : null}\\n {hasSleeveAccess ? {(snapshot.player.sleeves?.length ?? 0) + \\\" Sleeves\\\"} : null}\\n 0 ? displayStatusWarnStyle : displayStatusMutedStyle} onClick={unhideAll}>{\\\"Hidden \\\" + hiddenRows.length} \\n
\\n
\\n
\\n
\\n
setToolbarOpen(toolbarOpen === \\\"actions\\\" ? \\\"\\\" : \\\"actions\\\")}>{\\\"Actions\\\"} \\n {toolbarOpen === \\\"actions\\\" &&
\\n
{\\\"System\\\"}
\\n
runAction(() => {\\n exposeInternalGameObjects(true);\\n return \\\"Webpack bridge rescanned\\\";\\n }, \\\"Rescan\\\")}>{\\\"Rescan Webpack\\\"} \\n
runAction(() => {\\n globalThis.openDevMenu?.();\\n return \\\"Native dev menu requested\\\";\\n }, \\\"Open Native Dev Menu\\\")}>{\\\"Open Native Dev Menu\\\"} \\n
runAction(() => {\\n const next = resetSettings();\\n setViewMode(next.viewMode);\\n setSelectedRows(next.selectedRows);\\n setHiddenRows(next.hiddenRows);\\n setRowVersion((value) => value + 1);\\n return \\\"Menu layout reset\\\";\\n }, \\\"Reset Layout\\\")}>{\\\"Reset Layout\\\"} \\n
}\\n
\\n
\\n {\\\"View:\\\"} \\n setViewMode(viewMode === \\\"Mini\\\" ? \\\"Standard\\\" : \\\"Mini\\\")}>{viewMode} \\n
\\n
{status} \\n
\\n
\\n\\n {viewMode === \\\"Mini\\\"\\n ?
\\n : availableRows.map((row) =>
|
)}\\n
\\n );\\n}\\n\\nfunction makeSummary(snapshot) {\\n return {\\n bitNode: snapshot.bnLabel,\\n money: snapshot.player.money,\\n homeRam: snapshot.home?.maxRam,\\n sourceFiles: snapshot.sourceFiles,\\n corporation: !!snapshot.player.corporation,\\n gang: snapshot.player.gang?.facName ?? null,\\n bladeburner: !!snapshot.player.bladeburner,\\n sleeves: snapshot.player.sleeves?.length ?? 0,\\n servers: snapshot.servers.length,\\n modulesFound: snapshot.game.modules?.length ?? 0,\\n helperFunctions: Object.keys(snapshot.game.funcs ?? {}),\\n };\\n}\\n\\nfunction buildRows(snapshot, runAction, setStatus) {\\n const React = getReactLib();\\n const game = snapshot.game;\\n const player = snapshot.player;\\n const home = snapshot.home;\\n const rows = [];\\n\\n rows.push({\\n title: \\\"General\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Experience / Stats\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Factions\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Augmentations\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Source-Files\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Programs\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Servers\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Companies\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Bladeburner\\\",\\n bn: 6,\\n lvl: 1,\\n gate: (snap) => !!snap.player.bladeburner || hasBN(snap.resetInfo, snap.sourceFiles, 6) || hasBN(snap.resetInfo, snap.sourceFiles, 7),\\n body: ,\\n });\\n rows.push({\\n title: \\\"Gang\\\",\\n bn: 2,\\n lvl: 1,\\n gate: (snap) => !!snap.player.gang || hasBN(snap.resetInfo, snap.sourceFiles, 2),\\n body: ,\\n });\\n rows.push({\\n title: \\\"Corporation\\\",\\n bn: 3,\\n lvl: 3,\\n gate: (snap) => !!snap.player.corporation || hasBN(snap.resetInfo, snap.sourceFiles, 3, 3),\\n body: ,\\n });\\n rows.push({\\n title: \\\"Coding Contracts\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Stock Market\\\",\\n bn: true,\\n lvl: true,\\n gate: (snap) => snap.hasStockMarket,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Sleeves\\\",\\n bn: 10,\\n lvl: 1,\\n gate: (snap) => (snap.player.sleeves?.length ?? 0) > 0 || hasBN(snap.resetInfo, snap.sourceFiles, 10),\\n body: ,\\n });\\n rows.push({\\n title: \\\"Stanek's Gift\\\",\\n bn: 13,\\n lvl: 1,\\n gate: (snap) => snap.hasStanek || hasBN(snap.resetInfo, snap.sourceFiles, 13),\\n body: ,\\n });\\n rows.push({\\n title: \\\"Time Skip\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Achievements\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Entropy\\\",\\n bn: true,\\n lvl: true,\\n body: ,\\n });\\n rows.push({\\n title: \\\"Darknet\\\",\\n bn: 15,\\n lvl: 1,\\n gate: (snap) => snap.hasDarknet || hasBN(snap.resetInfo, snap.sourceFiles, 15),\\n body: ,\\n });\\n return rows;\\n}\\n\\nfunction GeneralTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [money, setMoney] = React.useState(\\\"1000000000\\\");\\n const [hashes, setHashes] = React.useState(\\\"100\\\");\\n const [corpName, setCorpName] = React.useState(\\\"DevCorp\\\");\\n const [gangFaction, setGangFaction] = React.useState(DEFAULT_GANG_FACTIONS[0]);\\n const player = snapshot.player;\\n const home = snapshot.home;\\n const hashManager = player.hashManager;\\n const hasCorpAccess = !!player.corporation || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 3, 3);\\n const hasGangAccess = !!player.gang || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 2);\\n const hasBladeburnerAccess = !!player.bladeburner || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 6) || hasBN(snapshot.resetInfo, snapshot.sourceFiles, 7);\\n return (\\n \\n \\n {[1e6, 1e9, 1e12, 1e15, Infinity].map((value) => runAction(() => {\\n player.gainMoney(value, \\\"other\\\");\\n return \\\"Added \\\" + formatMoney(value);\\n }, \\\"Add money\\\")}> )}\\n setMoney(event.target.value)}>\\n runAction(() => {\\n player.gainMoney(safeNumber(money), \\\"other\\\");\\n return \\\"Added \\\" + formatMoney(safeNumber(money));\\n }, \\\"Give money\\\")}> \\n runAction(() => {\\n player.money = safeNumber(money);\\n return \\\"Money set\\\";\\n }, \\\"Set money\\\")}> \\n runAction(() => {\\n player.money = 0;\\n return \\\"Money cleared\\\";\\n }, \\\"Clear money\\\")}> \\n \\n {hashManager?.capacity > 0 && \\n setHashes(event.target.value)}>\\n runAction(() => {\\n hashManager.storeHashes?.(safeNumber(hashes));\\n if (!hashManager.storeHashes) hashManager.hashes = safeNumber(hashes);\\n return \\\"Hashes added\\\";\\n }, \\\"Give hashes\\\")}> \\n runAction(() => {\\n hashManager.hashes = 0;\\n return \\\"Hashes cleared\\\";\\n }, \\\"Clear hashes\\\")}> \\n }\\n \\n {[8, 64, 1024, 1048576, 1073741824].map((gb) => runAction(() => {\\n home.maxRam = gb;\\n return \\\"Home RAM set to \\\" + formatRam(gb);\\n }, \\\"Set RAM\\\")}> )}\\n runAction(() => {\\n home.maxRam *= 2;\\n return \\\"Home RAM doubled\\\";\\n }, \\\"Double RAM\\\")}> \\n \\n {hasCorpAccess ? \\n {player.corporation\\n ? runAction(() => {\\n player.corporation = null;\\n return \\\"Corporation destroyed\\\";\\n }, \\\"Destroy corporation\\\")}> \\n : setCorpName(event.target.value)}> runAction(() => {\\n player.startCorporation?.(corpName || \\\"DevCorp\\\", false);\\n return \\\"Corporation created\\\";\\n }, \\\"Create corporation\\\")}> }\\n : null}\\n {hasGangAccess ? \\n {player.gang\\n ? runAction(() => {\\n player.gang = null;\\n return \\\"Gang removed\\\";\\n }, \\\"Leave gang\\\")}> \\n : runAction(() => {\\n player.startGang?.(gangFaction, gangFaction === \\\"NiteSec\\\" || gangFaction === \\\"The Black Hand\\\");\\n return \\\"Gang created\\\";\\n }, \\\"Create gang\\\")}> }\\n : null}\\n {hasBladeburnerAccess ? \\n {player.bladeburner\\n ? runAction(() => {\\n player.bladeburner = null;\\n return \\\"Bladeburner removed\\\";\\n }, \\\"Leave Bladeburner\\\")}> \\n : runAction(() => {\\n player.startBladeburner?.();\\n return \\\"Joined Bladeburner\\\";\\n }, \\\"Join Bladeburner\\\")}> }\\n : null}\\n \\n runAction(() => {\\n snapshot.game.Router?.toPage?.(\\\"BitVerse\\\", { flume: true, quick: true });\\n return \\\"Quick b1t_flum3 requested\\\";\\n }, \\\"Quick b1t_flum3\\\")}> \\n runAction(() => {\\n snapshot.game.Router?.toPage?.(\\\"BitVerse\\\", { flume: true, quick: false });\\n return \\\"b1t_flum3 requested\\\";\\n }, \\\"Run b1t_flum3\\\")}> \\n runAction(() => {\\n const wd = snapshot.game.GetServer?.(\\\"w0r1d_d43m0n\\\");\\n if (wd) wd.backdoorInstalled = true;\\n snapshot.game.Router?.toPage?.(\\\"BitVerse\\\", { flume: false, quick: true });\\n return \\\"Quick w0rld_d34m0n requested\\\";\\n }, \\\"Quick WD\\\")}> \\n runAction(() => {\\n const wd = snapshot.game.GetServer?.(\\\"w0r1d_d43m0n\\\");\\n if (wd) wd.backdoorInstalled = true;\\n snapshot.game.Router?.toPage?.(\\\"BitVerse\\\", { flume: false, quick: false });\\n return \\\"w0rld_d34m0n requested\\\";\\n }, \\\"Hack WD\\\")}> \\n \\n \\n runAction(() => {\\n snapshot.game.funcs.checkMessages?.();\\n return snapshot.game.funcs.checkMessages ? \\\"Message check requested\\\" : \\\"Message helper was not found\\\";\\n }, \\\"Check messages\\\")}> \\n runAction(() => {\\n globalThis.openDevMenu?.();\\n return \\\"Native dev menu requested\\\";\\n }, \\\"Open native menu\\\")}> \\n {\\n throw new Error(\\\"Manually thrown from Dev Menu Test\\\");\\n }}> \\n \\n \\n );\\n}\\n\\nfunction StatsTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [allLevel, setAllLevel] = React.useState(\\\"100\\\");\\n const player = snapshot.player;\\n return (\\n \\n \\n runAction(() => {\\n for (const [, , gainMethod] of STATS) player[gainMethod]?.(BIG);\\n player.updateSkillLevels?.();\\n return \\\"Tons of exp added\\\";\\n }, \\\"Tons of exp\\\")}> \\n runAction(() => {\\n for (const [, key] of STATS) player.exp[key] = 0;\\n if (player.persistentIntelligenceData) player.persistentIntelligenceData.exp = 0;\\n player.updateSkillLevels?.();\\n return \\\"All exp reset\\\";\\n }, \\\"Reset exp\\\")}> \\n setAllLevel(event.target.value)}>\\n runAction(() => {\\n for (const stat of STATS.filter((item) => item[1] !== \\\"intelligence\\\")) setStatLevel(snapshot, stat, safeNumber(allLevel, 1));\\n return \\\"Normal stats set\\\";\\n }, \\\"Set all stats\\\")}> \\n \\n {STATS.map((stat) => )}\\n \\n runAction(() => {\\n player.karma += -54000;\\n return \\\"Karma lowered\\\";\\n }, \\\"Karma tons\\\")} add={(value) => runAction(() => {\\n player.karma += value;\\n return \\\"Karma added\\\";\\n }, \\\"Add karma\\\")} subtract={(value) => runAction(() => {\\n player.karma -= value;\\n return \\\"Karma subtracted\\\";\\n }, \\\"Subtract karma\\\")} reset={() => runAction(() => {\\n player.karma = 0;\\n return \\\"Karma reset\\\";\\n }, \\\"Reset karma\\\")}> \\n \\n \\n );\\n}\\n\\nfunction StatRow({ snapshot, stat, runAction }) {\\n const React = getReactLib();\\n const [level, setLevel] = React.useState(\\\"100\\\");\\n const player = snapshot.player;\\n const [label, key, gainMethod] = stat;\\n return (\\n \\n runAction(() => {\\n player[gainMethod]?.(BIG);\\n player.updateSkillLevels?.();\\n return label + \\\" exp added\\\";\\n }, label + \\\" tons\\\")} add={(value) => runAction(() => {\\n player[gainMethod]?.(value);\\n player.updateSkillLevels?.();\\n return label + \\\" exp added\\\";\\n }, \\\"Add \\\" + label)} subtract={(value) => runAction(() => {\\n player[gainMethod]?.(-value);\\n player.updateSkillLevels?.();\\n return label + \\\" exp subtracted\\\";\\n }, \\\"Subtract \\\" + label)} reset={() => runAction(() => {\\n player.exp[key] = 0;\\n if (key === \\\"intelligence\\\" && player.persistentIntelligenceData) player.persistentIntelligenceData.exp = 0;\\n player.updateSkillLevels?.();\\n return label + \\\" reset\\\";\\n }, \\\"Reset \\\" + label)}> \\n setLevel(event.target.value)}>\\n runAction(() => {\\n setStatLevel(snapshot, stat, safeNumber(level, 1));\\n return label + \\\" level set\\\";\\n }, \\\"Set \\\" + label)}> \\n {key === \\\"intelligence\\\" && \\n runAction(() => {\\n if (player.skills.intelligence === 0) player.skills.intelligence = 1;\\n player.updateSkillLevels?.();\\n return \\\"Intelligence enabled\\\";\\n }, \\\"Enable int\\\")}> \\n runAction(() => {\\n player.exp.intelligence = 0;\\n player.skills.intelligence = 0;\\n if (player.persistentIntelligenceData) player.persistentIntelligenceData.exp = 0;\\n player.updateSkillLevels?.();\\n return \\\"Intelligence disabled\\\";\\n }, \\\"Disable int\\\")}> \\n }\\n \\n );\\n}\\n\\nfunction setStatLevel(snapshot, stat, level) {\\n const player = snapshot.player;\\n const targetLevel = Math.floor(level);\\n if (!Number.isFinite(targetLevel) || targetLevel < 1) return;\\n const [, key, , nodeMultKey] = stat;\\n let mult = getStatLevelMultiplier(snapshot, key, nodeMultKey);\\n if (key === \\\"intelligence\\\") {\\n player.exp.intelligence = calculateExp(targetLevel, 1);\\n if (player.persistentIntelligenceData) player.persistentIntelligenceData.exp = player.exp.intelligence;\\n player.skills.intelligence = calculateSkillWithPlayer(player, player.exp.intelligence, 1);\\n return;\\n } else {\\n for (let i = 0; i < 4; i++) {\\n player.exp[key] = calculateExp(targetLevel, mult);\\n refreshStatLevel(player, key, mult);\\n if (player.skills?.[key] === targetLevel) return;\\n mult = inferStatLevelMultiplier(player.exp[key], player.skills?.[key], mult);\\n }\\n player.exp[key] = calculateExp(targetLevel, mult);\\n refreshStatLevel(player, key, mult);\\n }\\n}\\n\\nfunction getStatLevelMultiplier(snapshot, key, nodeMultKey) {\\n const player = snapshot.player;\\n const directMult = player.mults?.[key] ?? player.mults?.[key + \\\"_skill\\\"] ?? 1;\\n const nodeMult = snapshot.game.currentNodeMults?.[nodeMultKey] ?? 1;\\n const inferredMult = inferStatLevelMultiplier(player.exp?.[key], player.skills?.[key], directMult * nodeMult);\\n return Number.isFinite(inferredMult) && inferredMult > 0 ? inferredMult : 1;\\n}\\n\\nfunction refreshStatLevel(player, key, mult) {\\n const usedNativeRefresh = typeof player.updateSkillLevels === \\\"function\\\";\\n player.updateSkillLevels?.();\\n if (!player.skills || !player.exp) return;\\n if (!usedNativeRefresh) {\\n const calculated = calculateSkillWithPlayer(player, player.exp[key], mult);\\n if (Number.isFinite(calculated)) player.skills[key] = calculated;\\n }\\n if (!usedNativeRefresh && key === \\\"defense\\\" && player.hp) {\\n const ratio = Math.min((player.hp.current ?? player.hp.max ?? 1) / (player.hp.max ?? 1), 1);\\n player.hp.max = Math.floor(10 + player.skills.defense / 10);\\n player.hp.current = Math.round(player.hp.max * ratio);\\n }\\n}\\n\\nfunction inferStatLevelMultiplier(exp, skill, fallback = 1) {\\n if (!Number.isFinite(exp) || !Number.isFinite(skill) || skill < 1) return fallback;\\n const base = 32 * Math.log(exp + 534.6) - 200;\\n if (!Number.isFinite(base) || base <= 0) return fallback;\\n return Math.max(skill / base, 1e-9);\\n}\\n\\nfunction calculateSkillWithPlayer(player, exp, mult = 1) {\\n try {\\n if (typeof player.calculateSkill === \\\"function\\\") return player.calculateSkill(exp, mult);\\n } catch { }\\n return calculateSkill(exp, mult);\\n}\\n\\nfunction calculateExp(skill, mult = 1) {\\n const floorSkill = Math.floor(skill);\\n let value = Math.exp((skill / mult + 200) / 32) - 534.6;\\n if (skill === floorSkill && Number.isFinite(skill)) {\\n let calcSkill = calculateSkill(value, mult);\\n let diff = Math.abs(value * Number.EPSILON);\\n let nextValue = value;\\n while (calcSkill < skill) {\\n nextValue = value + diff;\\n diff *= 2;\\n calcSkill = calculateSkill(nextValue, mult);\\n }\\n value = nextValue;\\n }\\n return Math.max(value, 0);\\n}\\n\\nfunction calculateSkill(exp, mult = 1) {\\n return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.6) - 200)), 1);\\n}\\n\\nfunction FactionTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [factionName, setFactionName] = React.useState(snapshot.factions[0] ?? \\\"Illuminati\\\");\\n const faction = snapshot.factionObjects.find((item) => item?.name === factionName) ?? snapshot.factionObjects[0];\\n const player = snapshot.player;\\n if (!faction) return {\\\"Faction internals were not found. Hit Actions -> Rescan Webpack.\\\"} ;\\n return (\\n \\n \\n \\n runAction(() => {\\n player.receiveRumor?.(faction.name);\\n return \\\"Rumor received\\\";\\n }, \\\"Faction rumor\\\")}> \\n runAction(() => {\\n player.receiveInvite?.(faction.name);\\n faction.alreadyInvited = true;\\n faction.discovery = \\\"known\\\";\\n return \\\"Invite received\\\";\\n }, \\\"Faction invite\\\")}> \\n {\\n faction.discovery = value;\\n }}> \\n \\n \\n runAction(() => {\\n faction.playerReputation += 1e12;\\n return \\\"Faction reputation added\\\";\\n }, \\\"Faction rep\\\")} add={(value) => runAction(() => {\\n faction.playerReputation += value;\\n return \\\"Faction reputation added\\\";\\n }, \\\"Add faction rep\\\")} subtract={(value) => runAction(() => {\\n faction.playerReputation -= value;\\n return \\\"Faction reputation subtracted\\\";\\n }, \\\"Subtract faction rep\\\")} reset={() => runAction(() => {\\n faction.playerReputation = 0;\\n return \\\"Faction reputation reset\\\";\\n }, \\\"Reset faction rep\\\")}> \\n \\n \\n runAction(() => {\\n faction.setFavor?.(MAX_FAVOR);\\n return \\\"Faction favor maxed\\\";\\n }, \\\"Faction favor\\\")} add={(value) => runAction(() => {\\n faction.setFavor?.((faction.favor ?? 0) + value);\\n return \\\"Faction favor added\\\";\\n }, \\\"Add faction favor\\\")} subtract={(value) => runAction(() => {\\n faction.setFavor?.((faction.favor ?? 0) - value);\\n return \\\"Faction favor subtracted\\\";\\n }, \\\"Subtract faction favor\\\")} reset={() => runAction(() => {\\n faction.setFavor?.(0);\\n return \\\"Faction favor reset\\\";\\n }, \\\"Reset faction favor\\\")}> \\n \\n \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => item.discovery = \\\"unknown\\\");\\n player.factionRumors?.clear?.();\\n return \\\"Faction discovery reset\\\";\\n }, \\\"Reset discovery\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => player.receiveRumor?.(item.name));\\n return \\\"All rumors received\\\";\\n }, \\\"All rumors\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => {\\n player.receiveInvite?.(item.name);\\n item.alreadyInvited = true;\\n item.discovery = \\\"known\\\";\\n });\\n return \\\"All invites received\\\";\\n }, \\\"All invites\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => item.playerReputation = 1e12);\\n return \\\"All faction rep maxed\\\";\\n }, \\\"All rep\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => item.playerReputation = 0);\\n return \\\"All faction rep reset\\\";\\n }, \\\"Reset all rep\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => item.setFavor?.(MAX_FAVOR));\\n return \\\"All faction favor maxed\\\";\\n }, \\\"All favor\\\")}> \\n runAction(() => {\\n snapshot.factionObjects.forEach((item) => item.setFavor?.(0));\\n return \\\"All faction favor reset\\\";\\n }, \\\"Reset all favor\\\")}> \\n \\n \\n );\\n}\\n\\nfunction AugmentationTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [augmentation, setAugmentation] = React.useState(snapshot.augmentations[0] ?? \\\"NeuroFlux Governor\\\");\\n const [factionName, setFactionName] = React.useState(snapshot.factions[0] ?? \\\"Illuminati\\\");\\n const player = snapshot.player;\\n const selectedFaction = snapshot.factionObjects.find((item) => item?.name === factionName);\\n return (\\n \\n \\n \\n runAction(() => {\\n queueAug(player, augmentation);\\n return \\\"Augmentation queued\\\";\\n }, \\\"Queue aug\\\")}> \\n runAction(() => {\\n snapshot.augmentations.forEach((name) => queueAug(player, name));\\n return \\\"All augmentations queued\\\";\\n }, \\\"Queue all augs\\\")}> \\n \\n \\n runAction(() => {\\n installQueuedAugs(snapshot);\\n return \\\"Queued augmentations installed\\\";\\n }, \\\"Install augs\\\")}> \\n runAction(() => {\\n player.queuedAugmentations = [];\\n return \\\"Queued augmentations cleared\\\";\\n }, \\\"Clear queued\\\")}> \\n runAction(() => {\\n player.augmentations = [];\\n player.reapplyAllAugmentations?.();\\n player.reapplyAllSourceFiles?.();\\n return \\\"Installed augmentations cleared\\\";\\n }, \\\"Clear installed\\\")}> \\n \\n \\n \\n runAction(() => {\\n (selectedFaction?.augmentations ?? []).forEach((name) => {\\n if (name !== \\\"NeuroFlux Governor\\\") queueAug(player, name);\\n });\\n return \\\"Faction augmentations queued\\\";\\n }, \\\"Queue faction augs\\\")}> \\n runAction(() => {\\n queueAug(player, \\\"Stanek's Gift - Genesis\\\");\\n return \\\"Stanek's Gift queued\\\";\\n }, \\\"Queue Stanek\\\")}> \\n \\n \\n );\\n}\\n\\nfunction queueAug(player, name) {\\n if (!name) return;\\n if (name !== \\\"NeuroFlux Governor\\\" && (player.queuedAugmentations ?? []).some((aug) => aug.name === name)) return;\\n if (name !== \\\"NeuroFlux Governor\\\" && (player.augmentations ?? []).some((aug) => aug.name === name)) return;\\n try {\\n player.queueAugmentation?.(name);\\n return;\\n } catch { }\\n player.queuedAugmentations ??= [];\\n const nextLevel = name === \\\"NeuroFlux Governor\\\"\\n ? Math.max(1, ...[...player.augmentations, ...player.queuedAugmentations].filter((aug) => aug.name === name).map((aug) => aug.level ?? 1)) + 1\\n : 1;\\n player.queuedAugmentations.push({ name, level: nextLevel });\\n}\\n\\nfunction installQueuedAugs(snapshot) {\\n const player = snapshot.player;\\n const apply = snapshot.game.funcs.applyAugmentation;\\n for (const aug of player.queuedAugmentations ?? []) {\\n if (apply) {\\n try {\\n apply(aug);\\n continue;\\n } catch { }\\n }\\n const existing = player.augmentations?.find((item) => item.name === aug.name);\\n if (existing && aug.name === \\\"NeuroFlux Governor\\\") existing.level = aug.level ?? existing.level ?? 1;\\n else if (!existing) player.augmentations.push({ name: aug.name, level: aug.level ?? 1 });\\n }\\n player.queuedAugmentations = [];\\n player.reapplyAllAugmentations?.();\\n player.reapplyAllSourceFiles?.();\\n}\\n\\nfunction SourceFileTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const player = snapshot.player;\\n return (\\n \\n \\n runAction(() => {\\n player.exploits = [];\\n return \\\"Exploits cleared\\\";\\n }, \\\"Clear exploits\\\")}> \\n \\n \\n {[0, 1, 2, 3].map((level) => runAction(() => {\\n VALID_BITNODES.forEach((bn) => setSourceFile(snapshot, bn, level));\\n return \\\"All Source-Files set to \\\" + level;\\n }, \\\"Set all SF\\\")}> )}\\n \\n {VALID_BITNODES.map((bn) => {\\n const currentLevel = sourceFileLevel(player, snapshot.sourceFiles, bn);\\n return \\n {[0, 1, 2, 3].map((level) => runAction(() => {\\n setSourceFile(snapshot, bn, level);\\n return \\\"SF-\\\" + bn + \\\" set to \\\" + level;\\n }, \\\"Set SF-\\\" + bn)}> )}\\n {bn === 12 && [1, 10, 100].map((increment) => runAction(() => {\\n setSourceFile(snapshot, 12, sourceFileLevel(player, snapshot.sourceFiles, 12) + increment);\\n return \\\"SF-12 increased\\\";\\n }, \\\"Increase SF-12\\\")}> )}\\n {bn === 10 && \\n runAction(() => {\\n const current = player.sleevesFromCovenant ?? 0;\\n if (current <= 0) return \\\"Extra sleeves are already at your minimum\\\";\\n player.sleevesFromCovenant = current - 1;\\n snapshot.game.funcs.recalculateSleeves?.();\\n return \\\"Extra sleeve count lowered\\\";\\n }, \\\"Remove sleeve\\\")}> \\n runAction(() => {\\n const current = player.sleevesFromCovenant ?? 0;\\n if (current >= 5) return \\\"Extra sleeves are already at maximum\\\";\\n player.sleevesFromCovenant = current + 1;\\n snapshot.game.funcs.recalculateSleeves?.();\\n return \\\"Extra sleeve count raised\\\";\\n }, \\\"Add sleeve\\\")}> \\n {\\\" Extra: \\\" + (player.sleevesFromCovenant ?? 0)} \\n }\\n ;\\n })}\\n \\n );\\n}\\n\\nfunction setSourceFile(snapshot, n, level) {\\n const player = snapshot.player;\\n player.sourceFiles ??= new Map();\\n player.bitNodeOptions ??= {};\\n player.bitNodeOptions.sourceFileOverrides ??= new Map();\\n if (n === 9 && Array.isArray(player.hacknetNodes)) {\\n player.hacknetNodes = level <= 0\\n ? player.hacknetNodes.filter((node) => typeof node !== \\\"string\\\")\\n : player.hacknetNodes.filter((node) => typeof node === \\\"string\\\");\\n }\\n if (n === 15 && level > 0) {\\n if (snapshot.game.funcs.getDarkscapeNavigator) snapshot.game.funcs.getDarkscapeNavigator();\\n else pushProgram(snapshot.home, \\\"DarkscapeNavigator.exe\\\");\\n }\\n if (level <= 0) {\\n player.sourceFiles.delete?.(n);\\n player.bitNodeOptions.sourceFileOverrides.delete?.(n);\\n } else {\\n player.sourceFiles.set?.(n, level);\\n player.bitNodeOptions.sourceFileOverrides.set?.(n, level);\\n }\\n if (n === 10) snapshot.game.funcs.recalculateSleeves?.();\\n}\\n\\nfunction ProgramTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [program, setProgram] = React.useState(snapshot.programs[0] ?? \\\"BruteSSH.exe\\\");\\n const home = snapshot.home;\\n return (\\n \\n \\n \\n runAction(() => {\\n home.pushProgram?.(program);\\n if (!home.pushProgram && !home.programs.includes(program)) home.programs.push(program);\\n return program + \\\" added\\\";\\n }, \\\"Add program\\\")}> \\n runAction(() => {\\n snapshot.programs.forEach((name) => pushProgram(home, name));\\n return \\\"All programs added\\\";\\n }, \\\"Add all programs\\\")}> \\n \\n \\n );\\n}\\n\\nfunction ServerTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [serverName, setServerName] = React.useState(\\\"home\\\");\\n const getSvr = snapshot.game.GetServer;\\n const selectedServer = getSvr?.(serverName);\\n const allHackable = snapshot.servers.filter((server) => isMutableServer(server));\\n return (\\n \\n \\n \\n {selectedServer ? \\\" \\\" + formatMoney(selectedServer.moneyAvailable ?? 0) + \\\" / \\\" + formatMoney(selectedServer.moneyMax ?? 0) : \\\"\\\"} \\n \\n \\n runAction(() => {\\n rootServer(selectedServer);\\n return serverName + \\\" rooted\\\";\\n }, \\\"Root server\\\")}> \\n runAction(() => {\\n allHackable.forEach(rootServer);\\n return \\\"All servers rooted\\\";\\n }, \\\"Root all\\\")}> \\n \\n \\n runAction(() => {\\n selectedServer.backdoorInstalled = true;\\n return serverName + \\\" backdoored\\\";\\n }, \\\"Backdoor server\\\")}> \\n runAction(() => {\\n allHackable.filter((server) => server.hostname !== \\\"w0r1d_d43m0n\\\").forEach((server) => server.backdoorInstalled = true);\\n return \\\"All eligible servers backdoored\\\";\\n }, \\\"Backdoor all\\\")}> \\n \\n \\n runAction(() => {\\n selectedServer.hackDifficulty = selectedServer.minDifficulty;\\n return serverName + \\\" security minimized\\\";\\n }, \\\"Min security\\\")}> \\n runAction(() => {\\n allHackable.forEach((server) => server.hackDifficulty = server.minDifficulty);\\n return \\\"All security minimized\\\";\\n }, \\\"Min all security\\\")}> \\n \\n \\n runAction(() => {\\n selectedServer.moneyAvailable = 0;\\n return serverName + \\\" money cleared\\\";\\n }, \\\"Min money\\\")}> \\n runAction(() => {\\n allHackable.forEach((server) => server.moneyAvailable = 0);\\n return \\\"All server money cleared\\\";\\n }, \\\"Min all money\\\")}> \\n runAction(() => {\\n selectedServer.moneyAvailable = selectedServer.moneyMax;\\n return serverName + \\\" money maxed\\\";\\n }, \\\"Max money\\\")}> \\n runAction(() => {\\n allHackable.forEach((server) => server.moneyAvailable = server.moneyMax);\\n return \\\"All server money maxed\\\";\\n }, \\\"Max all money\\\")}> \\n \\n \\n );\\n}\\n\\nfunction isMutableServer(server) {\\n return server && typeof server === \\\"object\\\" && \\\"hostname\\\" in server && \\\"hasAdminRights\\\" in server;\\n}\\n\\nfunction rootServer(server) {\\n if (!server) return;\\n server.hasAdminRights = true;\\n server.sshPortOpen = true;\\n server.ftpPortOpen = true;\\n server.smtpPortOpen = true;\\n server.httpPortOpen = true;\\n server.sqlPortOpen = true;\\n server.openPortCount = 5;\\n}\\n\\nfunction CompanyTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [companyName, setCompanyName] = React.useState(snapshot.companies[0] ?? \\\"ECorp\\\");\\n const company = snapshot.companyObjects.find((item) => item?.name === companyName) ?? snapshot.companyObjects[0];\\n const relatedFaction = company?.relatedFaction;\\n const relatedFactionObject = snapshot.factionObjects.find((item) => item?.name === relatedFaction);\\n const player = snapshot.player;\\n if (!company) return {\\\"Company internals were not found. Hit Actions -> Rescan Webpack.\\\"} ;\\n return (\\n \\n \\n \\n \\n {relatedFaction ? \\n runAction(() => {\\n player.receiveInvite?.(relatedFaction);\\n if (relatedFactionObject) {\\n relatedFactionObject.alreadyInvited = true;\\n relatedFactionObject.discovery = \\\"known\\\";\\n }\\n return relatedFaction + \\\" invite received\\\";\\n }, \\\"Company faction invite\\\")}> \\n : null}\\n \\n runAction(() => {\\n company.playerReputation = 1e12;\\n return \\\"Company reputation maxed\\\";\\n }, \\\"Company rep\\\")} add={(value) => runAction(() => {\\n company.playerReputation += value;\\n return \\\"Company reputation added\\\";\\n }, \\\"Add company rep\\\")} subtract={(value) => runAction(() => {\\n company.playerReputation -= value;\\n return \\\"Company reputation subtracted\\\";\\n }, \\\"Subtract company rep\\\")} reset={() => runAction(() => {\\n company.playerReputation = 0;\\n return \\\"Company reputation reset\\\";\\n }, \\\"Reset company rep\\\")}> \\n \\n \\n runAction(() => {\\n company.setFavor?.(MAX_FAVOR);\\n return \\\"Company favor maxed\\\";\\n }, \\\"Company favor\\\")} add={(value) => runAction(() => {\\n company.setFavor?.((company.favor ?? 0) + value);\\n return \\\"Company favor added\\\";\\n }, \\\"Add company favor\\\")} subtract={(value) => runAction(() => {\\n company.setFavor?.((company.favor ?? 0) - value);\\n return \\\"Company favor subtracted\\\";\\n }, \\\"Subtract company favor\\\")} reset={() => runAction(() => {\\n company.setFavor?.(0);\\n return \\\"Company favor reset\\\";\\n }, \\\"Reset company favor\\\")}> \\n \\n \\n runAction(() => {\\n snapshot.companyObjects.forEach((item) => item.playerReputation = 1e12);\\n return \\\"All company rep maxed\\\";\\n }, \\\"All company rep\\\")}> \\n runAction(() => {\\n snapshot.companyObjects.forEach((item) => item.playerReputation = 0);\\n return \\\"All company rep reset\\\";\\n }, \\\"Reset company rep\\\")}> \\n runAction(() => {\\n snapshot.companyObjects.forEach((item) => item.setFavor?.(MAX_FAVOR));\\n return \\\"All company favor maxed\\\";\\n }, \\\"All company favor\\\")}> \\n runAction(() => {\\n snapshot.companyObjects.forEach((item) => item.setFavor?.(0));\\n return \\\"All company favor reset\\\";\\n }, \\\"Reset company favor\\\")}> \\n \\n \\n );\\n}\\n\\nfunction BladeburnerTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [skill, setSkill] = React.useState(snapshot.bladeSkills[0] ?? DEFAULT_BLADE_SKILLS[0]);\\n const [contract, setContract] = React.useState(\\\"Tracking\\\");\\n const [operation, setOperation] = React.useState(\\\"Investigation\\\");\\n const player = snapshot.player;\\n const bb = player.bladeburner;\\n if (!bb) return runAction(() => {\\n player.startBladeburner?.();\\n return \\\"Joined Bladeburner\\\";\\n }, \\\"Join Bladeburner\\\")}> ;\\n const contracts = objectValues(bb.contracts).map((item) => item.name);\\n const operations = objectValues(bb.operations).map((item) => item.name);\\n const contractName = contracts.includes(contract) ? contract : (contracts[0] ?? \\\"Tracking\\\");\\n const operationName = operations.includes(operation) ? operation : (operations[0] ?? \\\"Investigation\\\");\\n return (\\n \\n \\n runAction(() => {\\n changeBladeburnerRank(bb, player, BIG);\\n return \\\"Bladeburner rank added\\\";\\n }, \\\"BB rank\\\")} add={(value) => runAction(() => {\\n changeBladeburnerRank(bb, player, value);\\n return \\\"Bladeburner rank added\\\";\\n }, \\\"Add BB rank\\\")} subtract={(value) => runAction(() => {\\n changeBladeburnerRank(bb, player, -value);\\n return \\\"Bladeburner rank subtracted\\\";\\n }, \\\"Subtract BB rank\\\")} reset={() => runAction(() => {\\n bb.rank = 0;\\n bb.maxRank = 0;\\n return \\\"Bladeburner rank reset\\\";\\n }, \\\"Reset BB rank\\\")}> \\n \\n \\n runAction(() => {\\n bb.skillPoints = BIG;\\n bb.totalSkillPoints = Math.max(bb.totalSkillPoints ?? 0, BIG);\\n return \\\"Bladeburner SP maxed\\\";\\n }, \\\"BB SP\\\")} add={(value) => runAction(() => {\\n bb.skillPoints += value;\\n bb.totalSkillPoints = (bb.totalSkillPoints ?? 0) + value;\\n return \\\"Bladeburner SP added\\\";\\n }, \\\"Add BB SP\\\")} subtract={(value) => runAction(() => {\\n bb.skillPoints -= value;\\n return \\\"Bladeburner SP subtracted\\\";\\n }, \\\"Subtract BB SP\\\")} reset={() => runAction(() => {\\n bb.skillPoints = 0;\\n bb.totalSkillPoints = 0;\\n return \\\"Bladeburner SP reset\\\";\\n }, \\\"Reset BB SP\\\")}> \\n \\n \\n runAction(() => {\\n bb.storedCycles += BIG;\\n return \\\"Bladeburner cycles added\\\";\\n }, \\\"BB cycles\\\")} add={(value) => runAction(() => {\\n bb.storedCycles += value;\\n return \\\"Bladeburner cycles added\\\";\\n }, \\\"Add BB cycles\\\")} subtract={(value) => runAction(() => {\\n bb.storedCycles -= value;\\n return \\\"Bladeburner cycles subtracted\\\";\\n }, \\\"Subtract BB cycles\\\")} reset={() => runAction(() => {\\n bb.storedCycles = 0;\\n return \\\"Bladeburner cycles reset\\\";\\n }, \\\"Reset BB cycles\\\")}> \\n \\n \\n runAction(() => {\\n objectValues(bb.cities).forEach((city) => changeCityChaos(city, BIG));\\n return \\\"City chaos added\\\";\\n }, \\\"BB chaos\\\")} add={(value) => runAction(() => {\\n objectValues(bb.cities).forEach((city) => changeCityChaos(city, value));\\n return \\\"City chaos added\\\";\\n }, \\\"Add chaos\\\")} subtract={(value) => runAction(() => {\\n objectValues(bb.cities).forEach((city) => changeCityChaos(city, -value));\\n return \\\"City chaos subtracted\\\";\\n }, \\\"Subtract chaos\\\")} reset={() => runAction(() => {\\n objectValues(bb.cities).forEach((city) => city.chaos = 0);\\n return \\\"City chaos wiped\\\";\\n }, \\\"Wipe chaos\\\")}> \\n runAction(() => {\\n if (bb.cities?.[bb.city]) bb.cities[bb.city].chaos = 0;\\n return \\\"Active city chaos wiped\\\";\\n }, \\\"Wipe active chaos\\\")}> \\n \\n \\n \\n runAction(() => {\\n //bb.setSkillLevel?.(skill, (bb.getSkillLevel?.(skill) ?? 0) + BIG);\\n bb.setSkillLevel?.(skill, (bb[\\\"getSkillLevel\\\"]?.(skill) ?? 0) + BIG);\\n bb.updateSkillMultipliers?.();\\n return \\\"Bladeburner skill raised\\\";\\n }, \\\"BB skill\\\")} add={(value) => runAction(() => {\\n bb.setSkillLevel?.(skill, (bb[\\\"getSkillLevel\\\"]?.(skill) ?? 0) + value);\\n bb.updateSkillMultipliers?.();\\n return \\\"Bladeburner skill raised\\\";\\n }, \\\"Add BB skill\\\")} subtract={(value) => runAction(() => {\\n bb.setSkillLevel?.(skill, (bb[\\\"getSkillLevel\\\"]?.(skill) ?? 0) - value);\\n bb.updateSkillMultipliers?.();\\n return \\\"Bladeburner skill lowered\\\";\\n }, \\\"Subtract BB skill\\\")} reset={() => runAction(() => {\\n bb.setSkillLevel?.(skill, 0);\\n bb.updateSkillMultipliers?.();\\n return \\\"Bladeburner skill reset\\\";\\n }, \\\"Reset BB skill\\\")}> \\n \\n item.name === contractName)} options={contracts} selected={contractName} setSelected={setContract} runAction={runAction}> \\n item.name === operationName)} options={operations} selected={operationName} setSelected={setOperation} runAction={runAction}> \\n \\n );\\n}\\n\\nfunction BladeActionEditor({ title, action, options, selected, setSelected, runAction }) {\\n const React = getReactLib();\\n const [field, setField] = React.useState(\\\"Count\\\");\\n const fieldKey = field.toLowerCase();\\n return (\\n \\n \\n \\n runAction(() => {\\n changeBladeActionField(action, fieldKey, BIG);\\n return title + \\\" \\\" + fieldKey + \\\" raised\\\";\\n }, title + \\\" \\\" + fieldKey)} add={(value) => runAction(() => {\\n changeBladeActionField(action, fieldKey, value);\\n return title + \\\" \\\" + fieldKey + \\\" raised\\\";\\n }, \\\"Add \\\" + title + \\\" \\\" + fieldKey)} subtract={(value) => runAction(() => {\\n changeBladeActionField(action, fieldKey, -value);\\n return title + \\\" \\\" + fieldKey + \\\" lowered\\\";\\n }, \\\"Subtract \\\" + title + \\\" \\\" + fieldKey)} reset={() => runAction(() => {\\n resetBladeActionField(action, fieldKey);\\n return title + \\\" \\\" + fieldKey + \\\" reset\\\";\\n }, \\\"Reset \\\" + title + \\\" \\\" + fieldKey)}> \\n \\n );\\n}\\n\\nfunction changeBladeActionField(action, fieldKey, value) {\\n if (!action) return;\\n const defaultValue = fieldKey === \\\"level\\\" ? 1 : 0;\\n action[fieldKey] = (action[fieldKey] ?? defaultValue) + value;\\n if (fieldKey === \\\"level\\\") action.maxLevel = action.level;\\n}\\n\\nfunction resetBladeActionField(action, fieldKey) {\\n if (!action) return;\\n action[fieldKey] = fieldKey === \\\"level\\\" ? 1 : 0;\\n if (fieldKey === \\\"level\\\") action.maxLevel = 1;\\n}\\n\\nfunction changeBladeburnerRank(bb, player, value) {\\n if (bb.changeRank) bb.changeRank(player, value);\\n else bb.rank = (bb.rank ?? 0) + value;\\n}\\n\\nfunction changeCityChaos(city, value) {\\n if (city.changeChaosByCount) city.changeChaosByCount(value);\\n else city.chaos = (city.chaos ?? 0) + value;\\n}\\n\\nfunction GangTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const gang = snapshot.player.gang;\\n if (!gang) return {\\\"Create a gang from the General row first.\\\"} ;\\n return (\\n \\n runAction(() => {\\n gang.storedCycles = BIG;\\n return \\\"Gang cycles maxed\\\";\\n }, \\\"Gang cycles\\\")} add={(value) => runAction(() => {\\n gang.storedCycles += value;\\n return \\\"Gang cycles added\\\";\\n }, \\\"Add gang cycles\\\")} subtract={(value) => runAction(() => {\\n gang.storedCycles -= value;\\n return \\\"Gang cycles subtracted\\\";\\n }, \\\"Subtract gang cycles\\\")} reset={() => runAction(() => {\\n gang.storedCycles = 0;\\n return \\\"Gang cycles reset\\\";\\n }, \\\"Reset gang cycles\\\")}> \\n \\n );\\n}\\n\\nfunction CorporationTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const corp = snapshot.player.corporation;\\n if (!corp) return {\\\"Create a corporation from the General row first.\\\"} ;\\n return (\\n \\n \\n runAction(() => {\\n gainCorpFunds(corp, BIG);\\n return \\\"Corporation funds added\\\";\\n }, \\\"Corp funds\\\")} add={(value) => runAction(() => {\\n gainCorpFunds(corp, value);\\n return \\\"Corporation funds added\\\";\\n }, \\\"Add corp funds\\\")} subtract={(value) => runAction(() => {\\n loseCorpFunds(corp, value);\\n return \\\"Corporation funds subtracted\\\";\\n }, \\\"Subtract corp funds\\\")} reset={() => runAction(() => {\\n loseCorpFunds(corp, corp.funds ?? 0);\\n return \\\"Corporation funds reset\\\";\\n }, \\\"Reset corp funds\\\")}> \\n \\n \\n runAction(() => {\\n corp.storedCycles = BIG;\\n return \\\"Corporation cycles maxed\\\";\\n }, \\\"Corp cycles\\\")} add={(value) => runAction(() => {\\n corp.storedCycles += value;\\n return \\\"Corporation cycles added\\\";\\n }, \\\"Add corp cycles\\\")} subtract={(value) => runAction(() => {\\n corp.storedCycles -= value;\\n return \\\"Corporation cycles subtracted\\\";\\n }, \\\"Subtract corp cycles\\\")} reset={() => runAction(() => {\\n corp.storedCycles = 0;\\n return \\\"Corporation cycles reset\\\";\\n }, \\\"Reset corp cycles\\\")}> \\n \\n \\n runAction(() => {\\n corp.divisions?.forEach?.((division) => division.products?.forEach?.((product) => product.developmentProgress = 99.9));\\n return \\\"Products nearly finished\\\";\\n }, \\\"Finish products\\\")}> \\n runAction(() => {\\n corp.divisions?.forEach?.((division) => division.researchPoints += 1e10);\\n return \\\"Research added\\\";\\n }, \\\"Corp research\\\")}> \\n runAction(() => {\\n corp.shareSaleCooldown = 0;\\n corp.issueNewSharesCooldown = 0;\\n return \\\"Stock cooldowns reset\\\";\\n }, \\\"Corp cooldowns\\\")}> \\n \\n \\n );\\n}\\n\\nfunction gainCorpFunds(corp, value) {\\n if (corp.gainFunds) corp.gainFunds(value, \\\"force majeure\\\");\\n else corp.funds = (corp.funds ?? 0) + value;\\n}\\n\\nfunction loseCorpFunds(corp, value) {\\n if (corp.loseFunds) corp.loseFunds(value, \\\"force majeure\\\");\\n else corp.funds = (corp.funds ?? 0) - value;\\n}\\n\\nfunction CodingContractTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [contractType, setContractType] = React.useState(snapshot.contractTypes[0] ?? DEFAULT_CONTRACT_TYPES[0]);\\n const [contractCount, setContractCount] = React.useState(\\\"1\\\");\\n return (\\n \\n \\n {\\\"Amt\\\"} setContractCount(event.target.value)}> \\n runAction(() => {\\n const count = Math.max(1, Math.floor(safeNumber(contractCount, 1)));\\n const created = [];\\n for (let i = 0; i < count; i++) {\\n const name = createDummyContractOnHome(snapshot, contractType);\\n if (name) created.push(name);\\n }\\n return created.length ? \\\"Generated \\\" + created.length + \\\" contract(s)\\\" : \\\"Contract generation failed\\\";\\n }, \\\"Generate contract\\\")}> \\n runAction(() => {\\n const count = Math.max(1, Math.floor(safeNumber(contractCount, 1)));\\n const created = [];\\n for (let i = 0; i < count; i++) {\\n const type = snapshot.contractTypes[Math.floor(Math.random() * snapshot.contractTypes.length)];\\n const name = createDummyContractOnHome(snapshot, type);\\n if (name) created.push(name);\\n }\\n return created.length ? \\\"Generated \\\" + created.length + \\\" random contract(s)\\\" : \\\"Contract generation failed\\\";\\n }, \\\"Generate random contract\\\")}> \\n \\n );\\n}\\n\\nfunction createDummyContractOnHome(snapshot, contractType) {\\n const game = globalThis.__devMenuTestBridge ?? snapshot.game;\\n const generator = game?.funcs?.generateDummyContract;\\n if (!generator) {\\n exposeInternalGameObjects(true);\\n }\\n const generateDummyContract = (globalThis.__devMenuTestBridge?.funcs ?? game?.funcs)?.generateDummyContract;\\n const home = globalThis.__devMenuTestBridge?.Player?.getHomeComputer?.() ?? snapshot.home;\\n if (!generateDummyContract || !home) return null;\\n return generateDummyContract(contractType, home);\\n}\\n\\nfunction StockTools({ snapshot, runAction, setStatus }) {\\n const React = getReactLib();\\n const [symbol, setSymbol] = React.useState(\\\"All\\\");\\n const [price, setPrice] = React.useState(\\\"1000000\\\");\\n const stocks = getStocks(snapshot.game);\\n const stockOptions = [\\\"All\\\", ...uniqueSorted([...snapshot.stockSymbols, ...stocks.map((stock) => stock.symbol)])];\\n const selectedSymbol = stockOptions.includes(symbol) ? symbol : \\\"All\\\";\\n const matchingStocks = () => {\\n if (!selectedSymbol || selectedSymbol === \\\"All\\\") return stocks;\\n return stocks.filter((stock) => stock.symbol === selectedSymbol);\\n };\\n return (\\n \\n \\n \\n \\n \\n setPrice(event.target.value)}>\\n runAction(() => {\\n matchingStocks().forEach((stock) => stock.price = safeNumber(price));\\n return \\\"Stock price set for \\\" + matchingStocks().length + \\\" stock(s)\\\";\\n }, \\\"Set stock price\\\")}> \\n runAction(() => {\\n const text = matchingStocks().map((stock) => stock.symbol + \\\": \\\" + formatMoney(stock.cap)).join(\\\" | \\\");\\n setStatus(text || \\\"No matching stocks\\\");\\n return \\\"Stock caps shown in toolbar\\\";\\n }, \\\"View stock caps\\\")}> \\n \\n \\n );\\n}\\n\\nfunction SleeveTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const sleeves = snapshot.player.sleeves ?? [];\\n const [sleeveTarget, setSleeveTarget] = React.useState(\\\"All\\\");\\n const [shockValue, setShockValue] = React.useState(\\\"\\\");\\n const [syncValue, setSyncValue] = React.useState(\\\"\\\");\\n const [cycleValue, setCycleValue] = React.useState(\\\"\\\");\\n const [sleeveAug, setSleeveAug] = React.useState(\\\"All\\\");\\n const sleeveOptions = [\\\"All\\\", ...sleeves.map((_, index) => \\\"Sleeve \\\" + index)];\\n const selectedTarget = sleeveOptions.includes(sleeveTarget) ? sleeveTarget : \\\"All\\\";\\n const targetSleeves = () => selectedTarget === \\\"All\\\" ? sleeves : [sleeves[Number(selectedTarget.replace(\\\"Sleeve \\\", \\\"\\\"))]].filter(Boolean);\\n const targets = targetSleeves();\\n const augOptions = [\\\"All\\\", ...getSleeveAugmentationNames(snapshot, targets)];\\n const selectedAug = augOptions.includes(sleeveAug) ? sleeveAug : \\\"All\\\";\\n const targetLabel = selectedTarget === \\\"All\\\" ? \\\"all sleeves\\\" : selectedTarget;\\n if (!sleeves.length) return {\\\"No sleeves are currently available.\\\"} ;\\n return (\\n \\n \\n {\\n setSleeveTarget(value);\\n setSleeveAug(\\\"All\\\");\\n }}> \\n {targetLabel} \\n \\n \\n setShockValue(event.target.value)}>\\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"shock\\\", clampNumber(safeNumber(shockValue), 0, 100));\\n return \\\"Sleeve shock set for \\\" + targetLabel;\\n }, \\\"Set sleeve shock\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"shock\\\", 100);\\n return \\\"Sleeve shock maxed\\\";\\n }, \\\"Sleeve shock\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"shock\\\", 0);\\n return \\\"Sleeve shock cleared\\\";\\n }, \\\"Clear sleeve shock\\\")}> \\n \\n \\n setSyncValue(event.target.value)}>\\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"sync\\\", clampNumber(safeNumber(syncValue), 0, 100));\\n return \\\"Sleeve sync set for \\\" + targetLabel;\\n }, \\\"Set sleeve sync\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"sync\\\", 100);\\n return \\\"Sleeve sync maxed\\\";\\n }, \\\"Sleeve sync\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"sync\\\", 0);\\n return \\\"Sleeve sync cleared\\\";\\n }, \\\"Clear sleeve sync\\\")}> \\n \\n \\n setCycleValue(event.target.value)}>\\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"storedCycles\\\", Math.max(0, safeNumber(cycleValue)));\\n return \\\"Sleeve cycles set for \\\" + targetLabel;\\n }, \\\"Set sleeve cycles\\\")}> \\n runAction(() => {\\n changeSleeveField(targetSleeves(), \\\"storedCycles\\\", safeNumber(cycleValue));\\n return \\\"Sleeve cycles added for \\\" + targetLabel;\\n }, \\\"Add sleeve cycles\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"storedCycles\\\", 10000000);\\n return \\\"Sleeve cycles set for \\\" + targetLabel;\\n }, \\\"Sleeve cycles\\\")}> \\n runAction(() => {\\n setSleeveField(targetSleeves(), \\\"storedCycles\\\", 0);\\n return \\\"Sleeve cycles reset\\\";\\n }, \\\"Reset sleeve cycles\\\")}> \\n \\n \\n \\n runAction(() => installSleeveAugmentations(snapshot, targetSleeves(), selectedAug), \\\"Install sleeve augments\\\")}> \\n {countSleeveAugmentations(snapshot, targets, selectedAug) + \\\" ready\\\"} \\n \\n \\n );\\n}\\n\\nfunction setSleeveField(sleeves, field, value) {\\n sleeves.forEach((sleeve) => sleeve[field] = value);\\n}\\n\\nfunction changeSleeveField(sleeves, field, value) {\\n sleeves.forEach((sleeve) => sleeve[field] = Math.max(0, safeNumber(sleeve[field]) + value));\\n}\\n\\nfunction clampNumber(value, min, max) {\\n return Math.min(max, Math.max(min, value));\\n}\\n\\nconst SLEEVE_AUGMENT_MULTS = [\\n \\\"hacking\\\",\\n \\\"strength\\\",\\n \\\"defense\\\",\\n \\\"dexterity\\\",\\n \\\"agility\\\",\\n \\\"charisma\\\",\\n \\\"hacking_exp\\\",\\n \\\"strength_exp\\\",\\n \\\"defense_exp\\\",\\n \\\"dexterity_exp\\\",\\n \\\"agility_exp\\\",\\n \\\"charisma_exp\\\",\\n \\\"company_rep\\\",\\n \\\"faction_rep\\\",\\n \\\"crime_money\\\",\\n \\\"crime_success\\\",\\n \\\"work_money\\\",\\n];\\n\\nfunction getSleeveAugmentationObjects(snapshot, sleeves) {\\n const byName = new Map();\\n const allAugs = getAugmentationObjects(snapshot.game);\\n if (allAugs.length) {\\n sleeves.forEach((sleeve) => {\\n for (const aug of allAugs) {\\n if (isSleeveAugReady(sleeve, aug) && !byName.has(aug.name)) byName.set(aug.name, aug);\\n }\\n });\\n } else {\\n sleeves.forEach((sleeve) => {\\n try {\\n for (const aug of sleeve.findPurchasableAugs?.() ?? []) {\\n if (aug?.name && !byName.has(aug.name)) byName.set(aug.name, aug);\\n }\\n } catch { }\\n });\\n }\\n return [...byName.values()].sort((a, b) => String(a.name).localeCompare(String(b.name)));\\n}\\n\\nfunction getSleeveAugmentationNames(snapshot, sleeves) {\\n return getSleeveAugmentationObjects(snapshot, sleeves).map((aug) => aug.name);\\n}\\n\\nfunction countSleeveAugmentations(snapshot, sleeves, augName) {\\n let count = 0;\\n const allAugs = getAugmentationObjects(snapshot.game);\\n if (allAugs.length) {\\n sleeves.forEach((sleeve) => {\\n count += allAugs.filter((aug) => isSleeveAugReady(sleeve, aug) && (augName === \\\"All\\\" || aug.name === augName)).length;\\n });\\n } else {\\n sleeves.forEach((sleeve) => {\\n try {\\n const available = sleeve.findPurchasableAugs?.() ?? [];\\n count += augName === \\\"All\\\" ? available.length : available.filter((aug) => aug?.name === augName).length;\\n } catch { }\\n });\\n }\\n return count;\\n}\\n\\nfunction installSleeveAugmentations(snapshot, sleeves, augName) {\\n const allAugs = getAugmentationObjects(snapshot.game);\\n if (!allAugs.length) return installSleeveAugmentationsFallback(sleeves, augName);\\n let installed = 0;\\n sleeves.forEach((sleeve) => {\\n if (augName === \\\"All\\\") {\\n let madeProgress = true;\\n while (madeProgress) {\\n madeProgress = false;\\n for (const aug of allAugs) {\\n if (!isSleeveAugReady(sleeve, aug)) continue;\\n if (forceInstallSleeveAugmentation(sleeve, aug)) {\\n installed++;\\n madeProgress = true;\\n }\\n }\\n }\\n return;\\n }\\n const aug = allAugs.find((item) => item.name === augName);\\n if (aug && isSleeveAugReady(sleeve, aug) && forceInstallSleeveAugmentation(sleeve, aug)) installed++;\\n });\\n return installed ? \\\"Installed \\\" + installed + \\\" sleeve augmentation(s)\\\" : \\\"No sleeve augmentations were installed\\\";\\n}\\n\\nfunction installSleeveAugmentationsFallback(sleeves, augName) {\\n let installed = 0;\\n sleeves.forEach((sleeve) => {\\n let available = [];\\n try {\\n available = sleeve.findPurchasableAugs?.() ?? [];\\n } catch { }\\n const selected = augName === \\\"All\\\" ? available : available.filter((aug) => aug?.name === augName);\\n selected.forEach((aug) => {\\n if (forceInstallSleeveAugmentation(sleeve, aug)) installed++;\\n });\\n });\\n return installed ? \\\"Installed \\\" + installed + \\\" sleeve augmentation(s)\\\" : \\\"No sleeve augmentations were installed\\\";\\n}\\n\\nfunction forceInstallSleeveAugmentation(sleeve, aug) {\\n try {\\n if (!aug || !isSleeveAugAllowed(aug) || sleeveHasAugmentation(sleeve, aug.name) || !hasSleeveAugPrereqs(sleeve, aug)) return false;\\n if (typeof sleeve.installAugmentation === \\\"function\\\") {\\n sleeve.installAugmentation(aug);\\n return true;\\n }\\n } catch { }\\n return false;\\n}\\n\\nfunction isSleeveAugReady(sleeve, aug) {\\n return isSleeveAugAllowed(aug) && !sleeveHasAugmentation(sleeve, aug.name) && hasSleeveAugPrereqs(sleeve, aug);\\n}\\n\\nfunction isSleeveAugAllowed(aug) {\\n if (!isAugmentationObject(aug)) return false;\\n if (String(aug.name).includes(\\\"Z.O.\\\")) return true;\\n if (aug.isSpecial) return false;\\n return SLEEVE_AUGMENT_MULTS.some((mult) => safeNumber(aug.mults?.[mult], 1) !== 1);\\n}\\n\\nfunction hasSleeveAugPrereqs(sleeve, aug) {\\n const owned = new Set((sleeve?.augmentations ?? []).map((item) => item?.name));\\n return (aug.prereqs ?? []).every((name) => owned.has(name));\\n}\\n\\nfunction sleeveHasAugmentation(sleeve, augName) {\\n return (sleeve?.augmentations ?? []).some((item) => item?.name === augName);\\n}\\n\\nfunction StanekTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const gift = snapshot.game.staneksGift;\\n if (!gift) return {\\\"Stanek internals were not found. If you own the Gift, hit Actions -> Rescan Webpack.\\\"} ;\\n return (\\n \\n \\n runAction(() => {\\n gift.storedCycles = 1e6;\\n return \\\"Stanek cycles set\\\";\\n }, \\\"Stanek cycles\\\")} add={(value) => runAction(() => {\\n gift.storedCycles += value;\\n return \\\"Stanek cycles added\\\";\\n }, \\\"Add Stanek cycles\\\")} subtract={(value) => runAction(() => {\\n gift.storedCycles -= value;\\n return \\\"Stanek cycles subtracted\\\";\\n }, \\\"Subtract Stanek cycles\\\")} reset={() => runAction(() => {\\n gift.storedCycles = 0;\\n return \\\"Stanek cycles reset\\\";\\n }, \\\"Reset Stanek cycles\\\")}> \\n \\n \\n runAction(() => {\\n gift.fragments.forEach((fragment) => {\\n fragment.highestCharge = 1e21;\\n fragment.numCharge = 1e21;\\n });\\n snapshot.player.applyEntropy?.(snapshot.player.entropy);\\n return \\\"Stanek charge maxed\\\";\\n }, \\\"Stanek charge\\\")} add={(value) => runAction(() => {\\n gift.fragments.forEach((fragment) => fragment.highestCharge += value);\\n snapshot.player.applyEntropy?.(snapshot.player.entropy);\\n return \\\"Stanek charge added\\\";\\n }, \\\"Add Stanek charge\\\")} subtract={(value) => runAction(() => {\\n gift.fragments.forEach((fragment) => fragment.highestCharge -= value);\\n snapshot.player.applyEntropy?.(snapshot.player.entropy);\\n return \\\"Stanek charge subtracted\\\";\\n }, \\\"Subtract Stanek charge\\\")} reset={() => runAction(() => {\\n gift.fragments.forEach((fragment) => {\\n fragment.highestCharge = 0;\\n fragment.numCharge = 0;\\n });\\n return \\\"Stanek charge reset\\\";\\n }, \\\"Reset Stanek charge\\\")}> \\n \\n \\n );\\n}\\n\\nfunction TimeSkipTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [minutes, setMinutes] = React.useState(\\\"\\\");\\n return (\\n \\n setMinutes(event.target.value)}>\\n runAction(() => {\\n const amount = safeNumber(minutes, 0);\\n if (amount <= 0) return \\\"Enter minutes to skip\\\";\\n applyTimeSkip(snapshot, amount * 60 * 1000);\\n return \\\"Time skip applied: \\\" + formatNumber(amount) + \\\" minute(s)\\\";\\n }, \\\"Time skip minutes\\\")}> \\n {[\\n [\\\"1 minute\\\", 60 * 1000],\\n [\\\"1 hour\\\", 60 * 60 * 1000],\\n [\\\"1 day\\\", 24 * 60 * 60 * 1000],\\n ].map(([label, time]) => runAction(() => {\\n applyTimeSkip(snapshot, time);\\n return \\\"Time skip applied: \\\" + label;\\n }, \\\"Time skip\\\")}> )}\\n \\n );\\n}\\n\\nfunction applyTimeSkip(snapshot, time) {\\n snapshot.player.lastUpdate -= time;\\n if (snapshot.game.Engine) snapshot.game.Engine._lastUpdate -= time;\\n}\\n\\nfunction AchievementTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const achievements = objectValues(snapshot.game.achievements).filter((item) => item?.ID);\\n const [achievementId, setAchievementId] = React.useState(achievements[0]?.ID ?? \\\"\\\");\\n const selected = achievements.find((item) => item.ID === achievementId);\\n return (\\n \\n \\n runAction(() => {\\n achievements.forEach((ach) => snapshot.player.giveAchievement?.(ach.ID));\\n return \\\"All achievements granted\\\";\\n }, \\\"Grant all achievements\\\")}> \\n runAction(() => {\\n snapshot.player.achievements = [];\\n return \\\"Achievements cleared\\\";\\n }, \\\"Clear achievements\\\")}> \\n runAction(() => {\\n if (snapshot.game.Engine?.Counters) snapshot.game.Engine.Counters.achievementsCounter = Number.MAX_VALUE;\\n return \\\"Achievement engine check disabled\\\";\\n }, \\\"Disable achievement check\\\")}> \\n runAction(() => {\\n if (snapshot.game.Engine?.Counters) snapshot.game.Engine.Counters.achievementsCounter = 0;\\n return \\\"Achievement engine check enabled\\\";\\n }, \\\"Enable achievement check\\\")}> \\n \\n \\n ach.ID)} onChange={setAchievementId} width={280}> \\n runAction(() => {\\n snapshot.player.giveAchievement?.(achievementId);\\n return \\\"Achievement granted\\\";\\n }, \\\"Grant achievement\\\")}> \\n runAction(() => {\\n snapshot.player.achievements = snapshot.player.achievements.filter((ach) => ach.ID !== achievementId);\\n return \\\"Achievement cleared\\\";\\n }, \\\"Clear achievement\\\")}> \\n {selected ? \\\" \\\" + selected.Name : \\\"\\\"} \\n \\n \\n );\\n}\\n\\nfunction EntropyTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const player = snapshot.player;\\n return (\\n \\n runAction(() => {\\n player.entropy += 1e12;\\n player.applyEntropy?.(player.entropy);\\n return \\\"Entropy added\\\";\\n }, \\\"Entropy\\\")} add={(value) => runAction(() => {\\n player.entropy += value;\\n player.applyEntropy?.(player.entropy);\\n return \\\"Entropy added\\\";\\n }, \\\"Add entropy\\\")} subtract={(value) => runAction(() => {\\n player.entropy -= value;\\n player.applyEntropy?.(player.entropy);\\n return \\\"Entropy subtracted\\\";\\n }, \\\"Subtract entropy\\\")} reset={() => runAction(() => {\\n player.entropy = 0;\\n player.applyEntropy?.(player.entropy);\\n return \\\"Entropy reset\\\";\\n }, \\\"Reset entropy\\\")}> \\n \\n );\\n}\\n\\nfunction DarknetTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n const [darkType, setDarkType] = React.useState(\\\"RANDOM\\\");\\n const [darkCount, setDarkCount] = React.useState(\\\"1\\\");\\n const [darkDifficulty, setDarkDifficulty] = React.useState(\\\"1\\\");\\n const [darkDepth, setDarkDepth] = React.useState(\\\"1\\\");\\n const state = snapshot.game.DarknetState;\\n const darkServers = snapshot.servers.filter((server) => isDarknetServerLike(server));\\n return (\\n \\n \\n runAction(() => {\\n if (state) {\\n state.showFullNetwork = !state.showFullNetwork;\\n snapshot.game.DarknetEvents?.emit?.();\\n }\\n return state ? \\\"Darknet full-network toggled\\\" : \\\"Darknet state was not found\\\";\\n }, \\\"Toggle full darknet\\\")}> \\n runAction(() => {\\n if (snapshot.game.funcs.getDarkscapeNavigator) snapshot.game.funcs.getDarkscapeNavigator();\\n else pushProgram(snapshot.home, \\\"DarkscapeNavigator.exe\\\");\\n return \\\"DarkscapeNavigator granted\\\";\\n }, \\\"Get Darkscape\\\")}> \\n \\n \\n runAction(() => {\\n let funcs = snapshot.game.funcs;\\n if (!funcs.clearDarknet || !funcs.populateDarknet) {\\n exposeInternalGameObjects(true);\\n funcs = globalThis.__devMenuTestBridge?.funcs ?? funcs;\\n }\\n const missing = missingDarknetHelpers(funcs, [\\\"clearDarknet\\\", \\\"populateDarknet\\\"]);\\n if (missing.length) return \\\"Darknet generator helpers were not found. Missing: \\\" + missing.join(\\\", \\\");\\n funcs.clearDarknet();\\n funcs.populateDarknet();\\n (globalThis.__devMenuTestBridge?.DarknetEvents ?? snapshot.game.DarknetEvents)?.emit?.();\\n return \\\"New dark network generated\\\";\\n }, \\\"Generate darknet\\\")}> \\n runAction(() => {\\n return shuffleDarknetServers(snapshot, darkServers);\\n }, \\\"Shuffle darknet\\\")}> \\n \\n \\n {\\\"Type\\\"} \\n {\\\"Count\\\"} setDarkCount(event.target.value)}> \\n {\\\"Difficulty\\\"} setDarkDifficulty(event.target.value)}> \\n {\\\"Depth\\\"} setDarkDepth(event.target.value)}> \\n runAction(() => {\\n const count = Math.max(1, Math.floor(safeNumber(darkCount, 1)));\\n const difficulty = Math.max(0, Math.floor(safeNumber(darkDifficulty, 1)));\\n const depth = Math.max(0, Math.floor(safeNumber(darkDepth, difficulty)));\\n return addDarknetServers(snapshot, darkType, count, difficulty, depth);\\n }, \\\"Add darknet servers\\\")}> \\n \\n \\n runAction(() => {\\n if (snapshot.game.funcs.handleSuccessfulAuth) darkServers.forEach((server) => snapshot.game.funcs.handleSuccessfulAuth(server, 1, -1));\\n else darkServers.forEach(rootServer);\\n return \\\"Darknet servers rooted\\\";\\n }, \\\"Root darknet\\\")}> \\n runAction(() => {\\n darkServers.forEach((server) => server.backdoorInstalled = true);\\n return \\\"Darknet servers backdoored\\\";\\n }, \\\"Backdoor darknet\\\")}> \\n runAction(() => {\\n return startWebstorm(snapshot, darkServers);\\n }, \\\"Webstorm\\\")}> \\n \\n \\n {darkServers.length + \\\" darknet-like servers visible to this script\\\"} \\n \\n \\n );\\n}\\n\\nfunction addDarknetServers(snapshot, type, count, difficulty, depth) {\\n const funcs = getFreshDarknetFuncs(snapshot, type === \\\"RANDOM\\\" ? [\\\"createDarknetServer\\\", \\\"moveDarknetServer\\\", \\\"addRandomDarknetServers\\\"] : [\\\"serverFactory\\\", \\\"moveDarknetServer\\\"]);\\n if (type === \\\"RANDOM\\\") {\\n if (funcs.createDarknetServer && funcs.moveDarknetServer) {\\n let success = 0;\\n const range = Math.max(3, Math.ceil(count / 4));\\n for (let i = 0; i < count; i++) {\\n const server = funcs.createDarknetServer(difficulty, -1, -1);\\n success += funcs.moveDarknetServer(server, range, range, depth) ? 1 : 0;\\n }\\n getFreshDarknetEvents(snapshot)?.emit?.();\\n return \\\"Added \\\" + success + \\\" random darknet server(s)\\\";\\n }\\n if (funcs.addRandomDarknetServers) {\\n funcs.addRandomDarknetServers(count, difficulty, true);\\n getFreshDarknetEvents(snapshot)?.emit?.();\\n return \\\"Added \\\" + count + \\\" random darknet server(s)\\\";\\n }\\n return \\\"Darknet random-server helper was not found. Missing: \\\" + missingDarknetHelpers(funcs, [\\\"createDarknetServer\\\", \\\"moveDarknetServer\\\", \\\"addRandomDarknetServers\\\"]).join(\\\", \\\");\\n }\\n const builder = (globalThis.__devMenuTestBridge?.darknetConfigBuilders ?? snapshot.game.darknetConfigBuilders)?.[type];\\n if (!builder || !funcs.serverFactory || !funcs.moveDarknetServer) return \\\"Specific darknet server helpers were not found for \\\" + type + \\\". Missing: \\\" + missingDarknetHelpers({ ...funcs, builder }, [\\\"builder\\\", \\\"serverFactory\\\", \\\"moveDarknetServer\\\"]).join(\\\", \\\");\\n let success = 0;\\n const range = Math.max(3, Math.ceil(count / 4));\\n for (let i = 0; i < count; i++) {\\n const server = funcs.serverFactory(builder, difficulty, -1, -1);\\n success += funcs.moveDarknetServer(server, range, range, depth) ? 1 : 0;\\n }\\n getFreshDarknetEvents(snapshot)?.emit?.();\\n return \\\"Added \\\" + success + \\\" \\\" + type + \\\" darknet server(s)\\\";\\n}\\n\\nfunction shuffleDarknetServers(snapshot, darkServers) {\\n const funcs = getFreshDarknetFuncs(snapshot, [\\\"moveRandomDarknetServers\\\", \\\"moveDarknetServer\\\"]);\\n const allDarknetServers = getAllDarknetServersForDev(snapshot, darkServers);\\n const count = Math.floor(allDarknetServers.length / 2);\\n if (funcs.moveRandomDarknetServers) {\\n funcs.moveRandomDarknetServers(count);\\n //refreshDarknetUi(snapshot);\\n return \\\"Darknet servers shuffled\\\";\\n }\\n if (funcs.moveDarknetServer) {\\n let moved = 0;\\n const movableServers = getMovableDarknetServers(snapshot, darkServers);\\n for (const server of shuffleArray(movableServers).slice(0, count)) {\\n const oldDepth = server.depth;\\n const oldOffset = server.leftOffset;\\n const didMove = funcs.moveDarknetServer(server);\\n if (didMove && (server.depth !== oldDepth || server.leftOffset !== oldOffset)) moved++;\\n }\\n //refreshDarknetUi(snapshot);\\n return \\\"Darknet servers shuffled (\\\" + moved + \\\"/\\\" + movableServers.length + \\\" moved)\\\";\\n }\\n return \\\"Darknet movement helper was not found. Missing: \\\" + missingDarknetHelpers(funcs, [\\\"moveRandomDarknetServers\\\", \\\"moveDarknetServer\\\"]).join(\\\", \\\");\\n}\\n\\nfunction getAllDarknetServersForDev(snapshot, darkServers) {\\n try {\\n const game = globalThis.__devMenuTestBridge ?? snapshot.game;\\n const servers = getAllServers(game).filter(isDarknetServerLike);\\n if (servers.length) return servers;\\n } catch { }\\n return darkServers ?? [];\\n}\\n\\nfunction getMovableDarknetServers(snapshot, darkServers) {\\n const state = globalThis.__devMenuTestBridge?.DarknetState ?? snapshot.game?.DarknetState;\\n const servers = getAllDarknetServersForDev(snapshot, darkServers);\\n return servers.filter((server) => {\\n if (!server || server === state?.openServer) return false;\\n if (server.isStationary || server.hasStasisLink || server.isConnectedTo) return false;\\n if (!Number.isFinite(server.depth) || server.depth < 0) return false;\\n if (!Number.isFinite(server.leftOffset) || server.leftOffset < 0) return false;\\n return true;\\n });\\n}\\n\\nfunction refreshDarknetUi(snapshot) {\\n const state = globalThis.__devMenuTestBridge?.DarknetState ?? snapshot.game?.DarknetState;\\n try {\\n state?.nextMutationResolver?.();\\n if (state && \\\"nextMutation\\\" in state) {\\n state[\\\"nextMutation\\\"] = new Promise((resolve) => {\\n state.nextMutationResolver = resolve;\\n });\\n }\\n } catch { }\\n getFreshDarknetEvents(snapshot)?.emit?.();\\n}\\n\\nfunction startWebstorm(snapshot, darkServers) {\\n const funcs = getFreshDarknetFuncs(snapshot, [\\n \\\"deleteRandomDarknetServers\\\",\\n \\\"moveRandomDarknetServers\\\",\\n \\\"restartAllDarknetServers\\\",\\n \\\"addRandomDarknetServers\\\",\\n \\\"balanceDarknetServers\\\",\\n \\\"validateDarknetNetwork\\\",\\n \\\"launchWebstorm\\\",\\n ]);\\n const manualHelpers = [\\\"deleteRandomDarknetServers\\\", \\\"moveRandomDarknetServers\\\", \\\"restartAllDarknetServers\\\", \\\"addRandomDarknetServers\\\", \\\"balanceDarknetServers\\\"];\\n const missingManual = missingDarknetHelpers(funcs, manualHelpers);\\n if (!missingManual.length) {\\n startManualWebstorm(snapshot, darkServers, funcs);\\n return \\\"Webstorm launched without game UI hooks\\\";\\n }\\n if (funcs.launchWebstorm) {\\n const launched = funcs.launchWebstorm(true);\\n if (launched?.catch) launched.catch((error) => console.error(error));\\n return \\\"Webstorm launched with suppressed game toast\\\";\\n }\\n return \\\"Webstorm helpers were not found. Missing: \\\" + missingManual.join(\\\", \\\");\\n}\\n\\nfunction startManualWebstorm(snapshot, darkServers, funcs) {\\n const state = globalThis.__devMenuTestBridge?.DarknetState ?? snapshot.game?.DarknetState;\\n if (state?.mutationLock) return;\\n let cancelled = false;\\n if (state) {\\n state.mutationLock = () => {\\n cancelled = true;\\n state.mutationLock = null;\\n };\\n }\\n const finish = () => {\\n if (state?.mutationLock) state.mutationLock = null;\\n };\\n const phase = (delay, action, final = false) => {\\n setTimeout(() => {\\n if (cancelled) return;\\n try {\\n action();\\n funcs.validateDarknetNetwork?.();\\n getFreshDarknetEvents(snapshot)?.emit?.();\\n } catch (error) {\\n cancelled = true;\\n console.error(error);\\n } finally {\\n if (final || cancelled) finish();\\n }\\n }, delay);\\n };\\n const netWidth = state?.Network?.[0]?.length || 8;\\n const currentCount = () => {\\n const game = globalThis.__devMenuTestBridge ?? snapshot.game;\\n try {\\n return getAllServers(game).filter(isDarknetServerLike).length || darkServers.length || netWidth;\\n } catch {\\n return darkServers.length || netWidth;\\n }\\n };\\n const estimatedDepth = () => Math.max(1, Math.ceil(currentCount() / Math.max(1, netWidth * 0.6)));\\n\\n phase(5000, () => {\\n const serversToDelete = Math.max(0, currentCount() * 0.6 + (Math.random() * estimatedDepth() - 6));\\n funcs.deleteRandomDarknetServers(serversToDelete);\\n funcs.moveRandomDarknetServers(Math.max(1, (currentCount() - serversToDelete) * 0.6));\\n funcs.restartAllDarknetServers();\\n });\\n phase(9000, () => funcs.addRandomDarknetServers(netWidth));\\n phase(13000, () => funcs.addRandomDarknetServers(netWidth * 2));\\n phase(17000, () => funcs.addRandomDarknetServers(netWidth * 2));\\n phase(25000, () => funcs.balanceDarknetServers(), true);\\n}\\n\\nfunction getFreshDarknetFuncs(snapshot, required = []) {\\n let funcs = snapshot.game?.funcs ?? {};\\n if (required.some((name) => !isUsableBridgeValue(funcs[name]))) {\\n exposeInternalGameObjects(true);\\n funcs = globalThis.__devMenuTestBridge?.funcs ?? funcs;\\n }\\n for (const [name, value] of objectEntries(funcs)) {\\n if (typeof value === \\\"function\\\" && !isCallableHelper(value)) delete funcs[name];\\n }\\n return funcs;\\n}\\n\\nfunction getFreshDarknetEvents(snapshot) {\\n return globalThis.__devMenuTestBridge?.DarknetEvents ?? snapshot.game?.DarknetEvents;\\n}\\n\\nfunction shuffleArray(values) {\\n const copy = [...values];\\n for (let i = copy.length - 1; i > 0; i--) {\\n const j = Math.floor(Math.random() * (i + 1));\\n [copy[i], copy[j]] = [copy[j], copy[i]];\\n }\\n return copy;\\n}\\n\\nfunction missingDarknetHelpers(record, names) {\\n return names.filter((name) => !isUsableBridgeValue(record?.[name]));\\n}\\n\\nfunction isUsableBridgeValue(value) {\\n if (!value) return false;\\n return typeof value !== \\\"function\\\" || isCallableHelper(value);\\n}\\n\\nfunction isDarknetServerLike(server) {\\n return !!server && typeof server === \\\"object\\\" && (\\\"modelId\\\" in server || \\\"passwordHintData\\\" in server || \\\"leftOffset\\\" in server) && \\\"depth\\\" in server;\\n}\\n\\nfunction ExtraTools({ snapshot, runAction }) {\\n const React = getReactLib();\\n return (\\n \\n \\n runAction(() => {\\n snapshot.servers.filter(isMutableServer).forEach((server) => {\\n rootServer(server);\\n if (\\\"moneyMax\\\" in server) server.moneyAvailable = server.moneyMax;\\n if (\\\"minDifficulty\\\" in server) server.hackDifficulty = server.minDifficulty;\\n });\\n return \\\"Servers rooted, maxed, and weakened\\\";\\n }, \\\"Root/max all\\\")}> \\n runAction(() => {\\n snapshot.player.gainMoney(1e12, \\\"other\\\");\\n snapshot.programs.forEach((name) => pushProgram(snapshot.home, name));\\n snapshot.servers.filter(isMutableServer).forEach(rootServer);\\n return \\\"Starter package applied\\\";\\n }, \\\"Starter package\\\")}> \\n \\n \\n runAction(() => {\\n exposeInternalGameObjects(true);\\n return \\\"Webpack bridge rescanned\\\";\\n }, \\\"Rescan webpack\\\")}> \\n \\n \\n );\\n}\\n\\nfunction ActionButton({ text, onClick, style }) {\\n const React = getReactLib();\\n return {text} ;\\n}\\n\\nfunction Adjuster({ label, placeholder, tons, add, subtract, reset }) {\\n const React = getReactLib();\\n const [value, setValue] = React.useState(\\\"\\\");\\n const numberValue = () => safeNumber(value);\\n return (\\n \\n setValue(event.target.value)}>\\n \\n add(numberValue())}> \\n subtract(numberValue())}> \\n \\n \\n );\\n}\\n\\nfunction SelectBox({ value, options, onChange, width }) {\\n const React = getReactLib();\\n const selectWidth = getSelectWidth(options, width);\\n return (\\n onChange(event.target.value)}>\\n {options.map((option) => {String(option)} )}\\n \\n );\\n}\\n\\nfunction getSelectWidth(options, maxWidth) {\\n const longest = Math.max(3, ...(options ?? []).map((option) => String(option).length));\\n const width = Math.max(62, Math.min(420, longest * 8 + 34));\\n return maxWidth ? Math.min(maxWidth, width) : width;\\n}\\n\\nfunction Line({ label, children }) {\\n const React = getReactLib();\\n return (\\n \\n {label} \\n {children} \\n
\\n );\\n}\\n\\nfunction normalizeRowContent(node) {\\n const React = getReactLib();\\n if (!React || node === null || node === undefined || typeof node === \\\"boolean\\\") return node;\\n if (typeof node === \\\"string\\\" || typeof node === \\\"number\\\") return node;\\n if (!React.isValidElement(node)) return node;\\n const childProps = node.props ?? {};\\n const normalizedChildren = React.Children.map(childProps.children, (child) => normalizeRowContent(child));\\n if (typeof node.type === \\\"string\\\" && node.type.toLowerCase() === \\\"button\\\") {\\n return React.cloneElement(node, { ...childProps, style: { ...rowButtonBaseStyle, ...(childProps.style ?? {}) } }, normalizedChildren);\\n }\\n return React.cloneElement(node, childProps, normalizedChildren);\\n}\\n\\nfunction Row({ row, onHideToggle }) {\\n const React = getReactLib();\\n const title = row.title;\\n const normalizedButtons = normalizeRowContent(row.body);\\n const hideToggle = event.stopPropagation()} onMouseDown={(event) => event.stopPropagation()} onChange={() => onHideToggle(title)}>;\\n const titleWithHide = {title}{hideToggle} ;\\n return (\\n \\n
{\\n if (event.currentTarget.open) openDB.add(title);\\n else openDB.delete(title);\\n }}>\\n {titleWithHide} \\n {normalizedButtons}
\\n \\n
\\n );\\n}\\n\\nfunction MiniView({ rows, selectedRows, onToggleRow, onHideToggle, rowVersion }) {\\n const React = getReactLib();\\n const openRows = rows.filter((row) => selectedRows.includes(row.title));\\n if (rows.length === 0) return {\\\"No rows are currently available in Mini view.\\\"}
;\\n return (\\n \\n
{\\\"Left Click to enable. Right Click to hide.\\\"}
\\n
\\n {rows.map((row) => onToggleRow(row.title)} onContextMenu={(event) => {\\n event.preventDefault();\\n onHideToggle(row.title);\\n }}>{row.title} )}\\n
\\n {openRows.length === 0\\n ?
{\\\"Select one or more rows above to show them here.\\\"}
\\n : openRows.map((row) =>
)}\\n
\\n );\\n}\\n\\nfunction MiniRowPanel({ row, onHideToggle }) {\\n const React = getReactLib();\\n return (\\n \\n
\\n
\\n
{row.title}
\\n
\\n onHideToggle(row.title)}>\\n {\\\"Visible\\\"}\\n \\n
\\n
\\n
{normalizeRowContent(row.body)}
\\n
\\n );\\n}\\n\\nconst appStyle = {\\n fontFamily: \\\"monospace\\\",\\n fontSize: 12,\\n lineHeight: 1.25,\\n};\\nconst greenStyle = {\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst redStyle = {\\n backgroundColor: \\\"var(--bb-theme-error)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst alwaysOnStyle = {\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst rowHideCheckboxStyle = {\\n marginLeft: 8,\\n verticalAlign: \\\"middle\\\",\\n};\\nconst rowBodyStyle = {\\n paddingTop: 6,\\n paddingBottom: 2,\\n};\\nconst summaryStyle = {\\n fontSize: 18,\\n cursor: \\\"pointer\\\",\\n};\\nconst rowButtonBaseStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"center\\\",\\n minWidth: 54,\\n height: 28,\\n padding: \\\"2px 7px\\\",\\n marginRight: 4,\\n marginBottom: 4,\\n borderRadius: 4,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n boxShadow: \\\"inset 0 1px 0 rgba(255,255,255,0.05)\\\",\\n textAlign: \\\"center\\\",\\n whiteSpace: \\\"normal\\\",\\n fontSize: 12,\\n lineHeight: 1.05,\\n overflow: \\\"hidden\\\",\\n verticalAlign: \\\"middle\\\",\\n cursor: \\\"pointer\\\",\\n};\\nconst topPanelWrapStyle = {\\n position: \\\"relative\\\",\\n marginBottom: 10,\\n padding: \\\"10px 12px 12px 12px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.02))\\\",\\n};\\nconst topPanelInfoStyle = {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n alignItems: \\\"center\\\",\\n gap: 10,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 10,\\n};\\nconst topPanelTitleStyle = {\\n fontSize: 18,\\n fontWeight: \\\"bold\\\",\\n};\\nconst topPanelMetaStyle = {\\n opacity: 0.8,\\n fontSize: 12,\\n lineHeight: 1.3,\\n};\\nconst displayStatusTrayStyle = {\\n display: \\\"flex\\\",\\n gap: 6,\\n flexWrap: \\\"wrap\\\",\\n};\\nconst displayStatusBaseStyle = {\\n appearance: \\\"none\\\",\\n padding: \\\"3px 8px\\\",\\n borderRadius: 999,\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n};\\nconst displayStatusMutedStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-infodark)\\\",\\n color: \\\"var(--bb-theme-secondarylight)\\\",\\n};\\nconst displayStatusWarnStyle = {\\n ...displayStatusBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-warning)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst toolbarBarStyle = {\\n display: \\\"flex\\\",\\n gap: 8,\\n alignItems: \\\"center\\\",\\n flexWrap: \\\"wrap\\\",\\n paddingTop: 8,\\n borderTop: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n};\\nconst viewModeToggleWrapStyle = {\\n display: \\\"inline-flex\\\",\\n gap: 6,\\n alignItems: \\\"center\\\",\\n padding: 3,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n background: \\\"rgba(255,255,255,0.04)\\\",\\n};\\nconst viewModeLabelStyle = {\\n fontSize: 12,\\n fontWeight: \\\"bold\\\",\\n opacity: 0.82,\\n paddingLeft: 4,\\n};\\nconst viewModeButtonStyle = {\\n appearance: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n borderRadius: 6,\\n padding: \\\"7px 12px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.06)\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n fontWeight: \\\"bold\\\",\\n};\\nconst viewModeButtonActiveStyle = {\\n ...viewModeButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst viewModeMiniActiveStyle = {\\n ...viewModeButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst toolbarMenuStyle = {\\n position: \\\"relative\\\",\\n};\\nconst toolbarSummaryStyle = {\\n appearance: \\\"none\\\",\\n listStyle: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n userSelect: \\\"none\\\",\\n borderRadius: 6,\\n padding: \\\"7px 12px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"var(--bb-theme-secondarylight)\\\",\\n fontWeight: \\\"bold\\\",\\n};\\nconst toolbarSummaryOpenStyle = {\\n ...toolbarSummaryStyle,\\n backgroundColor: \\\"var(--bb-theme-info)\\\",\\n border: \\\"1px solid rgba(138, 180, 255, 0.38)\\\",\\n};\\nconst toolbarDropdownStyle = {\\n position: \\\"absolute\\\",\\n top: \\\"50%\\\",\\n left: \\\"calc(100% + 4px)\\\",\\n transform: \\\"translateY(-50%)\\\",\\n display: \\\"flex\\\",\\n flexDirection: \\\"column\\\",\\n gap: 8,\\n padding: 10,\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n backgroundColor: \\\"rgba(10, 12, 18, 0.96)\\\",\\n boxShadow: \\\"0 14px 30px rgba(0,0,0,0.35)\\\",\\n zIndex: 40,\\n width: \\\"24ch\\\",\\n maxHeight: 360,\\n overflowY: \\\"auto\\\",\\n};\\nconst toolbarSectionTitleStyle = {\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n letterSpacing: \\\"0.08em\\\",\\n textTransform: \\\"uppercase\\\",\\n opacity: 0.72,\\n};\\nconst toolbarHintStyle = {\\n fontSize: 12,\\n opacity: 0.72,\\n paddingLeft: 4,\\n};\\nconst displayButtonBaseStyle = {\\n display: \\\"block\\\",\\n width: \\\"100%\\\",\\n textAlign: \\\"left\\\",\\n borderRadius: 6,\\n padding: \\\"6px 10px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n boxShadow: \\\"inset 0 1px 0 rgba(255,255,255,0.05)\\\",\\n};\\nconst displaySecondaryStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-cha)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst displayDangerStyle = {\\n ...displayButtonBaseStyle,\\n backgroundColor: \\\"var(--bb-theme-error)\\\",\\n color: \\\"var(--bb-theme-white)\\\",\\n};\\nconst miniRowSelectorWrapStyle = {\\n display: \\\"flex\\\",\\n flexWrap: \\\"wrap\\\",\\n gap: 4,\\n marginBottom: 4,\\n padding: \\\"4px 6px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.025))\\\",\\n};\\nconst miniHintStyle = {\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n opacity: 0.72,\\n marginBottom: 2,\\n paddingLeft: 2,\\n lineHeight: 1.1,\\n};\\nconst miniRowSelectorButtonStyle = {\\n appearance: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n borderRadius: 999,\\n padding: \\\"3px 9px\\\",\\n border: \\\"1px solid rgba(255,255,255,0.1)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.05)\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n};\\nconst miniRowSelectorActiveStyle = {\\n ...miniRowSelectorButtonStyle,\\n backgroundColor: \\\"var(--bb-theme-primarydark)\\\",\\n color: \\\"var(--bb-theme-backgroundprimary)\\\",\\n};\\nconst miniRowPanelStyle = {\\n marginBottom: 6,\\n padding: \\\"6px 8px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.12)\\\",\\n background: \\\"linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0.02))\\\",\\n};\\nconst miniRowPanelHeaderStyle = {\\n display: \\\"flex\\\",\\n alignItems: \\\"center\\\",\\n justifyContent: \\\"flex-start\\\",\\n gap: 4,\\n flexWrap: \\\"wrap\\\",\\n};\\nconst miniRowTitleWrapStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n gap: 6,\\n flexWrap: \\\"wrap\\\",\\n};\\nconst miniRowPanelTitleStyle = {\\n fontSize: 15,\\n fontWeight: \\\"bold\\\",\\n};\\nconst miniRowHideWrapStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n fontSize: 11,\\n opacity: 0.85,\\n};\\nconst miniRowHideCheckboxStyle = {\\n marginLeft: 0,\\n marginRight: 4,\\n verticalAlign: \\\"middle\\\",\\n};\\nconst miniEmptyStateStyle = {\\n padding: \\\"6px 8px\\\",\\n borderRadius: 8,\\n border: \\\"1px solid rgba(255,255,255,0.08)\\\",\\n backgroundColor: \\\"rgba(255,255,255,0.03)\\\",\\n opacity: 0.8,\\n};\\nconst miniMetaStyle = {\\n opacity: 0.75,\\n fontSize: 11,\\n marginLeft: 4,\\n};\\nconst lineStyle = {\\n display: \\\"flex\\\",\\n alignItems: \\\"flex-start\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 5,\\n};\\nconst lineLabelStyle = {\\n minWidth: 132,\\n maxWidth: 210,\\n paddingTop: 6,\\n color: \\\"var(--bb-theme-primary)\\\",\\n fontWeight: \\\"bold\\\",\\n};\\nconst lineBodyStyle = {\\n flex: \\\"1 1 480px\\\",\\n};\\nconst inputStyle = {\\n height: 26,\\n minWidth: 150,\\n marginRight: 4,\\n marginBottom: 4,\\n padding: \\\"2px 6px\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n background: \\\"rgba(255,255,255,0.05)\\\",\\n border: \\\"1px solid rgba(255,255,255,0.15)\\\",\\n borderRadius: 4,\\n fontFamily: \\\"monospace\\\",\\n fontSize: 12,\\n};\\nconst smallInputStyle = {\\n ...inputStyle,\\n minWidth: 82,\\n width: 92,\\n};\\nconst tinyInputStyle = {\\n ...inputStyle,\\n minWidth: 44,\\n width: 48,\\n};\\nconst fieldGroupStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n gap: 5,\\n marginRight: 6,\\n marginBottom: 4,\\n};\\nconst fieldLabelStyle = {\\n color: \\\"var(--bb-theme-secondarylight)\\\",\\n fontSize: 11,\\n fontWeight: \\\"bold\\\",\\n};\\nconst selectStyle = {\\n height: 30,\\n marginRight: 4,\\n marginBottom: 4,\\n padding: \\\"2px 6px\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n background: \\\"#000\\\",\\n border: \\\"1px solid rgba(255,255,255,0.15)\\\",\\n borderRadius: 4,\\n fontFamily: \\\"monospace\\\",\\n fontSize: 12,\\n};\\nconst optionStyle = {\\n background: \\\"#000\\\",\\n color: \\\"var(--bb-theme-primary)\\\",\\n};\\nconst adjusterWrapStyle = {\\n display: \\\"inline-flex\\\",\\n alignItems: \\\"center\\\",\\n flexWrap: \\\"wrap\\\",\\n marginRight: 6,\\n};\\n\""},{"filename":"SphyxOS/codingContracts/attemptCCT.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const info = JSON.parse(ns.args[0])\\n let results\\n ns.atExit(() => ns.writePort(ns.pid, results))\\n try { results = ns.codingcontract.attempt(info[0], info[1], info[2]) } catch { results = false }\\n}\""},{"filename":"SphyxOS/codingContracts/getContractData.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(ns.codingcontract.getData(ns.args[0], ns.args[1])))\\n}\""},{"filename":"SphyxOS/codingContracts/getContractType.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(ns.codingcontract.getContractType(ns.args[0], ns.args[1])))\\n}\""},{"filename":"SphyxOS/darknet/heartbleed.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const result = await ns.dnet.heartbleed(ns.args[1], { logsToCapture: ns.args[2], additionalMsec: ns.args[3] })\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}\""},{"filename":"SphyxOS/darknet/labHunter.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n let finalMessage = { finished: false, workerExited: true, authResults: false }\\n const sanitizeAuthResult = (result) => ({\\n success: Boolean(result?.success),\\n code: result?.code ?? null,\\n message: typeof result?.message === \\\"string\\\" ? result.message : \\\"\\\",\\n data: typeof result?.data === \\\"string\\\" ? result.data : result?.data ?? null\\n })\\n const sanitizeLabReport = (report) => {\\n if (!report || typeof report !== \\\"object\\\") return false\\n return {\\n success: report.success !== false,\\n coords: Array.isArray(report.coords) ? report.coords.slice() : null,\\n north: Boolean(report.north),\\n east: Boolean(report.east),\\n south: Boolean(report.south),\\n west: Boolean(report.west)\\n }\\n }\\n const currentRoomCommand = \\\"nothing\\\"\\n ns.nextPortWrite(24).then(() => { ns.clearPort(26); ns.exit() })\\n ns.atExit(() => { ns.writePort(ns.args[1], finalMessage) })\\n while (true) {\\n let dir = ns.readPort(ns.pid)\\n if (dir === \\\"NULL PORT DATA\\\") {\\n await ns.nextPortWrite(ns.pid)\\n dir = ns.readPort(ns.pid)\\n }\\n if (typeof dir !== \\\"string\\\") dir = \\\"\\\"\\n if (dir === currentRoomCommand) {\\n ns.writePort(ns.args[1], { finished: false, report: sanitizeLabReport(await ns.dnet.labreport()), authResults: false })\\n continue\\n }\\n const results = await ns.dnet.authenticate(ns.args[0], dir)\\n const response = { finished: Boolean(results?.success), authResults: sanitizeAuthResult(results) }\\n if (results.success) {\\n finalMessage = response\\n ns.writePort(ns.args[1], response)\\n ns.exit()\\n }\\n else {\\n ns.writePort(ns.args[1], response)\\n }\\n }\\n}\""},{"filename":"SphyxOS/extras/crawl-Basic.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.clearLog()\\n ns.ui.openTail()\\n virus(ns)\\n const servers = targets.filter((s) => ns.getHackingLevel() >= ns.getServerRequiredHackingLevel(s) && ns.hasRootAccess(s) && !ns.getServer(s).backdoorInstalled)//)\\n servers.sort()\\n ns.print(\\\"Stay on the terminal page or the script will fail!\\\")\\n ns.printf(\\\"Servers: %s\\\", servers.length)\\n let eta = 0\\n servers.forEach(s => eta += (ns.getHackTime(s) / 4) + 2000)\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"ETA: %s\\\", fTime(ns, eta), 3)\\n else ns.printf(\\\"ETA: %s\\\", fTime(ns, eta), 3)\\n for (let point of servers) {\\n let target = point\\n const path = [target]\\n while ((target = ns.scan(target)[0]) !== \\\"home\\\") path.unshift(target)\\n path.unshift(\\\"home\\\")\\n await terminal(\\\"connect \\\" + path.join(\\\";connect \\\"))\\n await ns.sleep(4)\\n await terminal(\\\"backdoor\\\")\\n await ns.sleep(4)\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"%s - %s\\\", point, fTime(ns, (ns.getHackTime(point) / 4) + 2000))\\n else ns.printf(\\\"%s - %s\\\", point, fTime(ns, (ns.getHackTime(point) / 4) + 2000))\\n await ns.sleep((ns.getHackTime(point) / 4) + 2000)\\n }\\n if (servers.length > 0) await terminal(\\\"home\\\")\\n}\\n\\n//This will put something into the terminal and hit enter. You however, need to be on the terminal to do it or it won't work.\\nasync function terminal(text) {\\n const slp = ms => new Promise(r => setTimeout(r, ms))\\n //Capture the terminal button\\n const terminalButton = [...globalThis[\\\"document\\\"].querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n //Click it\\n terminalButton.filter(e => e.textContent === \\\"Terminal\\\")[0]?.click()\\n await slp(4)\\n //Get the terminal input field\\n const input = globalThis[\\\"document\\\"].getElementById('terminal-input');\\n //Get it's handler\\n const handler = Object.keys(input)[1];\\n //Set the change that will happen, ie: add it to the terminal\\n input[handler].onChange({ target: { value: text } });\\n //Click enter on the terminal\\n input[handler].onKeyDown({ key: 'Enter', preventDefault: () => null });\\n}\\nfunction virus(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try { ns.nuke(server) } catch { }\\n }\\n}\\nfunction getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n}\\nfunction fTime(ns, ms, msPrecision = false) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) return ns.format.time(ms, msPrecision)\\n else return ns.tFormat(ms, msPrecision)\\n}\\nconst targets = [\\n \\\"CSEC\\\",\\n \\\"I.I.I.I\\\",\\n \\\"avmnite-02h\\\",\\n \\\"run4theh111z\\\",\\n \\\"powerhouse-fitness\\\",\\n \\\"fulcrumassets\\\"\\n];\""},{"filename":"SphyxOS/extras/currentBN.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n\\n const resetInfo = ns.getResetInfo()\\n const result = resetInfo.currentNode\\n}\""},{"filename":"SphyxOS/extras/getHackP.js","file":"\"import { getHackPercent, getGrowThreads, getHackChance, getBNMults } from \\\"SphyxOS/forms.js\\\"\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n //ns.args[0] is the target, 1 is batches, 2 is threads, 3 is starthacks\\n const server = ns.getServer(ns.args[0])\\n const hack_chance = getHackChance(ns, ns.args[0], server.minDifficulty)\\n const weakenStrength = ns.weakenAnalyze(1)\\n const hackperc = getHackPercent(ns, ns.args[0], server.minDifficulty)\\n let moneytotake = 0\\n let hytotalbatches = 1\\n let hgwtotalbatches = 1\\n let hwgwtotalbatches = 1\\n let besttake = 0\\n let besth1threads = 0\\n let bestw1threads = 0\\n let bestg1threads = 0\\n let bestw2threads = 0\\n let besttype = \\\"HGW\\\"\\n let bestratio = 0\\n\\n for (let testthreads = Math.min(Math.ceil(1 / hackperc), ns.args[3]); testthreads <= Math.max(Math.ceil(1 / hackperc), ns.args[3]); testthreads++) {\\n moneytotake = hackperc * testthreads >= 1 ? server.moneyMax - 1 : hackperc * server.moneyMax * testthreads\\n // Hybrid hacking threads and it's security threads\\n let hysechack = testthreads * .002 //Security added from hacking\\n const hyw1threads = Math.floor(hysechack / weakenStrength) //Take out the hybrid amount - just enough\\n hysechack -= hyw1threads * weakenStrength\\n // HGW hacking threads and it's security threads\\n const hgwsechack = testthreads * .002 //Security added from hacking which will carry over\\n // HWGW hacking threads and it's security threads\\n let hwgwsechack = testthreads * .002 //Security added from hacking\\n const hwgww1threads = Math.ceil(hwgwsechack / weakenStrength) //Take it all out \\n //Hybrid and HGW have some security left. HWGW does not\\n const hygthreads = getGrowThreads(ns, ns.args[0], server.moneyMax - moneytotake, server.minDifficulty + hysechack)\\n const hgwgthreads = getGrowThreads(ns, ns.args[0], server.moneyMax - moneytotake, server.minDifficulty + hgwsechack)\\n const hwgwgthreads = getGrowThreads(ns, ns.args[0], server.moneyMax - moneytotake, server.minDifficulty)\\n\\n moneytotake *= hack_chance\\n //Last weaken threads for the grows and remaining from hacks\\n const hysecgrow = hygthreads * .004\\n const hgwsecgrow = hgwgthreads * .004\\n const hwgwsecgrow = hwgwgthreads * .004\\n\\n //Get weaken threads\\n const hyw2threads = Math.ceil((hysecgrow + hysechack) / weakenStrength)\\n const hgww2threads = Math.ceil((hgwsecgrow + hgwsechack) / weakenStrength)\\n const hwgww2threads = Math.ceil((hwgwsecgrow) / weakenStrength)\\n\\n //Get total thread count\\n const hytotalthreads = testthreads + hyw1threads + hygthreads + hyw2threads\\n const hgwtotalthreads = testthreads + hgwgthreads + hgww2threads\\n const hwgwtotalthreads = testthreads + hwgww1threads + hwgwgthreads + hwgww2threads\\n\\n if (ns.args[2] > 0) {\\n hytotalbatches = Math.floor(ns.args[2] / hytotalthreads) > ns.args[1] || ns.args[1] < 1 ? 0 : Math.floor(ns.args[2] / hytotalthreads)\\n hgwtotalbatches = Math.floor(ns.args[2] / hgwtotalthreads) > ns.args[1] || ns.args[1] < 1 ? 0 : Math.floor(ns.args[2] / hgwtotalthreads)\\n hwgwtotalbatches = Math.floor(ns.args[2] / hwgwtotalthreads) > ns.args[1] || ns.args[1] < 1 ? 0 : Math.floor(ns.args[2] / hwgwtotalthreads)\\n }\\n\\n let VALIDTEST = false\\n let hyratio = 0\\n let hgwratio = 0\\n let hwgwratio = 0\\n\\n if (ns.args[1] === -1 && ns.args[2] === -1) { //Simply get the best. Assume unlimited batches/threads\\n hyratio = moneytotake / hytotalthreads\\n hgwratio = moneytotake / hgwtotalthreads\\n hwgwratio = moneytotake / hwgwtotalthreads\\n }\\n else {\\n hyratio = moneytotake / hytotalthreads * hytotalbatches\\n hgwratio = moneytotake / hgwtotalthreads * hgwtotalbatches\\n hwgwratio = moneytotake / hwgwtotalthreads * hwgwtotalbatches\\n }\\n if (hyratio || hgwratio || hwgwratio) VALIDTEST = true\\n\\n // Just cascade the possibilities\\n let failed = 0\\n //HGW\\n if (hgwratio > bestratio || (testthreads === Math.ceil(1 / hackperc) && bestratio === 0)) {\\n bestratio = hgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = 0\\n bestg1threads = hgwgthreads\\n bestw2threads = hgww2threads\\n besttype = \\\"HGW\\\"\\n }\\n else failed++\\n //Hybrid\\n if (hyratio > bestratio) {\\n bestratio = hyratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hyw1threads\\n bestg1threads = hygthreads\\n bestw2threads = hyw2threads\\n besttype = \\\"Hybrid\\\"\\n }\\n else failed++\\n //HWGW\\n if (hwgwratio > bestratio) {// || testthreads == Math.ceil(1 / hackperc)) { //Our default for the highest possible\\n bestratio = hwgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hwgww1threads\\n bestg1threads = hwgwgthreads\\n bestw2threads = hwgww2threads\\n besttype = \\\"HWGW\\\"\\n }\\n else failed++\\n if (failed === 3 && VALIDTEST) break//We are done. Nothing better\\n } // for loop to max threads\\n\\n let takemult = 1\\n try {\\n const mults = getBNMults(ns)\\n takemult = mults.ScriptHackMoneyGain\\n } catch { }\\n //Create return object\\n const record = {\\n \\\"H1\\\": besth1threads,\\n \\\"W1\\\": bestw1threads,\\n \\\"G1\\\": bestg1threads,\\n \\\"W2\\\": bestw2threads,\\n \\\"Type\\\": besttype,\\n \\\"Take\\\": besttake * takemult,\\n \\\"HackP\\\": hackperc,\\n \\\"Chance\\\": hack_chance\\n }\\n\\n ns.atExit(() => { port.write(record) })\\n}\\n\\n\""},{"filename":"SphyxOS/extras/getOptimalTarget.js","file":"\"import { printProfit } from \\\"SphyxOS/util.js\\\"\\nimport { getHackPercent, getHckTime, getGrowThreads, getHackChance } from \\\"SphyxOS/forms.js\\\"\\nlet weakenStrength = 0.05\\n/** @param {NS} ns **/\\nexport async function main(ns) {\\n /** @type {Server[]} servers */\\n const servers = getServers(ns)\\n const first = ns.args[0]\\n const player = ns.getPlayer()\\n weakenStrength = ns.weakenAnalyze(1)\\n let bestratio = 0\\n let bestsec = Infinity\\n let bestserver;\\n for (const server of servers) {\\n if (server.minDifficulty === 100 || server.requiredHackingSkill > player.skills.hacking || !server.hasAdminRights || server.hostname === \\\"home\\\" || server.moneyMax === 0 || server.purchasedByPlayer) continue\\n const batchinfo = getHackP(ns, server, -1, -1, 1)\\n const hchance = getHackChance(ns, server.hostname, server.minDifficulty)\\n const hackingTime = getHckTime(ns, server.hostname, server.minDifficulty)\\n\\n //Weaken time at minimal difficulty\\n let weaktime = hackingTime * 4\\n weaktime = (weaktime === 0) ? 4 : weaktime\\n const totalthreads = (batchinfo.H1 + batchinfo.G1 + batchinfo.W2 + batchinfo.W1)\\n const ratio = printProfit(ns, weaktime, batchinfo.Take, 1, totalthreads, hchance)\\n \\n if (first && server.hackDifficulty - server.minDifficulty < bestsec) {\\n bestsec = server.hackDifficulty - server.minDifficulty\\n bestratio = ratio\\n bestserver = server\\n }\\n else if (first && server.hackDifficulty - server.minDifficulty === bestsec && ratio > bestratio) {\\n bestsec = server.hackDifficulty - server.minDifficulty\\n bestratio = ratio\\n bestserver = server\\n }\\n else if (!first && ratio > bestratio) {\\n bestratio = ratio\\n bestserver = server\\n }\\n\\n\\n }\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(bestserver))\\n}\\n\\n/** @param {NS} ns */\\nexport function getServers(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n const serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(ns.getServer(server))\\n }\\n return serverDetails\\n}\\n/** @param {NS} ns */\\nfunction getHackP(ns, server, batches, threads, starthacks) {\\n const hack_chance = getHackChance(ns, server.hostname, server.minDifficulty)\\n const hackperc = getHackPercent(ns, server.hostname, server.minDifficulty)\\n let moneytotake = 0\\n let hytotalbatches = 1\\n let hgwtotalbatches = 1\\n let hwgwtotalbatches = 1\\n let besttake = 0\\n let besth1threads = 0\\n let bestw1threads = 0\\n let bestg1threads = 0\\n let bestw2threads = 0\\n let besttype = \\\"HGW\\\"\\n let bestratio = 0\\n\\n for (let testthreads = starthacks; testthreads <= Math.min(Math.ceil(1 / hackperc), starthacks); testthreads++) {\\n moneytotake = hackperc * testthreads >= 1 ? server.moneyMax - 1 : hackperc * server.moneyMax * testthreads\\n // Hybrid hacking threads and it's security threads\\n let hysechack = testthreads * .002 //Security added from hacking\\n const hyw1threads = Math.floor(hysechack / weakenStrength) //Take out the hybrid amount - just enough\\n hysechack -= hyw1threads * weakenStrength\\n // HGW hacking threads and it's security threads\\n const hgwsechack = testthreads * .002 //Security added from hacking which will carry over\\n // HWGW hacking threads and it's security threads\\n let hwgwsechack = testthreads * .002 //Security added from hacking\\n const hwgww1threads = Math.ceil(hwgwsechack / weakenStrength) //Take it all out \\n //Hybrid and HGW have some security left. HWGW does not\\n const hygthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty + hysechack)\\n const hgwgthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty + hgwsechack)\\n const hwgwgthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty)\\n\\n moneytotake *= hack_chance\\n //Last weaken threads for the grows and remaining from hacks\\n const hysecgrow = hygthreads * .004\\n const hgwsecgrow = hgwgthreads * .004\\n const hwgwsecgrow = hwgwgthreads * .004\\n\\n //Get weaken threads\\n const hyw2threads = Math.ceil((hysecgrow + hysechack) / weakenStrength)\\n const hgww2threads = Math.ceil((hgwsecgrow + hgwsechack) / weakenStrength)\\n const hwgww2threads = Math.ceil((hwgwsecgrow) / weakenStrength)\\n\\n //Get total thread count\\n const hytotalthreads = testthreads + hyw1threads + hygthreads + hyw2threads\\n const hgwtotalthreads = testthreads + hgwgthreads + hgww2threads\\n const hwgwtotalthreads = testthreads + hwgww1threads + hwgwgthreads + hwgww2threads\\n\\n if (threads > 0) {\\n hytotalbatches = Math.floor(threads / hytotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hytotalthreads)\\n hgwtotalbatches = Math.floor(threads / hgwtotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hgwtotalthreads)\\n hwgwtotalbatches = Math.floor(threads / hwgwtotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hwgwtotalthreads)\\n }\\n\\n let VALIDTEST = false\\n let hyratio = 0\\n let hgwratio = 0\\n let hwgwratio = 0\\n\\n if (batches === -1 && threads === -1) { //Simply get the best. Assume unlimited batches/threads\\n hyratio = moneytotake / hytotalthreads\\n hgwratio = moneytotake / hgwtotalthreads\\n hwgwratio = moneytotake / hwgwtotalthreads\\n }\\n else {\\n hyratio = moneytotake / hytotalthreads * hytotalbatches\\n hgwratio = moneytotake / hgwtotalthreads * hgwtotalbatches\\n hwgwratio = moneytotake / hwgwtotalthreads * hwgwtotalbatches\\n }\\n if (hyratio || hgwratio || hwgwratio) VALIDTEST = true\\n\\n // Just cascade the possibilities\\n let failed = 0\\n //HGW\\n if (hgwratio > bestratio) {\\n bestratio = hgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = 0\\n bestg1threads = hgwgthreads\\n bestw2threads = hgww2threads\\n besttype = \\\"HGW\\\"\\n }\\n else failed++\\n //Hybrid\\n if (hyratio > bestratio) {\\n bestratio = hyratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hyw1threads\\n bestg1threads = hygthreads\\n bestw2threads = hyw2threads\\n besttype = \\\"Hybrid\\\"\\n }\\n else failed++\\n //HWGW\\n if (hwgwratio > bestratio || (testthreads === Math.min(Math.ceil(1 / hackperc), starthacks) && bestratio === 0)) {// || testthreads == Math.ceil(1 / hackperc)) { //Our default for the highest possible\\n bestratio = hwgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hwgww1threads\\n bestg1threads = hwgwgthreads\\n bestw2threads = hwgww2threads\\n besttype = \\\"HWGW\\\"\\n }\\n else failed++\\n if (failed === 3 && VALIDTEST) break//We are done. Nothing better\\n } // for loop to max threads\\n\\n let takemult = 1\\n try {\\n const mults = ns.getBitNodeMultipliers()\\n takemult = mults.ScriptHackMoneyGain\\n } catch { }\\n //Create return object\\n const record = {\\n \\\"H1\\\": besth1threads,\\n \\\"W1\\\": bestw1threads,\\n \\\"G1\\\": bestg1threads,\\n \\\"W2\\\": bestw2threads,\\n \\\"Type\\\": besttype,\\n \\\"Take\\\": besttake * takemult,\\n \\\"HackP\\\": hackperc,\\n \\\"Chance\\\": hack_chance\\n }\\n return record\\n}\""},{"filename":"SphyxOS/extras/getPortOpeners.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let count = 0\\n if (ns.fileExists(\\\"BruteSSH.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"FTPCrack.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"relaySMTP.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"HTTPWorm.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"SQLInject.exe\\\", \\\"home\\\")) count++\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(count))\\n}\\n\""},{"filename":"SphyxOS/extras/getPortOpenersSing.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.singularity.purchaseTor()\\n ns.singularity.purchaseProgram(\\\"BruteSSH.exe\\\")\\n ns.singularity.purchaseProgram(\\\"FTPCrack.exe\\\")\\n ns.singularity.purchaseProgram(\\\"relaySMTP.exe\\\")\\n ns.singularity.purchaseProgram(\\\"HTTPWorm.exe\\\")\\n ns.singularity.purchaseProgram(\\\"SQLInject.exe\\\")\\n \\n let count = 0\\n if (ns.fileExists(\\\"BruteSSH.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"FTPCrack.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"relaySMTP.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"HTTPWorm.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"SQLInject.exe\\\", \\\"home\\\")) count++\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(count))\\n}\\n\""},{"filename":"SphyxOS/extras/getServers.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n\\n const serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(ns.getServer(server))\\n }\\n serverDetails.sort((a, b) => { return (a.maxRam - a.ramUsed) - (b.maxRam - b.ramUsed) })\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(serverDetails))\\n}\""},{"filename":"SphyxOS/extras/getServersLight.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n\\n let serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(server)\\n }\\n serverDetails = serverDetails.sort((a, b) => { return (ns.getServerMaxRam(a) - ns.getServerUsedRam(a)) - (ns.getServerMaxRam(b) - ns.getServerUsedRam(b)) })\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(serverDetails))\\n}\""},{"filename":"SphyxOS/extras/hasBN.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n\\n const bn = ns.args[0]\\n const bnLvl = ns.args[1] ? ns.args[1] : 1\\n const forced = ns.args[2] ?? false\\n const resetInfo = ns.getResetInfo()\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let result = 0\\n if (resetInfo.currentNode === bn && !forced) {\\n result = 1\\n return\\n }\\n for (const sf of sourceFiles) if (sf.n === bn && sf.lvl >= bnLvl) {\\n result = 1\\n return\\n }\\n result = 0\\n}\""},{"filename":"SphyxOS/extras/hashIt.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n //arg[0] is Type; money, corp, min, max, study, train, research, bbrank, bbsp, coding, favor, \\n //Target needs to be determined. peek(3) for current hacking target\\n //Will need to figure out Target for company favor - working for should do it but it's singularity\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(1))\\n \\n const hackTarget = ns.peek(3)\\n switch (ns.args[0]) {\\n case \\\"money\\\":\\n while (ns.hacknet.spendHashes(\\\"Sell for Money\\\", \\\"home\\\")) { }\\n break;\\n case \\\"corp\\\":\\n while (ns.hacknet.spendHashes(\\\"Sell for Corporation Funds\\\", \\\"home\\\")) { }\\n break;\\n case \\\"min\\\":\\n if (hackTarget === \\\"NULL PORT DATA\\\") return\\n if (ns.getServerMinSecurityLevel(hackTarget) === 1) break\\n while (ns.hacknet.spendHashes(\\\"Reduce Minimum Security\\\", hackTarget)) { if (ns.getServerMinSecurityLevel(hackTarget) === 1) break }\\n break;\\n case \\\"max\\\":\\n if (hackTarget === \\\"NULL PORT DATA\\\") return\\n while (ns.hacknet.spendHashes(\\\"Increase Maximum Money\\\", hackTarget)) { }\\n break;\\n case \\\"study\\\":\\n while (ns.hacknet.spendHashes(\\\"Improve Studying\\\")) { }\\n break;\\n case \\\"train\\\":\\n while (ns.hacknet.spendHashes(\\\"Improve Gym Training\\\")) { }\\n break;\\n case \\\"research\\\":\\n while (ns.hacknet.spendHashes(\\\"Exchange for Corporation Research\\\", \\\"home\\\")) { }\\n break;\\n case \\\"bbrank\\\":\\n while (ns.hacknet.spendHashes(\\\"Exchange for Bladeburner Rank\\\")) { }\\n break;\\n case \\\"bbsp\\\":\\n while (ns.hacknet.spendHashes(\\\"Exchange for Bladeburner SP\\\")) { }\\n break;\\n case \\\"coding\\\":\\n while (ns.hacknet.spendHashes(\\\"Generate Coding Contract\\\", \\\"home\\\")) { }\\n break;\\n case \\\"favor\\\":\\n let favorTarget = \\\"home\\\"\\n try { favorTarget = ns.singularity.getCurrentWork().companyName } catch { return }\\n if (favorTarget) while (ns.hacknet.spendHashes(\\\"Company Favor\\\", favorTarget)) { }\\n break;\\n default:\\n break;\\n }\\n}\""},{"filename":"SphyxOS/extras/nsProxy.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}\""},{"filename":"SphyxOS/extras/nsProxyAuth.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let [server, password, func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n ns.dnet.connectToSession(server, password)\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}\""},{"filename":"SphyxOS/extras/nsProxyTry.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let result = false\\n try {\\n const res = nsFunction(...argmnts)\\n if (res) result = res\\n else result = true\\n }\\n catch { }\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}\""},{"filename":"SphyxOS/extras/runIt.js","file":"\"import { reservedRam } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n //Any runIt now has a persistent argument to pass along if it can run on hacknet servers.\\n //This way you can choose to run something like puppet on a hacknet server\\n let thispid = 0\\n let threads = 1\\n const [script, persistent, scriptOverride, ...argmts] = ns.args\\n const scriptRam = scriptOverride === 0 ? ns.getScriptRam(script) : scriptOverride\\n if (!persistent && Math.floor((ns.getServerMaxRam(\\\"home\\\") - ns.getServerUsedRam(\\\"home\\\")) / scriptRam) >= 1) {\\n thispid = ns.exec(script, \\\"home\\\", { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmts)\\n if (thispid > 0)\\n threads--\\n }\\n if (threads >= 1) {\\n const servers = getServersLight(ns, persistent)\\n let emergencyReserve = ns.getServerMaxRam(\\\"home\\\") <= 16 ? true : false\\n const maxRam = !persistent ? 0 : maxRun(ns, persistent)\\n const resRam = !persistent ? 0 : maxRam >= 256 ? 256 : maxRam >= 128 ? 128 : maxRam >= 64 ? 64 : maxRam >= 32 ? 32 : 16\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (persistent && emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n }\\n if (server.startsWith(\\\"home\\\") && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable <= 0) continue\\n const threadsonserver = Math.floor(tmpramavailable / scriptRam)\\n // How many threads can we run? If we can run something, do it\\n if (threadsonserver <= 0) continue\\n ns.scp([script, \\\"SphyxOS/util.js\\\", \\\"SphyxOS/forms.js\\\"], server, \\\"home\\\")\\n thispid = ns.exec(script, server, { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmts)\\n if (thispid === 0) continue //ns.tprintf(\\\"Failed to run: %s on %s\\\", script, server)\\n threads--\\n break\\n }// All servers\\n }\\n if (threads >= 1) ns.tprintf(\\\"Failed to allocate all threads for script: %s\\\", script)\\n\\n await ns.nextPortWrite(thispid)\\n const result = ns.readPort(thispid)\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}\\n\\n/** @param {NS} ns */\\nfunction getServersLight(ns, persistent) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n let serverDetails = Array.from(serverList)\\n if (persistent)\\n serverDetails = serverDetails.sort((a, b) => { return (ns.getServerMaxRam(b) - ns.getServerUsedRam(b)) - (ns.getServerMaxRam(a) - ns.getServerUsedRam(a)) })\\n return serverDetails\\n}\\n\\n/** @param {NS} ns */\\nfunction maxRun(ns, persistent, useHacknet = false) {\\n //Any runIt now has a persistent argument to pass along if it can run on hacknet servers.\\n //This way you can choose to run something like puppet on a hacknet server\\n let highest = 0\\n /**@type {String[]} servers */\\n const servers = getServersLight(ns, persistent)\\n let emergencyReserve = ns.getServerMaxRam(\\\"home\\\") <= 16 ? true : false\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && !useHacknet)) continue\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest)\\n highest = tmpramavailable\\n }// All servers\\n if (!persistent)\\n return highest\\n //Highest is now max run\\n const resRam = highest >= 256 ? 256 : highest >= 128 ? 128 : highest >= 64 ? 64 : highest >= 32 ? 32 : 16\\n //Now that we have the highest, we go again\\n let highest2 = 0\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (persistent && emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n }\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest2)\\n highest2 = tmpramavailable\\n }// All servers\\n return highest2\\n}\""},{"filename":"SphyxOS/extras/scan.js","file":"\"/** @param {NS} ns */\\nexport let main = (ns,c=\\\"home\\\",l,p='') => {\\n ns.tprintf(p+(l?\\\"┣\\\":\\\"┗\\\")+c);\\n ns.scan(c).map((e,i,a)=>(i||(c==\\\"home\\\"))&&main(ns,e,i+1!=a.length,p+(l?\\\"┃\\\":\\\" \\\")));\\n}\""},{"filename":"SphyxOS/extras/serverPurchaser.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let upgradecost = 1e150\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(upgradecost))\\n\\n const startRam = 2\\n // Itterator we'll use for our loop\\n let i = getNames(ns).length\\n if (getLimit(ns) === 0) return\\n\\n //Buy the base servers\\n while (i < getLimit(ns)) {\\n // Check if we have enough money to purchase a server\\n if (ns.getServerMoneyAvailable(\\\"home\\\") >= getCost(ns, startRam)) {\\n const server = i >= 10 ? buy(ns, \\\"pserv-\\\" + i, startRam) : buy(ns, \\\"pserv-0\\\" + i, startRam)\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n i++;\\n }\\n else {\\n upgradecost = getCost(ns, startRam)\\n return\\n }\\n }\\n\\n const servers = getNames(ns)\\n while (true) {\\n //Cycle through every server. Check each attribute for cost of upgrade\\n //Upgrade the cheapest. Keep upgrading indefinitally\\n let upgradeitem = \\\"\\\"\\n let ramupgrade = 0\\n upgradecost = 1e150\\n\\n //Check all servers\\n for (const server of servers) {\\n //Get the cheapest one and document it\\n if (getUpgradeCost(ns, server, ns.getServerMaxRam(server) * 2) < upgradecost) {\\n upgradecost = getUpgradeCost(ns, server, ns.getServerMaxRam(server) * 2)\\n upgradeitem = server\\n ramupgrade = ns.getServerMaxRam(server) * 2\\n }\\n }\\n //upgrade the server if we can\\n if (ns.getServerMoneyAvailable(\\\"home\\\") >= upgradecost) upgrade(ns, upgradeitem, ramupgrade)\\n else {\\n upgradecost = upgradecost === Number.POSITIVE_INFINITY ? 0 : upgradecost\\n return\\n }\\n }\\n}\\n\\n\\n/** @param {NS} ns */\\nfunction getLimit(ns) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.getServerLimit()\\n else return ns.getPurchasedServerLimit()\\n}\\n/** @param {NS} ns */\\nfunction getNames(ns) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.getServerNames()\\n else return ns.getPurchasedServers()\\n}\\n/** @param {NS} ns */\\nfunction buy(ns, id, startRam) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.purchaseServer(id, startRam)\\n else return ns.purchaseServer(id, startRam)\\n}\\n/** @param {NS} ns */\\nfunction getCost(ns, startRam) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.getServerCost(startRam)\\n else return ns.getPurchasedServerCost(startRam)\\n}\\n/** @param {NS} ns */\\nfunction getUpgradeCost(ns, server, newRam) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.getServerUpgradeCost(server, newRam)\\n else return ns.getPurchasedServerUpgradeCost(server, newRam)\\n}\\n/** @param {NS} ns */\\nfunction upgrade(ns, server, newRam) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 45) return ns.cloud.upgradeServer(server, newRam)\\n else return ns.upgradePurchasedServer(server, newRam)\\n}\""},{"filename":"SphyxOS/extras/serverRun.js","file":"\"import { reservedRam } from \\\"SphyxOS/util.js\\\"\\n/**@type {String[]} servers */\\nlet servers;\\nlet max;\\nlet chunkSwitch;\\nlet logging;\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n logging = ns.args[0]\\n const target = ns.args[1]\\n const w1 = ns.args[2]\\n const g1 = ns.args[3]\\n const w2 = ns.args[4]\\n const h1 = ns.args[5]\\n const w3 = ns.args[6]\\n const g2 = ns.args[7]\\n const w4 = ns.args[8]\\n const batchh1 = ns.args[9]\\n const batchw1 = ns.args[10]\\n const batchg1 = ns.args[11]\\n const batchw2 = ns.args[12]\\n const batches = ns.args[13]\\n const useHacknet = ns.args[14]\\n servers = getServers(ns, useHacknet)\\n let results;\\n const hacktime = ns.getHackTime(target)\\n const growtime = ns.getGrowTime(target)\\n const weaktime = ns.getWeakenTime(target)\\n let waitTime = 0\\n let recalc = false\\n chunkSwitch = true\\n max = maxRun(ns, false, useHacknet)\\n //Run the wave!\\n //chunkswitch1 = check_batch(ns, w1, g1, w2, h1, w3, g2, w4, useHacknet)\\n let starttime = performance.now()\\n waitTime = w1 + w2 + w3 + w4 > 0 ? weaktime : growtime\\n if (w1) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w1, false, useHacknet])\\n if (g1) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, waitTime - growtime, g1, chunkSwitch, useHacknet])\\n if (w2) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w2, false, useHacknet])\\n if (h1) results = runIt_Local(ns, \\\"SphyxOS/basic/hack.js\\\", [target, waitTime - hacktime, h1, chunkSwitch, useHacknet])\\n if (w3) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w3, false, useHacknet])\\n if (g2) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, waitTime - growtime, g2, chunkSwitch, useHacknet])\\n if (w4) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w4, false, useHacknet])\\n let batchesrun = 0\\n let start = performance.now()\\n for (let i = 1; i <= Math.min(batches, 99999); i++) {\\n if (starttime + weaktime <= performance.now()) { //The performance wall\\n recalc = true\\n break\\n }\\n if (i === 99999) recalc = true\\n\\n batchesrun++\\n //chunkswitch2 = check_batch(ns, 0, 0, 0, batchh1, batchw1, batchg1, batchw2, useHacknet)\\n if (batchh1) results = runIt_Local(ns, \\\"SphyxOS/basic/hack.js\\\", [target, weaktime - hacktime, batchh1, chunkSwitch, useHacknet])\\n if (batchw1) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, batchw1, false, useHacknet])\\n if (batchg1) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, weaktime - growtime, batchg1, chunkSwitch, useHacknet])\\n if (batchw2) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, batchw2, false, useHacknet])\\n\\n if (performance.now() - start >= 200) {\\n start = performance.now()\\n await ns.sleep(0)\\n }\\n }\\n\\n\\n const record = {\\n \\\"lastpid\\\": results,\\n \\\"recalc\\\": recalc,\\n \\\"batches\\\": batchesrun,\\n \\\"batching\\\": chunkSwitch\\n }\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(record))\\n}\\n/** @param {NS} ns */\\nfunction runIt_Local(ns, script, argmts) {//target, sleeptm, threads, chunks, opt) {\\n const target = argmts[0]\\n const sleeptm = argmts[1]\\n let threads = argmts[2]\\n const chunks = argmts[3]\\n const useHacknet = argmts[4]\\n let thispid = 0\\n const serversRemove = []\\n let emergencyReserve = ns.getServerMaxRam(\\\"home\\\") <= 16 ? true : false\\n const resRam = !emergencyReserve ? 0 : max >= 256 ? 256 : max >= 128 ? 128 : max >= 64 ? 64 : max >= 32 ? 32 : 16\\n for (let i = 0; i < servers.length; i++) {//const server of servers) {\\n const server = servers[i][0]\\n if (server.startsWith(\\\"hacknet\\\") && !useHacknet) continue\\n let tmpramavailable = servers[i][1]\\n if (server === \\\"home\\\") tmpramavailable = Math.max(tmpramavailable - reservedRam + 4, 0) //Reserve home ram, + 4 is this script. This run the ram is missing, but in the original count it's there\\n //Reserve our home threads\\n\\n if (emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n } //Reserve if home ram is 16GB or less\\n let threadsonserver = Math.floor(tmpramavailable / 1.75)\\n if (threadsonserver <= 0) {\\n serversRemove.push(server)\\n continue\\n }\\n if (chunks) { //We NEED enough to finish the whole operation at once\\n if (threadsonserver >= threads) {\\n thispid = ns.exec(script, server, { threads: threads, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (logging && thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n servers[i][1] -= threads * 1.75\\n threads = 0\\n break\\n }\\n } // chunks\\n else {\\n if (threadsonserver >= threads) { //We have enough to finish it off\\n thispid = ns.exec(script, server, { threads: threads, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (logging && thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n servers[i][1] -= threads * 1.75\\n threads = 0\\n break\\n }\\n else { //We have threads but not enough \\n thispid = ns.exec(script, server, { threads: threadsonserver, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (logging && thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n servers[i][1] -= threadsonserver * 1.75\\n threads -= threadsonserver\\n i = 0\\n }\\n }//No chunks\\n //await ns.sleep(0)\\n //await ns.sleep(0)\\n }// All servers\\n if (threads > 0 && chunks) {\\n chunkSwitch = false\\n thispid = runIt_Local(ns, script, [target, sleeptm, threads, false, useHacknet])\\n }\\n else if (logging && threads > 0) ns.tprintf(\\\"Failed to allocate all %s threads. %s left. Chunk: %s Error!\\\", script, threads, chunks)\\n servers = servers.filter(([f, r]) => !serversRemove.includes(f))\\n return thispid\\n}\\n\\n/** @param {NS} ns */\\nfunction getServers(ns, useHacknet) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n\\n const serverDetails = []\\n for (const server of serverList) {\\n if (!ns.hasRootAccess(server) || ns.getServerMaxRam(server) <= 0) continue\\n if (server.startsWith(\\\"hacknet\\\") && !useHacknet) continue\\n ns.scp([\\\"SphyxOS/basic/hack.js\\\", \\\"SphyxOS/basic/grow.js\\\", \\\"SphyxOS/basic/weaken.js\\\"], server, \\\"home\\\")\\n serverDetails.push([server, ns.getServerMaxRam(server) - ns.getServerUsedRam(server)])\\n }\\n serverDetails.sort((a, b) => { return (ns.getServerMaxRam(a[0]) - ns.getServerUsedRam(a[0])) - (ns.getServerMaxRam(b[0]) - ns.getServerUsedRam(b[0])) })\\n\\n return serverDetails\\n}\\n/** @param {NS} ns */\\nexport function maxRun(ns, persistent, useHacknet) {\\n //Any runIt now has a persistent argument to pass along if it can run on hacknet servers.\\n //This way you can choose to run something like puppet on a hacknet server\\n let highest = 0\\n /**@type {String[]} servers */\\n const servers = getServers(ns, useHacknet)\\n let emergencyReserve = ns.getServerMaxRam(\\\"home\\\") <= 16 ? true : false\\n for (const [server, ram] of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest)\\n highest = tmpramavailable\\n }// All servers\\n if (!persistent) return highest\\n //Highest is now max run\\n const resRam = highest >= 256 ? 256 : highest >= 128 ? 128 : highest >= 64 ? 64 : highest >= 32 ? 32 : 16\\n //Now that we have the highest, we go again\\n let highest2 = 0\\n for (const [server, ram] of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (persistent && emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n }\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest2)\\n highest2 = tmpramavailable\\n }// All servers\\n return highest2\\n}\""},{"filename":"SphyxOS/extras/teleport.js","file":"\"import { getServersLight, terminal, hasBN, proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n let servers = await getServersLight(ns)\\n servers = servers.filter((s) => !ns.getServer(s).purchasedByPlayer)\\n servers.sort()\\n let target = await ns.prompt(\\\"Select target:\\\", { type: \\\"select\\\", choices: servers })\\n if (target === \\\"\\\") return\\n const path = [target]\\n while ((target = ns.scan(target)[0]) !== \\\"home\\\") path.unshift(target)\\n path.unshift(\\\"home\\\")\\n if (await hasBN(ns, 4, 2))\\n for (const host of path)\\n await proxy(ns, \\\"singularity.connect\\\", host)\\n else\\n await terminal(\\\"connect \\\" + path.join(\\\";connect \\\"))\\n}\""},{"filename":"SphyxOS/extras/update.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n //await ns.wget(\\\"https://raw.githubusercontent.com/Sphyxis/SphyxOS/main/SphyxOS.txt\\\", \\\"SphyxOSUserData/loaderData/SphyxOS.txt\\\")\\n await ns.sleep(100)\\n const collection = JSON.parse(ns.read(\\\"SphyxOSUserData/loaderData/SphyxOS.txt\\\"))\\n for (const item of collection) {\\n ns.write(item.filename, JSON.parse(item.file), \\\"w\\\")\\n }\\n ns.rm(\\\"SphyxOSUserData/loaderData/SphyxOS.txt\\\") //Get rid of our JSON file as we have a hashkey now to check version\\n ns.exec(\\\"Loader.js\\\", \\\"home\\\")\\n}\""},{"filename":"SphyxOS/extras/virus.js","file":"\"/** @param {NS} ns **/\\nexport async function main(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try { ns.nuke(server) } catch { }\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n }\\n ns.atExit(() => ns.writePort(ns.pid, true))\\n}\\n\\n/** @param {NS} ns */\\nexport function getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n}\""},{"filename":"SphyxOS/extras/wastePids.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n \\n}\""},{"filename":"SphyxOS/forms.js","file":"\"/** @param {NS} ns */\\nexport function getHckTime(ns, server, sec) {\\n const host = ns.getServer(server)\\n /** @type {Person} person */\\n const person = ns.getPlayer()\\n\\n host.hackDifficulty = sec\\n let hackingTime = 0\\n try {\\n return ns.formulas.hacking.hackTime(host, person)\\n }\\n catch {\\n const { hackDifficulty, requiredHackingSkill } = host;\\n if (hackDifficulty >= 100 || requiredHackingSkill > person.skills.hacking) {\\n hackingTime = Number.POSITIVE_INFINITY\\n return hackingTime\\n }\\n const difficultyMult = requiredHackingSkill * hackDifficulty;\\n\\n const baseDiff = 500;\\n const baseSkill = 50;\\n const diffFactor = 2.5;\\n let skillFactor = diffFactor * difficultyMult + baseDiff;\\n skillFactor /= person.skills.hacking + baseSkill;\\n\\n const hackTimeMultiplier = 5;\\n try {\\n hackingTime = 1000 *\\n (hackTimeMultiplier * skillFactor) /\\n (person.mults.hacking_speed *\\n 1 + Math.pow(person.skills.intelligence, 0.8) / 600)\\n }\\n catch { hackingTime = 1000 * hackTimeMultiplier * skillFactor / person.mults.hacking_speed }\\n }\\n return hackingTime\\n}\\n/** @param {NS} ns */\\nexport function getHackPercent(ns, server, sec) {\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n const player = ns.getPlayer()\\n let hackperc = 0\\n try {\\n hackperc = ns.formulas.hacking.hackPercent(host, player)\\n return hackperc\\n }\\n catch {\\n const hackDifficulty = host.minDifficulty ?? 100\\n if (hackDifficulty >= 100) {\\n hackperc = 0\\n return hackperc\\n }\\n const requiredHackingSkill = host.requiredHackingSkill ?? 1e9\\n const balanceFactor = 240\\n const difficultyMult = (100 - hackDifficulty) / 100\\n const skillMult = (player.skills.hacking - (requiredHackingSkill - 1)) / player.skills.hacking\\n\\n let percentMoneyHacked = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = getBNMults(ns)\\n percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money * mults.ScriptHackMoney / balanceFactor\\n }\\n catch { percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money / balanceFactor }\\n hackperc = Math.min(1, Math.max(percentMoneyHacked, 0))\\n }\\n return hackperc\\n}\\n/** @param {NS} ns */\\nexport function getGrowThreads(ns, server, money, sec) {\\n const player = ns.getPlayer()\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n host.moneyAvailable = money\\n let gthreads = 0\\n try {\\n gthreads = ns.formulas.hacking.growThreads(host, player, host.moneyMax)\\n return gthreads\\n }\\n catch {\\n const server = host\\n const targetMoney = host.moneyMax\\n let startMoney = host.moneyAvailable\\n const cores = 1\\n const person = player\\n /*\\n if (!server.serverGrowth) {\\n gthreads = Infinity\\n }\\n */\\n const moneyMax = server.moneyMax ?? 1;\\n const hackDifficulty = server.hackDifficulty ?? 100;\\n\\n if (startMoney < 0) startMoney = 0; // servers \\\"can't\\\" have less than 0 dollars on them\\n if (targetMoney > moneyMax) targetMoney = moneyMax; // can't grow a server to more than its moneyMax\\n if (targetMoney <= startMoney) {\\n gthreads = 0; // no growth --> no threads\\n return gthreads\\n }\\n // exponential base adjusted by security\\n const adjGrowthRate = 1 + (1.03 - 1) / hackDifficulty;\\n const exponentialBase = Math.min(adjGrowthRate, 1.0035); // cap growth rate\\n\\n // total of all grow thread multipliers\\n const serverGrowthPercentage = server.serverGrowth / 100.0;\\n const coreMultiplier = 1 + (cores - 1) / 16\\n let threadMultiplier = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = getBNMults(ns)\\n threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier * mults.ServerGrowthRate\\n }\\n catch { threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier }\\n\\n const x = threadMultiplier * Math.log(exponentialBase)\\n const y = startMoney * x + Math.log(targetMoney * x)\\n let w;\\n if (y < Math.log(2.5)) {\\n const ey = Math.exp(y);\\n w = (ey + (4 / 3) * ey * ey) / (1 + (7 / 3) * ey + (5 / 6) * ey * ey);\\n } else {\\n w = y;\\n if (y > 0) w -= Math.log(y);\\n }\\n let cycles = w / x - startMoney;\\n let bt = exponentialBase ** threadMultiplier;\\n if (bt == Infinity) bt = 1e300;\\n let corr = Infinity;\\n // Two sided error because we do not want to get stuck if the error stays on the wrong side\\n do {\\n // c should be above 0 so Halley's method can't be used, we have to stick to Newton-Raphson\\n let bct = bt ** cycles;\\n if (bct == Infinity) bct = 1e300;\\n const opc = startMoney + cycles;\\n let diff = opc * bct - targetMoney;\\n if (diff == Infinity) diff = 1e300;\\n corr = diff / (opc * x + 1.0) / bct;\\n cycles -= corr;\\n } while (Math.abs(corr) >= 1);\\n\\n const fca = Math.floor(cycles);\\n if (targetMoney <= (startMoney + fca) * Math.pow(exponentialBase, fca * threadMultiplier)) {\\n gthreads = fca;\\n return gthreads\\n }\\n const cca = Math.ceil(cycles);\\n if (targetMoney <= (startMoney + cca) * Math.pow(exponentialBase, cca * threadMultiplier)) {\\n gthreads = cca;\\n return gthreads\\n }\\n gthreads = cca + 1;\\n return gthreads\\n }\\n}\\n/** @param {NS} ns */\\nexport function getHackChance(ns, server, sec) {\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n try { return ns.formulas.hacking.hackChance(host, ns.getPlayer()) }\\n catch {\\n const person = ns.getPlayer()\\n const hackDifficulty = sec\\n const requiredHackingSkill = host.requiredHackingSkill\\n // Unrooted or unhackable server\\n if (!host.hasAdminRights || hackDifficulty >= 100 || host.minDifficulty >= 100) {\\n return 0\\n }\\n const hackFactor = 1.75;\\n const difficultyMult = (100 - hackDifficulty) / 100;\\n const skillMult = hackFactor * person.skills.hacking;\\n const skillChance = (skillMult - requiredHackingSkill) / skillMult;\\n let chance = 0\\n try {\\n chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance *\\n 1 + Math.pow(person.skills.intelligence, 0.8) / 600\\n }\\n catch {\\n chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance\\n }\\n return Math.min(1, Math.max(chance, 0));\\n }\\n}\\n/** @param {NS} ns */\\nexport function getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,//Old\\n \\\"CloudServerCost\\\": 1,//New\\n \\\"CloudServerSoftcap\\\": 1,//Old\\n \\\"CloudServerSoftcap\\\": 1,//New\\n \\\"CloudServerLimit\\\": 1,//Old\\n \\\"CloudServerLimit\\\": 1,//New\\n \\\"CloudServerMaxRam\\\": 1,//Old\\n \\\"CloudServerMaxRam\\\": 1,//New\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n\\n}\""},{"filename":"SphyxOS/forms/getGrowThreads.js","file":"\"/** @param {NS} ns */\\nexport function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(gthreads))\\n\\n const player = ns.getPlayer()\\n const host = ns.getServer(ns.args[0])\\n host.hackDifficulty = ns.args[2]\\n host.moneyAvailable = ns.args[1]\\n let gthreads = 0\\n try {\\n gthreads = ns.formulas.hacking.growThreads(host, player, host.moneyMax)\\n return\\n }\\n catch {\\n const server = host\\n const targetMoney = host.moneyMax\\n let startMoney = host.moneyAvailable\\n const cores = 1\\n const person = player\\n /*\\n if (!server.serverGrowth) {\\n gthreads = Infinity\\n }\\n */\\n const moneyMax = server.moneyMax ?? 1;\\n const hackDifficulty = server.hackDifficulty ?? 100;\\n\\n if (startMoney < 0) startMoney = 0; // servers \\\"can't\\\" have less than 0 dollars on them\\n if (targetMoney > moneyMax) targetMoney = moneyMax; // can't grow a server to more than its moneyMax\\n if (targetMoney <= startMoney) {\\n gthreads = 0; // no growth --> no threads\\n return\\n }\\n // exponential base adjusted by security\\n const adjGrowthRate = 1 + (1.03 - 1) / hackDifficulty;\\n const exponentialBase = Math.min(adjGrowthRate, 1.0035); // cap growth rate\\n\\n // total of all grow thread multipliers\\n const serverGrowthPercentage = server.serverGrowth / 100.0;\\n const coreMultiplier = 1 + (cores - 1) / 16\\n let threadMultiplier = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = ns.getBitNodeMultipliers()\\n threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier * mults.ServerGrowthRate\\n }\\n catch { threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier }\\n\\n const x = threadMultiplier * Math.log(exponentialBase)\\n const y = startMoney * x + Math.log(targetMoney * x)\\n let w;\\n if (y < Math.log(2.5)) {\\n const ey = Math.exp(y);\\n w = (ey + (4 / 3) * ey * ey) / (1 + (7 / 3) * ey + (5 / 6) * ey * ey);\\n } else {\\n w = y;\\n if (y > 0) w -= Math.log(y);\\n }\\n let cycles = w / x - startMoney;\\n let bt = exponentialBase ** threadMultiplier;\\n if (bt == Infinity) bt = 1e300;\\n let corr = Infinity;\\n // Two sided error because we do not want to get stuck if the error stays on the wrong side\\n do {\\n // c should be above 0 so Halley's method can't be used, we have to stick to Newton-Raphson\\n let bct = bt ** cycles;\\n if (bct == Infinity) bct = 1e300;\\n const opc = startMoney + cycles;\\n let diff = opc * bct - targetMoney;\\n if (diff == Infinity) diff = 1e300;\\n corr = diff / (opc * x + 1.0) / bct;\\n cycles -= corr;\\n } while (Math.abs(corr) >= 1);\\n\\n const fca = Math.floor(cycles);\\n if (targetMoney <= (startMoney + fca) * Math.pow(exponentialBase, fca * threadMultiplier)) {\\n gthreads = fca;\\n return\\n }\\n const cca = Math.ceil(cycles);\\n if (targetMoney <= (startMoney + cca) * Math.pow(exponentialBase, cca * threadMultiplier)) {\\n gthreads = cca;\\n return\\n }\\n gthreads = cca + 1;\\n return\\n }\\n}\""},{"filename":"SphyxOS/forms/getHackChance.js","file":"\"/** @param {NS} ns */\\nexport function getHackChance(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(Math.min(1, Math.max(chance, 0))))\\n\\n const person = ns.getPlayer()\\n const hackDifficulty = ns.args[1]\\n const requiredHackingSkill = ns.getServerRequiredHackingLevel(ns.args[0])\\n let chance = 0\\n // Unrooted or unhackable server\\n if (!ns.hasRootAccess(ns.args[0]) || hackDifficulty >= 100 || ns.getServerMinSecurityLevel(ns.args[0]) >= 100) {\\n return\\n }\\n const hackFactor = 1.75;\\n const difficultyMult = (100 - hackDifficulty) / 100;\\n const skillMult = hackFactor * person.skills.hacking;\\n const skillChance = (skillMult - requiredHackingSkill) / skillMult;\\n try { chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance *\\n 1 + Math.pow(person.skills.intelligence, 0.8) / 600\\n }\\n catch {\\n chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance\\n }\\n}\""},{"filename":"SphyxOS/forms/getHackPercent.js","file":"\"/** @param {NS} ns */\\nexport function getHackPercent(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(hackperc))\\n\\n const host = ns.getServer(ns.args[0])\\n host.hackDifficulty = ns.args[1]\\n const player = ns.getPlayer()\\n let hackperc = 0\\n try { hackperc = ns.formulas.hacking.hackPercent(host, player) }\\n catch {\\n const hackDifficulty = host.minDifficulty ?? 100\\n if (hackDifficulty >= 100) {\\n hackperc = 0\\n return\\n }\\n const requiredHackingSkill = host.requiredHackingSkill ?? 1e9\\n const balanceFactor = 240\\n const difficultyMult = (100 - hackDifficulty) / 100\\n const skillMult = (player.skills.hacking - (requiredHackingSkill - 1)) / player.skills.hacking\\n\\n let percentMoneyHacked = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = ns.getBitNodeMultipliers()\\n percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money * mults.ScriptHackMoney / balanceFactor\\n }\\n catch { percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money / balanceFactor }\\n hackperc = Math.min(1, Math.max(percentMoneyHacked, 0))\\n }\\n return\\n}\""},{"filename":"SphyxOS/forms/getHckTime.js","file":"\"/** @param {NS} ns */\\nexport function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(hackingTime))\\n \\n const host = ns.getServer(ns.args[0])\\n /** @type {Person} person */\\n const person = ns.getPlayer()\\n\\n host.hackDifficulty = ns.args[1]\\n let hackingTime = 0\\n try { hackingTime = ns.formulas.hacking.hackTime(host, person) }\\n catch {\\n const { hackDifficulty, requiredHackingSkill } = host;\\n if (hackDifficulty >= 100 || requiredHackingSkill > person.skills.hacking) {\\n hackingTime = Number.POSITIVE_INFINITY\\n return\\n }\\n const difficultyMult = requiredHackingSkill * hackDifficulty;\\n\\n const baseDiff = 500;\\n const baseSkill = 50;\\n const diffFactor = 2.5;\\n let skillFactor = diffFactor * difficultyMult + baseDiff;\\n skillFactor /= person.skills.hacking + baseSkill;\\n\\n const hackTimeMultiplier = 5;\\n try {\\n hackingTime = 1000 *\\n (hackTimeMultiplier * skillFactor) /\\n (person.mults.hacking_speed *\\n 1 + Math.pow(person.skills.intelligence, 0.8) / 600)\\n }\\n catch { hackingTime = 1000 * hackTimeMultiplier * skillFactor / person.mults.hacking_speed }\\n }\\n}\""},{"filename":"SphyxOS/forms/getReputationFromDonation.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n //Amount === ns.args[0]\\n /**@type {BitNodeMultipliers} mults */\\n let mults = null\\n try { mults = ns.getBitNodeMultipliers() } catch { }\\n let result = 0\\n try { result = ns.args[0] / 1e6 * ns.getPlayer().mults.faction_rep * mults.FactionWorkRepGain }\\n catch { result = ns.args[0] / 1e6 * ns.getPlayer().mults.faction_rep }\\n\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/full/IPvGo.js","file":"\"/**Author:\\n * Discord:\\n * - Sphyxis\\n * \\n * Additional Contributers:\\n * Discord:\\n * - Stoneware\\n * - gmcew\\n *\\n * Compressed all into main to allow you to run 2 side by side as white and black\\n */\\n/*\\nopponent2 is the full list, including the end game board.\\nopponent is the falback, in case you get the end board but have not unlocked it.\\nconst opponent = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\"]\\nconst opponent2 = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\", \\\"????????????\\\"]\\n*/\\nconst opponent = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\"]\\nconst opponent2 = [\\\"Netburners\\\", \\\"Slum Snakes\\\", \\\"The Black Hand\\\", \\\"Tetrads\\\", \\\"Daedalus\\\", \\\"Illuminati\\\", \\\"????????????\\\"]\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.ui.openTail()\\n ns.disableLog(\\\"ALL\\\")\\n writeProxy()\\n writeProxyTry()\\n writeGetMoves()\\n const CHEATS = true\\n const LOGTIME = false\\n let STYLE = 0\\n const REPEAT = true\\n let currentValidMovesTurn = 0 //The turn count that the currentValidMoves is valid for\\n let currentValidMoves //All valid moves for this turn\\n let currentValidContestedMoves //All valid moves that occupy a contested space\\n let turn = 0\\n let board;\\n let contested;\\n let validMove;\\n let validLibMoves;\\n let chains;\\n let testBoard = []\\n\\n //Run it with no arguments or the argument \\\"false\\\" to play as black.\\n //Run it with any other argument to play as white\\n const playAsWhite = !!ns.args[0]\\n ns.print(\\\"Playing as \\\", playAsWhite ? \\\"White\\\" : \\\"Black\\\")\\n const me = playAsWhite ? \\\"O\\\" : \\\"X\\\"\\n const you = me === \\\"X\\\" ? \\\"O\\\" : \\\"X\\\"\\n ns.disableLog(\\\"disableLog\\\")\\n ns.disableLog(\\\"go.makeMove\\\")\\n ns.disableLog(\\\"go.passTurn\\\")\\n ns.disableLog(\\\"sleep\\\")\\n const startBoard = await proxy(\\\"go.getBoardState\\\")\\n let inProgress = false\\n let START = performance.now()\\n //If we have already moved, jump the turn to 3 to get out of Opening Moves\\n for (let x = 0; x < startBoard[0].length; x++) {\\n for (let y = 0; y < startBoard[0].length; y++) {\\n if (startBoard[x][y] === me) {\\n inProgress = true\\n turn = 3\\n break\\n }\\n }\\n if (inProgress) break\\n }\\n getStyle()\\n const currentGame = await ns.go.opponentNextTurn(false, playAsWhite)\\n checkNewGame(currentGame, false)\\n while (true) {\\n await ns.sleep(4)\\n let passed = false\\n turn++\\n board = await proxy(\\\"go.getBoardState\\\")\\n contested = await proxy(\\\"go.analysis.getControlledEmptyNodes\\\")\\n validMove = await getMoves(playAsWhite)\\n validLibMoves = await proxy(\\\"go.analysis.getLiberties\\\")\\n chains = await proxy(\\\"go.analysis.getChains\\\")\\n const size = board[0].length\\n //Build a test board with walls\\n testBoard = []\\n let testWall = \\\"\\\"\\n let results;\\n if (size === 13) testWall = \\\"WWWWWWWWWWWWWWW\\\"\\n else if (size === 9) testWall = \\\"WWWWWWWWWWW\\\"\\n else if (size === 7) testWall = \\\"WWWWWWWWW\\\"\\n else if (size === 19) testWall = \\\"WWWWWWWWWWWWWWWWWWWWW\\\"\\n else testWall = \\\"WWWWWWW\\\"\\n testBoard.push(testWall)\\n for (const b of board) testBoard.push(\\\"W\\\" + b + \\\"W\\\")\\n testBoard.push(testWall)\\n //We have our test board\\n\\n if (turn <= 1)\\n results = await movePiece(getOpeningMove())\\n else {\\n switch (STYLE) {\\n case 0: //Netburners\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 3, 3, 1, 6))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getAggroAttack(4, 7, 3, 1, 6))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getDefAttack(8, 20, 2))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 1: //The Black Hand\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 3, 3, 1, 6))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getAggroAttack(4, 7, 3, 1, 6))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 2: //Mr. Mustacio - Slum Snakes\\t\\t\\t\\t\\t\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 3, 3, 1, 6))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getDefAttack(4, 7, 3, 1, 6))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 3: //Daedalus\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 4, 3, 1, 6))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getDefAttack(5, 7, 3, 2, 6))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false, 1))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 4: //Tetrads\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getAggroAttack(5, 7, 3))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat(),)) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 5: //Illum\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n case 6: //??????\\n if (results = await movePiece(getRandomCounterLib())) break\\n if (results = await movePiece(getRandomLibAttack(88))) break\\n if (results = await movePiece(getRandomLibDefend())) break\\n if (results = await moveSnakeEyes(getSnakeEyes(6))) break\\n if (results = await movePiece(getAggroAttack(2, 2, 2))) break\\n if (results = await movePiece(disruptEyes())) break\\n if (results = await movePiece(getDefPattern())) break\\n if (results = await movePiece(getAggroAttack(3, 4, 3))) break\\n if (results = await movePiece(getRandomBolster(2, 1))) break\\n if (results = await movePiece(getDefAttack(5, 7, 3))) break\\n if (results = await movePiece(attackGrowDragon(1))) break\\n if (results = await movePiece(getRandomExpand())) break\\n if (results = await movePiece(getRandomBolster(2, 1, false))) break\\n if (results = await movePiece(getRandomLibAttack())) break\\n if (results = await movePiece(getRandomStrat())) break\\n if (results = await moveWallBreaker(getWallBreaker())) break\\n if (results = await moveWallBreaker(getWallBreaker(4))) break\\n if (results = await moveWallBreaker(getWallBreaker(-1))) break\\n ns.print(\\\"Turn Passed\\\")\\n passed = true\\n results = await ns.go.passTurn(playAsWhite)\\n break\\n } //End of style switch\\n } // end of turn >= 3\\n checkNewGame(results, passed)\\n }\\n function getStyle() {\\n const facing = ns.go.getOpponent()\\n switch (facing) {\\n case \\\"Netburners\\\":\\n STYLE = 0\\n break\\n case \\\"The Black Hand\\\":\\n STYLE = 1\\n break\\n case \\\"Slum Snakes\\\":\\n STYLE = 2\\n break\\n case \\\"Daedalus\\\":\\n STYLE = 3\\n break\\n case \\\"Tetrads\\\":\\n STYLE = 4\\n break\\n case \\\"Illuminati\\\":\\n STYLE = 5\\n break\\n default:\\n STYLE = 6\\n }\\n }\\n\\n function checkNewGame(gameInfo, passed) {\\n if (gameInfo.type === \\\"gameOver\\\" || (gameInfo.type === \\\"pass\\\" && passed)) {\\n if (!REPEAT) ns.exit()\\n if (playAsWhite || ns.go.getOpponent() === \\\"No AI\\\") ns.go.resetBoardState(\\\"No AI\\\", 13)\\n else {\\n try { ns.go.resetBoardState(opponent2[Math.floor(Math.random() * opponent2.length)], 13) }\\n catch { ns.go.resetBoardState(opponent[Math.floor(Math.random() * opponent.length)], 13) }\\n }\\n turn = 0\\n ns.clearLog()\\n getStyle()\\n }\\n }\\n /** @param {NS} ns */\\n function isPattern(x, y, pattern) {\\n //Move the pattern around with x/y loops, check if pattern matches IF a move is placed\\n //We can assume that x and y are valid moves\\n\\n const size = testBoard[0].length\\n const patterns = getAllPatterns(pattern)\\n const patternSize = pattern.length\\n\\n for (const patternCheck of patterns) {\\n //cx and cy - the spots of the pattern we are checking against the test board\\n //For, say a 3x3 pattern, we do a grid of 0,0 -> 2, 2\\n for (let cx = ((patternSize - 1) * -1); cx <= 0; cx++) { // We've added a wall around everything, so 0 is a wall\\n if (cx + x + 1 < 0 || cx + x + 1 > size - 1) continue\\n for (let cy = ((patternSize - 1) * -1); cy <= 0; cy++) {\\n //We now have a cycle that will check each section of the grid against the pattern\\n //Safety checks: We know 0,0 is safe, we were sent it, but each other section could be bad \\n if (cy + y + 1 < 0 || cy + y + 1 > size - 1) continue\\n let count = 0\\n let abort = false\\n for (let px = 0; px < patternSize && !abort; px++) {\\n if (x + cx + px + 1 < 0 || x + cx + px + 1 >= size) { //Don't go off grid\\n abort = true\\n break\\n }\\n for (let py = 0; py < patternSize && !abort; py++) {\\n if (y + cy + py + 1 < 0 || y + cy + py + 1 >= size) { //Are we off the map?\\n abort = true\\n break\\n }\\n if (cx + px === 0 && cy + py === 0 && ![me, \\\"*\\\"].includes(patternCheck[px][py])) {\\n abort = true\\n break\\n }\\n if (cx + px === 0 && cy + py === 0 && [me].includes(contested[x][y]) && patternCheck[px][py] !== \\\"*\\\") {\\n abort = true\\n break\\n }\\n //We now have a cycles for each spot in the pattern\\n //0,0 -> 2,2 for a 3x3\\n switch (patternCheck[px][py]) {\\n case \\\"X\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === me || (cx + px === 0 && cy + py === 0 && testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\")) {\\n count++\\n }\\n else if (cx + px === 0 && cy + py === 0) {\\n count++ // Our placement piece\\n }\\n else abort = true\\n break\\n case \\\"*\\\": // Special case. We move here next or break the test\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\" && cx + px === 0 && cy + py === 0) {\\n count++\\n }\\n else abort = true\\n break\\n case \\\"O\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === you)\\n count++\\n else abort = true\\n break\\n case \\\"x\\\":\\n if ([me, \\\".\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"o\\\":\\n if ([you, \\\".\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"?\\\":\\n count++\\n break\\n case \\\".\\\":\\n if (testBoard[cx + x + 1 + px][cy + y + 1 + py] === \\\".\\\")\\n count++\\n else abort = true\\n break\\n case \\\"W\\\":\\n if ([\\\"W\\\", \\\"#\\\"].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"B\\\":\\n if ([\\\"W\\\", \\\"#\\\", me].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"b\\\":\\n if ([\\\"W\\\", \\\"#\\\", you].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n case \\\"A\\\":\\n if ([\\\"W\\\", \\\"#\\\", me, you].includes(testBoard[cx + x + 1 + px][cy + y + 1 + py]))\\n count++\\n else abort = true\\n break\\n }\\n if (count === patternSize * patternSize) return true\\n }\\n }\\n }\\n }\\n }\\n return false\\n }\\n /** @param {NS} ns */\\n function getAllPatterns(pattern) {\\n const rotations = [\\n pattern,\\n rotate90Degrees(pattern),\\n rotate90Degrees(rotate90Degrees(pattern)),\\n rotate90Degrees(rotate90Degrees(rotate90Degrees(pattern))),\\n ]\\n return [...rotations, ...rotations.map(verticalMirror)]\\n }\\n\\n //Special thanks to @gmcew for the next 2 functions!\\n /** @param {NS} ns */\\n function rotate90Degrees(pattern) {\\n return pattern.map((val, index) => pattern.map(row => row[index]).reverse().join(\\\"\\\"))\\n }\\n /** @param {NS} ns */\\n function verticalMirror(pattern) {\\n return pattern.toReversed()\\n }\\n\\n /** @param {NS} ns */\\n function getSnakeEyes(minKilled = 6) {\\n if (!CHEATS) return []\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n\\n const checked = new Set\\n\\n for (let x = 0; x < size - 1; x++)\\n for (let y = 0; y < size - 1; y++) {\\n if (contested[x][y] === me || board[x][y] !== you || validLibMoves[x][y] !== 2 || checked.has(JSON.stringify([x, y]))) continue\\n //Is it the enemy, with 2 libs (we can kill) and we have not checked this spot and the chain is large enough\\n const chain = getChainValue(x, y, you, true)\\n checked.add(JSON.stringify([x, y]))\\n if (chain < minKilled) continue\\n //We have a winner! Check all it's spots and find the 2 killing blows. Add the checked spots to the checked list so we don't recheck\\n const enemySearch = new Set\\n const move1 = []\\n const move2 = []\\n enemySearch.add(JSON.stringify([x, y]))\\n for (const explore of enemySearch) {\\n const [fx, fy] = JSON.parse(explore)\\n //Find your eyes\\n if (board[fx][fy] === \\\".\\\") {\\n move1.length ? move2.push([fx, fy]) : move1.push([fx, fy])\\n checked.add(JSON.stringify([fx, fy]))\\n continue\\n }\\n\\n //Find more of yourself to search...\\n if (fx < size - 1 && [you, \\\".\\\"].includes(board[fx + 1][fy])) {\\n enemySearch.add(JSON.stringify([fx + 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fx > 0 && [you, \\\".\\\"].includes(board[fx - 1][fy])) {\\n enemySearch.add(JSON.stringify([fx - 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy > 0 && [you, \\\".\\\"].includes(board[fx][fy - 1])) {\\n enemySearch.add(JSON.stringify([fx, fy - 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy < size - 1 && [you, \\\".\\\"].includes(board[fx][fy + 1])) {\\n enemySearch.add(JSON.stringify([fx, fy + 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n } // End of searching the enemy\\n\\n if (chain > highValue) {\\n highValue = chain\\n moveOptions.length = 0\\n const mv1 = move1.pop()\\n const mv2 = move2.pop()\\n moveOptions.push([mv1[0], mv1[1], mv2[0], mv2[1]])\\n }\\n else if (chain === highValue) {\\n const mv1 = move1.pop()\\n const mv2 = move2.pop()\\n moveOptions.push([mv1[0], mv1[1], mv2[0], mv2[1]])\\n }\\n } // Search whole board\\n\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"SnakeEyes Cheat\\\"\\n } : []\\n }\\n\\n /** @param {NS} ns */\\n function getWallBreaker(eyesToBreak = 3) {\\n if (!CHEATS) return []\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n\\n const checked = new Set\\n\\n for (let x = 0; x < size - 1; x++)\\n for (let y = 0; y < size - 1; y++) {\\n if (contested[x][y] === me || board[x][y] !== you || (validLibMoves[x][y] !== eyesToBreak && eyesToBreak > 0) || checked.has(JSON.stringify([x, y]))) continue\\n //Is it the enemy, with 2 libs (we can kill) and we have not checked this spot and the chain is large enough\\n const chain = getChainValue(x, y, you, true)\\n checked.add(JSON.stringify([x, y]))\\n //We have a winner! Check all it's spots and find the 2 killing blows. Add the checked spots to the checked list so we don't recheck\\n const enemySearch = new Set\\n const moves = []\\n enemySearch.add(JSON.stringify([x, y]))\\n for (const explore of enemySearch) {\\n const [fx, fy] = JSON.parse(explore)\\n //Find your eyes\\n if (board[fx][fy] === \\\".\\\") {\\n moves.push([fx, fy])\\n checked.add(JSON.stringify([fx, fy]))\\n continue\\n }\\n\\n //Find more of yourself to search...\\n if (fx < size - 1 && [you, \\\".\\\"].includes(board[fx + 1][fy])) {\\n enemySearch.add(JSON.stringify([fx + 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fx > 0 && [you, \\\".\\\"].includes(board[fx - 1][fy])) {\\n enemySearch.add(JSON.stringify([fx - 1, fy]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy > 0 && [you, \\\".\\\"].includes(board[fx][fy - 1])) {\\n enemySearch.add(JSON.stringify([fx, fy - 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n if (fy < size - 1 && [you, \\\".\\\"].includes(board[fx][fy + 1])) {\\n enemySearch.add(JSON.stringify([fx, fy + 1]))\\n checked.add(JSON.stringify([fx, fy]))\\n }\\n } // End of searching the enemy\\n\\n if (chain > highValue) {\\n highValue = chain\\n moveOptions.length = 0\\n moveOptions.push(...moves)\\n }\\n else if (chain === highValue) {\\n moveOptions.push(...moves)\\n }\\n } // Search whole board\\n\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"WallBreaker Cheat\\\"\\n } : []\\n }\\n /** @param {NS} ns */\\n function getRandomLibAttack(minKilled = 1) {\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 1\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (contested[x][y] === me || validLibMoves[x][y] !== -1) continue\\n\\n let count = 0\\n let chains = 0\\n\\n //We are only checking up, down, left and right\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] === 1) {\\n count++\\n chains += getChainValue(x - 1, y, you)\\n }\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] === 1) {\\n count++\\n chains += getChainValue(x + 1, y, you)\\n }\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] === 1) {\\n count++\\n chains += getChainValue(x, y - 1, you)\\n }\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] === 1) {\\n count++\\n chains += getChainValue(x, y + 1, you)\\n }\\n const enemyLibs = getSurroundLibs(x, y, you)\\n if (count === 0 || (chains < minKilled && enemyLibs <= 1)) continue\\n\\n const result = count * chains\\n if (result > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = result\\n }\\n else if (result === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Lib Attack\\\"\\n } : []\\n }\\n /** @param {NS} ns */\\n function getRandomLibDefend(savedMin = 1) {\\n const moveOptions = []\\n const size = board[0].length\\n let highValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n const surround = getSurroundLibs(x, y, me)\\n const myEyes = getEyeValue(x, y, me)\\n if (surround + myEyes < 2 || createsLib(x, y, me)) continue //Abort. Let it go, let it go...\\n\\n if (validLibMoves[x][y] === -1) {\\n let count = 0\\n //We are only checking up, down, left and right\\n if (x > 0 && validLibMoves[x - 1][y] === 1 && board[x - 1][y] === me) count += getChainValue(x - 1, y, me)\\n if (x < size - 1 && validLibMoves[x + 1][y] === 1 && board[x + 1][y] === me) count += getChainValue(x + 1, y, me)\\n if (y > 0 && validLibMoves[x][y - 1] === 1 && board[x][y - 1] === me) count += getChainValue(x, y - 1, me)\\n if (y < size - 1 && validLibMoves[x][y + 1] === 1 && board[x][y + 1] === me) count += getChainValue(x, y + 1, me)\\n if (count === 0 || count < savedMin) continue\\n //Just HOW effective will this move be? Counter attack if we can.\\n count *= surround\\n\\n if (count > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = count\\n }\\n else if (count === highValue) moveOptions.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Lib Defend\\\"\\n } : []\\n }\\n /** @param {NS} ns */\\n function getRandomCounterLib() {\\n //Advanced strategy\\n //If we have a chain that's going to die, and a hanging lib attached to it\\n //Find that hanging lib and kill it to save the chain\\n const size = board[0].length\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n const movesAvailable = new Set //Contains the empty squares that we are looking to see if we should take\\n const friendlyToCheckForOpp = new Set\\n for (const [x, y] of moves) {\\n //We are checking up, down, left and right first\\n\\n if (x > 0 && validLibMoves[x - 1][y] === 1 && board[x - 1][y] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x - 1, y]))\\n }\\n if (x < size - 1 && validLibMoves[x + 1][y] === 1 && board[x + 1][y] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x + 1, y]))\\n }\\n if (y > 0 && validLibMoves[x][y - 1] === 1 && board[x][y - 1] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x, y - 1]))\\n }\\n if (y < size - 1 && validLibMoves[x][y + 1] === 1 && board[x][y + 1] === me) {\\n movesAvailable.add(JSON.stringify([x, y]))\\n friendlyToCheckForOpp.add(JSON.stringify([x, y + 1]))\\n }\\n }\\n //Shortcut. While there's 1, is it THE one?\\n //We know that 1 side of this is a friendly with 1 lib at risk. Is another side the enemy?\\n for (const explore of movesAvailable) {\\n const [fx, fy] = JSON.parse(explore)\\n if (!validMove[fx][fy]) continue\\n if (fx < size - 1 && board[fx + 1][fy] === you && validLibMoves[fx + 1][fy] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the east\\\"\\n }\\n }\\n if (fx > 0 && board[fx - 1][fy] === you && validLibMoves[fx - 1][fy] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the west\\\"\\n }\\n }\\n if (fy > 0 && board[fx][fy - 1] === you && validLibMoves[fx][fy - 1] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the south\\\"\\n }\\n }\\n if (fy < size - 1 && board[fx][fy + 1] === you && validLibMoves[fx][fy + 1] === 1) {\\n return {\\n coords: [fx, fy],\\n msg: \\\"Counter Lib Attack - Fist of the north\\\"\\n }\\n }\\n }\\n const enemiesToSearch = new Set\\n //We have our empty chain. Look through him to find adjoining O's that can be killed and other friendies\\n for (const explore of friendlyToCheckForOpp) {\\n const [fx, fy] = JSON.parse(explore)\\n if (fx < size - 1 && board[fx + 1][fy] === you && validLibMoves[fx + 1][fy] === 1) enemiesToSearch.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && board[fx - 1][fy] === you && validLibMoves[fx - 1][fy] === 1) enemiesToSearch.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && board[fx][fy - 1] === you && validLibMoves[fx][fy - 1] === 1) enemiesToSearch.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && board[fx][fy + 1] === you && validLibMoves[fx][fy + 1] === 1) enemiesToSearch.add(JSON.stringify([fx, fy + 1]))\\n\\n if (fx < size - 1 && [me].includes(board[fx + 1][fy])) friendlyToCheckForOpp.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && [me].includes(board[fx - 1][fy])) friendlyToCheckForOpp.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && [me].includes(board[fx][fy - 1])) friendlyToCheckForOpp.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && [me].includes(board[fx][fy + 1])) friendlyToCheckForOpp.add(JSON.stringify([fx, fy + 1]))\\n }\\n\\n for (const explore of enemiesToSearch) {\\n const [fx, fy] = JSON.parse(explore)\\n if (fx < size - 1 && board[fx + 1][fy] === you) enemiesToSearch.add(JSON.stringify([fx + 1, fy]))\\n if (fx > 0 && board[fx - 1][fy] === you) enemiesToSearch.add(JSON.stringify([fx - 1, fy]))\\n if (fy > 0 && board[fx][fy - 1] === you) enemiesToSearch.add(JSON.stringify([fx, fy - 1]))\\n if (fy < size - 1 && board[fx][fy + 1] === you) enemiesToSearch.add(JSON.stringify([fx, fy + 1]))\\n\\n if (fx < size - 1 && board[fx + 1][fy] === \\\".\\\" && validMove[fx + 1][fy]) {\\n return {\\n coords: [fx + 1, fy],\\n msg: \\\"Counter Lib Attack - The wind blows\\\"\\n }\\n }\\n if (fx > 0 && board[fx - 1][fy] === \\\".\\\" && validMove[fx - 1][fy]) {\\n return {\\n coords: [fx - 1, fy],\\n msg: \\\"Counter Lib Attack - The earth grows\\\"\\n }\\n }\\n if (fy > 0 && board[fx][fy - 1] === \\\".\\\" && validMove[fx][fy - 1]) {\\n return {\\n coords: [fx, fy - 1],\\n msg: \\\"Counter Lib Attack - The fire burns\\\"\\n }\\n }\\n if (fy < size - 1 && board[fx][fy + 1] === \\\".\\\" && validMove[fx][fy + 1]) {\\n return {\\n coords: [fx, fy + 1],\\n msg: \\\"Counter Lib Attack - The water flows\\\"\\n }\\n }\\n }\\n return []\\n }\\n /** @param {NS} ns */\\n function getRandomExpand() {\\n const moveOptions = []\\n const size = board[0].length;\\n let highValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n const surroundLibs = getSurroundLibs(x, y, me)\\n const enemySurroundLibs = getSurroundLibs(x, y, you)\\n if (contested[x][y] !== \\\"?\\\" || surroundLibs <= 2 || createsLib(x, y, me) || enemySurroundLibs <= 1) continue\\n let count = 0\\n //We are only checking up, down, left and right. Don't expand if you're surrounded by friendlies\\n if (x > 0 && board[x - 1][y] === me) count++\\n if (x < size - 1 && board[x + 1][y] === me) count++\\n if (y > 0 && board[x][y - 1] === me) count++\\n if (y < size - 1 && board[x][y + 1] === me) count++\\n if (count >= 3 || count <= 0) continue\\n\\n const surroundSpace = getSurroundSpaceFull(x, y) + 1\\n const enemySurroundChains = getChainAttack(x, y) + 1\\n const myEyes = getEyeValueFull(x, y, me) + 1\\n const enemies = getSurroundEnemiesFull(x, y) + 1\\n const freeSpace = getFreeSpace(x, y)\\n const rank = myEyes * enemySurroundLibs * enemies * enemySurroundChains * freeSpace * surroundSpace\\n\\n if (rank > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = rank\\n }\\n else if (rank === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Expansion\\\"\\n } : []\\n }\\n /** @param {NS} ns */\\n function getRandomBolster(libRequired, savedNodesMin, onlyContested = true) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highValue = 1\\n // Look through all the points on the board\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n if ((onlyContested && contested[x][y] !== \\\"?\\\")) continue\\n if (createsLib(x, y, me)) continue\\n let right = 0\\n let left = 0\\n let up = 0\\n let down = 0\\n\\n //We are only checking up, down, left and right\\n //We are checking for linking chains of friendlies, filtering out those already checked\\n let checkedChains = []\\n if (x < size - 1 && board[x + 1][y] === me && validLibMoves[x + 1][y] === libRequired) {\\n right = getChainValue(x + 1, y, me)\\n checkedChains.push(chains[x + 1][y])\\n }\\n if (x > 0 && board[x - 1][y] === me && !checkedChains.includes(chains[x - 1][y]) && validLibMoves[x - 1][y] === libRequired) {\\n left = getChainValue(x - 1, y, me)\\n checkedChains.push(chains[x - 1][y])\\n }\\n if (y < size - 1 && board[x][y + 1] === me && !checkedChains.includes(chains[x][y + 1]) && validLibMoves[x][y + 1] === libRequired) {\\n up = getChainValue(x, y + 1, me)\\n checkedChains.push(chains[x][y + 1])\\n }\\n if (y > 0 && board[x][y - 1] === me && !checkedChains.includes(chains[x][y - 1]) && validLibMoves[x][y - 1] === libRequired)\\n down = getChainValue(x, y - 1, me)\\n\\n let count = 0\\n let total = 0\\n if (right >= savedNodesMin) {\\n count++\\n total += right\\n }\\n if (left >= savedNodesMin) {\\n count++\\n total += left\\n }\\n if (up >= savedNodesMin) {\\n count++\\n total += up\\n }\\n if (down >= savedNodesMin) {\\n count++\\n total += down\\n }\\n if (count <= 0) continue\\n const surroundMulti = getSurroundLibSpread(x, y, me)\\n const rank = total * count * surroundMulti\\n if (rank > highValue) {\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n highValue = rank\\n }\\n else if (rank === highValue) moveOptions.push([x, y]);\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Bolster - Libs: \\\" + libRequired + \\\" Nodes: \\\" + savedNodesMin + \\\" OnlyContested: \\\" + onlyContested\\n } : []\\n }\\n /** @param {NS} ns */\\n function getChainValue(checkx, checky, player, isolated = false) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (contested[checkx][checky] === \\\"?\\\" || contested[checkx][checky] === \\\"#\\\" || board[checkx][checky] === otherPlayer) return 0\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 1\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer || (isolated && board[x][y] === \\\".\\\")) continue\\n count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n }\\n /** @param {NS} ns */\\n function getEyeValue(checkx, checky, player) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 0\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer) continue\\n if (contested[x][y] === player) count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n }\\n /** @param {NS} ns */\\n function getFreeSpace(checkx, checky) {\\n const size = board[0].length\\n if (contested[checkx][checky] !== \\\"?\\\") return 0\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n let count = 1\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if ([\\\"#\\\", me, you].includes(contested[x][y])) continue\\n if (contested[x][y] === \\\"?\\\") count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n }\\n /** @param {NS} ns */\\n function getEyeValueFull(checkx, checky, player) {\\n const size = board[0].length\\n const otherPlayer = player === me ? you : me\\n const explored = new Set()\\n if (checkx < size - 1) explored.add(JSON.stringify([checkx + 1, checky]))\\n if (checkx > 0) explored.add(JSON.stringify([checkx - 1, checky]))\\n if (checky > 0) explored.add(JSON.stringify([checkx, checky - 1]))\\n if (checky < size - 1) explored.add(JSON.stringify([checkx, checky + 1]))\\n if (checkx < size - 1 && checky < size - 1) explored.add(JSON.stringify([checkx + 1, checky + 1]))\\n if (checkx > 0 && checky < size - 1) explored.add(JSON.stringify([checkx - 1, checky + 1]))\\n if (checkx < size - 1 && checky > 0) explored.add(JSON.stringify([checkx + 1, checky - 1]))\\n if (checkx > 0 && checky > 0) explored.add(JSON.stringify([checkx - 1, checky - 1]))\\n let count = 0\\n for (const explore of explored) {\\n const [x, y] = JSON.parse(explore)\\n if (contested[x][y] === \\\"?\\\" || contested[x][y] === \\\"#\\\" || board[x][y] === otherPlayer) continue\\n if (contested[x][y] === player) count++\\n if (x < size - 1) explored.add(JSON.stringify([x + 1, y]))\\n if (x > 0) explored.add(JSON.stringify([x - 1, y]))\\n if (y > 0) explored.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1) explored.add(JSON.stringify([x, y + 1]))\\n }\\n return count\\n }\\n /** @param {NS} ns */\\n function getChainAttack(x, y) {\\n const size = board[0].length\\n let count = 0\\n if (x > 0 && board[x - 1][y] === you) count += getChainValue(x - 1, y, you)\\n if (x < size - 1 && board[x + 1][y] === you) count += getChainValue(x + 1, y, you)\\n if (y > 0 && board[x][y - 1] === you) count += getChainValue(x, y - 1, you)\\n if (y < size - 1 && board[x][y + 1] === you) count += getChainValue(x, y + 1, you)\\n\\n return count\\n }\\n /** @param {NS} ns */\\n function getChainAttackFull(x, y) {\\n const size = board[0].length\\n let count = 0\\n if (x < size - 1) count += getChainValue(x + 1, y, you)\\n if (x > 0) count += getChainValue(x - 1, y, you)\\n if (y > 0) count += getChainValue(x, y - 1, you)\\n if (y < size - 1) count += getChainValue(x, y + 1, you)\\n if (x < size - 1 && y < size - 1) count += getChainValue(x + 1, y + 1, you)\\n if (x > 0 && y < size - 1) count += getChainValue(x - 1, y + 1, you)\\n if (x < size - 1 && y > 0) count += getChainValue(x + 1, y - 1, you)\\n if (x > 0 && y > 0) count += getChainValue(x - 1, y - 1, you)\\n return count\\n }\\n /** @param {NS} ns */\\n function getSurroundSpace(x, y) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && board[x - 1][y] === \\\".\\\") surround++\\n if (x < size - 1 && board[x + 1][y] === \\\".\\\") surround++\\n if (y > 0 && board[x][y - 1] === \\\".\\\") surround++\\n if (y < size - 1 && board[x][y + 1] === \\\".\\\") surround++\\n return surround\\n }\\n /** @param {NS} ns */\\n function getSurroundSpaceFull(startx, starty, player = me, depth = 1) {\\n const size = board[0].length\\n let surround = 0\\n for (let x = startx - depth; x <= startx + depth; x++)\\n for (let y = starty - depth; y <= starty + depth; y++)\\n if (x >= 0 && x <= size - 1 && y >= 0 && y <= size - 1 && [\\\".\\\", player].includes(board[x][y])) surround++\\n return surround\\n }\\n /** @param {NS} ns */\\n function getHeatMap(startx, starty, player = me, depth = 2) {\\n const size = board[0].length\\n let count = 1\\n for (let x = startx - depth; x <= startx + depth; x++)\\n for (let y = starty - depth; y <= starty + depth; y++)\\n if (x >= 0 && x <= size - 1 && y >= 0 && y <= size - 1 && [\\\".\\\", player].includes(board[x][y])) count += board[x][y] === player ? 1.5 : board[x][y] === \\\".\\\" ? 1 : 0\\n return count\\n }\\n /** @param {NS} ns */\\n function getSurroundLibs(x, y, player) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && (board[x - 1][y] === \\\".\\\" || board[x - 1][y] === player)) surround += board[x - 1][y] === \\\".\\\" ? 1 : validLibMoves[x - 1][y] - 1\\n if (x < size - 1 && (board[x + 1][y] === \\\".\\\" || board[x + 1][y] === player)) surround += board[x + 1][y] === \\\".\\\" ? 1 : validLibMoves[x + 1][y] - 1\\n if (y > 0 && (board[x][y - 1] === \\\".\\\" || board[x][y - 1] === player)) surround += board[x][y - 1] === \\\".\\\" ? 1 : validLibMoves[x][y - 1] - 1\\n if (y < size - 1 && (board[x][y + 1] === \\\".\\\" || board[x][y + 1] === player)) surround += board[x][y + 1] === \\\".\\\" ? 1 : validLibMoves[x][y + 1] - 1\\n return surround\\n }\\n /** @param {NS} ns */\\n function getSurroundLibSpread(x, y, player) {\\n const size = board[0].length\\n let surround = 0\\n const checks = new Set\\n if (board[x][y] === \\\".\\\") checks.add(JSON.stringify([x, y]))\\n else return 0\\n if (x > 0 && board[x - 1][y] === \\\".\\\") checks.add(JSON.stringify([x - 1, y]))\\n if (x < size - 1 && board[x + 1][y] === \\\".\\\") checks.add(JSON.stringify([x + 1, y]))\\n if (y > 0 && board[x][y - 1] === \\\".\\\") checks.add(JSON.stringify([x, y - 1]))\\n if (y < size - 1 && board[x][y + 1] === \\\".\\\") checks.add(JSON.stringify([x, y + 1]))\\n //Now, check the liberty values of all the checks\\n for (const check of checks) {\\n const [x, y] = JSON.parse(check)\\n surround += getSurroundLibs(x, y, player)\\n }\\n return surround\\n }\\n /** @param {NS} ns */\\n function getSurroundEnemiesFull(x, y) {\\n const size = board[0].length\\n let surround = 0\\n if (x > 0 && board[x - 1][y] === you) surround += getChainValue(x - 1, y, you)\\n if (x < size - 1 && board[x + 1][y] === you) surround += getChainValue(x + 1, y, you)\\n if (y > 0 && board[x][y - 1] === you) surround += getChainValue(x, y - 1, you)\\n if (y < size - 1 && board[x][y + 1] === you) surround += getChainValue(x, y + 1, you)\\n\\n if (x > 0 && y > 0 && board[x - 1][y - 1] === you) surround += getChainValue(x - 1, y - 1, you)\\n if (x < size - 1 && y > 0 && board[x + 1][y - 1] === you) surround += getChainValue(x + 1, y - 1, you)\\n if (y < size - 1 && x > 0 && board[x - 1][y + 1] === you) surround += getChainValue(x - 1, y - 1, you)\\n if (y < size - 1 && x < size - 1 && board[x + 1][y + 1] === you) surround += getChainValue(x + 1, y + 1, you)\\n\\n return surround\\n }\\n /** @param {NS} ns */\\n function getRandomStrat() {\\n const moveOptions = []\\n const moveOptions2 = []\\n const size = board[0].length\\n\\n // Look through all the points on the board\\n let bestRank = 0\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (![\\\"?\\\", you].includes(contested[x][y]) || createsLib(x, y, me)) continue\\n let isSupport = ((x > 0 && board[x - 1][y] === me && validLibMoves[x - 1][y] >= 1) || (x < size - 1 && board[x + 1][y] === me && validLibMoves[x + 1][y] >= 1) || (y > 0 && board[x][y - 1] === me && validLibMoves[x][y - 1] >= 1) || (y < size - 1 && board[x][y + 1] === me && validLibMoves[x][y + 1] >= 1)) ? true : false\\n let isAttack = ((x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= 2) || (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= 2) || (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= 2) || (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= 2)) ? true : false\\n\\n const surround = getSurroundSpace(x, y)\\n if (isSupport || isAttack) {\\n if (surround > bestRank) {\\n moveOptions.length = 0\\n bestRank = surround\\n moveOptions.push([x, y]);\\n }\\n else if (surround === bestRank) {\\n moveOptions.push([x, y])\\n }\\n }\\n else {\\n moveOptions2.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length);\\n const randomIndex2 = Math.floor(Math.random() * moveOptions2.length);\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Random Safe\\\"\\n } : moveOptions2[randomIndex2] ? {\\n coords: moveOptions2[randomIndex2],\\n msg: \\\"Random Unsafe\\\"\\n } : []\\n }\\n /** @param {NS} ns */\\n function getAggroAttack(libsMin, libsMax, minSurround = 3, minChain = 1, minFreeSpace = 0) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (createsLib(x, y, me)) continue\\n const isAttack = (\\n (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= libsMin && validLibMoves[x - 1][y] <= libsMax) ||\\n (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= libsMin && validLibMoves[x + 1][y] <= libsMax) ||\\n (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= libsMin && validLibMoves[x][y - 1] <= libsMax) ||\\n (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= libsMin && validLibMoves[x][y + 1] <= libsMax)) ? true : false\\n const surround = getSurroundLibs(x, y, me)\\n const freeSpace = getFreeSpace(x, y)\\n if (freeSpace < minFreeSpace) continue\\n if (!isAttack || surround < minSurround) continue\\n const chainAtk = getChainAttack(x, y)\\n if (chainAtk < minChain) continue\\n let lowestLibs = 999\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] < lowestLibs) lowestLibs = validLibMoves[x - 1][y]\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] < lowestLibs) lowestLibs = validLibMoves[x + 1][y]\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] < lowestLibs) lowestLibs = validLibMoves[x][y - 1]\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] < lowestLibs) lowestLibs = validLibMoves[x][y + 1]\\n\\n const enemyLibs = getSurroundLibSpread(x, y, you)\\n const startEyeValue = getEyeValue(x, y, you)\\n const eyeValue = startEyeValue > 1 ? startEyeValue : 1\\n const atk = enemyLibs * chainAtk / eyeValue / lowestLibs\\n if (atk > highestValue) {\\n highestValue = atk\\n moveOptions.length = 0\\n moveOptions.push([x, y]);\\n }\\n else if (atk === highestValue) {\\n highestValue = atk\\n moveOptions.push([x, y]);\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Aggro Attack: \\\" + libsMin + \\\"/\\\" + libsMax + \\\" Surround: \\\" + minSurround\\n } : []\\n }\\n /** @param {NS} ns */\\n function getDefAttack(libsMin, libsMax, minSurround = 3, minChain = 1, minFreeSpace = 0) {\\n const moveOptions = [];\\n const size = board[0].length;\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (createsLib(x, y, me)) continue\\n const isAttack = (\\n (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] >= libsMin && validLibMoves[x - 1][y] <= libsMax) ||\\n (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] >= libsMin && validLibMoves[x + 1][y] <= libsMax) ||\\n (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] >= libsMin && validLibMoves[x][y - 1] <= libsMax) ||\\n (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] >= libsMin && validLibMoves[x][y + 1] <= libsMax)) ? true : false\\n const surround = getSurroundLibs(x, y, me)\\n const freeSpace = getFreeSpace(x, y)\\n if (freeSpace < minFreeSpace) continue\\n if (!isAttack || surround < minSurround) continue\\n const chainAtk = getChainAttack(x, y)\\n if (chainAtk < minChain) continue\\n let lowestLibs = 999\\n if (x > 0 && board[x - 1][y] === you && validLibMoves[x - 1][y] < lowestLibs) lowestLibs = validLibMoves[x - 1][y]\\n if (x < size - 1 && board[x + 1][y] === you && validLibMoves[x + 1][y] < lowestLibs) lowestLibs = validLibMoves[x + 1][y]\\n if (y > 0 && board[x][y - 1] === you && validLibMoves[x][y - 1] < lowestLibs) lowestLibs = validLibMoves[x][y - 1]\\n if (y < size - 1 && board[x][y + 1] === you && validLibMoves[x][y + 1] < lowestLibs) lowestLibs = validLibMoves[x][y + 1]\\n\\n const friendlyLibs = getSurroundLibs(x, y, me)\\n const startEyeValue = getEyeValue(x, y, you)\\n const eyeValue = startEyeValue > 1 ? startEyeValue : 1\\n\\n const atk = friendlyLibs * chainAtk / eyeValue * getHeatMap(x, y, me) / lowestLibs * (getEyeValue(x, y, me) + 1)\\n\\n if (atk > highestValue) {\\n highestValue = atk\\n moveOptions.length = 0\\n moveOptions.push([x, y]);\\n }\\n else if (atk === highestValue) {\\n highestValue = atk\\n moveOptions.push([x, y]);\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Defensive Attack: \\\" + libsMin + \\\"/\\\" + libsMax + \\\" Surround: \\\" + minSurround\\n } : []\\n }\\n /** @param {NS} ns */\\n function attackGrowDragon(requiredEyes, killLib = false) {\\n const moveOptions = [];\\n let highestValue = 0\\n // Look through all the points on the board\\n const moves = getAllValidMoves(true)\\n for (const [x, y] of moves) {\\n if (contested[x][y] !== \\\"?\\\" || createsLib(x, y, me)) continue\\n const surround = getSurroundEnemiesFull(x, y)\\n const myLibs = getSurroundLibs(x, y, me)\\n if (surround < 1 || myLibs < 3) continue\\n const enemyLibs = getSurroundLibs(x, y, you)\\n if (enemyLibs === 1 && !killLib) continue\\n const enemyChains = getChainAttackFull(x, y)\\n const myEyes = getEyeValueFull(x, y, me)\\n if (myEyes < requiredEyes) continue // || count === 3) continue\\n const result = enemyLibs * enemyChains // surround * enemyLibs * myChains * /*freeSpace * */ enemyEyes * enemyChains\\n\\n if (result > highestValue) {\\n highestValue = result\\n moveOptions.length = 0\\n moveOptions.push([x, y])\\n }\\n else if (result === highestValue) {\\n highestValue = result\\n moveOptions.push([x, y])\\n }\\n }\\n // Choose one of the found moves at random\\n const randomIndex = Math.floor(Math.random() * moveOptions.length)\\n return moveOptions[randomIndex] ? {\\n coords: moveOptions[randomIndex],\\n msg: \\\"Attack/Grow Dragon: \\\" + requiredEyes\\n } : []\\n }\\n /** @param {NS} ns */\\n function getDefPattern() {\\n let def = []\\n def.push(...def5)\\n\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n for (const pattern of def)\\n if (isPattern(x, y, pattern)) {\\n const msg = sprintf(\\\"Def Pattern: %s\\\\n%s\\\\n%s\\\", pattern.length, pattern.join(\\\"\\\\n\\\"), \\\"---------------\\\")\\n return {\\n coords: [x, y],\\n msg: msg\\n }\\n }\\n }\\n return []\\n }\\n /** @param {NS} ns */\\n function disruptEyes() {\\n let disrupt = []\\n disrupt.push(...disrupt4)\\n disrupt.push(...disrupt5)\\n\\n const moves = getAllValidMoves()\\n for (const [x, y] of moves) {\\n for (const pattern of disrupt)\\n if (isPattern(x, y, pattern)) {\\n const msg = sprintf(\\\"Eye Disruption: %s\\\\n%s\\\\n%s\\\", pattern.length, pattern.join(\\\"\\\\n\\\"), \\\"---------------\\\")\\n return {\\n coords: [x, y],\\n msg: msg\\n }\\n }\\n }\\n return []\\n }\\n /** @param {NS} ns */\\n async function movePiece(attack) {\\n if (attack?.coords === undefined) return false\\n const [x, y] = attack.coords\\n if (x === undefined) return false\\n let mid = performance.now()\\n ns.printf(\\\"%s\\\", attack.msg)\\n const results = await ns.go.makeMove(x, y, playAsWhite)\\n let END = performance.now()\\n if (LOGTIME) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n else ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n }\\n START = performance.now()\\n return results\\n }\\n /** @param {NS} ns */\\n async function moveWallBreaker(attack) {\\n if (attack?.coords === undefined || !CHEATS) return false\\n const [s1x, s1y] = attack.coords\\n if (s1x === undefined) return false\\n try {\\n const chance = ns.go.cheat.getCheatSuccessChance(undefined, playAsWhite)\\n if (chance < .7) return false\\n let mid = performance.now()\\n const results = await ns.go.cheat.destroyNode(s1x, s1y, playAsWhite)\\n ns.printf(\\\"%s\\\", attack.msg)\\n let END = performance.now()\\n if (LOGTIME) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n else ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n }\\n START = performance.now()\\n return results\\n }\\n catch { return false }\\n }\\n async function moveSnakeEyes(attack) {\\n if (attack?.coords === undefined || !CHEATS) return false\\n const [s1x, s1y, s2x, s2y] = attack.coords\\n if (s1x === undefined) return false\\n try {\\n const chance = ns.go.cheat.getCheatSuccessChance(undefined, playAsWhite)\\n if (chance < .7) return false\\n let mid = performance.now()\\n const results = await ns.go.cheat.playTwoMoves(s1x, s1y, s2x, s2y, playAsWhite)\\n ns.printf(\\\"%s\\\", attack.msg)\\n let END = performance.now()\\n if (LOGTIME) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n else ns.printf(\\\"Time: Me: %s Them: %s\\\", ns.format.time(mid - START, true), ns.format.time(END - mid, true))\\n }\\n START = performance.now()\\n return results\\n }\\n catch { return false }\\n }\\n function getAllValidMoves(notMine = false) {\\n if (currentValidMovesTurn === turn) return notMine ? currentValidContestedMoves : currentValidMoves\\n let moves = []\\n let contestedMoves = []\\n for (let x = 0; x < board[0].length; x++)\\n for (let y = 0; y < board[0].length; y++) {\\n if (validMove[x][y]) {\\n if ([you, \\\"?\\\"].includes(contested[x][y])) contestedMoves.push([x, y])\\n moves.push([x, y])\\n }\\n }\\n\\n //Moves contains a randomized array of x,y\\n moves = moves.sort(() => Math.random() - Math.random())\\n contestedMoves = contestedMoves.sort(() => Math.random() - Math.random())\\n currentValidMoves = moves\\n currentValidContestedMoves = contestedMoves\\n currentValidMovesTurn = turn\\n return notMine ? currentValidContestedMoves : currentValidMoves\\n }\\n function createsLib(x, y, player) {\\n const size = board[0].length\\n\\n if (x > 0 && board[x - 1][y] === player && validLibMoves[x - 1][y] > 2) return false\\n if (x < size - 1 && board[x + 1][y] === player && validLibMoves[x + 1][y] > 2) return false\\n if (y > 0 && board[x][y - 1] === player && validLibMoves[x][y - 1] > 2) return false\\n if (y < size - 1 && board[x][y + 1] === player && validLibMoves[x][y + 1] > 2) return false\\n\\n if (x > 0 && board[x - 1][y] === player && validLibMoves[x - 1][y] === 2 && getSurroundLibs(x - 1, y, player) === 1) return true\\n if (x < size - 1 && board[x + 1][y] === player && validLibMoves[x + 1][y] === 2 && getSurroundLibs(x + 1, y, player) === 1) return true\\n if (y > 0 && board[x][y - 1] === player && validLibMoves[x][y - 1] === 2 && getSurroundLibs(x, y - 1, player) === 1) return true\\n if (y < size - 1 && board[x][y + 1] === player && validLibMoves[x][y + 1] === 2 && getSurroundLibs(x, y + 1, player) === 1) return true\\n\\n return false\\n }\\n function getOpeningMove() {\\n const size = board[0].length\\n switch (size) {\\n case 13:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 10) === 4 && validMove[2][10]) return ({\\n coords: [2, 10],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(10, 10) === 4 && validMove[10][10]) return ({\\n coords: [10, 10],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(10, 2) === 4 && validMove[10][2]) return ({\\n coords: [10, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 9) === 4 && validMove[3][9]) return ({\\n coords: [3, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(9, 9) === 4 && validMove[9][9]) return ({\\n coords: [9, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(9, 3) === 4 && validMove[9][3]) return ({\\n coords: [9, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 8) === 4 && validMove[4][8]) return ({\\n coords: [4, 8],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(8, 8) === 4 && validMove[8][8]) return ({\\n coords: [8, 8],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(8, 4) === 4 && validMove[8][4]) return ({\\n coords: [8, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 9:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 6) === 4 && validMove[2][6]) return ({\\n coords: [2, 6],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(6, 6) === 4 && validMove[6][6]) return ({\\n coords: [6, 6],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(6, 2) === 4 && validMove[6][2]) return ({\\n coords: [6, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 5) === 4 && validMove[3][5]) return ({\\n coords: [3, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 5) === 4 && validMove[5][5]) return ({\\n coords: [5, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 3) === 4 && validMove[5][3]) return ({\\n coords: [5, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 7:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 4) === 4 && validMove[2][4]) return ({\\n coords: [2, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 2) === 4 && validMove[4][2]) return ({\\n coords: [4, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 1) === 4 && validMove[1][1]) return ({\\n coords: [1, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 1) === 4 && validMove[5][1]) return ({\\n coords: [5, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(5, 5) === 4 && validMove[5][5]) return ({\\n coords: [5, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 5) === 4 && validMove[1][5]) return ({\\n coords: [1, 5],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 5:\\n if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 1) === 4 && validMove[3][1]) return ({\\n coords: [3, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 3) === 4 && validMove[1][3]) return ({\\n coords: [1, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(1, 1) === 4 && validMove[1][1]) return ({\\n coords: [1, 1],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n case 19:\\n if (getSurroundSpace(9, 9) === 4 && validMove[9][9]) return ({\\n coords: [9, 9],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 2) === 4 && validMove[2][2]) return ({\\n coords: [2, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(16, 2) === 4 && validMove[16][2]) return ({\\n coords: [16, 2],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(2, 16) === 4 && validMove[2][16]) return ({\\n coords: [2, 16],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(16, 16) === 4 && validMove[16][16]) return ({\\n coords: [16, 16],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 3) === 4 && validMove[3][3]) return ({\\n coords: [3, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(3, 15) === 4 && validMove[3][15]) return ({\\n coords: [3, 15],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(15, 15) === 4 && validMove[15][15]) return ({\\n coords: [15, 15],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(15, 3) === 4 && validMove[15][3]) return ({\\n coords: [15, 3],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 4) === 4 && validMove[4][4]) return ({\\n coords: [4, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(4, 14) === 4 && validMove[4][14]) return ({\\n coords: [4, 14],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(14, 14) === 4 && validMove[14][14]) return ({\\n coords: [14, 14],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else if (getSurroundSpace(14, 4) === 4 && validMove[14][4]) return ({\\n coords: [14, 4],\\n msg: \\\"Opening Move: \\\" + turn\\n })\\n else return getRandomStrat()\\n }\\n }\\n async function proxy(func, ...argmnts) { return await runIt(\\\"SphyxOS/extras/nsProxy.js\\\", ns.getFunctionRamCost(func) + 1.6, [func, ...argmnts]) }\\n async function proxyTry(func, ...argmnts) { return await runIt(\\\"SphyxOS/extras/nsProxyTry.js\\\", ns.getFunctionRamCost(func) + 1.6, [func, ...argmnts]) }\\n async function getMoves(playAsWhite) { return await runIt(\\\"SphyxOS/ipvgo/getvalidmoves.js\\\", false, [playAsWhite]) }\\n/** @param {NS} ns */\\n async function runIt(script, scriptOverride, argmnts) {\\n let thispid = 0\\n let threads = 1\\n const scriptRam = scriptOverride === 0 ? ns.getScriptRam(script) : scriptOverride\\n\\n const threadsOnHome = Math.floor((ns.getServerMaxRam(\\\"home\\\") - ns.getServerUsedRam(\\\"home\\\")) / scriptRam)\\n if (threadsOnHome >= 1) {\\n thispid = ns.exec(script, \\\"home\\\", { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmnts)\\n if (thispid > 0)\\n threads--\\n }\\n if (threads >= 1) {\\n const servers = getServersLight()\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n const tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n const threadsonserver = Math.floor(tmpramavailable / scriptRam)\\n // How many threads can we run? If we can run something, do it\\n if (threadsonserver <= 0) continue\\n ns.scp([script], server, \\\"home\\\")\\n thispid = ns.exec(script, server, { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmnts)\\n if (thispid === 0) continue\\n threads--\\n break\\n }// All servers\\n }\\n if (threads >= 1) ns.tprintf(\\\"Failed to allocate all threads for script: %s\\\", script)\\n await ns.nextPortWrite(thispid)\\n const result = ns.readPort(thispid)\\n return result\\n }\\n\\n /** @param {NS} ns */\\n function getServersLight() {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n }\\n function writeGetMoves() {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.analysis.getValidMoves(undefined, undefined, ns.args[0])\\n ns.atExit(() => port.write(result))\\n}`\\n ns.write(\\\"SphyxOS/ipvgo/getvalidmoves.js\\\", data, \\\"w\\\")\\n }\\n /** @param {NS} ns */\\n function writeProxy() {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let finalResult\\n try {\\n const result = nsFunction(...argmnts)\\n if (result instanceof Promise) finalResult = await result\\n else if (result instanceof Object) {\\n promiseRemoval(result)\\n finalResult = result\\n }\\n else finalResult = result\\n } catch { } //finalResult is undefined if it failed to run.\\n ns.atExit(() => ns.writePort(ns.pid, finalResult))\\n}\\nfunction promiseRemoval(object) {\\n for (const key in object)\\n if (object[key] instanceof Promise) delete object[key]\\n else if (object[key] instanceof Object) promiseRemoval(object[key])\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxy.js\\\", data, \\\"w\\\")\\n }\\n\\n function writeProxyTry() {\\n const data = `/** @param {NS} ns */\\nexport async function main(ns) {\\n let [func, ...argmnts] = ns.args\\n let nsFunction = ns\\n for (let prop of func.split(\\\".\\\")) nsFunction = nsFunction[prop]\\n let result = false\\n try {\\n const res = nsFunction(...argmnts)\\n if (res) result = res\\n else result = true\\n }\\n catch { }\\n ns.atExit(() => ns.writePort(ns.pid, result))\\n}`\\n ns.write(\\\"SphyxOS/extras/nsProxyTry.js\\\", data, \\\"w\\\")\\n }\\n}\\n\\n//X,O = Me, You x, o = Anything but the other person or a blocking, \\\"W\\\" space is off the board, ? is anything goes\\n//B is blocking(Wall or you, not empty or enemy), b is blocking but could be enemy, A is All but . (Wall, Me, You, Blank)\\n//* is move here next if you can - no safeties\\n\\nconst disrupt4 = [\\n [\\\"??b?\\\", \\\"?b.b\\\", \\\"b.*b\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"?bb?\\\", \\\"b..b\\\", \\\"b*Xb\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"?bb?\\\", \\\"b..b\\\", \\\"b.*b\\\", \\\"?bb?\\\"], //Pattern# Sphyxis - buy a turn #GREAT\\n [\\\"??b?\\\", \\\"?b.b\\\", \\\"?b*b\\\", \\\"??O?\\\"], //Pattern# Sphyxis - Sacrifice to kill an eye\\n [\\\"?bbb\\\", \\\"bb.b\\\", \\\"W.*b\\\", \\\"?oO?\\\"], //Pattern# Sphyxis - 2x2 nook breatk\\n [\\\"?bbb\\\", \\\"bb.b\\\", \\\"W.*b\\\", \\\"?Oo?\\\"], //Pattern# Sphyxis - 2x2 nook break\\n [\\\".bbb\\\", \\\"o*.b\\\", \\\".bbb\\\", \\\"????\\\"], //Pattern# Sphyxis - Dangling 2 break\\n]\\nconst disrupt5 = [\\n [\\\"?bbb?\\\", \\\"b.*.b\\\", \\\"?bbb?\\\", \\\"?????\\\", \\\"?????\\\"], //Pattern# Sphyxis - Convert to 1 eye\\n [\\\"??OO?\\\", \\\"?b*.b\\\", \\\"?b..b\\\", \\\"??bb?\\\", \\\"?????\\\"], //Pattern# Sphyxis - Buy time\\n [\\\"?????\\\", \\\"??bb?\\\", \\\"?b*Xb\\\", \\\"?boob\\\", \\\"??bb?\\\"], //Pattern# Sphyxis - Buy time\\n [\\\"WWW??\\\", \\\"WWob?\\\", \\\"Wo*b?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 attack corner if possible\\n [\\\"??b??\\\", \\\"?b.b?\\\", \\\"?b*b?\\\", \\\"?b.A?\\\", \\\"??b??\\\"], //Pattern# Sphyxis - Break two eyes into 1, buy a turn\\n [\\\"??b??\\\", \\\"?b.b?\\\", \\\"??*.b\\\", \\\"?b?b?\\\", \\\"?????\\\"], //Pattern# Sphyxis - Break eyes, buy time\\n [\\\"?WWW?\\\", \\\"WoOoW\\\", \\\"WOO*W\\\", \\\"W???W\\\", \\\"?????\\\"], //Block 3x3 corner\\n [\\\"?WWW?\\\", \\\"Wo*oW\\\", \\\"WOOOW\\\", \\\"W???W\\\", \\\"?????\\\"], //Block 3x3 corner\\n]\\n\\nconst def5 = [\\n [\\\"?WW??\\\", \\\"WW.X?\\\", \\\"W.XX?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - Eyes in a nook\\n [\\\"WWW??\\\", \\\"WW.X?\\\", \\\"W.*X?\\\", \\\"WWW??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 corner contain #GREAT\\n [\\\"BBB??\\\", \\\"BB.X?\\\", \\\"B..X?\\\", \\\"BBB??\\\", \\\"?????\\\"], //Pattern# Sphyxis - 2x2 corner contain #GREAT\\n [\\\"?WWW?\\\", \\\"W.*.W\\\", \\\"WXXXW\\\", \\\"?????\\\", \\\"?????\\\"], //Take the 3x3 back corner\\n]\""},{"filename":"SphyxOS/full/bb-noSingularity.js","file":"\"let INTMODE = true\\nlet LVLUP = 1\\nlet SLEEVEINFILSTATUS = false\\nlet SLEEVES_ENABLED = false\\nconst HEIGHT = 710\\nconst WIDTH = 760\\nconst CSTATS = 100\\nconst TRAIN_STATS = 110\\nconst SLEEVE_STATS = 5\\nconst TRAIN_STAMINA = 50\\nconst CHAOS_TOP = 60\\nconst CHAOS_FLOOR = 55\\nconst BOPS_SUCCESS_TRY = .8\\nconst MIN_CHANCE_SUCCESS = .85\\nconst SLEEVE_SHOCK = 98\\nconst SLEEVE_CHANCE = .9\\nlet PRIORITY_CITY = false\\nlet sleeve_infil = false\\nlet sleeve_analyze = false\\nlet sleeve_bounty = false\\nlet sleeve_retire = false\\nlet sleeve_tracking = false\\nlet sleeve_diplomacy = false\\nconst queues = []\\nlet queuestask = [null, null, null, null]\\nlet queueswait = 0\\n\\nconst argsSchema = [\\n [\\\"intmode\\\", false],\\n [\\\"lvlup\\\", 1],\\n [\\\"sleeveinfilonly\\\", false]\\n]\\n\\nexport function autocomplete(data, args) {\\n data.flags(argsSchema)\\n return []\\n}\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n const b = ns.bladeburner\\n init(ns)\\n //Are we already in or do we have the stats for it?\\n while (!b.joinBladeburnerDivision()) {\\n trainUp(ns)\\n await ns.sleep(1000)\\n }\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n for (const contract of ns.bladeburner.getContractNames())\\n ns.bladeburner.setActionAutolevel(\\\"Contracts\\\", contract, false)\\n for (const op of ns.bladeburner.getOperationNames())\\n ns.bladeburner.setActionAutolevel(\\\"Operations\\\", op, false)\\n while (true) { //Main loop\\n updatedisplay(ns)\\n await b.nextUpdate()\\n b.joinBladeburnerFaction()\\n await updateskills(ns)\\n if (SLEEVES_ENABLED) updatesleeves(ns)\\n if (queueswait > performance.now()) continue //Trap inside the start of the loop until our job is done\\n if (queues.length > 0) { //We have a queued command\\n runmission(ns, queues.shift())\\n continue\\n }\\n if (checkChaos(ns)) {\\n queue(\\\"General\\\", \\\"Diplomacy\\\", checkChaos(ns), 1)\\n continue\\n }\\n if (gettrainstats(ns) < TRAIN_STATS || b.getStamina()[1] < TRAIN_STAMINA) {\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n if (b.getStamina()[0] / b.getStamina()[1] < .5) {\\n queue(\\\"General\\\", \\\"Hyperbolic Regeneration Chamber\\\", b.getCity(), 1)\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n if (checkTracking(ns)) {\\n queue(\\\"General\\\", \\\"Field Analysis\\\", checkTracking(ns), 1)\\n continue\\n }\\n const best = getBestMission(ns) // Get the best mission. null means there are none\\n if (best === null) {\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n else {\\n queue(best[0], best[1], best[2], best[3])\\n continue\\n }\\n }\\n} //End of main\\n/** @param {NS} ns */\\nfunction updatesleeves(ns) {\\n let s = ns.sleeve\\n let b = ns.bladeburner\\n\\n // get our sleeve ratings\\n const isleeves = []\\n for (let islv = 0; islv < s.getNumSleeves(); islv++) {\\n let record = {\\n \\\"Sleeve\\\": islv,\\n \\\"Power\\\": getslvpower(ns, islv)\\n }\\n isleeves.push(record)\\n if (s.getSleeve(islv).shock > SLEEVE_SHOCK) {\\n s.setToShockRecovery(islv)\\n }\\n else if (s.getTask(islv)?.type === \\\"RECOVERY\\\") {\\n s.setToIdle(islv)\\n }\\n }\\n isleeves.sort((a, b) => { return s.getSleeve(b.Sleeve).storedCycles - s.getSleeve(a.Sleeve).storedCycles }) //Lowest first so we cycle\\n\\n if (SLEEVEINFILSTATUS) {\\n const bestslv = isleeves.shift()\\n if (!sleeve_infil && s.getTask(bestslv.Sleeve) === null) {\\n s.setToBladeburnerAction(bestslv.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (s.getSleeve(bestslv.Sleeve).storedCycles > s.getTask(bestslv.Sleeve).cyclesNeeded) {\\n sleeve_infil = true\\n s.getTask(bestslv.Sleeve).nextCompletion.then(() => {\\n sleeve_infil = false\\n s.setToIdle(bestslv.Sleeve)\\n })\\n }\\n else s.setToIdle(bestslv.Sleeve)\\n }\\n }\\n else { //We are assigning all sleeves to their respective tasks\\n const cityChaos = b.getCityChaos(b.getCity())\\n const analyze = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\")[0] !== b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\")[1]\\n const stamina = b.getStamina()\\n const stamPerc = stamina[0] / stamina[1]\\n for (const me of isleeves) {\\n let trainSlv = false\\n if (s.getTask(me.Sleeve) !== null) {\\n continue //Our sleeve is working...\\n }\\n if (getsleevestats(ns, me.Sleeve) < SLEEVE_STATS && stamPerc > .55) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Training\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue // Save up for training. Move on to the next\\n }\\n }\\n if (s.getSleeve(me.Sleeve).hp.current + 2 <= s.getSleeve(me.Sleeve).hp.max) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Hyperbolic Regeneration Chamber\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue\\n }\\n if (!sleeve_analyze && analyze) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Field Analysis\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_analyze = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_analyze = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && !sleeve_tracking && b.getCurrentAction()?.name !== \\\"Tracking\\\" && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Tracking\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Tracking\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Tracking\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Tracking\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_tracking = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_tracking = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && b.getCurrentAction()?.name !== \\\"Bounty Hunter\\\" && !sleeve_bounty && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Bounty Hunter\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Bounty Hunter\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Bounty Hunter\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Bounty Hunter\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_bounty = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_bounty = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && b.getCurrentAction()?.name !== \\\"Retirement\\\" && !sleeve_retire && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Retirement\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Retirement\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Retirement\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Retirement\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_retire = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_retire = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (cityChaos > CHAOS_FLOOR && !sleeve_diplomacy) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Diplomacy\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_diplomacy = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_diplomacy = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n if (!sleeve_infil) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_infil = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_infil = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n if (trainSlv && stamPerc > .55) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Training\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue // Save up for training. Move on to the next\\n }\\n }\\n\\n }\\n }\\n} // Updatesleeves function\\n/** @param {NS} ns */\\nasync function updateskills(ns) {\\n let b = ns.bladeburner\\n let count = 0\\n while (true) {\\n count++\\n if (count > 2000) {\\n await ns.asleep(4)\\n count = 0\\n }\\n if (INTMODE) {\\n const maxUpgrade = calcMaxUpgradeCount(ns, \\\"Hyperdrive\\\", b.getSkillPoints())\\n if (!maxUpgrade) break\\n if (b.getSkillLevel(\\\"Hyperdrive\\\") <= Number.MAX_SAFE_INTEGER - 1) {\\n b.upgradeSkill(\\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else if (maxUpgrade >= b.getSkillLevel(\\\"Hyperdrive\\\") / 1e8) {\\n b.upgradeSkill(\\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else break\\n }\\n else {\\n let bestcost = Number.POSITIVE_INFINITY\\n let bestskill = \\\"Hyperdrive\\\"\\n for (const skl of b.getSkillNames()) {\\n if (skillrating(ns, skl) < bestcost) {\\n bestcost = skillrating(ns, skl)\\n bestskill = skl\\n }\\n }\\n if (LVLUP > 0 && !b.upgradeSkill(bestskill, LVLUP)) break\\n if (LVLUP <= 0 && !b.upgradeSkill(bestskill, calcMaxUpgradeCount(ns, bestskill, b.getSkillPoints()))) break\\n }\\n }\\n}\\nfunction skillrating(ns, skill) {\\n let b = ns.bladeburner\\n let mod = 0\\n skillmods.map(x => { x[0] === skill ? mod = x[1] : null })// ((x => { \\n //let cost = calculateCost(ns, skill)\\n let cost = b.getSkillUpgradeCost(skill)\\n return cost / mod === 0 ? Number.POSITIVE_INFINITY : cost / mod\\n}\\nfunction cityneedsanalysis(ns, city) {\\n const b = ns.bladeburner\\n const startcity = b.getCity()\\n b.switchCity(city)\\n for (const bop of b.getBlackOpNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Black Ops\\\", bop)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n for (const contract of b.getContractNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n for (const op of b.getOperationNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Operations\\\", op)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n b.switchCity(startcity)\\n return false\\n}\\nfunction checkTracking(ns) {\\n for (const city of cities) {\\n if (cityneedsanalysis(ns, city))\\n return city\\n }\\n return false\\n}\\n//Returns an array. [0] is missions name, [1] is missions type, [2] is the city\\n/** @param {NS} ns */\\nfunction getBestMission(ns) {\\n let b = ns.bladeburner\\n\\n const startcity = b.getCity()\\n let bestresult = 0\\n let bestoperation = null\\n let bestoperationtype = null\\n let bestoperationcity = null\\n let bestoperationlevel = 1\\n\\n let blackops = b.getBlackOpNames().filter(x => b.getActionCountRemaining(\\\"Black Ops\\\", x) > 0)\\n blackops = blackops.sort((x, y) => { return b.getBlackOpRank(y) - b.getBlackOpRank(x) })\\n let next = blackops.pop()\\n if (next !== undefined && b.getActionEstimatedSuccessChance(\\\"Black Ops\\\", next)[1] >= BOPS_SUCCESS_TRY && b.getBlackOpRank(next) <= b.getRank()) return [\\\"BlackOp\\\", next, b.getCity(), 1]\\n\\n for (const city of cities) {\\n b.switchCity(city)\\n for (const contract of b.getContractNames()) {\\n if (contract === \\\"Tracking\\\" && sleeve_tracking) continue // If a sleeve is doing something, move on.\\n if (contract === \\\"Bounty Hunter\\\" && sleeve_bounty) continue // Not because it causes a conflict\\n if (contract === \\\"Retirement\\\" && sleeve_retire) continue // But so we can focus on getting to Operations\\n if (b.getActionCountRemaining(\\\"Contracts\\\", contract) < 1) continue\\n for (let level = b.getActionMaxLevel(\\\"Contracts\\\", contract); level > 0; level--) {\\n b.setActionLevel(\\\"Contracts\\\", contract, level)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)[1] >= MIN_CHANCE_SUCCESS) {\\n const result = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)[1] * b.getActionRepGain(\\\"Contracts\\\", contract) / b.getActionTime(\\\"Contracts\\\", contract)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = contract\\n bestoperationtype = \\\"Contracts\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n const ops = [\\\"Undercover Operation\\\", \\\"Sting Operation\\\", \\\"Assassination\\\"]\\n for (const o of ops) {\\n if (b.getActionCountRemaining(\\\"Operations\\\", o) < 1) continue\\n for (let level = b.getActionMaxLevel(\\\"Operations\\\", o); level > 0; level--) {\\n b.setActionLevel(\\\"Operations\\\", o, level)\\n if (b.getActionEstimatedSuccessChance(\\\"Operations\\\", o)[1] >= MIN_CHANCE_SUCCESS) {\\n let result = b.getActionEstimatedSuccessChance(\\\"Operations\\\", o)[1] * b.getActionRepGain(\\\"Operations\\\", o) / b.getActionTime(\\\"Operations\\\", o)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = o\\n bestoperationtype = \\\"Operations\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n }\\n b.switchCity(startcity)\\n return bestoperation !== null ? [bestoperationtype, bestoperation, bestoperationcity, bestoperationlevel] : null\\n}\\n/** @param {NS} ns */\\nfunction checkChaos(ns) {\\n let b = ns.bladeburner\\n\\n if (PRIORITY_CITY && b.getCityChaos(PRIORITY_CITY) <= CHAOS_FLOOR) PRIORITY_CITY = false\\n if (!PRIORITY_CITY) {\\n for (const city of cities) { //New emergency?\\n if (b.getCityChaos(city) >= CHAOS_TOP) {\\n PRIORITY_CITY = city\\n return PRIORITY_CITY\\n }\\n }\\n }\\n return PRIORITY_CITY\\n}\\n/** @param {NS} ns */\\nfunction updatedisplay(ns) {\\n ns.clearLog()\\n const b = ns.bladeburner\\n const s = ns.sleeve\\n ns.printf(\\\"Rank: %s Operations Queued: %s\\\", ns.format.number(b.getRank()), queues.length)\\n ns.printf(\\\"Stamina: %s/%s(%s%s)\\\", ns.format.number(b.getStamina()[0]), ns.format.number(b.getStamina()[1]), ns.format.number(b.getStamina()[0] / b.getStamina()[1] * 100, 2), \\\"%\\\")\\n ns.printf(\\\"Current City: %s\\\", b.getCity())\\n ns.printf(\\\"Est. Population: %s\\\", ns.format.number(b.getCityEstimatedPopulation(b.getCity())))\\n ns.printf(\\\"Synth Comms: %s\\\", ns.format.number(b.getCityCommunities(b.getCity()), 0))\\n ns.printf(\\\"Chaos: %s\\\", ns.format.number(b.getCityChaos(b.getCity())))\\n ns.printf(\\\"Skill Points: %s\\\", b.getSkillPoints() > 1000 ? ns.format.number(b.getSkillPoints()) : b.getSkillPoints())\\n ns.printf(\\\"Bonus Time: %s\\\", b.getBonusTime() / 1000 >= 1000 ? ns.format.number(b.getBonusTime() / 1000) : b.getBonusTime() / 1000)\\n updatemissions(ns)\\n if (queuestask.Type === undefined) ns.printf(\\\"Current Task: None(0/0)\\\")\\n else ns.printf(\\\"Current Task: %s(%s/%s) %s\\\", queuestask.Type, queuestask.Level, queuestask.Type === \\\"BlackOp\\\" || queuestask.Type === \\\"General\\\" ? 1 : b.getActionMaxLevel(queuestask.Type, queuestask.Name), queuestask.Name)\\n queuestask.Type !== undefined ? ns.printf(\\\"Progress: %s Time: %s\\\", updateprogress(b.getActionTime(queuestask.Type, queuestask.Name), b.getActionCurrentTime()), ns.format.time(b.getActionTime(queuestask.Type, queuestask.Name) - b.getActionCurrentTime())) : ns.printf(\\\"Progress: %s Time: n/a\\\", updateprogress(10, 0))\\n ns.printf(\\\"------------------------------------------------------------------------------\\\")\\n if (!SLEEVES_ENABLED) ns.printf(\\\"SLEEVE SUPPORT DISABLED\\\")\\n else {\\n for (let slv = 0; slv < s.getNumSleeves(); slv++) {\\n let task = s.getTask(slv)\\n let cycles = s.getSleeve(slv).storedCycles > 1000 ? ns.format.number(s.getSleeve(slv).storedCycles, 2) : s.getSleeve(slv).storedCycles\\n let buf = ns.sprintf(\\\"Sleeve: %s Cycles: %-7s \\\", slv, cycles)\\n if (task !== null) {\\n if (task.type === \\\"INFILTRATE\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: Infiltration\\\")\\n else if (task.type === \\\"CRIME\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Crime: \\\" + task.crimeType)\\n else if (task.type === \\\"BLADEBURNER\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: \\\" + task.actionName.substring(0, 14))\\n else if (task.type === \\\"RECOVERY\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Shock Recovery\\\")\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"?\\\" + task.type)\\n }\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"Idle: ------------\\\")\\n if (task !== null) buf += ns.sprintf(updateprogress(task.cyclesNeeded, task.cyclesWorked))\\n else buf += ns.sprintf(updateprogress(10, 0))\\n buf += ns.sprintf(\\\" Augs: %2s%s\\\", s.getSleeveAugmentations(slv).length, \\\"\\\\n\\\")\\n ns.printf(\\\"%s\\\", buf)\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction updatemissions(ns) {\\n //Cycle through all the mission types and show how many we currently have in our city and how many we have overall\\n let b = ns.bladeburner\\n\\n for (const contract of b.getContractNames()) {\\n b.getActionCountRemaining(\\\"Contract\\\", contract) >= 1000 ? ns.printf(\\\"Contracts: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Contract\\\", contract)) + \\\" \\\" + contract) : ns.printf(\\\"Contracts: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Contract\\\", contract), 2) + \\\" \\\" + contract)\\n }\\n for (const operation of b.getOperationNames()) {\\n b.getActionCountRemaining(\\\"Operation\\\", operation) >= 1000 ? ns.printf(\\\"Operation: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Operation\\\", operation)) + \\\" \\\" + operation) : ns.printf(\\\"Operation: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Operation\\\", operation), 2) + \\\" \\\" + operation)\\n }\\n}\\n/** @param {NS} ns */\\nfunction updateprogress(max_time, run_time) {\\n let done = run_time > 0 ? Math.max(max_time / run_time, 1) : 0\\n let buffer = \\\"[\\\"\\n if (done > 0) buffer = buffer.padEnd(Math.round(20 / done), \\\"|\\\")\\n if (done > 0) buffer += \\\"*\\\"\\n buffer = buffer.padEnd(21, \\\"-\\\")\\n buffer += \\\"]\\\"\\n\\n return buffer\\n}\\n/** @param {NS} ns */\\nfunction runmission(ns, best) {\\n //best.Type, best.Name, best.City, best.Level\\n let b = ns.bladeburner\\n queuestask = best\\n const action = b.getCurrentAction()\\n //Resuming?\\n if (action !== null && best.City === b.getCity() && best.Type === action.type && best.Name === action.name && (best.Type === \\\"General\\\" || best.Type === \\\"BlackOp\\\" || best.Level === b.getActionCurrentLevel(best.Type, best.Name))) {\\n if ((b.getBonusTime() - 1000) > b.getActionTime(best.Type, best.Name)) { //All under bonus time\\n queueswait = performance.now() + Math.max((b.getActionTime(best.Type, best.Name) / 5) - b.getActionCurrentTime(), 500)\\n }\\n else queueswait = performance.now() + Math.max(b.getActionTime(best.Type, best.Name) - b.getBonusTime() - b.getActionCurrentTime(), 500)\\n }\\n else {\\n //New action\\n if (b.getCity() !== best.City) b.switchCity(best.City)\\n try { b.setActionLevel(best.Type, best.Name, best.Level) } catch { /*Catch the unlevelable actions*/ }\\n b.startAction(best.Type, best.Name)\\n if (b.getBonusTime() - 1000 > b.getActionTime(best.Type, best.Name)) { //All under bonus time\\n queueswait = performance.now() + Math.max((b.getActionTime(best.Type, best.Name) / 5), 500)\\n }\\n else queueswait = performance.now() + Math.max(b.getActionTime(best.Type, best.Name) - b.getBonusTime(), 500)\\n }\\n}\\nfunction gettrainstats(ns) {\\n const me = ns.getPlayer()\\n return (me.skills.agility + me.skills.defense + me.skills.dexterity + me.skills.strength) / 4\\n}\\n/** @param {NS} ns */\\nfunction getsleevestats(ns, slv) {\\n const s = ns.sleeve.getSleeve(slv)\\n return (s.skills.agility + s.skills.defense + s.skills.dexterity + s.skills.strength) / 4\\n}\\nfunction queue(type, name, city, level) {\\n let mission = {\\n \\\"Type\\\": type,\\n \\\"Name\\\": name,\\n \\\"City\\\": city,\\n \\\"Level\\\": level\\n }\\n queues.push(mission)\\n}\\n/** @param {NS} ns */\\nfunction init(ns) {\\n try { // Enable Sleeves\\n ns.sleeve.getNumSleeves()\\n SLEEVES_ENABLED = true\\n }\\n catch { SLEEVES_ENABLED = false }\\n sleeve_infil = false\\n sleeve_analyze = false\\n sleeve_tracking = false\\n sleeve_bounty = false\\n sleeve_retire = false\\n sleeve_diplomacy = false\\n queues.length = 0\\n if (SLEEVES_ENABLED)\\n for (let slv = 0; slv < ns.sleeve.getNumSleeves(); slv++)\\n ns.sleeve.setToIdle(slv)\\n queuestask = [null, null, null, null]\\n queueswait = 0\\n PRIORITY_CITY = false\\n const data = ns.flags(argsSchema)\\n LVLUP = data.lvlup\\n INTMODE = data.intmode\\n SLEEVEINFILSTATUS = data.sleeveinfilonly\\n}\\n/** @param {NS} ns */\\nfunction trainUp(ns) {\\n const me = ns.getPlayer()\\n const skls = me.skills\\n if (me.city !== \\\"Sector-12\\\") {\\n ns.clearLog()\\n //Travel to our Gym\\n ns.print(\\\"Please go to Sector-12\\\")\\n }\\n else if (skls.strength < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Str to 100\\\")\\n }\\n else if (skls.defense < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Def to 100\\\")\\n }\\n else if (skls.dexterity < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Dex to 100\\\")\\n }\\n else if (skls.agility < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Agi to 100\\\")\\n }\\n}\\n/** @param {NS} ns */\\nfunction getslvpower(ns, slv) {\\n let s = ns.sleeve\\n let skill = s.getSleeve(slv).skills\\n return ((skill.agility + skill.defense + skill.dexterity + skill.strength + skill.charisma + skill.hacking) / 6)\\n}\\n/** @param {NS} ns */\\nfunction calcMaxUpgradeCount(ns, skill, cost) {\\n const b = ns.bladeburner\\n let baseCost;\\n let costInc;\\n const currentLevel = b.getSkillLevel(skill)\\n const currentNodeMults = getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n const m = -baseCost - costInc * currentLevel + costInc / 2\\n const delta = Math.sqrt(m * m + (2 * costInc * cost) / currentNodeMults.BladeburnerSkillCost)\\n const result = Math.round((m + delta) / costInc)\\n const costOfResultPlus1 = calculateCost(ns, skill, result + 1)\\n if (costOfResultPlus1 <= cost) {\\n return result + 1\\n }\\n const costOfResult = calculateCost(ns, skill, result)\\n if (costOfResult <= cost) {\\n return result\\n }\\n return result - 1\\n}\\nfunction calculateCost(ns, skill, count = 1) {\\n const currentLevel = ns.bladeburner.getSkillLevel(skill)\\n const actualCount = currentLevel + count - currentLevel\\n let baseCost;\\n let costInc;\\n const currentNodeMults = getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n return Math.round(\\n actualCount *\\n currentNodeMults.BladeburnerSkillCost *\\n (baseCost + costInc * (currentLevel + (actualCount - 1) / 2)))\\n}\\n/** @param {NS} ns */\\nfunction getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,\\n \\\"CloudServerSoftcap\\\": 1,\\n \\\"CloudServerLimit\\\": 1,\\n \\\"CloudServerMaxRam\\\": 1,\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\\nconst cities = [\\\"Sector-12\\\", \\\"Aevum\\\", \\\"Volhaven\\\", \\\"Chongqing\\\", \\\"New Tokyo\\\", \\\"Ishima\\\"]\\n//skillmods [0] name, [1] My rating, [2] baseCost, [3] costInc\\nconst skillmods = [\\n [\\\"Blade\\\\'s Intuition\\\", 2.0, 3, 2.1],\\n [\\\"Cloak\\\", 0.8, 1, 1.1],\\n [\\\"Short-Circuit\\\", 1.0, 2, 2.1],\\n [\\\"Digital Observer\\\", 1.6, 2, 2.1],\\n [\\\"Tracer\\\", 1.0, 2, 2.1],\\n [\\\"Overclock\\\", 2.2, 3, 1.4],\\n [\\\"Reaper\\\", 1.0, 2, 2.1],\\n [\\\"Evasive System\\\", 2.0, 2, 2.1],\\n [\\\"Datamancer\\\", 1.0, 3, 1],\\n [\\\"Cyber\\\\'s Edge\\\", 1.0, 1, 3],\\n [\\\"Hands of Midas\\\", 0.1, 2, 2.5],\\n [\\\"Hyperdrive\\\", 2.5, 1, 2.5],\\n]\""},{"filename":"SphyxOS/full/bb-singularitySupport.js","file":"\"const STARTUP_SCRIPT = \\\"Loader.js\\\"\\nlet FINISHER = false\\nlet INTMODE = true\\nlet LVLUP = 1\\nlet SLEEVEINFILSTATUS = false\\nlet SLEEVES_ENABLED = false\\nlet HASBN4 = false\\nconst HEIGHT = 710\\nconst WIDTH = 760\\nconst CSTATS = 100\\nconst TRAIN_STATS = 110\\nconst SLEEVE_STATS = 5\\nconst TRAIN_STAMINA = 50\\nconst CHAOS_TOP = 60\\nconst CHAOS_FLOOR = 55\\nconst BOPS_SUCCESS_TRY = .8\\nconst MIN_CHANCE_SUCCESS = .85\\nconst SLEEVE_SHOCK = 98\\nconst SLEEVE_CHANCE = .9\\nlet PRIORITY_CITY = false\\nlet sleeve_infil = false\\nlet sleeve_analyze = false\\nlet sleeve_bounty = false\\nlet sleeve_retire = false\\nlet sleeve_tracking = false\\nlet sleeve_diplomacy = false\\nconst queues = []\\nlet queuestask = [null, null, null, null]\\nlet queueswait = 0\\n\\nconst argsSchema = [\\n [\\\"intmode\\\", false],\\n [\\\"finisher\\\", false],\\n [\\\"lvlup\\\", 1],\\n [\\\"sleeveinfilonly\\\", false]\\n]\\n\\nexport function autocomplete(data, args) {\\n data.flags(argsSchema)\\n return []\\n}\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n const b = ns.bladeburner\\n init(ns)\\n //Are we already in or do we have the stats for it?\\n while (!b.joinBladeburnerDivision()) {\\n trainUp(ns)\\n await ns.sleep(1000)\\n }\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n for (const contract of ns.bladeburner.getContractNames())\\n ns.bladeburner.setActionAutolevel(\\\"Contracts\\\", contract, false)\\n for (const op of ns.bladeburner.getOperationNames())\\n ns.bladeburner.setActionAutolevel(\\\"Operations\\\", op, false)\\n while (true) { //Main loop\\n if (HASBN4 && FINISHER) endIt(ns)\\n updatedisplay(ns)\\n await b.nextUpdate()\\n b.joinBladeburnerFaction()\\n await updateskills(ns)\\n if (SLEEVES_ENABLED) updatesleeves(ns)\\n if (queueswait > performance.now()) continue //Trap inside the start of the loop until our job is done\\n if (queues.length > 0) { //We have a queued command\\n runmission(ns, queues.shift())\\n continue\\n }\\n if (checkChaos(ns)) {\\n queue(\\\"General\\\", \\\"Diplomacy\\\", checkChaos(ns), 1)\\n continue\\n }\\n if (gettrainstats(ns) < TRAIN_STATS || b.getStamina()[1] < TRAIN_STAMINA) {\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n if (b.getStamina()[0] / b.getStamina()[1] < .5) {\\n queue(\\\"General\\\", \\\"Hyperbolic Regeneration Chamber\\\", b.getCity(), 1)\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n if (checkTracking(ns)) {\\n queue(\\\"General\\\", \\\"Field Analysis\\\", checkTracking(ns), 1)\\n continue\\n }\\n const best = getBestMission(ns) // Get the best mission. null means there are none\\n if (best === null) {\\n queue(\\\"General\\\", \\\"Training\\\", b.getCity(), 1)\\n continue\\n }\\n else {\\n queue(best[0], best[1], best[2], best[3])\\n continue\\n }\\n }\\n} //End of main\\n/** @param {NS} ns */\\nfunction updatesleeves(ns) {\\n let s = ns.sleeve\\n let b = ns.bladeburner\\n\\n // get our sleeve ratings\\n const isleeves = []\\n for (let islv = 0; islv < s.getNumSleeves(); islv++) {\\n let record = {\\n \\\"Sleeve\\\": islv,\\n \\\"Power\\\": getslvpower(ns, islv)\\n }\\n isleeves.push(record)\\n if (s.getSleeve(islv).shock > SLEEVE_SHOCK) {\\n s.setToShockRecovery(islv)\\n }\\n else if (s.getTask(islv)?.type === \\\"RECOVERY\\\") {\\n s.setToIdle(islv)\\n }\\n }\\n isleeves.sort((a, b) => { return s.getSleeve(b.Sleeve).storedCycles - s.getSleeve(a.Sleeve).storedCycles }) //Lowest first so we cycle\\n\\n if (SLEEVEINFILSTATUS) {\\n const bestslv = isleeves.shift()\\n if (!sleeve_infil && s.getTask(bestslv.Sleeve) === null) {\\n s.setToBladeburnerAction(bestslv.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (s.getSleeve(bestslv.Sleeve).storedCycles > s.getTask(bestslv.Sleeve).cyclesNeeded) {\\n sleeve_infil = true\\n s.getTask(bestslv.Sleeve).nextCompletion.then(() => {\\n sleeve_infil = false\\n s.setToIdle(bestslv.Sleeve)\\n })\\n }\\n else s.setToIdle(bestslv.Sleeve)\\n }\\n }\\n else { //We are assigning all sleeves to their respective tasks\\n const cityChaos = b.getCityChaos(b.getCity())\\n const analyze = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\")[0] !== b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\")[1]\\n const stamina = b.getStamina()\\n const stamPerc = stamina[0] / stamina[1]\\n for (const me of isleeves) {\\n let trainSlv = false\\n if (s.getTask(me.Sleeve) !== null) {\\n continue //Our sleeve is working...\\n }\\n if (getsleevestats(ns, me.Sleeve) < SLEEVE_STATS && stamPerc > .55) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Training\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue // Save up for training. Move on to the next\\n }\\n }\\n if (s.getSleeve(me.Sleeve).hp.current + 2 <= s.getSleeve(me.Sleeve).hp.max) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Hyperbolic Regeneration Chamber\\\")\\n if (me.Cycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue\\n }\\n if (!sleeve_analyze && analyze) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Field Analysis\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_analyze = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_analyze = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && !sleeve_tracking && b.getCurrentAction()?.name !== \\\"Tracking\\\" && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Tracking\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Tracking\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Tracking\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Tracking\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Tracking\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_tracking = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_tracking = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && b.getCurrentAction()?.name !== \\\"Bounty Hunter\\\" && !sleeve_bounty && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Bounty Hunter\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Bounty Hunter\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Bounty Hunter\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Bounty Hunter\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Bounty Hunter\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_bounty = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_bounty = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (!analyze && cityChaos <= CHAOS_FLOOR && b.getCurrentAction()?.name !== \\\"Retirement\\\" && !sleeve_retire && b.getActionCountRemaining(\\\"Contracts\\\", \\\"Retirement\\\") >= 1) {\\n for (let i = b.getActionMaxLevel(\\\"Contracts\\\", \\\"Retirement\\\"); i > 0; i--) {\\n b.setActionLevel(\\\"Contracts\\\", \\\"Retirement\\\", i)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)[1] >= SLEEVE_CHANCE) {\\n break\\n }\\n }\\n const chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", \\\"Retirement\\\", me.Sleeve)\\n if (chance[1] < SLEEVE_CHANCE)\\n trainSlv = true\\n else {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Take on contracts\\\", \\\"Retirement\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_retire = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_retire = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n }\\n if (cityChaos > CHAOS_FLOOR && !sleeve_diplomacy) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Diplomacy\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_diplomacy = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_diplomacy = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n if (!sleeve_infil) {\\n s.setToBladeburnerAction(me.Sleeve, \\\"Infiltrate Synthoids\\\")\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n sleeve_infil = true\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n sleeve_infil = false\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n }\\n if (trainSlv && stamPerc > .55) {\\n if (s.setToBladeburnerAction(me.Sleeve, \\\"Training\\\")) {\\n if (s.getSleeve(me.Sleeve).storedCycles > s.getTask(me.Sleeve).cyclesNeeded) {\\n s.getTask(me.Sleeve).nextCompletion.then(() => {\\n s.setToIdle(me.Sleeve)\\n })\\n continue\\n }\\n else s.setToIdle(me.Sleeve)\\n continue // Save up for training. Move on to the next\\n }\\n }\\n\\n }\\n }\\n} // Updatesleeves function\\n/** @param {NS} ns */\\nasync function updateskills(ns) {\\n let b = ns.bladeburner\\n let count = 0\\n while (true) {\\n count++\\n if (count > 2000) {\\n await ns.asleep(4)\\n count = 0\\n }\\n if (INTMODE) {\\n const maxUpgrade = calcMaxUpgradeCount(ns, \\\"Hyperdrive\\\", b.getSkillPoints())\\n if (!maxUpgrade) break\\n if (b.getSkillLevel(\\\"Hyperdrive\\\") <= Number.MAX_SAFE_INTEGER - 1) {\\n b.upgradeSkill(\\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else if (maxUpgrade >= b.getSkillLevel(\\\"Hyperdrive\\\") / 1e8) {\\n b.upgradeSkill(\\\"Hyperdrive\\\", maxUpgrade)\\n break\\n }\\n else break\\n }\\n else {\\n let bestcost = Number.POSITIVE_INFINITY\\n let bestskill = \\\"Hyperdrive\\\"\\n for (const skl of b.getSkillNames()) {\\n if (skillrating(ns, skl) < bestcost) {\\n bestcost = skillrating(ns, skl)\\n bestskill = skl\\n }\\n }\\n if (LVLUP > 0 && !b.upgradeSkill(bestskill, LVLUP)) break\\n if (LVLUP <= 0 && !b.upgradeSkill(bestskill, calcMaxUpgradeCount(ns, bestskill, b.getSkillPoints()))) break\\n }\\n }\\n}\\nfunction skillrating(ns, skill) {\\n let b = ns.bladeburner\\n let mod = 0\\n skillmods.map(x => { x[0] === skill ? mod = x[1] : null })// ((x => { \\n //let cost = calculateCost(ns, skill)\\n let cost = b.getSkillUpgradeCost(skill)\\n return cost / mod === 0 ? Number.POSITIVE_INFINITY : cost / mod\\n}\\nfunction cityneedsanalysis(ns, city) {\\n const b = ns.bladeburner\\n const startcity = b.getCity()\\n b.switchCity(city)\\n for (const bop of b.getBlackOpNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Black Ops\\\", bop)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n for (const contract of b.getContractNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n for (const op of b.getOperationNames()) {\\n let chance = b.getActionEstimatedSuccessChance(\\\"Operations\\\", op)\\n if (chance[0] !== chance[1]) {\\n b.switchCity(startcity)\\n return true\\n }\\n }\\n b.switchCity(startcity)\\n return false\\n}\\nfunction checkTracking(ns) {\\n for (const city of cities) {\\n if (cityneedsanalysis(ns, city))\\n return city\\n }\\n return false\\n}\\n//Returns an array. [0] is missions name, [1] is missions type, [2] is the city\\n/** @param {NS} ns */\\nfunction getBestMission(ns) {\\n let b = ns.bladeburner\\n\\n const startcity = b.getCity()\\n let bestresult = 0\\n let bestoperation = null\\n let bestoperationtype = null\\n let bestoperationcity = null\\n let bestoperationlevel = 1\\n\\n let blackops = b.getBlackOpNames().filter(x => b.getActionCountRemaining(\\\"Black Ops\\\", x) > 0)\\n blackops = blackops.sort((x, y) => { return b.getBlackOpRank(y) - b.getBlackOpRank(x) })\\n let next = blackops.pop()\\n if (next !== undefined && b.getActionEstimatedSuccessChance(\\\"Black Ops\\\", next)[1] >= BOPS_SUCCESS_TRY && b.getBlackOpRank(next) <= b.getRank()) return [\\\"BlackOp\\\", next, b.getCity(), 1]\\n\\n for (const city of cities) {\\n b.switchCity(city)\\n for (const contract of b.getContractNames()) {\\n if (contract === \\\"Tracking\\\" && sleeve_tracking) continue // If a sleeve is doing something, move on.\\n if (contract === \\\"Bounty Hunter\\\" && sleeve_bounty) continue // Not because it causes a conflict\\n if (contract === \\\"Retirement\\\" && sleeve_retire) continue // But so we can focus on getting to Operations\\n if (b.getActionCountRemaining(\\\"Contracts\\\", contract) < 1) continue\\n for (let level = b.getActionMaxLevel(\\\"Contracts\\\", contract); level > 0; level--) {\\n b.setActionLevel(\\\"Contracts\\\", contract, level)\\n if (b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)[1] >= MIN_CHANCE_SUCCESS) {\\n const result = b.getActionEstimatedSuccessChance(\\\"Contracts\\\", contract)[1] * b.getActionRepGain(\\\"Contracts\\\", contract) / b.getActionTime(\\\"Contracts\\\", contract)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = contract\\n bestoperationtype = \\\"Contracts\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n const ops = [\\\"Undercover Operation\\\", \\\"Sting Operation\\\", \\\"Assassination\\\"]\\n for (const o of ops) {\\n if (b.getActionCountRemaining(\\\"Operations\\\", o) < 1) continue\\n for (let level = b.getActionMaxLevel(\\\"Operations\\\", o); level > 0; level--) {\\n b.setActionLevel(\\\"Operations\\\", o, level)\\n if (b.getActionEstimatedSuccessChance(\\\"Operations\\\", o)[1] >= MIN_CHANCE_SUCCESS) {\\n const result = b.getActionEstimatedSuccessChance(\\\"Operations\\\", o)[1] * b.getActionRepGain(\\\"Operations\\\", o) / b.getActionTime(\\\"Operations\\\", o)\\n if (result > bestresult) {\\n bestresult = result\\n bestoperation = o\\n bestoperationtype = \\\"Operations\\\"\\n bestoperationcity = city\\n bestoperationlevel = level\\n }\\n else break\\n }\\n }\\n }\\n }\\n b.switchCity(startcity)\\n return bestoperation !== null ? [bestoperationtype, bestoperation, bestoperationcity, bestoperationlevel] : null\\n}\\n/** @param {NS} ns */\\nfunction checkChaos(ns) {\\n let b = ns.bladeburner\\n\\n if (PRIORITY_CITY && b.getCityChaos(PRIORITY_CITY) <= CHAOS_FLOOR) PRIORITY_CITY = false\\n if (!PRIORITY_CITY) {\\n for (const city of cities) { //New emergency?\\n if (b.getCityChaos(city) >= CHAOS_TOP) {\\n PRIORITY_CITY = city\\n return PRIORITY_CITY\\n }\\n }\\n }\\n return PRIORITY_CITY\\n}\\n/** @param {NS} ns */\\nfunction updatedisplay(ns) {\\n ns.clearLog()\\n const b = ns.bladeburner\\n const s = ns.sleeve\\n ns.printf(\\\"Rank: %s Operations Queued: %s\\\", ns.format.number(b.getRank()), queues.length)\\n ns.printf(\\\"Stamina: %s/%s(%s%s)\\\", ns.format.number(b.getStamina()[0]), ns.format.number(b.getStamina()[1]), ns.format.number(b.getStamina()[0] / b.getStamina()[1] * 100, 2), \\\"%\\\")\\n ns.printf(\\\"Current City: %s\\\", b.getCity())\\n ns.printf(\\\"Est. Population: %s\\\", ns.format.number(b.getCityEstimatedPopulation(b.getCity())))\\n ns.printf(\\\"Synth Comms: %s\\\", ns.format.number(b.getCityCommunities(b.getCity()), 0))\\n ns.printf(\\\"Chaos: %s\\\", ns.format.number(b.getCityChaos(b.getCity())))\\n ns.printf(\\\"Skill Points: %s\\\", b.getSkillPoints() > 1000 ? ns.format.number(b.getSkillPoints()) : b.getSkillPoints())\\n ns.printf(\\\"Bonus Time: %s\\\", b.getBonusTime() / 1000 >= 1000 ? ns.format.number(b.getBonusTime() / 1000) : b.getBonusTime() / 1000)\\n updatemissions(ns)\\n if (queuestask.Type === undefined) ns.printf(\\\"Current Task: None(0/0)\\\")\\n else ns.printf(\\\"Current Task: %s(%s/%s) %s\\\", queuestask.Type, queuestask.Level, queuestask.Type === \\\"BlackOp\\\" || queuestask.Type === \\\"General\\\" ? 1 : b.getActionMaxLevel(queuestask.Type, queuestask.Name), queuestask.Name)\\n queuestask.Type !== undefined ? ns.printf(\\\"Progress: %s Time: %s\\\", updateprogress(b.getActionTime(queuestask.Type, queuestask.Name), b.getActionCurrentTime()), ns.format.time(b.getActionTime(queuestask.Type, queuestask.Name) - b.getActionCurrentTime())) : ns.printf(\\\"Progress: %s Time: n/a\\\", updateprogress(10, 0))\\n ns.printf(\\\"------------------------------------------------------------------------------\\\")\\n if (!SLEEVES_ENABLED) ns.printf(\\\"SLEEVE SUPPORT DISABLED\\\")\\n else {\\n for (let slv = 0; slv < s.getNumSleeves(); slv++) {\\n let task = s.getTask(slv)\\n let cycles = s.getSleeve(slv).storedCycles > 1000 ? ns.format.number(s.getSleeve(slv).storedCycles, 2) : s.getSleeve(slv).storedCycles\\n let buf = ns.sprintf(\\\"Sleeve: %s Cycles: %-7s \\\", slv, cycles)\\n if (task !== null) {\\n if (task.type === \\\"INFILTRATE\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: Infiltration\\\")\\n else if (task.type === \\\"CRIME\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Crime: \\\" + task.crimeType)\\n else if (task.type === \\\"BLADEBURNER\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"BB: \\\" + task.actionName.substring(0, 14))\\n else if (task.type === \\\"RECOVERY\\\") buf += ns.sprintf(\\\"%-18s \\\", \\\"Shock Recovery\\\")\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"?\\\" + task.type)\\n }\\n else buf += ns.sprintf(\\\"%-18s \\\", \\\"Idle: ------------\\\")\\n if (task !== null) buf += ns.sprintf(updateprogress(task.cyclesNeeded, task.cyclesWorked))\\n else buf += ns.sprintf(updateprogress(10, 0))\\n buf += ns.sprintf(\\\" Augs: %2s%s\\\", s.getSleeveAugmentations(slv).length, \\\"\\\\n\\\")\\n ns.printf(\\\"%s\\\", buf)\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction updatemissions(ns) {\\n //Cycle through all the mission types and show how many we currently have in our city and how many we have overall\\n let b = ns.bladeburner\\n\\n for (const contract of b.getContractNames()) {\\n b.getActionCountRemaining(\\\"Contract\\\", contract) >= 1000 ? ns.printf(\\\"Contracts: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Contract\\\", contract)) + \\\" \\\" + contract) : ns.printf(\\\"Contracts: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Contract\\\", contract), 2) + \\\" \\\" + contract)\\n }\\n for (const operation of b.getOperationNames()) {\\n b.getActionCountRemaining(\\\"Operation\\\", operation) >= 1000 ? ns.printf(\\\"Operation: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Operation\\\", operation)) + \\\" \\\" + operation) : ns.printf(\\\"Operation: \\\" + ns.format.number(b.getActionCountRemaining(\\\"Operation\\\", operation), 2) + \\\" \\\" + operation)\\n }\\n}\\n/** @param {NS} ns */\\nfunction updateprogress(max_time, run_time) {\\n let done = run_time > 0 ? Math.max(max_time / run_time, 1) : 0\\n let buffer = \\\"[\\\"\\n if (done > 0) buffer = buffer.padEnd(Math.round(20 / done), \\\"|\\\")\\n if (done > 0) buffer += \\\"*\\\"\\n buffer = buffer.padEnd(21, \\\"-\\\")\\n buffer += \\\"]\\\"\\n\\n return buffer\\n}\\n/** @param {NS} ns */\\nfunction runmission(ns, best) {\\n //best.Type, best.Name, best.City, best.Level\\n let b = ns.bladeburner\\n queuestask = best\\n const action = b.getCurrentAction()\\n //Resuming?\\n if (action !== null && best.City === b.getCity() && best.Type === action.type && best.Name === action.name && (best.Type === \\\"General\\\" || best.Type === \\\"BlackOp\\\" || best.Level === b.getActionCurrentLevel(best.Type, best.Name))) {\\n if ((b.getBonusTime() - 1000) > b.getActionTime(best.Type, best.Name)) { //All under bonus time\\n queueswait = performance.now() + Math.max((b.getActionTime(best.Type, best.Name) / 5) - b.getActionCurrentTime(), 500)\\n }\\n else queueswait = performance.now() + Math.max(b.getActionTime(best.Type, best.Name) - b.getBonusTime() - b.getActionCurrentTime(), 500)\\n }\\n else {\\n //New action\\n if (b.getCity() !== best.City) b.switchCity(best.City)\\n try { b.setActionLevel(best.Type, best.Name, best.Level) } catch { /*Catch the unlevelable actions*/ }\\n b.startAction(best.Type, best.Name)\\n if (b.getBonusTime() - 1000 > b.getActionTime(best.Type, best.Name)) { //All under bonus time\\n queueswait = performance.now() + Math.max((b.getActionTime(best.Type, best.Name) / 5), 500)\\n }\\n else queueswait = performance.now() + Math.max(b.getActionTime(best.Type, best.Name) - b.getBonusTime(), 500)\\n }\\n}\\nfunction gettrainstats(ns) {\\n const me = ns.getPlayer()\\n return (me.skills.agility + me.skills.defense + me.skills.dexterity + me.skills.strength) / 4\\n}\\n/** @param {NS} ns */\\nfunction getsleevestats(ns, slv) {\\n const s = ns.sleeve.getSleeve(slv)\\n return (s.skills.agility + s.skills.defense + s.skills.dexterity + s.skills.strength) / 4\\n}\\nfunction queue(type, name, city, level) {\\n let mission = {\\n \\\"Type\\\": type,\\n \\\"Name\\\": name,\\n \\\"City\\\": city,\\n \\\"Level\\\": level\\n }\\n queues.push(mission)\\n}\\n/** @param {NS} ns */\\nfunction init(ns) {\\n try { // Enable Sleeves\\n ns.sleeve.getNumSleeves()\\n SLEEVES_ENABLED = true\\n }\\n catch { SLEEVES_ENABLED = false }\\n sleeve_infil = false\\n sleeve_analyze = false\\n sleeve_tracking = false\\n sleeve_bounty = false\\n sleeve_retire = false\\n sleeve_diplomacy = false\\n queues.length = 0\\n if (SLEEVES_ENABLED)\\n for (let slv = 0; slv < ns.sleeve.getNumSleeves(); slv++)\\n ns.sleeve.setToIdle(slv)\\n HASBN4 = hasBN(ns, 4, 2)\\n queuestask = [null, null, null, null]\\n queueswait = 0\\n PRIORITY_CITY = false\\n const data = ns.flags(argsSchema)\\n LVLUP = data.lvlup\\n FINISHER = data.finisher\\n INTMODE = data.intmode\\n SLEEVEINFILSTATUS = data.sleeveinfilonly\\n}\\n/** @param {NS} ns */\\nfunction trainUp(ns) {\\n const me = ns.getPlayer()\\n const skls = me.skills\\n const wrk = HASBN4 ? ns.singularity.getCurrentWork() : false\\n if (me.city !== \\\"Sector-12\\\") {\\n ns.clearLog()\\n //Travel to our Gym\\n ns.print(\\\"Please go to Sector-12\\\")\\n if (HASBN4) ns.singularity.travelToCity(\\\"Sector-12\\\")\\n }\\n else if (skls.strength < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Str to 100\\\")\\n if (HASBN4 && (wrk === null || wrk.classType !== \\\"str\\\"))\\n ns.singularity.gymWorkout(\\\"Powerhouse Gym\\\", \\\"str\\\", false)\\n }\\n else if (skls.defense < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Def to 100\\\")\\n if (HASBN4 && (wrk === null || (wrk && wrk.classType !== \\\"def\\\")))\\n ns.singularity.gymWorkout(\\\"Powerhouse Gym\\\", \\\"def\\\", false)\\n }\\n else if (skls.dexterity < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Dex to 100\\\")\\n if (HASBN4 && (wrk === null || (wrk && wrk.classType !== \\\"dex\\\")))\\n ns.singularity.gymWorkout(\\\"Powerhouse Gym\\\", \\\"dex\\\", false)\\n }\\n else if (skls.agility < CSTATS) {\\n ns.clearLog()\\n ns.print(\\\"Train Agi to 100\\\")\\n if (HASBN4 && (wrk === null || (wrk && wrk.classType !== \\\"agi\\\")))\\n ns.singularity.gymWorkout(\\\"Powerhouse Gym\\\", \\\"agi\\\", false)\\n }\\n}\\n/** @param {NS} ns */\\nfunction hasBN(ns, bn, bnLvl = 1) {\\n const resetInfo = ns.getResetInfo()\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n if (resetInfo.currentNode === bn) {\\n return true\\n }\\n for (const sf of sourceFiles) if (sf.n === bn && sf.lvl >= bnLvl) {\\n return true\\n }\\n return false\\n}\\n/** @param {NS} ns */\\nfunction getslvpower(ns, slv) {\\n let s = ns.sleeve\\n let skill = s.getSleeve(slv).skills\\n return ((skill.agility + skill.defense + skill.dexterity + skill.strength + skill.charisma + skill.hacking) / 6)\\n}\\n/** @param {NS} ns */\\nfunction calcMaxUpgradeCount(ns, skill, cost) {\\n const b = ns.bladeburner\\n let baseCost;\\n let costInc;\\n const currentLevel = b.getSkillLevel(skill)\\n const currentNodeMults = getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n const m = -baseCost - costInc * currentLevel + costInc / 2\\n const delta = Math.sqrt(m * m + (2 * costInc * cost) / currentNodeMults.BladeburnerSkillCost)\\n const result = Math.round((m + delta) / costInc)\\n const costOfResultPlus1 = calculateCost(ns, skill, result + 1)\\n if (costOfResultPlus1 <= cost) {\\n return result + 1\\n }\\n const costOfResult = calculateCost(ns, skill, result)\\n if (costOfResult <= cost) {\\n return result\\n }\\n return result - 1\\n}\\nfunction calculateCost(ns, skill, count = 1) {\\n const currentLevel = ns.bladeburner.getSkillLevel(skill)\\n const actualCount = currentLevel + count - currentLevel\\n let baseCost;\\n let costInc;\\n const currentNodeMults = getBNMults(ns)\\n for (const skl of skillmods)\\n if (skl[0] === skill) {\\n baseCost = skl[2]\\n costInc = skl[3]\\n break\\n }\\n return Math.round(\\n actualCount *\\n currentNodeMults.BladeburnerSkillCost *\\n (baseCost + costInc * (currentLevel + (actualCount - 1) / 2)))\\n}\\n/** @param {NS} ns */\\nfunction endIt(ns) {\\n ns.singularity.destroyW0r1dD43m0n(getNextBN(ns), STARTUP_SCRIPT)\\n}\\n/** @param {NS} ns */\\nfunction getNextBN(ns) {\\n let nextbn = 0\\n let nextbnlvl = 0\\n for (let check of bnorder) {\\n let isthere = false\\n for (const bn of ns.singularity.getOwnedSourceFiles()) {\\n let bonus = 0\\n if (ns.getResetInfo().currentNode == check[0]) bonus = 1\\n if (bn.n == check[0] && bn.lvl + bonus >= check[1]) isthere = true\\n if (bn.n == ns.getResetInfo().currentNode && 1 >= check[1]) isthere = true\\n }\\n if (isthere == false) {\\n nextbn = check[0]\\n nextbnlvl = check[1]\\n break\\n }\\n }\\n let value = ns.sprintf(\\\"%s\\\" + \\\".\\\" + \\\"%s\\\", nextbn, nextbnlvl)\\n return Number.parseInt(value)\\n}\\n\\n//[0] is Node, [1] is lvl\\nconst bnorder = [[1, 3], [2, 3], [5, 1], [4, 3], [7, 3], [6, 3], [3, 3], [13, 3], [5, 3], [9, 3], [10, 3], [11, 3], [14, 3], [8, 3], [12, 36000]]\\n/** @param {NS} ns */\\nfunction getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,\\n \\\"CloudServerSoftcap\\\": 1,\\n \\\"CloudServerLimit\\\": 1,\\n \\\"CloudServerMaxRam\\\": 1,\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\\nconst cities = [\\\"Sector-12\\\", \\\"Aevum\\\", \\\"Volhaven\\\", \\\"Chongqing\\\", \\\"New Tokyo\\\", \\\"Ishima\\\"]\\n//skillmods [0] name, [1] My rating, [2] baseCost, [3] costInc\\nconst skillmods = [\\n [\\\"Blade\\\\'s Intuition\\\", 2.0, 3, 2.1],\\n [\\\"Cloak\\\", 0.8, 1, 1.1],\\n [\\\"Short-Circuit\\\", 1.0, 2, 2.1],\\n [\\\"Digital Observer\\\", 1.6, 2, 2.1],\\n [\\\"Tracer\\\", 1.0, 2, 2.1],\\n [\\\"Overclock\\\", 2.2, 3, 1.4],\\n [\\\"Reaper\\\", 1.0, 2, 2.1],\\n [\\\"Evasive System\\\", 2.0, 2, 2.1],\\n [\\\"Datamancer\\\", 1.0, 3, 1],\\n [\\\"Cyber\\\\'s Edge\\\", 1.0, 1, 3],\\n [\\\"Hands of Midas\\\", 0.1, 2, 2.5],\\n [\\\"Hyperdrive\\\", 2.5, 1, 2.5],\\n]\""},{"filename":"SphyxOS/full/corpFull.js","file":"\"const corpName = \\\"Sphyx-Corp\\\"\\nconst div1 = \\\"Family Farm\\\" //Agriculture\\nconst div2 = \\\"The Bog Pit\\\" //Chemical\\nconst div3 = \\\"Ciggy\\\\'s r Us\\\" //Tobacco\\nconst div4 = \\\"Bob\\\\'s Burgers\\\" //Restaurant\\nconst div5 = \\\"Brawndo\\\" //Water Utilities\\nconst div6 = \\\"Fabrikator\\\" //Computer Hardware\\nconst div7 = \\\"The Furnace\\\" //Refinery\\nconst div8 = \\\"Diggers Inc.\\\" //Mining\\n\\nconst round1Money = 440e9 //b\\nconst round2Money = 8.8e12 //t\\nconst round3Money = 12e15 //q\\nlet tobaccoBooster = false\\nconst round4Money = 500e18 //Q\\nconst ta2DB = [] //TA2 DB\\nconst indDataDB = []\\nconst matDataDB = []\\nlet researchedDB = []\\nlet hasDivDB = []\\nlet hasOfficeDB = []\\nlet hasWarehouseDB = []\\nlet roundTrigger = false\\nlet bnMults\\nlet oldRound\\nlet teaNeeded\\nlet investOffer\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n ns.clearLog()\\n hasDivDB = []\\n researchedDB = []\\n hasOfficeDB = []\\n hasWarehouseDB = []\\n const c = ns.corporation\\n const myBN = currentBN(ns)\\n bnMults = getBNMults(ns)\\n const selfFund = myBN === 3 ? false : true\\n while (!c.hasCorporation() && c.canCreateCorporation(selfFund) && !c.createCorporation(corpName, selfFund)) await ns.sleep(1000)\\n\\n let round = c.getInvestmentOffer().round\\n teaNeeded = true\\n oldRound = 0\\n tobaccoBooster = false\\n while (round === 1) {\\n prep(ns)\\n updateHud(ns)\\n if (c.getDivision(div1).numAdVerts < 2)\\n while (c.getDivision(div1).numAdVerts < 2) c.hireAdVert(div1)\\n const nState = c.getCorporation().nextState\\n if (nState === \\\"SALE\\\")\\n sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n\\n if (!teaNeeded && c.getOffice(div1, \\\"Sector-12\\\").employeeJobs.Business > 0) {\\n optimizeMats(ns)\\n }\\n purchase(ns)\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = teaParty(ns)\\n round = checkInvest(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n manageOffice(ns)\\n warehouseUpgrade(ns)\\n }\\n try { c.levelUpgrade(\\\"ABC SalesBots\\\") } catch { }\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 2) {\\n prep(ns)\\n updateHud(ns)\\n let hasDiv2 = false\\n //Set up Tobacco \\n let count = 0\\n if (researchedDB[\\\"Export\\\"])\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n while (hasDiv2 && c.getUpgradeLevel(\\\"Smart Factories\\\") < 16 && c.getUpgradeLevelCost(\\\"Smart Factories\\\") <= corpFunds(ns))\\n c.levelUpgrade(\\\"Smart Factories\\\")\\n const nState = c.getCorporation().nextState\\n if (nState === \\\"SALE\\\")\\n sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n basicExporImport(ns)\\n purchase(ns)\\n while (corpFunds(ns) > c.getHireAdVertCost(div1) && c.getHireAdVertCount(div1) < 12 && hasDiv2)\\n try {\\n c.hireAdVert(div1)\\n } catch { }\\n if (c.getHireAdVertCount(div1) < 11 && c.getMaterial(div1, \\\"Sector-12\\\", \\\"Plants\\\").stored > 200)\\n try {\\n c.hireAdVert(div1)\\n } catch { }\\n else if (hasDiv2 && c.getMaterial(div1, \\\"Sector-12\\\", \\\"Plants\\\").stored > 200)\\n try {\\n c.hireAdVert(div1)\\n } catch { }\\n if (ns.ui.getGameInfo()?.versionNumber === undefined) {\\n if (!teaNeeded && c.getOffice(div1, \\\"Sector-12\\\").employeeJobs.Business > 0 && c.getUpgradeLevel(\\\"DreamSense\\\") === 0)\\n try { c.levelUpgrade(\\\"DreamSense\\\") }\\n catch { }\\n }\\n\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = teaParty(ns)\\n round = checkInvest(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n manageOffice(ns)\\n warehouseUpgrade(ns)\\n if (!teaNeeded && c.getOffice(div1, \\\"Sector-12\\\").employeeJobs.Business > 0) {\\n\\n while (hasDiv2 && corpFunds(ns) >= c.getUpgradeLevelCost(\\\"ABC SalesBots\\\") && c.getUpgradeLevel(\\\"ABC SalesBots\\\") < 30)\\n c.levelUpgrade(\\\"ABC SalesBots\\\")\\n optimizeMats(ns)\\n }\\n while (corpFunds(ns) >= c.getUpgradeLevelCost(\\\"ABC SalesBots\\\") && c.getUpgradeLevel(\\\"ABC SalesBots\\\") < 10)\\n c.levelUpgrade(\\\"ABC SalesBots\\\")\\n }\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 3 || round === 4) {\\n prep(ns)\\n updateHud(ns)\\n while (c.getUpgradeLevel(\\\"Smart Factories\\\") < 20 && c.getUpgradeLevelCost(\\\"Smart Factories\\\") <= corpFunds(ns))\\n c.levelUpgrade(\\\"Smart Factories\\\")\\n manageProducts(ns)\\n spendRP(ns)\\n const nState = c.getCorporation().nextState\\n if (nState === \\\"SALE\\\")\\n sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n basicExporImport(ns)\\n purchase(ns)\\n if (c.getMaterial(div1, \\\"Sector-12\\\", \\\"Plants\\\").stored > 200)\\n try {\\n c.hireAdVert(div1)\\n } catch { }\\n if (ns.ui.getGameInfo()?.versionNumber === undefined) {\\n if (!teaNeeded && c.getOffice(div1, \\\"Sector-12\\\").employeeJobs.Business > 0 && c.getUpgradeLevel(\\\"DreamSense\\\") === 0)\\n try { c.levelUpgrade(\\\"DreamSense\\\") }\\n catch { }\\n }\\n }\\n if (nState === \\\"START\\\") {\\n teaNeeded = teaParty(ns)\\n round = checkInvest(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n updateMisc(ns)\\n manageOffice(ns)\\n warehouseUpgrade(ns)\\n optimizeMats(ns)\\n }\\n\\n await ns.corporation.nextUpdate()\\n }\\n while (round === 5) {\\n prep(ns)\\n updateHud(ns)\\n manageProducts(ns)\\n spendRP(ns)\\n const nState = c.getCorporation().nextState\\n if (nState === \\\"SALE\\\")\\n sell(ns)\\n if (nState === \\\"PURCHASE\\\") {\\n updateMisc(ns)\\n basicExporImport(ns)\\n purchase(ns)\\n }\\n if (nState === \\\"START\\\") {\\n manageOffice(ns)\\n teaNeeded = teaParty(ns)\\n }\\n if (nState === \\\"EXPORT\\\") {\\n warehouseUpgrade(ns)\\n optimizeMats(ns)\\n }\\n await ns.corporation.nextUpdate()\\n }\\n}\\n/** @param {NS} ns */\\nfunction checkInvest(ns) {\\n const c = ns.corporation\\n const round = investOffer.round\\n const corp = c.getCorporation()\\n\\n if (round === 1) {\\n if (round1Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n c.acceptInvestmentOffer()\\n teaNeeded = true\\n roundTrigger = false\\n ns.tprintf(\\\"Off to round 2!\\\")\\n return 2\\n }\\n }\\n return 1\\n }\\n if (round === 2) {\\n let hasDiv2 = false\\n //Set up Tobacco \\n let count = 0\\n if (researchedDB[\\\"Export\\\"])\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n if ((hasDiv2 && investOffer.funds + corp.funds > 30e9 && round2Money * bnMults.CorporationValuation < investOffer.funds + corp.funds) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (Math.min(30e9, corp.funds))) {\\n oldRound = investOffer.funds + (Math.min(30e9, corp.funds))\\n }\\n else {\\n c.acceptInvestmentOffer()\\n teaNeeded = true\\n roundTrigger = false\\n ns.tprintf(\\\"Off to round 3!\\\")\\n return 3\\n }\\n }\\n return 2\\n }\\n if (round === 3) {\\n if (round3Money * bnMults.CorporationValuation < (investOffer.funds * 4) + (corp.funds * bnMults.CorporationValuation)) {\\n tobaccoBooster = true\\n }\\n if ((round3Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation)) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n c.acceptInvestmentOffer()\\n teaNeeded = true\\n roundTrigger = false\\n tobaccoBooster = false\\n ns.tprintf(\\\"Off to round 4!\\\")\\n return 4\\n }\\n }\\n return 3\\n }\\n if (round === 4) {\\n if (round4Money * bnMults.CorporationValuation < (investOffer.funds * 4) + (corp.funds * bnMults.CorporationValuation)) {\\n tobaccoBooster = true\\n }\\n if ((round4Money * bnMults.CorporationValuation < investOffer.funds + (corp.funds * bnMults.CorporationValuation)) || roundTrigger) {\\n roundTrigger = true\\n if (oldRound <= investOffer.funds + (corp.funds * bnMults.CorporationValuation)) {\\n oldRound = investOffer.funds + (corp.funds * bnMults.CorporationValuation)\\n }\\n else {\\n c.acceptInvestmentOffer()\\n teaNeeded = true\\n roundTrigger = false\\n ns.tprintf(\\\"Off to round 5!\\\")\\n return 5\\n }\\n }\\n return 4\\n }\\n}\\n/** @param {NS} ns */\\nfunction corpFunds(ns) {\\n const corp = ns.corporation.getCorporation()\\n return corp.funds\\n}\\n/** @param {NS} ns */\\nfunction prep(ns) {\\n const c = ns.corporation\\n investOffer = c.getInvestmentOffer()\\n const round = investOffer.round\\n if (round >= 1) {\\n if (!hasDivDB[div1]) {\\n try {\\n const div = c.getDivision(div1)\\n hasDivDB[div1] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Agriculture\\\", div1) } catch { }\\n try {\\n const div = c.getDivision(div1)\\n hasDivDB[div1] = div\\n }\\n catch { }\\n }\\n }\\n for (const city of cities) {\\n if (!hasOfficeDB[div1 + city]) {\\n try { c.expandCity(div1, city) } catch { }\\n try {\\n c.getOffice(div1, city)\\n hasOfficeDB[div1 + city] = true\\n }\\n catch { }\\n }\\n if (!hasWarehouseDB[div1 + city]) {\\n try { c.purchaseWarehouse(div1, city) } catch { }\\n if (c.hasWarehouse(div1, city))\\n hasWarehouseDB[div1 + city] = true\\n }\\n }\\n }\\n if (round >= 2) {\\n if (!researchedDB[\\\"Export\\\"]) {\\n try { c.purchaseUnlock(\\\"Export\\\") } catch { }\\n if (c.hasUnlock(\\\"Export\\\")) researchedDB[\\\"Export\\\"] = true\\n }\\n if (researchedDB[\\\"Export\\\"]) {\\n if (!hasDivDB[div2]) {\\n try {\\n const div = c.getDivision(div2)\\n hasDivDB[div2] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Chemical\\\", div2) } catch { }\\n try {\\n const div = c.getDivision(div2)\\n hasDivDB[div2] = div\\n }\\n catch { }\\n }\\n }\\n if (hasDivDB[div2]) {\\n for (const city of cities) {\\n if (!hasOfficeDB[div2 + city]) {\\n try { c.expandCity(div2, city) } catch { }\\n try {\\n c.getOffice(div2, city)\\n hasOfficeDB[div2 + city] = true\\n }\\n catch { }\\n }\\n if (!hasWarehouseDB[div2 + city]) {\\n try { c.purchaseWarehouse(div2, city) } catch { }\\n if (c.hasWarehouse(div2, city))\\n hasWarehouseDB[div2 + city] = true\\n }\\n }\\n }\\n }\\n }\\n if (round >= 3) {\\n if (!researchedDB[\\\"Market Research - Demand\\\"]) {\\n try { c.purchaseUnlock(\\\"Market Research - Demand\\\") } catch { }\\n if (c.hasUnlock(\\\"Market Research - Demand\\\"))\\n researchedDB[\\\"Market Research - Demand\\\"] = true\\n }\\n if (!researchedDB[\\\"Market Data - Competition\\\"]) {\\n try { c.purchaseUnlock(\\\"Market Data - Competition\\\") } catch { }\\n if (c.hasUnlock(\\\"Market Data - Competition\\\"))\\n researchedDB[\\\"Market Data - Competition\\\"] = true\\n }\\n if (!hasDivDB[div3] && researchedDB[\\\"Market Research - Demand\\\"] && researchedDB[\\\"Market Data - Competition\\\"]) {\\n try {\\n const div = c.getDivision(div3)\\n hasDivDB[div3] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Tobacco\\\", div3) } catch { }\\n try {\\n const div = c.getDivision(div3)\\n hasDivDB[div3] = div\\n }\\n catch { }\\n }\\n }\\n if (hasDivDB[div3]) {\\n for (const city of cities) {\\n if (!hasOfficeDB[div3 + city]) {\\n try { c.expandCity(div3, city) } catch { }\\n try {\\n c.getOffice(div3, city)\\n hasOfficeDB[div3 + city] = true\\n }\\n catch { }\\n }\\n if (!hasWarehouseDB[div3 + city]) {\\n try { c.purchaseWarehouse(div3, city) } catch { }\\n if (c.hasWarehouse(div3, city))\\n hasWarehouseDB[div3 + city] = true\\n\\n }\\n }\\n }\\n }\\n if (round >= 5) {\\n try {\\n const div = c.getDivision(div4)\\n hasDivDB[div4] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Restaurant\\\", div4) } catch { }\\n try {\\n const div = c.getDivision(div4)\\n hasDivDB[div4] = div\\n }\\n catch { }\\n }\\n for (const city of cities) {\\n if (!hasOfficeDB[div4 + city]) {\\n try { c.expandCity(div4, city) } catch { }\\n try {\\n c.getOffice(div4, city)\\n hasOfficeDB[div4 + city] = true\\n }\\n catch { }\\n }\\n if (!hasWarehouseDB[div4 + city]) {\\n try { c.purchaseWarehouse(div4, city) } catch { }\\n if (c.hasWarehouse(div4, city))\\n hasWarehouseDB[div4 + city] = true\\n }\\n }\\n if (c.getCorporation().revenue >= 1e70) {\\n if (!researchedDB[\\\"Government Partnership\\\"]) {\\n try { c.purchaseUnlock(\\\"Government Partnership\\\") } catch { }\\n if (c.hasUnlock(\\\"Government Partnership\\\"))\\n researchedDB[\\\"Government Partnership\\\"] = true\\n }\\n if (!researchedDB[\\\"Shady Accounting\\\"]) {\\n try { c.purchaseUnlock(\\\"Shady Accounting\\\") } catch { }\\n if (c.hasUnlock(\\\"Shady Accounting\\\"))\\n researchedDB[\\\"Shady Accounting\\\"] = true\\n }\\n if (!c.getCorporation().public) c.goPublic(0)\\n c.issueDividends(0.01)\\n\\n try {\\n const div = c.getDivision(div5)\\n hasDivDB[div5] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Water Utilities\\\", div5) } catch { }\\n try {\\n const div = c.getDivision(div5)\\n hasDivDB[div5] = div\\n }\\n catch { }\\n }\\n try {\\n const div = c.getDivision(div6)\\n hasDivDB[div6] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Computer Hardware\\\", div6) } catch { }\\n try {\\n const div = c.getDivision(div6)\\n hasDivDB[div6] = div\\n }\\n catch { }\\n }\\n try {\\n const div = c.getDivision(div7)\\n hasDivDB[div7] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Refinery\\\", div7) } catch { }\\n try {\\n const div = c.getDivision(div7)\\n hasDivDB[div7] = div\\n }\\n catch { }\\n }\\n try {\\n const div = c.getDivision(div8)\\n hasDivDB[div8] = div\\n }\\n catch {\\n try { c.expandIndustry(\\\"Mining\\\", div8) } catch { }\\n try {\\n const div = c.getDivision(div8)\\n hasDivDB[div8] = div\\n }\\n catch { }\\n }\\n for (const city of cities) {\\n //Set up divs\\n const divs = [div5, div6, div7, div8]\\n for (const div of divs) {\\n if (!hasOfficeDB[div + city]) {\\n try { c.expandCity(div, city) } catch { }\\n try {\\n c.getOffice(div, city)\\n hasOfficeDB[div + city] = true\\n }\\n catch { }\\n }\\n if (!hasWarehouseDB[div + city]) {\\n try { c.purchaseWarehouse(div, city) } catch { }\\n if (c.hasWarehouse(div, city))\\n hasWarehouseDB[div + city] = true\\n }\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction updateMisc(ns) {\\n const c = ns.corporation\\n const round = investOffer.round\\n let corp = c.getCorporation()\\n const mult = round === 3 ? 3 : 2.5\\n let hasDiv4 = false\\n let hasDiv3 = false\\n let div3Count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div3 + city])\\n div3Count++\\n if (div3Count === 6) hasDiv3 = true\\n\\n\\n let div4Count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div4 + city])\\n div4Count++\\n if (div4Count === 6) hasDiv4 = true\\n\\n if (round === 3 && !hasDiv3) return\\n if (round >= 3\\n && c.getUpgradeLevelCost(\\\"Wilson Analytics\\\") < corp.funds\\n && (((round >= 5)\\n && (hasDiv4\\n && (c.getDivision(div4).awareness < Number.MAX_VALUE\\n || c.getDivision(div4).popularity < Number.MAX_VALUE)))\\n || (hasDiv3\\n && (c.getDivision(div3).awareness < Number.MAX_VALUE\\n || c.getDivision(div3).popularity < Number.MAX_VALUE)))) {\\n c.levelUpgrade(\\\"Wilson Analytics\\\")\\n corp = c.getCorporation()\\n }\\n while ((round === 3)\\n && c.getUpgradeLevelCost(\\\"Wilson Analytics\\\") < corpFunds(ns)\\n && c.getUpgradeLevel(\\\"Wilson Analytics\\\") < 2) {\\n c.levelUpgrade(\\\"Wilson Analytics\\\")\\n corp = c.getCorporation()\\n }\\n if (round < 5 && c.getUpgradeLevelCost(\\\"ABC SalesBots\\\") * mult / 2 < corp.funds) {\\n c.levelUpgrade(\\\"ABC SalesBots\\\")\\n corp = c.getCorporation()\\n }\\n while (round >= 5 && c.getUpgradeLevelCost(\\\"ABC SalesBots\\\") * mult / 2 < corpFunds(ns)) c.levelUpgrade(\\\"ABC SalesBots\\\")\\n corp = c.getCorporation()\\n if ((round === 3 && c.getCorporation().revenue >= 8e7) || round >= 4) {\\n if (c.getUpgradeLevel(\\\"Neural Accelerators\\\") < 500 && c.getUpgradeLevelCost(\\\"Neural Accelerators\\\") * mult < corp.funds) {\\n c.levelUpgrade(\\\"Neural Accelerators\\\")\\n corp = c.getCorporation()\\n }\\n if (c.getUpgradeLevel(\\\"Project Insight\\\") < 500 && c.getUpgradeLevelCost(\\\"Project Insight\\\") * mult < corp.funds) {\\n c.levelUpgrade(\\\"Project Insight\\\")\\n corp = c.getCorporation()\\n }\\n if (c.getUpgradeLevel(\\\"Nuoptimal Nootropic Injector Implants\\\") < 500 && c.getUpgradeLevelCost(\\\"Nuoptimal Nootropic Injector Implants\\\") * mult < corp.funds) {\\n c.levelUpgrade(\\\"Nuoptimal Nootropic Injector Implants\\\")\\n corp = c.getCorporation()\\n }\\n if (c.getUpgradeLevel(\\\"FocusWires\\\") < 500 && c.getUpgradeLevelCost(\\\"FocusWires\\\") * mult < corp.funds) {\\n c.levelUpgrade(\\\"FocusWires\\\")\\n corp = c.getCorporation()\\n }\\n if (c.getUpgradeLevel(\\\"Speech Processor Implants\\\") < 500 && c.getUpgradeLevelCost(\\\"Speech Processor Implants\\\") * mult < corp.funds) {\\n c.levelUpgrade(\\\"Speech Processor Implants\\\")\\n corp = c.getCorporation()\\n }\\n }\\n\\n if (round >= 3 && round <= 4) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if ([\\\"Tobacco\\\", \\\"Restaurant\\\"].includes(hasDivDB[div].type)\\n && corp.funds >= c.getHireAdVertCost(div) * mult / 2\\n && (c.getDivision(div).awareness < Number.MAX_VALUE || c.getDivision(div).popularity < Number.MAX_VALUE)) {\\n c.hireAdVert(div)\\n corp = c.getCorporation()\\n }\\n }\\n }\\n if (round === 5) {\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n while ([\\\"Tobacco\\\", \\\"Restaurant\\\", \\\"Computer Hardware\\\"].includes(hasDivDB[div].type)\\n && corpFunds(ns) >= c.getHireAdVertCost(div) * mult / 2\\n && (c.getDivision(div).awareness < Number.MAX_VALUE || c.getDivision(div).popularity < Number.MAX_VALUE))\\n c.hireAdVert(div)\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction spendRP(ns) {\\n const c = ns.corporation\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n switch (hasDivDB[div].type) {\\n case \\\"Mining\\\":\\n case \\\"Refinery\\\":\\n case \\\"Computer Hardware\\\":\\n case \\\"Water Utilities\\\":\\n case \\\"Chemical\\\":\\n case \\\"Agriculture\\\": {\\n const rp = c.getDivision(div).researchPoints\\n if (!researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"]) {\\n if (rp / 2 > c.getResearchCost(div, \\\"Hi-Tech R&D Laboratory\\\")) {\\n c.research(div, \\\"Hi-Tech R&D Laboratory\\\")\\n researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Overclock\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Overclock\\\")) {\\n c.research(div, \\\"Overclock\\\")\\n researchedDB[div + \\\"Overclock\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Sti.mu\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Sti.mu\\\")) {\\n c.research(div, \\\"Sti.mu\\\")\\n researchedDB[div + \\\"Sti.mu\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Automatic Drug Administration\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Automatic Drug Administration\\\")) {\\n c.research(div, \\\"Automatic Drug Administration\\\")\\n researchedDB[div + \\\"Automatic Drug Administration\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"Go-Juice\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Go-Juice\\\")) {\\n c.research(div, \\\"Go-Juice\\\")\\n researchedDB[div + \\\"Go-Juice\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"CPH4 Injections\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"CPH4 Injections\\\")) {\\n c.research(div, \\\"CPH4 Injections\\\")\\n researchedDB[div + \\\"CPH4 Injections\\\"] = true\\n }\\n else break\\n }\\n }\\n break\\n case \\\"Restaurant\\\":\\n case \\\"Tobacco\\\": {\\n const rp = c.getDivision(div).researchPoints\\n if (!researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"]) {\\n if (rp / 2 > c.getResearchCost(div, \\\"Hi-Tech R&D Laboratory\\\")) {\\n c.research(div, \\\"Hi-Tech R&D Laboratory\\\")\\n researchedDB[div + \\\"Hi-Tech R&D Laboratory\\\"] = true\\n }\\n else break\\n }\\n if (!researchedDB[div + \\\"uPgrade: Fulcrum\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"uPgrade: Fulcrum\\\")) {\\n c.research(div, \\\"uPgrade: Fulcrum\\\")\\n researchedDB[div + \\\"uPgrade: Fulcrum\\\"] = true\\n }\\n else break\\n break\\n }\\n /*if (!researchedDB[div + \\\"uPgrade: Capacity.I\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"uPgrade: Capacity.I\\\")) {\\n c.research(div, \\\"uPgrade: Capacity.I\\\")\\n researchedDB[div + \\\"uPgrade: Capacity.I\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"uPgrade: Capacity.II\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"uPgrade: Capacity.II\\\")) {\\n c.research(div, \\\"uPgrade: Capacity.II\\\")\\n researchedDB[div + \\\"uPgrade: Capacity.II\\\"] = true\\n }\\n else break\\n break\\n }\\n */\\n if (!researchedDB[div + \\\"Self-Correcting Assemblers\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Self-Correcting Assemblers\\\")) {\\n c.research(div, \\\"Self-Correcting Assemblers\\\")\\n researchedDB[div + \\\"Self-Correcting Assemblers\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Drones\\\")) {\\n c.research(div, \\\"Drones\\\")\\n researchedDB[div + \\\"Drones\\\"] = true\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones - Assembly\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Drones - Assembly\\\")) {\\n c.research(div, \\\"Drones - Assembly\\\")\\n researchedDB[div + \\\"Drones - Assembly\\\"] = false\\n }\\n else break\\n break\\n }\\n if (!researchedDB[div + \\\"Drones - Transport\\\"]) {\\n if (rp / 10 > c.getResearchCost(div, \\\"Drones - Transport\\\")) {\\n c.research(div, \\\"Drones - Transport\\\")\\n researchedDB[div + \\\"Drones - Transport\\\"] = true\\n }\\n else break\\n break\\n }\\n }\\n break\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction manageProducts(ns) {\\n const c = ns.corporation\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (!hasDivDB[div].makesProducts) continue\\n let active = 0\\n let calculating = 0\\n let division = c.getDivision(div)\\n for (const prod of division.products) {\\n if (c.getProduct(div, \\\"Sector-12\\\", prod).developmentProgress === 100) {\\n const ta2 = ta2DB[div + \\\"Sector-12\\\" + prod]\\n if (ta2 !== undefined && ta2.markupLimit !== 0)\\n active++\\n else\\n calculating++\\n }\\n }\\n //Discontinue?\\n if (active + calculating === division.maxProducts && calculating <= 1) {\\n let worstProd = \\\"none\\\"\\n let worstRating = Infinity\\n for (const prod of division.products) {\\n\\n if (c.getProduct(div, \\\"Sector-12\\\", prod).developmentProgress != 100 || getSellPrice(ns, div, \\\"Sector-12\\\", prod) === 0) continue\\n if (getSellPrice(ns, div, \\\"Sector-12\\\", prod) < worstRating) {\\n worstProd = prod\\n worstRating = getSellPrice(ns, div, \\\"Sector-12\\\", prod)\\n }\\n }\\n for (const city of cities)\\n delete ta2DB[div + city + worstProd]\\n c.discontinueProduct(div, worstProd)\\n division = c.getDivision(div)\\n }\\n //Discontinue?\\n else if (active + calculating === division.maxProducts) {\\n let worstProd = \\\"none\\\"\\n let worstRating = Infinity\\n for (const prod of division.products) {\\n const product = c.getProduct(div, \\\"Sector-12\\\", prod)\\n if (product.developmentProgress === 100 && product.stats.quality < worstRating) {\\n worstProd = prod\\n worstRating = product.stats.quality\\n }\\n }\\n for (const city of cities)\\n delete ta2DB[div + city + worstProd]\\n c.discontinueProduct(div, worstProd)\\n division = c.getDivision(div)\\n }\\n let researching = false\\n if (division.products.length <= division.maxProducts) {\\n //Are we researching one?\\n for (const prod of division.products)\\n if (c.getProduct(div, \\\"Sector-12\\\", prod).developmentProgress < 100) {\\n researching = true\\n break\\n }\\n }\\n let prodname = \\\"none:\\\" + Math.random()\\n if (hasDivDB[div].type === \\\"Tobacco\\\") {\\n prodname = cigaretts[Math.floor(Math.random() * cigaretts.length)]\\n while (division.products.includes(prodname)) {\\n prodname = cigaretts[Math.floor(Math.random() * cigaretts.length)]\\n }\\n }\\n else if (hasDivDB[div].type === \\\"Restaurant\\\") {\\n prodname = burgers[Math.floor(Math.random() * burgers.length)]\\n while (division.products.includes(prodname)) {\\n prodname = burgers[Math.floor(Math.random() * burgers.length)]\\n }\\n }\\n else if (hasDivDB[div].type === \\\"Computer Hardware\\\") {\\n prodname = hardwares[Math.floor(Math.random() * hardwares.length)]\\n while (division.products.includes(prodname)) {\\n prodname = hardwares[Math.floor(Math.random() * hardwares.length)]\\n }\\n }\\n let active2 = 0\\n for (const prod of division.products) {\\n if (c.getProduct(div, \\\"Sector-12\\\", prod).developmentProgress === 100)\\n active2++\\n }\\n const corp = c.getCorporation()\\n if (!researching && active2 < division.maxProducts && corp.funds > 200) c.makeProduct(div, \\\"Sector-12\\\", prodname, corp.funds / 100, corp.funds / 100)\\n }\\n}\\n//setJob is used due to migrating to 3.0.0 breakages\\n/** @param {NS} ns */\\nfunction setJob(ns, div, city, job, total) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.corporation.setJobAssignment(div, city, job, total)\\n else ns.corporation.setJobAssignment(div, city, job, total)\\n}\\nfunction manageOffice(ns) {\\n const c = ns.corporation\\n const round = investOffer.round\\n let hasDiv2 = false\\n if (hasDivDB[div2]) {\\n let cityCount = 0\\n for (const city of cities) {\\n if (hasWarehouseDB[div2 + city])\\n cityCount++\\n }\\n if (cityCount === 6) hasDiv2 = true\\n }\\n let hasDiv3 = false\\n if (hasDivDB[div3]) {\\n let cityCount = 0\\n for (const city of cities) {\\n if (hasWarehouseDB[div3 + city]) {\\n cityCount++\\n }\\n }\\n if (cityCount === 6) hasDiv3 = true\\n }\\n\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n switch (hasDivDB[div].type) {\\n case \\\"Agriculture\\\":\\n switch (round) {\\n case 1:\\n while (c.getOffice(div, city).size < 4 && c.getOfficeSizeUpgradeCost(div, city, 1) <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (c.getDivision(div).researchPoints < 60)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", 1)\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", 1)\\n }\\n break\\n case 2:\\n while (hasDiv2 && c.getOffice(div, city).size < 8 && c.getOfficeSizeUpgradeCost(div, city, 1) <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (c.getDivision(div).researchPoints < 700)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 2.66))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n const remainder = c.getOffice(div, city).numEmployees - 1 - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 2.66)\\n setJob(div, city, \\\"Management\\\", remainder)\\n }\\n break\\n case 3:\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n const left = c.getOffice(div, city).numEmployees - 1 - Math.floor(c.getOffice(div, city).numEmployees / 3) - 1 - Math.floor(c.getOffice(div, city).numEmployees / 4)\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n if (!hasDiv3) break\\n while (c.getOffice(div, city).size < 8 && c.getOfficeSizeUpgradeCost(div, city, 1) <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n const left = c.getOffice(div, city).numEmployees - 1 - Math.floor(c.getOffice(div, city).numEmployees / 3) - 1 - Math.floor(c.getOffice(div, city).numEmployees / 4)\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n case 4:\\n if (c.getOffice(div, city).size < 60) c.upgradeOfficeSize(div, city, 1)\\n if (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size) c.hireEmployee(div, city)\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 2))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n const left = c.getOffice(div, city).numEmployees - 1 - Math.floor(c.getOffice(div, city).numEmployees / 2) - 1 - Math.floor(c.getOffice(div, city).numEmployees / 4)\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n case 5:\\n if (c.getOffice(div, city).size < 300) c.upgradeOfficeSize(div, city, 1)\\n if (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size) c.hireEmployee(div, city)\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 2.5))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 2.5))\\n const left = c.getOffice(div, city).numEmployees - 1 - Math.floor(c.getOffice(div, city).numEmployees / 2.5) - Math.floor(c.getOffice(div, city).numEmployees / 2.5) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Chemical\\\":\\n switch (round) {\\n case 2:\\n while (c.getOffice(div, city).size < 3 && c.getOfficeSizeUpgradeCost(div, city, 1) <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (c.getDivision(div).researchPoints < 390)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", 1)\\n setJob(div, city, \\\"Business\\\", 1)\\n }\\n break\\n case 3:\\n if (!hasDiv3) break\\n while (c.getOffice(div, city).size < 8 && c.getOfficeSizeUpgradeCost(div, city, 1) <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.max(1, Math.floor(c.getOffice(div, city).numEmployees / 4)))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n const left = c.getOffice(div, city).numEmployees - Math.max(1, Math.floor(c.getOffice(div, city).numEmployees / 4)) - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n case 4:\\n if (c.getOffice(div, city).size < 60) c.upgradeOfficeSize(div, city, 1)\\n if (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size) c.hireEmployee(div, city)\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n const left = c.getOffice(div, city).numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n case 5:\\n if (c.getOffice(div, city).size < 300) c.upgradeOfficeSize(div, city, 1)\\n if (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size) c.hireEmployee(div, city)\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Tobacco\\\":\\n switch (round) {\\n case 3: {\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - 1\\n setJob(div, city, \\\"Management\\\", left)\\n }\\n if (!hasDiv3) break\\n const corpRev = c.getCorporation().revenue\\n while (c.getOffice(div, city).size < 106 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 5e8)\\n while (c.getOffice(div, city).size < 116 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 1e9)\\n while (c.getOffice(div, city).size < 136 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 2.5e9)\\n while (c.getOffice(div, city).size < 146 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 5e9)\\n while (c.getOffice(div, city).size < 156 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 10e9)\\n while (c.getOffice(div, city).size < 176 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 20e9)\\n while (c.getOffice(div, city).size < 200 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 50e9)\\n while (c.getOffice(div, city).size < 226 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - 1\\n setJob(div, city, \\\"Management\\\", left)\\n }\\n }\\n break\\n case 4: {\\n const corpRev = c.getCorporation().revenue\\n if (c.getOffice(div, city).size < 250) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 100e9)\\n while (c.getOffice(div, city).size < 270 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 200e9)\\n while (c.getOffice(div, city).size < 290 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 400e9)\\n while (c.getOffice(div, city).size < 320 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 1e12)\\n while (c.getOffice(div, city).size < 360 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 2e12)\\n while (c.getOffice(div, city).size < 380 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (corpRev > 5e12)\\n while (c.getOffice(div, city).size < 380 && c.getOfficeSizeUpgradeCost(div, city, 1) * 1.5 <= corpFunds(ns)) c.upgradeOfficeSize(div, city, 1)\\n if (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size) c.hireEmployee(div, city)\\n resetOffice(ns, div, city)\\n if (city !== \\\"Sector-12\\\" && !tobaccoBooster)\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n const left = c.getOffice(div, city).numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - 1\\n setJob(div, city, \\\"Management\\\", left)\\n }\\n }\\n break\\n case 5:\\n while (c.getOffice(div, city).size < 1500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (city !== \\\"Sector-12\\\")\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n const left = c.getOffice(div, city).numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Management\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Restaurant\\\":\\n switch (round) {\\n case 5:\\n while (c.getOffice(div, city).size < 1500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n if (city !== \\\"Sector-12\\\")\\n setJob(div, city, \\\"Research & Development\\\", c.getOffice(div, city).numEmployees)\\n else {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n const left = c.getOffice(div, city).numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 4) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Management\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Water Utilities\\\":\\n switch (round) {\\n case 5:\\n while (c.getOffice(div, city).size < 6500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Computer Hardware\\\":\\n switch (round) {\\n case 5:\\n while (c.getOffice(div, city).size < 4500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Refinery\\\":\\n switch (round) {\\n case 5:\\n while (c.getOffice(div, city).size < 6500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n case \\\"Mining\\\":\\n switch (round) {\\n case 5:\\n while (c.getOffice(div, city).size < 1500 && corpFunds(ns) >= c.getOfficeSizeUpgradeCost(div, city, 1)) c.upgradeOfficeSize(div, city, 1)\\n while (c.getOffice(div, city).numEmployees < c.getOffice(div, city).size && c.hireEmployee(div, city)) { }\\n resetOffice(ns, div, city)\\n {\\n setJob(div, city, \\\"Operations\\\", Math.floor(c.getOffice(div, city).numEmployees / 4))\\n setJob(div, city, \\\"Business\\\", 1)\\n setJob(div, city, \\\"Engineer\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n setJob(div, city, \\\"Management\\\", Math.floor(c.getOffice(div, city).numEmployees / 3))\\n const office = c.getOffice(div, city)\\n const left = office.numEmployees - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 3) - Math.floor(c.getOffice(div, city).numEmployees / 4) - 1\\n setJob(div, city, \\\"Research & Development\\\", left)\\n }\\n break\\n }\\n break\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction resetOffice(ns, div, city) {\\n setJob(div, city, \\\"Operations\\\", 0)\\n setJob(div, city, \\\"Engineer\\\", 0)\\n setJob(div, city, \\\"Business\\\", 0)\\n setJob(div, city, \\\"Management\\\", 0)\\n setJob(div, city, \\\"Research & Development\\\", 0)\\n setJob(div, city, \\\"Intern\\\", 0)\\n}\\n/** @param {NS} ns */\\nfunction teaParty(ns) {\\n const c = ns.corporation\\n let needed = false\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n const office = c.getOffice(div, city)\\n if (office.avgEnergy < office.maxEnergy - .5) {\\n c.buyTea(div, city)\\n needed = true\\n }\\n if (office.avgMorale < office.maxMorale - 10) {\\n c.throwParty(div, city, 500000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale - 5) {\\n c.throwParty(div, city, 200000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale - .5) {\\n c.throwParty(div, city, 100000)\\n needed = true\\n }\\n else if (office.avgMorale < office.maxMorale) {\\n c.throwParty(div, city, 50000)\\n needed = false\\n }\\n }\\n }\\n return needed\\n}\\n/** @param {NS} ns */\\nfunction purchase(ns) {\\n const c = ns.corporation\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const smartBuy = []\\n const warehouse = c.getWarehouse(div, city)\\n if (!indDataDB[hasDivDB[div].type]) {\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n }\\n /* Process purchase of materials, not from smart supply */\\n for (const [matName, mat] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n // Smart supply\\n let buyAmt = maxMatRequired(ns, div, city, matName)\\n\\n buyAmt -= c.getMaterial(div, city, matName).stored\\n if (!matDataDB[matName])\\n matDataDB[matName] = c.getMaterialData(matName)\\n const maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / matDataDB[matName].size);\\n buyAmt = Math.min(buyAmt, maxAmt);\\n smartBuy[matName] = [buyAmt, mat];\\n } //End process purchase of materials\\n\\n // Use the materials already in the warehouse if the option is on.\\n for (const [matName, [buy, reqMat]] of Object.entries(smartBuy)) {\\n const buyAmt = buy\\n const mult = getMult(ns, div, city)\\n if (mult[0] === 0) {\\n c.buyMaterial(div, city, matName, 0)\\n c.sellMaterial(div, city, matName, \\\"MAX\\\", \\\"0\\\")\\n }\\n else if (buyAmt > 0) {\\n c.buyMaterial(div, city, matName, buyAmt / 10)\\n c.sellMaterial(div, city, matName, 0, \\\"MP\\\")\\n }\\n else {\\n c.buyMaterial(div, city, matName, 0)\\n if (c.getMaterial(div, city, matName).quality <= 1) c.sellMaterial(div, city, matName, buyAmt / 10 * -1, \\\"0\\\")\\n else c.sellMaterial(div, city, matName, buyAmt / 10 * -1, \\\"MP\\\")\\n }\\n }\\n }//city\\n }//div\\n\\n}\\n/** @param {NS} ns */\\nfunction basicExporImport(ns) {\\n const c = ns.corporation\\n if (!researchedDB[\\\"Export\\\"]) return\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n if (!indDataDB[hasDivDB[div].type].makesMaterials) continue\\n for (const city of cities) {\\n //We make this. Export it\\n for (const name of Object.values(indDataDB[hasDivDB[div].type].producedMaterials)) {\\n if (name === \\\"Plants\\\") { //(IPROD+IINV/10)*(-1) (-IPROD-IINV/10)\\n try { c.cancelExportMaterial(div, city, div3, \\\"Sector-12\\\", name) } catch { }\\n try { c.cancelExportMaterial(div, city, div3, city, name) } catch { }\\n try { c.cancelExportMaterial(div, city, div2, city, name) } catch { }\\n try { c.exportMaterial(div, city, div2, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div3, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div3, \\\"Sector-12\\\", name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Chemicals\\\") {\\n try { c.cancelExportMaterial(div, city, div1, city, name) } catch { }\\n try { c.exportMaterial(div, city, div1, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Food\\\") {\\n try { c.cancelExportMaterial(div, city, div4, \\\"Sector-12\\\", name) } catch { }\\n try { c.cancelExportMaterial(div, city, div4, city, name) } catch { }\\n try { c.exportMaterial(div, city, div4, \\\"Sector-12\\\", name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div4, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Water\\\") {\\n try { c.cancelExportMaterial(div, city, div1, city, name) } catch { }\\n try { c.cancelExportMaterial(div, city, div2, city, name) } catch { }\\n try { c.cancelExportMaterial(div, city, div4, city, name) } catch { }\\n try { c.exportMaterial(div, city, div1, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div2, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div4, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Hardware\\\") {\\n try { c.cancelExportMaterial(div, city, div5, city, name) } catch { }\\n try { c.cancelExportMaterial(div, city, div8, city, name) } catch { }\\n try { c.exportMaterial(div, city, div5, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n try { c.exportMaterial(div, city, div8, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Metal\\\") {\\n try { c.cancelExportMaterial(div, city, div6, city, name) } catch { }\\n try { c.exportMaterial(div, city, div6, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n else if (name === \\\"Ore\\\") {\\n try { c.cancelExportMaterial(div, city, div7, city, name) } catch { }\\n try { c.exportMaterial(div, city, div7, city, name, `(IPROD+IINV/10)*(-1)`) } catch { }\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction optimizeMats(ns) {\\n const c = ns.corporation\\n const round = investOffer.round\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n let maxProd = maxProduced(ns, div, city)\\n if (round < 3) maxProd *= 1.01\\n else maxProd *= 1.1\\n const warehouse = c.getWarehouse(div, city)\\n //[Hardware, Robots, AI Cores, Real Estate]\\n const [hardware, robots, aicores, realestate] = optimizeCorpoMaterials(ns, div, warehouse.size - maxProd)\\n const hardwareStored = c.getMaterial(div, city, \\\"Hardware\\\").stored\\n if (hardwareStored === hardware) {\\n c.buyMaterial(div, city, \\\"Hardware\\\", 0)\\n c.sellMaterial(div, city, \\\"Hardware\\\", 0, \\\"MP\\\")\\n }\\n else if (hardwareStored < hardware) {\\n if (round >= 4) c.buyMaterial(div, city, \\\"Hardware\\\", (hardware - hardwareStored) / 10 / 10)\\n else c.buyMaterial(div, city, \\\"Hardware\\\", (hardware - hardwareStored) / 10)\\n c.sellMaterial(div, city, \\\"Hardware\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n c.sellMaterial(div, city, \\\"Hardware\\\", (hardwareStored - hardware) / 10 / 10, \\\"0\\\")\\n }\\n else c.sellMaterial(div, city, \\\"Hardware\\\", (hardwareStored - hardware) / 10, \\\"MP\\\")\\n c.buyMaterial(div, city, \\\"Hardware\\\", 0)\\n }\\n\\n const robotsStored = c.getMaterial(div, city, \\\"Robots\\\").stored\\n if (robotsStored === robots) {\\n c.buyMaterial(div, city, \\\"Robots\\\", 0)\\n c.sellMaterial(div, city, \\\"Robots\\\", 0, \\\"MP\\\")\\n }\\n else if (robotsStored < robots) {\\n if (round >= 4) c.buyMaterial(div, city, \\\"Robots\\\", (robots - robotsStored) / 10 / 10)\\n else c.buyMaterial(div, city, \\\"Robots\\\", (robots - robotsStored) / 10)\\n c.sellMaterial(div, city, \\\"Robots\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n (c.sellMaterial(div, city, \\\"Robots\\\", (robotsStored - robots) / 10 / 10, \\\"0\\\"))\\n }\\n else c.sellMaterial(div, city, \\\"Robots\\\", (robotsStored - robots) / 10, \\\"MP\\\")\\n c.buyMaterial(div, city, \\\"Robots\\\", 0)\\n }\\n\\n const aiCoresStored = c.getMaterial(div, city, \\\"AI Cores\\\").stored\\n if (aiCoresStored === aicores) {\\n c.buyMaterial(div, city, \\\"AI Cores\\\", 0)\\n c.sellMaterial(div, city, \\\"AI Cores\\\", 0, \\\"MP\\\")\\n }\\n else if (aiCoresStored < aicores) {\\n if (round >= 4) c.buyMaterial(div, city, \\\"AI Cores\\\", (aicores - aiCoresStored) / 10 / 10)\\n else c.buyMaterial(div, city, \\\"AI Cores\\\", (aicores - aiCoresStored) / 10)\\n c.sellMaterial(div, city, \\\"AI Cores\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n (c.sellMaterial(div, city, \\\"AI Cores\\\", (aiCoresStored - aicores) / 10 / 10, \\\"0\\\"))\\n }\\n else c.sellMaterial(div, city, \\\"AI Cores\\\", (aiCoresStored - aicores) / 10, \\\"MP\\\")\\n c.buyMaterial(div, city, \\\"AI Cores\\\", 0)\\n }\\n\\n const realEstateStored = c.getMaterial(div, city, \\\"Real Estate\\\").stored\\n if (realEstateStored === realestate) {\\n c.buyMaterial(div, city, \\\"Real Estate\\\", 0)\\n c.sellMaterial(div, city, \\\"Real Estate\\\", 0, \\\"MP\\\")\\n }\\n else if (realEstateStored < realestate) {\\n if (round >= 4) c.buyMaterial(div, city, \\\"Real Estate\\\", (realestate - realEstateStored) / 10 / 10)\\n else c.buyMaterial(div, city, \\\"Real Estate\\\", (realestate - realEstateStored) / 10)\\n c.sellMaterial(div, city, \\\"Real Estate\\\", 0, \\\"MP\\\")\\n }\\n else {\\n if (round >= 4) {\\n c.sellMaterial(div, city, \\\"Real Estate\\\", (realEstateStored - realestate) / 10 / 10, \\\"0\\\")\\n }\\n else c.sellMaterial(div, city, \\\"Real Estate\\\", (realEstateStored - realestate) / 10, \\\"MP\\\")\\n c.buyMaterial(div, city, \\\"Real Estate\\\", 0)\\n }\\n }\\n }\\n}\\nfunction optimizeCorpoMaterials_raw(matSizes, divWeights, spaceConstraint, round) {\\n let p = divWeights.reduce((a, b) => a + b, 0);\\n let w = matSizes.reduce((a, b) => a + b, 0);\\n let r = [];\\n for (let i = 0; i < matSizes.length; ++i) {\\n let m = (spaceConstraint - 500 * ((matSizes[i] / divWeights[i]) * (p - divWeights[i]) - (w - matSizes[i]))) / (p / divWeights[i]) / matSizes[i];\\n if (divWeights[i] <= 0 || m < 0) {\\n return optimizeCorpoMaterials_raw(matSizes.toSpliced(i, 1), divWeights.toSpliced(i, 1), spaceConstraint, round).toSpliced(i, 0, 0);\\n } else {\\n if (round) m = Math.round(m);\\n r.push(m);\\n }\\n }\\n return r;\\n}\\n//SpaceConstraint is how much space to dedicate to it\\n/** @param {NS} ns */\\nfunction optimizeCorpoMaterials(ns, div, spaceConstraint, round = true) {\\n const type = hasDivDB[div].type\\n if (!indDataDB[type])\\n indDataDB[type] = ns.corporation.getIndustryData(type)\\n let { hardwareFactor, robotFactor, aiCoreFactor, realEstateFactor } = indDataDB[type]\\n if (isNaN(hardwareFactor)) hardwareFactor = 0\\n if (isNaN(robotFactor)) robotFactor = 0\\n if (isNaN(aiCoreFactor)) aiCoreFactor = 0\\n if (isNaN(realEstateFactor)) realEstateFactor = 0\\n\\n const divWeights = [hardwareFactor, robotFactor, aiCoreFactor, realEstateFactor]\\n if (!matDataDB[\\\"Hardware\\\"])\\n matDataDB[\\\"Hardware\\\"] = ns.corporation.getMaterialData(\\\"Hardware\\\")\\n if (!matDataDB[\\\"Robots\\\"])\\n matDataDB[\\\"Robots\\\"] = ns.corporation.getMaterialData(\\\"Robots\\\")\\n if (!matDataDB[\\\"AI Cores\\\"])\\n matDataDB[\\\"AI Cores\\\"] = ns.corporation.getMaterialData(\\\"AI Cores\\\")\\n if (!matDataDB[\\\"Real Estate\\\"])\\n matDataDB[\\\"Real Estate\\\"] = ns.corporation.getMaterialData(\\\"Real Estate\\\")\\n const matSizes = [\\\"Hardware\\\", \\\"Robots\\\", \\\"AI Cores\\\", \\\"Real Estate\\\"].map((mat) => matDataDB[mat].size)\\n return optimizeCorpoMaterials_raw(matSizes, divWeights, spaceConstraint, round)\\n}\\n/** @param {NS} ns */\\nfunction maxProduction(ns, div, city) {\\n if (!hasWarehouseDB[div + city]) return [0, 0]\\n const mult = getMult(ns, div, city)\\n return [10 * mult[0], 10 * mult[1]]\\n}\\n/** @param {NS} ns */\\nfunction maxMatRequired(ns, div, city, matID) {\\n const c = ns.corporation\\n if (!hasDivDB[div]) return 0\\n if (!hasWarehouseDB[div + city]) return 0\\n let productMult = 0\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n let products = 0\\n const division = c.getDivision(div)\\n for (const prod of division.products)\\n if (c.getProduct(div, city, prod).developmentProgress === 100)\\n products++\\n productMult = products\\n }\\n else productMult = 1\\n\\n for (const [matName, mat] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n if (matName !== matID) continue\\n // Smart supply\\n let required = 0\\n const mult = getMult(ns, div, city)\\n if (hasDivDB[div].makesProducts) required += 10 * mult[1] * mat * productMult\\n if (indDataDB[hasDivDB[div].type].makesMaterials) required += 10 * mult[0] * mat\\n return required\\n } //End process purchase of materials\\n return 0\\n}\\n/** @param {NS} ns */\\nfunction maxProduced(ns, div, city) {\\n const c = ns.corporation\\n if (!hasWarehouseDB[div + city]) return 0\\n const mult = getMult(ns, div, city)\\n const multMaterial = mult[0]\\n const multProduct = mult[1]\\n if (multMaterial === 0) return 0\\n\\n let totalSize = 0\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n for (const [matName, matAmount] of Object.entries(indDataDB[hasDivDB[div].type].requiredMaterials)) {\\n if (matDataDB[matName] === undefined)\\n matDataDB[matName] = c.getMaterialData(matName)\\n totalSize += maxMatRequired(ns, div, city, matName) * matDataDB[matName].size\\n }\\n if (indDataDB[hasDivDB[div].type].makesMaterials)\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n if (matDataDB[mat] === undefined)\\n matDataDB[mat] = c.getMaterialData(mat)\\n totalSize += matDataDB[mat].size * 10 * multMaterial\\n totalSize += c.getMaterial(div, city, mat).stored * matDataDB[mat].size\\n }\\n const division = c.getDivision(div)\\n for (const prod of division.products)\\n if (c.getProduct(div, city, prod).developmentProgress === 100) {\\n totalSize += c.getProduct(div, city, prod).size * 10 * multProduct\\n totalSize += c.getProduct(div, city, prod).stored * c.getProduct(div, city, prod).size\\n }\\n return totalSize\\n}\\n/** @param {NS} ns */\\nfunction warehouseUpgrade(ns) {\\n const c = ns.corporation\\n const round = investOffer.round\\n\\n let hasDiv2 = false\\n let count = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div2 + city]) count++\\n if (count === 6)\\n hasDiv2 = true\\n\\n let hasDiv3 = false\\n let cityCount = 0\\n for (const city of cities)\\n if (hasWarehouseDB[div3 + city]) cityCount++\\n if (cityCount === 6) hasDiv3 = true\\n\\n while (count < 8) {\\n if (round >= 3) count++\\n let smartStorageIncrease = 0\\n const smartStorage = c.getUpgradeLevel(\\\"Smart Storage\\\")\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n if (round === 2 && hasDivDB[div].type === \\\"Chemical\\\") continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const warehouse = c.getWarehouse(div, city)\\n let divMult = researchedDB[div + \\\"Drones - Transport\\\"] ? 1.5 : 1\\n smartStorageIncrease += (warehouse.level * 100 * (1 + ((smartStorage + 1) * .1)) * divMult) - (warehouse.level * 100 * (1 + (smartStorage * .1)) * divMult)\\n }\\n }\\n const funds = corpFunds(ns)\\n if ((hasDiv2 && smartStorage >= 30)\\n || (!hasDiv2 && smartStorage >= 10))\\n smartStorageIncrease = 0\\n\\n let bestUpgradeType = \\\"none\\\"\\n let bestUpgradeCity = \\\"none\\\"\\n let bestUpgradeRatio = 0\\n let bestAgriCity = \\\"none\\\"\\n let bestAgriRatio = 0\\n let bestChemCity = \\\"none\\\"\\n let bestChemRatio = 0\\n let bestWaterCity = \\\"none\\\"\\n let bestWaterRatio = 0\\n let bestComputerCity = \\\"none\\\"\\n let bestComputerRatio = 0\\n let bestRefineryCity = \\\"none\\\"\\n let bestRefineryRatio = 0\\n let bestMiningCity = \\\"none\\\"\\n let bestMiningRatio = 0\\n const smartUpgrade = c.getUpgradeLevelCost(\\\"Smart Storage\\\")\\n let smartRatio = smartStorageIncrease === 0 ? 0 : smartStorageIncrease / smartUpgrade\\n\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n const warehouse = c.getWarehouse(div, city)\\n const warehouseUpgrade = c.getUpgradeWarehouseCost(div, city)\\n const smartStorageMult = 1 + (smartStorage * .1)\\n let divMult = 1\\n try { divMult = researchedDB[div + \\\"Drones - Transport\\\"] ? 1.5 : 1 } catch { continue }\\n let warehouseIncrease = ((warehouse.level + 1) * 100 * smartStorageMult * divMult) - warehouse.size\\n let warehouseRatio = warehouseIncrease / warehouseUpgrade\\n\\n if (round === 2 && (warehouse.level === 2 || !hasDiv2) && hasDivDB[div].type === \\\"Chemical\\\") warehouseRatio = 0 //Early break on Chemical warehouse upgrade until we get all of Chemical\\n if (hasDivDB[div].type === \\\"Agriculture\\\" && warehouseRatio > bestAgriRatio) {\\n bestAgriCity = city\\n bestAgriRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Chemical\\\" && warehouseRatio > bestChemRatio) {\\n bestChemCity = city\\n bestChemRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Water Utilities\\\" && warehouseRatio > bestWaterRatio) {\\n bestWaterCity = city\\n bestWaterRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Computer Hardware\\\" && warehouseRatio > bestComputerRatio) {\\n bestComputerCity = city\\n bestComputerRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Refinery\\\" && warehouseRatio > bestRefineryRatio) {\\n bestRefineryCity = city\\n bestRefineryRatio = warehouseRatio\\n }\\n else if (hasDivDB[div].type === \\\"Mining\\\" && warehouseRatio > bestMiningRatio) {\\n bestMiningCity = city\\n bestMiningRatio = warehouseRatio\\n }\\n const maxProd = maxProduction(ns, div, city)\\n if (round >= 3 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div4, city, \\\"Food\\\") && maxProd[0] > (maxMatRequired(ns, div2, city, \\\"Plants\\\") + maxMatRequired(ns, div3, \\\"Sector-12\\\", \\\"Plants\\\")))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n if (round >= 3 && hasDivDB[div].type === \\\"Chemical\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div1, city, \\\"Chemicals\\\") || !hasDiv3)\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n if (round >= 5 && hasDivDB[div].type === \\\"Water Utilities\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div1, city, \\\"Water\\\") + maxMatRequired(ns, div2, city, \\\"Water\\\") + maxMatRequired(ns, div4, city, \\\"Water\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n if (round >= 5 && hasDivDB[div].type === \\\"Computer Hardware\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div5, city, \\\"Hardware\\\") + maxMatRequired(ns, div8, city, \\\"Hardware\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n if (round >= 5 && hasDivDB[div].type === \\\"Refinery\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div6, city, \\\"Metal\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n if (round >= 5 && hasDivDB[div].type === \\\"Mining\\\") {\\n if (maxProd[0] > maxMatRequired(ns, div7, city, \\\"Metal\\\"))\\n warehouseRatio = 0\\n else warehouseRatio *= .9\\n }\\n\\n if (round === 2 && !hasDiv2 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if (round === 2 && hasDiv2 && warehouse.level >= 20 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if (round === 3 && !hasDiv3 && hasDivDB[div].type === \\\"Agriculture\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if (round === 3 && !hasDiv3 && warehouse.level >= 3 && hasDivDB[div].type === \\\"Chemical\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if (round === 3 && !hasDiv3 && hasDivDB[div].type === \\\"Tobacco\\\") {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if (round === 2 && ((hasDivDB[div].type === \\\"Chemical\\\" && (warehouse.level === 2 || !hasDiv2)))) {\\n warehouseRatio = 0\\n smartRatio = 0\\n }\\n if ((round >= 3) && [\\\"Tobacco\\\", \\\"Restaurant\\\"].includes(hasDivDB[div].type) && warehouse.level >= 5)\\n warehouseRatio = 0\\n //Round 2 - upgrade chem once\\n if (round === 2 && hasDivDB[div].type === \\\"Chemical\\\" && warehouse.level === 1) {\\n bestUpgradeType = div\\n bestUpgradeCity = city\\n bestUpgradeRatio = Infinity\\n }\\n else if (warehouseRatio > smartRatio && warehouseRatio > bestUpgradeRatio) {\\n bestUpgradeType = div\\n bestUpgradeCity = city\\n bestUpgradeRatio = warehouseRatio\\n }\\n else if (smartRatio > bestUpgradeRatio) {\\n bestUpgradeType = \\\"Smart\\\"\\n bestUpgradeRatio = smartRatio\\n }\\n }\\n }\\n if (![\\\"Smart\\\", \\\"none\\\"].includes(bestUpgradeType)) {\\n if (hasDivDB[bestUpgradeType].type === \\\"Agriculture\\\") {\\n bestUpgradeCity = bestAgriCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Chemical\\\") {\\n bestUpgradeCity = bestChemCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Water Utilities\\\") {\\n bestUpgradeCity = bestWaterCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Computer Hardware\\\") {\\n bestUpgradeCity = bestComputerCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Refinery\\\") {\\n bestUpgradeCity = bestRefineryCity\\n }\\n else if (hasDivDB[bestUpgradeType].type === \\\"Mining\\\") {\\n bestUpgradeCity = bestMiningCity\\n }\\n }\\n if (round >= 3) {\\n if (bestUpgradeType === \\\"none\\\") break\\n else if (bestUpgradeType === \\\"Smart\\\" && funds >= c.getUpgradeLevelCost(\\\"Smart Storage\\\") * 1.5) {\\n c.levelUpgrade(\\\"Smart Storage\\\")\\n }\\n else if (bestUpgradeCity !== \\\"none\\\" && funds >= c.getUpgradeWarehouseCost(bestUpgradeType, bestUpgradeCity) * 1.5) {\\n c.upgradeWarehouse(bestUpgradeType, bestUpgradeCity)\\n }\\n else break\\n }\\n else {\\n if (bestUpgradeType === \\\"none\\\") break\\n else if (bestUpgradeType === \\\"Smart\\\" && funds >= c.getUpgradeLevelCost(\\\"Smart Storage\\\")) {\\n c.levelUpgrade(\\\"Smart Storage\\\")\\n }\\n else if (bestUpgradeCity !== \\\"none\\\" && funds >= c.getUpgradeWarehouseCost(bestUpgradeType, bestUpgradeCity)) {\\n c.upgradeWarehouse(bestUpgradeType, bestUpgradeCity)\\n }\\n else break\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction getSellPrice(ns, div, city, prod) {\\n const c = ns.corporation\\n const ta2 = ta2DB[div + city + prod]\\n if (ta2 === undefined || ta2.markupLimit === 0) return 0\\n const product = c.getProduct(div, city, prod)\\n const prodMarketPrice = 5 * product.productionCost\\n return (((ta2.markupLimit * Math.sqrt(1)) / Math.sqrt(1)) + prodMarketPrice) * 10\\n}\\n/** @param {NS} ns */\\nfunction sell(ns) {\\n const c = ns.corporation\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n const hasMTAII = c.hasResearched(div, \\\"Market-TA.II\\\")\\n for (const city of cities) {\\n if (!hasWarehouseDB[div + city]) continue\\n if (researchedDB[\\\"Market Research - Demand\\\"] && researchedDB[\\\"Market Data - Competition\\\"]) {\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n const division = c.getDivision(div)\\n for (const prod of division.products) {\\n if (c.getProduct(div, city, prod).developmentProgress !== 100) continue\\n if (c.getProduct(div, city, prod).stored === 0) continue\\n //Setting Market TA II if researchedDB\\n if (hasMTAII) { //I don't research it, but it could be there from manual purchase\\n c.setProductMarketTA2(div, prod, true)\\n c.sellProduct(div, city, prod, \\\"MAX\\\", \\\"0\\\")\\n continue\\n }\\n\\n let ta2 = ta2DB[div + city + prod]\\n const product = c.getProduct(div, city, prod)\\n if (ta2 === undefined) { //No TA2 data\\n ta2DB[div + city + prod] = {\\n \\\"sellingPrice\\\": product.rating,\\n \\\"sellingQuantity\\\": product.stored,\\n \\\"markupLimit\\\": 0\\n }\\n c.sellProduct(div, city, prod, \\\"MAX\\\", (product.rating).toString())\\n continue\\n }\\n const prodMarketPrice = 5 * product.productionCost\\n if (ta2.markupLimit === 0) { //Not calculated yet\\n const actualSellAmount = product.actualSellAmount\\n if (actualSellAmount >= ta2.sellingQuantity / 10) { // We failed to set it high enough. Set it higher and try again\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice * 1000\\n ta2DB[div + city + prod].sellingQuantity = product.stored\\n c.sellProduct(div, city, prod, \\\"MAX\\\", (oldSalePrice * 1000).toString())\\n continue\\n }\\n else if (actualSellAmount <= ta2.sellingQuantity / 10 * .15) { //Not enough sold, lower the price!\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice / 3\\n ta2DB[div + city + prod].sellingQuantity = product.stored\\n c.sellProduct(div, city, prod, \\\"MAX\\\", (oldSalePrice / 3).toString())\\n continue\\n }\\n const mult = getMult(ns, div, city)\\n const m = mult[1]\\n const markupLimit = (ta2.sellingPrice - prodMarketPrice) * Math.sqrt(actualSellAmount / m)\\n ta2DB[div + city + prod].markupLimit = markupLimit\\n ta2 = ta2DB[div + city + prod]\\n }\\n const prodStored = product.stored\\n let sellingPrice = (((ta2.markupLimit * Math.sqrt(prodStored)) / Math.sqrt(prodStored)) + prodMarketPrice) * 10\\n const priceMult = product.productionAmount / prodStored\\n if (priceMult !== Infinity) sellingPrice *= priceMult >= 1 ? 1 : priceMult\\n if (sellingPrice < 0 || isNaN(sellingPrice)) {\\n const oldSalePrice = ta2DB[div + city + prod].sellingPrice\\n ta2DB[div + city + prod].sellingPrice = oldSalePrice * 10\\n ta2DB[div + city + prod].sellingQuantity = prodStored\\n ta2DB[div + city + prod].markupLimit = 0\\n c.sellProduct(div, city, prod, \\\"MAX\\\", (oldSalePrice * 10).toString())\\n continue\\n }\\n c.sellProduct(div, city, prod, \\\"MAX\\\", sellingPrice.toString())\\n } //Products\\n } //Product check\\n if (indDataDB[hasDivDB[div].type].producedMaterials)\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n const material = c.getMaterial(div, city, mat)\\n let exported = 0\\n for (const xp of material.exports)\\n exported += c.getMaterial(xp.division, xp.city, mat).importAmount\\n if (material.stored === 0) continue\\n //Set TA2 if we have it\\n if (researchedDB[div + \\\"Market-TA.II\\\"]) {\\n c.setMaterialMarketTA2(div, city, mat, true)\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", \\\"0\\\")\\n continue\\n }\\n let ta2 = ta2DB[div + city + mat]\\n if (ta2 === undefined) { //No TA2 data \\n ta2DB[div + city + mat] = {\\n \\\"sellingPrice\\\": material.marketPrice,\\n \\\"sellingQuantity\\\": material.stored + (exported * 10),\\n \\\"markupLimit\\\": 0\\n }\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", (material.marketPrice).toString())\\n continue\\n }\\n const prodMarketPrice = material.marketPrice\\n const mult = getMult(ns, div, city)\\n const m = mult[0]\\n if (ta2.markupLimit === 0) { //Not calculated yet\\n const actualSellAmount = material.actualSellAmount\\n if (actualSellAmount >= (ta2.sellingQuantity) / 10) { // We failed to set it high enough. Set it higher and try again\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * 1.2\\n ta2DB[div + city + mat].sellingQuantity = material.stored + (exported * 10)\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", (oldSalePrice * 1.2).toString())\\n continue\\n }\\n else if (actualSellAmount <= (ta2.sellingQuantity) / 10 * .1) { //Not enough sold, lower the price!\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * .9\\n ta2DB[div + city + mat].sellingQuantity = material.stored + (exported * 10)\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", (oldSalePrice * .9).toString())\\n continue\\n }\\n const markupLimit = (ta2.sellingPrice - prodMarketPrice) * Math.sqrt(actualSellAmount / m)\\n ta2DB[div + city + mat].markupLimit = markupLimit\\n ta2 = ta2DB[div + city + mat]\\n }\\n const prodStored = material.stored\\n let sellingPrice = (((ta2.markupLimit * Math.sqrt(prodStored)) / Math.sqrt(prodStored)) + prodMarketPrice) * 10\\n const priceMult = (material.productionAmount - exported) / prodStored\\n if (priceMult !== Infinity) sellingPrice *= priceMult >= 1 ? 1 : priceMult\\n if (sellingPrice < 0 || isNaN(sellingPrice)) {\\n const oldSalePrice = ta2DB[div + city + mat].sellingPrice\\n ta2DB[div + city + mat].sellingPrice = oldSalePrice * 2\\n ta2DB[div + city + mat].sellingQuantity = prodStored + (exported * 10)\\n ta2DB[div + city + mat].markupLimit = 0\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", (oldSalePrice * 2).toString())\\n continue\\n }\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", sellingPrice.toString())\\n }\\n } //TA2\\n else { // No TA2\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n if (indDataDB[hasDivDB[div].type].producedMaterials) {\\n for (const mat of indDataDB[hasDivDB[div].type].producedMaterials) {\\n const material = c.getMaterial(div, city, mat)\\n if (material.stored === 0) continue\\n const marketPrice = material.marketPrice\\n if (!matDataDB[mat])\\n matDataDB[mat] = c.getMaterialData(mat)\\n let price = marketPrice + (material.quality / matDataDB[mat].baseMarkup)\\n const maxProd = maxProduction(ns, div, city)\\n const priceMult = maxProd[0] / (material.stored)\\n price *= priceMult >= 1 ? 1 : priceMult >= .6 ? priceMult : priceMult / 10\\n c.sellMaterial(div, city, mat, \\\"MAX\\\", price)\\n }\\n }\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction getMult(ns, div, city) {\\n const c = ns.corporation\\n if (!hasOfficeDB[div + city]) return [0, 0]\\n const office = c.getOffice(div, city)\\n const operationEmployeesProduction = office.employeeProductionByJob.Operations\\n const engineerEmployeesProduction = office.employeeProductionByJob.Engineer\\n const managementEmployeesProduction = office.employeeProductionByJob.Management\\n const totalEmployeesProduction = operationEmployeesProduction + engineerEmployeesProduction + managementEmployeesProduction;\\n if (totalEmployeesProduction <= 0) return [0, 0]\\n const managementFactor = 1 + managementEmployeesProduction / (1.2 * totalEmployeesProduction)\\n const employeesProductionMultiplier = (Math.pow(operationEmployeesProduction, 0.4) + Math.pow(engineerEmployeesProduction, 0.3)) * managementFactor;\\n const balancingMultiplier = 0.05;\\n const officeMultiplierProduct = 0.5 * balancingMultiplier * employeesProductionMultiplier;\\n const officeMultiplierMaterial = balancingMultiplier * employeesProductionMultiplier;\\n\\n // Multiplier from Smart Factories\\n const upgradeMultiplier = 1 + (c.getUpgradeLevel(\\\"Smart Factories\\\") * 0.03)\\n // Multiplier from researches\\n let researchMultiplier = 1\\n researchMultiplier *=\\n (researchedDB[div + \\\"Drones - Assembly\\\"] ? 1.2 : 1)\\n * (researchedDB[div + \\\"Self-Correcting Assemblers\\\"] ? 1.1 : 1);\\n if (hasDivDB[div].makesProducts) {\\n researchMultiplier *= (researchedDB[div + \\\"uPgrade: Fulcrum\\\"] ? 1.05 : 1);\\n }\\n let multSum = 0;\\n if (!indDataDB[hasDivDB[div].type])\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(hasDivDB[div].type)\\n for (const scity of cities) {\\n if (!hasWarehouseDB[div + scity]) continue\\n let realestate = Math.pow(0.002 * c.getMaterial(div, scity, \\\"Real Estate\\\").stored + 1, indDataDB[hasDivDB[div].type].realEstateFactor)\\n let hardware = Math.pow(0.002 * c.getMaterial(div, scity, \\\"Hardware\\\").stored + 1, indDataDB[hasDivDB[div].type].hardwareFactor)\\n let robots = Math.pow(0.002 * c.getMaterial(div, scity, \\\"Robots\\\").stored + 1, indDataDB[hasDivDB[div].type].robotFactor)\\n let aicores = Math.pow(0.002 * c.getMaterial(div, scity, \\\"AI Cores\\\").stored + 1, indDataDB[hasDivDB[div].type].aiCoreFactor);\\n if (isNaN(realestate)) realestate = 1\\n if (isNaN(hardware)) hardware = 1\\n if (isNaN(robots)) robots = 1\\n if (isNaN(aicores)) aicores = 1\\n const cityMult =\\n realestate *\\n hardware *\\n robots *\\n aicores\\n multSum += Math.pow(cityMult, 0.73);\\n }\\n const productionMult = multSum < 1 ? 1 : multSum\\n const multMaterial = officeMultiplierMaterial * productionMult * upgradeMultiplier * researchMultiplier\\n const multProduct = officeMultiplierProduct * productionMult * upgradeMultiplier * researchMultiplier\\n return [multMaterial, multProduct]\\n}\\n\\n/** @param {NS} ns */\\nfunction currentBN(ns) {\\n return ns.getResetInfo().currentNode\\n}\\n\\n/** @param {NS} ns */\\nfunction updateHud(ns) {\\n ns.clearLog()\\n const c = ns.corporation\\n const cObj = c.getCorporation()\\n const bnMults = getBNMults(ns)\\n ns.printf(\\\"%s\\\", cObj.name)\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"Funds : $%s Profit: $%s/s\\\", ns.format.number(cObj.funds, 3), ns.format.number(cObj.revenue - cObj.expenses, 3))\\n else ns.printf(\\\"Funds : $%s Profit: $%s/s\\\", ns.format.number(cObj.funds, 3), ns.format.number(cObj.revenue - cObj.expenses, 3))\\n const invest = investOffer\\n const upgrades = c.getUpgradeLevel(\\\"Neural Accelerators\\\")\\n + c.getUpgradeLevel(\\\"Project Insight\\\")\\n + c.getUpgradeLevel(\\\"Nuoptimal Nootropic Injector Implants\\\")\\n + c.getUpgradeLevel(\\\"FocusWires\\\")\\n + c.getUpgradeLevel(\\\"Speech Processor Implants\\\")\\n + c.getUpgradeLevel(\\\"FocusWires\\\")\\n const offer = invest.round === 1 ? (round1Money * bnMults.CorporationValuation)\\n : invest.round === 2 ? (round2Money * bnMults.CorporationValuation)\\n : invest.round === 3 ? (round3Money * bnMults.CorporationValuation)\\n : invest.round === 4 ? (round4Money * bnMults.CorporationValuation)\\n : 0\\n const minRound = invest.round === 2 ? \\\"-BareMin 30b\\\" : \\\"\\\"\\n const produpgrades = c.getUpgradeLevel(\\\"Smart Factories\\\") + c.getUpgradeLevel(\\\"Smart Storage\\\")\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"Round: %s Offer: %s FundsReq: %s %s\\\", invest.round, ns.format.number(invest.funds, 3), ns.format.number(offer, 3), minRound)\\n else ns.printf(\\\"Round: %s Offer: %s FundsReq: %s %s\\\", invest.round, ns.format.number(invest.funds, 3), ns.format.number(offer, 3), minRound)\\n if (ns.ui.getGameInfo()?.versionNumber >= 44)\\n ns.printf(\\\"Empl Upgrades: %s Prod Upgrades: %s Profit Upgrades: %s Wilson: %s\\\", upgrades, produpgrades, c.getUpgradeLevel(\\\"ABC SalesBots\\\"), c.getUpgradeLevel(\\\"Wilson Analytics\\\"))\\n else\\n ns.printf(\\\"Empl Upgrades: %s Prod Upgrades: %s Profit Upgrades: %s Wilson: %s Dream: %s/1\\\", upgrades, produpgrades, c.getUpgradeLevel(\\\"ABC SalesBots\\\"), c.getUpgradeLevel(\\\"Wilson Analytics\\\"), c.getUpgradeLevel(\\\"DreamSense\\\"))\\n const state = cObj.nextState === \\\"PURCHASE\\\" ? \\\"START\\\"\\n : cObj.nextState === \\\"PRODUCTION\\\" ? \\\"PURCHASE\\\"\\n : cObj.nextState === \\\"EXPORT\\\" ? \\\"PRODUCTION\\\"\\n : cObj.nextState === \\\"SALE\\\" ? \\\"EXPORT\\\"\\n : \\\"SALE\\\"\\n ns.printf(\\\"Stage: %s\\\", state)\\n for (const div of industries) {\\n if (!hasDivDB[div]) continue\\n const division = c.getDivision(div)\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\"-%s(%s) Profit: $%s/s Awareness: %s Pop: %s\\\", div, division.type, ns.format.number(division.lastCycleRevenue - division.lastCycleExpenses, 3), ns.format.number(division.awareness, 3), ns.format.number(division.popularity, 3))\\n else ns.printf(\\\"-%s(%s) Profit: $%s/s Awareness: %s Pop: %s\\\", div, division.type, ns.format.number(division.lastCycleRevenue - division.lastCycleExpenses, 3), ns.format.number(division.awareness, 3), ns.format.number(division.popularity, 3))\\n let wCount = 0\\n let wSpace = 0\\n let wSpaceUsed = 0\\n let oCount = 0\\n let oEmployees = 0\\n let oSize = 0\\n for (const city of cities) {\\n if (!hasOfficeDB[div + city]) continue\\n if (hasWarehouseDB[div + city]) {\\n wCount++\\n const warehouse = c.getWarehouse(div, city)\\n wSpace += warehouse.size\\n wSpaceUsed += warehouse.sizeUsed\\n }\\n try {\\n const office = c.getOffice(div, city)\\n oEmployees += office.numEmployees\\n oCount++\\n oSize += office.size\\n }\\n catch { }\\n }\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\" Warehouse Space: (%s/6) %s/%s Office Usage: (%s/6) %s/%s Research: %s\\\", wCount, Math.round(wSpaceUsed), Math.round(wSpace), oCount, oEmployees, oSize, ns.format.number(division.researchPoints, 3))\\n else ns.printf(\\\" Warehouse Space: (%s/6) %s/%s Office Usage: (%s/6) %s/%s Research: %s\\\", wCount, Math.round(wSpaceUsed), Math.round(wSpace), oCount, oEmployees, oSize, ns.format.number(division.researchPoints, 3))\\n if (indDataDB[hasDivDB[div].type] === undefined)\\n indDataDB[hasDivDB[div].type] = c.getIndustryData(division.type)\\n if (indDataDB[hasDivDB[div].type].makesProducts) {\\n for (const product of division.products) {\\n const prog = c.getProduct(div, \\\"Sector-12\\\", product).developmentProgress\\n const sellPrice = getSellPrice(ns, div, \\\"Sector-12\\\", product)\\n if (prog === 100) {\\n if (sellPrice === 0) ns.printf(\\\" Calculating - %s\\\", product)\\n else {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\" $%s - %s\\\", ns.format.number(getSellPrice(ns, div, \\\"Sector-12\\\", product), 3), product)\\n else ns.printf(\\\" $%s - %s\\\", ns.format.number(getSellPrice(ns, div, \\\"Sector-12\\\", product), 3), product)\\n }\\n }\\n else {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) ns.printf(\\\" %s%s - %s\\\", ns.format.number(prog, 2), \\\"%\\\", product)\\n else ns.printf(\\\" %s%s - %s\\\", ns.format.number(prog, 2), \\\"%\\\", product)\\n }\\n }\\n }\\n }\\n ns.ui.renderTail()\\n}\\n\\n\\n/** @param {NS} ns */\\nfunction getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,\\n \\\"CloudServerSoftcap\\\": 1,\\n \\\"CloudServerLimit\\\": 1,\\n \\\"CloudServerMaxRam\\\": 1,\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\\n\\n\\nconst cities = [\\\"Sector-12\\\", \\\"Aevum\\\", \\\"Volhaven\\\", \\\"Chongqing\\\", \\\"New Tokyo\\\", \\\"Ishima\\\"]\\nconst industries = [div1, div2, div3, div4, div5, div6, div7, div8]\\nconst cigaretts = [\\\"Pall Mall\\\", \\\"Camel\\\", \\\"Marlboro\\\", \\\"Kool\\\", \\\"American Spirit\\\", \\\"Bastos\\\", \\\"Philip Morris\\\", \\\"USA Gold\\\", \\\"Winston\\\", \\\"Backwoods Smokes\\\", \\\"Capstan\\\", \\\"Chesterfield\\\", \\\"Davidoff\\\", \\\"Maverick\\\", \\\"Newport\\\", \\\"Black Devil\\\", \\\"Dunhill\\\", \\\"Rothman\\\\'s\\\"]\\nconst burgers = [\\\"Double Bacon Cheeseburger\\\", \\\"Plain Hamburger\\\", \\\"Pickle Burger\\\", \\\"Onion Burger\\\", \\\"Turkey Burger\\\", \\\"Mozza Burger\\\", \\\"Chili Cheeseburger\\\", \\\"Tropical Burger\\\", \\\"The BLT\\\", \\\"Spicy Extreem Burger\\\", \\\"Deconstructed Burger\\\", \\\"Junior Delux\\\"]\\nconst hardwares = [\\\"Home Entertainment Threater\\\", \\\"Next-Gen Graphics Card\\\", \\\"Portable Soldering Kit (PSK)\\\", \\\"Advanced Micro-Fluidics Home Kit\\\", \\\"xPhone MAX\\\", \\\"Hyper-RAM\\\", \\\"Superior xDisplay\\\", \\\"A Lamp (It's just a lamp)\\\", \\\"Personal Electric Transportation ULTRA\\\"]\""},{"filename":"SphyxOS/full/gangStandAlone.js","file":"\"const WIDTH = 1055\\nconst HEIGHT = 660\\nconst GANG_NAME = \\\"Slum Snakes\\\"\\nconst MAX_MEMBERS = 12\\nconst WIN_WAR_CHANCE = .8\\nconst WAR_CUTOFF = .9\\nconst PURCHASE_UNLOCK = 6000\\nconst MIN_TERRITORY_START_WAR = .99\\nconst COMBAT_STAT_TRAIN = 60\\nconst WORKERS = 9 / 12\\nlet BUYING_GEAR = false\\nlet MODE = \\\"Respect\\\" //Respect, Money, Regular\\nlet AUTO = true //Whether or not we automatically switch workers, turn on buying eq, ascend, etc.\\nlet memberNames;\\nlet fullMembers;\\nlet gangInfo;\\nlet otherGangInfo;\\nlet respectForNext;\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n\\n let count = 0\\n let prev = 0\\n //Are we in a gang yet?\\n ns.gang.createGang(GANG_NAME)\\n while (!ns.gang.inGang()) {\\n \\n ns.gang.createGang(GANG_NAME)\\n count--\\n if (count < 0) {\\n count = 30\\n const karma = ns.heart.break()\\n let result = 0\\n if (prev === 0) {\\n result = 0\\n }\\n else {\\n result = ((-54000 - karma) / ((karma - prev) / 30)) * 1000\\n }\\n ns.clearLog()\\n ns.printf(\\\"Karma: %s / -54000 ETA: %s\\\", karma.toFixed(0), ns.format.time(result))\\n ns.printf(\\\"Join Slum Snakes\\\")\\n prev = karma\\n }\\n await ns.sleep(1000)\\n }\\n ns.ui.resizeTail(WIDTH, HEIGHT)\\n MODE = ns.args.includes(\\\"money\\\") ? \\\"Money\\\" : \\\"Respect\\\"\\n while (true) {\\n memberNames = ns.gang.getMemberNames()\\n fullMembers = memberNames.map((m) => ns.gang.getMemberInformation(m))\\n gangInfo = ns.gang.getGangInformation()\\n otherGangInfo = ns.gang.getOtherGangInformation()\\n respectForNext = ns.gang.respectForNextRecruit()\\n\\n BUYING_GEAR = AUTO && memberNames.length === MAX_MEMBERS ? true : AUTO ? false : BUYING_GEAR\\n if (memberNames.length !== MAX_MEMBERS) gangRecruit(ns)\\n if (AUTO && BUYING_GEAR) gangEquip(ns)\\n gangAscend(ns)\\n const territoryWinChance = war(ns)\\n assignMembers(ns, territoryWinChance)\\n\\n updateDisplay(ns)\\n //Read in commands - auto, reputation, money, equip, ascend\\n await ns.sleep(200)\\n }\\n}\\n\\nfunction war(ns) {\\n if (gangInfo.territory < MIN_TERRITORY_START_WAR) {\\n let lowestwinchance = 1\\n\\n for (const otherGang of combatGangs.concat(hackingGangs)) {\\n if (otherGang == gangInfo.faction) {\\n continue\\n }\\n else if (otherGangInfo[otherGang].territory <= 0) {\\n continue\\n }\\n else {\\n let othergangpower = otherGangInfo[otherGang].power\\n let winChance = gangInfo.power / (gangInfo.power + othergangpower)\\n lowestwinchance = Math.min(lowestwinchance, winChance)\\n }\\n }\\n if (lowestwinchance > WIN_WAR_CHANCE) {\\n if (!gangInfo.territoryWarfareEngaged) {\\n ns.gang.setTerritoryWarfare(true)\\n }\\n }\\n else if (gangInfo.territoryWarfareEngaged) {\\n ns.gang.setTerritoryWarfare(false)\\n }\\n return lowestwinchance\\n }\\n else if (gangInfo.territoryWarfareEngaged) {\\n ns.gang.setTerritoryWarfare(false)\\n }\\n return 1\\n}\\n/** @param {NS} ns */\\nfunction assignMembers(ns, territoryWinChance) {\\n const sortedNames = fullMembers.sort((a, b) => memberCombatStats(b) - memberCombatStats(a))\\n let workJobs = Math.ceil((memberNames.length) * WORKERS)\\n let wantedLevelIncrease = 0\\n for (let member of sortedNames) {\\n let highestTaskValue = 0\\n let highestValueTask = \\\"Train Combat\\\"\\n const vigilanteDecrease = fWantedGain(member, ns.gang.getTaskStats(\\\"Vigilante Justice\\\"))\\n if (workJobs > 0 && gangInfo.territory < 1 && memberNames.length >= MAX_MEMBERS && territoryWinChance < WAR_CUTOFF) {\\n // support territory warfare if max team size, not at max territory yet and win chance not high enough yet\\n workJobs--;\\n highestValueTask = \\\"Territory Warfare\\\";\\n }\\n else if (memberCombatStats(member) < COMBAT_STAT_TRAIN) {\\n highestValueTask = \\\"Train Combat\\\";\\n }\\n else if (workJobs > 0 && (wantedLevelIncrease + gangInfo.wantedLevel - 1 > vigilanteDecrease * -1 * 5 || wantedLevelIncrease + gangInfo.wantedLevel > 20)) {\\n workJobs--\\n highestValueTask = \\\"Vigilante Justice\\\"\\n wantedLevelIncrease += vigilanteDecrease * 5\\n }\\n else if (workJobs > 0) {\\n workJobs--;\\n for (const task of tasks.map((t) => ns.gang.getTaskStats(t))) {\\n if (taskValue(ns, member, task) > highestTaskValue) {\\n highestTaskValue = taskValue(ns, member, task)\\n highestValueTask = task;\\n }\\n }\\n wantedLevelIncrease += fWantedGain(member, highestValueTask) * 5\\n highestValueTask = highestValueTask.name\\n }\\n\\n if (member.task != highestValueTask) {\\n //ns.tprintf(\\\"Assign \\\" + member + \\\" to \\\" + highestValueTask);\\n ns.gang.setMemberTask(member.name, highestValueTask);\\n }\\n }\\n}\\nfunction memberCombatStats(member) {\\n return (member.str + member.def + member.dex + member.agi) / 4;\\n}\\n/** @param {NS} ns */\\nfunction taskValue(ns, member, task) {\\n // determine money and reputation gain for a task\\n let respect = fRespectGain(ns, member, task)\\n let cash = fMoneyGain(ns, member, task)//ns.formulas.gang.moneyGain(gangInfo, member, ns.gang.getTaskStats(task));\\n let wantedLevelIncrease = fWantedGain(member, task)\\n let vigilanteWantedDecrease = fWantedGain(member, ns.gang.getTaskStats(\\\"Vigilante Justice\\\"))\\n\\n if (wantedLevelIncrease + vigilanteWantedDecrease > 0) {\\n // avoid tasks where more than one vigilante justice is needed to compensate\\n return 0;\\n }\\n //else if ((2 * wantedLevelIncrease) + vigilanteWantedDecrease > 0) {\\n // Simple compensation for wanted level since we need more vigilante then\\n // ToDo: Could be a more sophisticated formula here\\n // cash *= 0.75;\\n //}\\n if (ns.gang.getMemberNames().length >= MAX_MEMBERS) return cash\\n return MODE === \\\"Respect\\\" ? respect : cash\\n}\\n/** @param {NS} ns */\\nfunction updateDisplay(ns) {\\n ns.clearLog()\\n ns.printf(\\\"Name: %s\\\", gangInfo.faction)\\n ns.printf(\\\"Respect: %s (%s/s)\\\", ns.format.number(gangInfo.respect), ns.format.number(gangInfo.respectGainRate * 5))\\n ns.printf(\\\"Next Recruit: %s\\\", respectForNext === Number.POSITIVE_INFINITY ? \\\"MAXED\\\" : ns.format.number(respectForNext))\\n ns.printf(\\\"Mode: %s\\\", MODE)\\n ns.printf(\\\"Wanted Level: %s (%s/s)\\\", ns.format.number(gangInfo.wantedLevel, 3), ns.format.number(gangInfo.wantedLevelGainRate * 5, 2))\\n ns.printf(\\\"Wanted Penalty: %s%s\\\", ns.format.number((gangInfo.wantedPenalty - 1) * 100), \\\"%\\\")\\n ns.printf(\\\"Money Gains: %s/s\\\", ns.format.number(moneyIncrease(ns) * 5))\\n //ns.printf(\\\"Reputation: %s\\\", ns.format.number(ns.singularity.getFactionRep(gangInfo.faction)))\\n //if (hasBN(4, 2)) ns.printf(\\\"Reputation: %s\\\", ns.format.number(ns.singularity.getFactionRep(gangInfo.faction)))\\n ns.printf(\\\"Territory: %s%s\\\", ns.format.number(gangInfo.territory * 100, 2), \\\"%\\\")\\n ns.printf(\\\"Power: %s\\\", ns.format.number(gangInfo.power))\\n ns.printf(\\\"Clash Win Chance: %s%s\\\", ns.format.number(clashwin(ns) * 100, 2), \\\"%\\\")\\n ns.printf(\\\"Territory Warfare: %s\\\", gangInfo.territoryWarfareEngaged ? \\\"Engaged\\\" : gangInfo.territory == 1 ? \\\"Finished\\\" : \\\"Waiting\\\")\\n ns.printf(\\\"------------------------------------------------------------------------------------------------------------\\\")\\n ns.printf(\\\"%10s %20s %6s %6s %6s %6s %6s %6s %6s %8s %8s %6s %2s\\\", \\\"Name\\\", \\\"Task\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"$/s\\\", \\\"R/s\\\", \\\"Wanted\\\", \\\"Respct\\\", \\\"EQ\\\")\\n for (const me of fullMembers.sort((a, b) => a.str > b.str)) {\\n ns.printf(\\\"%10s %20s %6s %6s %6s %6s %6s %6s %6s %8s %8s %6s %2s\\\", me.name, me.task.substring(0, 19), ns.format.number(me.hack, 1), ns.format.number(me.str, 1), ns.format.number(me.def, 1), ns.format.number(me.dex, 1), ns.format.number(me.agi, 1), ns.format.number(me.cha, 1), ns.format.number(me.moneyGain * 5, 1), ns.format.number(me.respectGain * 5), ns.format.number(me.wantedLevelGain * 5), ns.format.number(me.earnedRespect, 1), geteq(ns, me))\\n }\\n}\\n\\n/** @param {NS} ns */\\nfunction moneyIncrease(ns) {\\n let moneygain = 0\\n for (const name of fullMembers) moneygain += name.moneyGain\\n return moneygain\\n}\\n\\n/** @param {NS} ns */\\nfunction geteq(ns, soldier) {\\n return soldier.augmentations.length + soldier.upgrades.length\\n}\\n\\n/** @param {NS} ns */\\nfunction clashwin(ns) {\\n let lowestwinchance = 1\\n for (const otherGang of combatGangs.concat(hackingGangs)) {\\n if (otherGang === gangInfo.faction) continue\\n else if (otherGangInfo[otherGang].territory <= 0) continue\\n else {\\n let othergangpower = otherGangInfo[otherGang].power\\n let winChance = gangInfo.power / (gangInfo.power + othergangpower)\\n lowestwinchance = Math.min(lowestwinchance, winChance)\\n }\\n }\\n return lowestwinchance\\n}\\n/** @param {NS} ns */\\nfunction fWantedGain(member, task) {\\n if (task.baseWanted === 0) return 0;\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha;\\n statWeight -= 3.5 * task.difficulty;\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.wanted) / 100);\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n if (task.baseWanted < 0) {\\n return 0.4 * task.baseWanted * statWeight * territoryMult;\\n }\\n const calc = (7 * task.baseWanted) / Math.pow(3 * statWeight * territoryMult, 0.8);\\n\\n // Put an arbitrary cap on this to prevent wanted level from rising too fast if the\\n // denominator is very small. Might want to rethink formula later\\n return Math.min(100, calc);\\n}\\n/** @param {NS} ns */\\nfunction fRespectGain(ns, member, task) {\\n if (task.baseRespect === 0) return 0;\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha;\\n statWeight -= 4 * task.difficulty;\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.respect) / 100);\\n let territoryPenalty;\\n try { territoryPenalty = (0.2 * gangInfo.territory + 0.8) * getBNMults(ns).GangSoftcap } \\n catch { territoryPenalty = (0.2 * gangInfo.territory + 0.8) }\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n const respectMult = calculateWantedPenalty();\\n return Math.pow(11 * task.baseRespect * statWeight * territoryMult * respectMult, territoryPenalty);\\n}\\n/** @param {NS} ns */\\nfunction fMoneyGain(ns, member, task) {\\n if (task.baseMoney === 0) return 0;\\n let statWeight =\\n (task.hackWeight / 100) * member.hack +\\n (task.strWeight / 100) * member.str +\\n (task.defWeight / 100) * member.def +\\n (task.dexWeight / 100) * member.dex +\\n (task.agiWeight / 100) * member.agi +\\n (task.chaWeight / 100) * member.cha;\\n\\n statWeight -= 3.2 * task.difficulty;\\n if (statWeight <= 0) return 0;\\n const territoryMult = Math.max(0.005, Math.pow(gangInfo.territory * 100, task.territory.money) / 100);\\n if (isNaN(territoryMult) || territoryMult <= 0) return 0;\\n const respectMult = calculateWantedPenalty();\\n let territoryPenalty\\n try { territoryPenalty = (0.2 * gangInfo.territory + 0.8) * getBNMults(ns).GangSoftcap }\\n catch { territoryPenalty = (0.2 * gangInfo.territory + 0.8) }\\n return Math.pow(5 * task.baseMoney * statWeight * territoryMult * respectMult, territoryPenalty);\\n}\\n\\nfunction calculateWantedPenalty() {\\n return gangInfo.respect / (gangInfo.respect + gangInfo.wantedLevel);\\n}\\n/** @param {NS} ns */\\nfunction gangEquip(ns) {\\n const weaps = ns.ui.getGameInfo()?.versionNumber >= 44 ? weaps_new : weaps_old\\n const vehicles = ns.ui.getGameInfo()?.versionNumber >= 44 ? vehicles_new : vehicles_old\\n ns.gang.getMemberNames().forEach((m) => {\\n augs.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n weaps.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n armors.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n vehicles.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n //rootkits.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n })\\n}\\n/** @param {NS} ns */\\nfunction gangAscend(ns) {\\n for (let member of memberNames) {\\n const memberAscensionResult = ns.gang.getAscensionResult(member)\\n if (memberAscensionResult !== undefined) {\\n const ascendRequirement = calculateAscendTreshold(ns, member)\\n const memberAscensionResultMultiplier = (memberAscensionResult.agi + memberAscensionResult.def + memberAscensionResult.dex + memberAscensionResult.str) / 4\\n if ((memberAscensionResultMultiplier > ascendRequirement)) {\\n ns.gang.ascendMember(member)\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction calculateAscendTreshold(ns, soldier) {\\n const member = ns.gang.getMemberInformation(soldier)\\n const mult = (member.agi_asc_mult + member.def_asc_mult + member.dex_asc_mult + member.str_asc_mult) / 4\\n if (mult < 1.632) return 1.6326\\n if (mult < 2.336) return 1.4315\\n if (mult < 2.999) return 1.284\\n if (mult < 3.363) return 1.2125\\n if (mult < 4.253) return 1.1698\\n if (mult < 4.860) return 1.1428\\n if (mult < 5.455) return 1.1225\\n if (mult < 5.977) return 1.0957\\n if (mult < 6.496) return 1.0869\\n if (mult < 7.008) return 1.0789\\n if (mult < 7.519) return 1.073\\n if (mult < 8.025) return 1.0673\\n if (mult < 8.513) return 1.0631\\n if (mult < 20) return 1.0591\\n return 1.04\\n}\\n/** @param {NS} ns */\\nfunction gangRecruit(ns) {\\n if (ns.gang.canRecruitMember()) {\\n let name = names[Math.floor(Math.random() * names.length)]\\n while (memberNames.includes(name)) name = names[Math.floor(Math.random() * names.length)]\\n //ns.printf(`INFO: Recruiting: ${name}`)\\n ns.gang.recruitMember(name)\\n }\\n}\\n/** @param {NS} ns */\\nfunction getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,\\n \\\"CloudServerSoftcap\\\": 1,\\n \\\"CloudServerLimit\\\": 1,\\n \\\"CloudServerMaxRam\\\": 1,\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\\nconst names = [\\\"Rocko\\\", \\\"Mike\\\", \\\"Jack\\\", \\\"Rudo\\\", \\\"Charmichal\\\", \\\"Percy\\\", \\\"Gloria\\\", \\\"Jessica\\\", \\\"Kelly\\\", \\\"Sam\\\", \\\"Gloria\\\", \\\"Sarah\\\",\\n \\\"Jackson\\\", \\\"Adam\\\", \\\"Bob\\\", \\\"Carl\\\", \\\"Dominique\\\", \\\"Enrique\\\", \\\"Falcon\\\", \\\"Garry\\\", \\\"Helen\\\", \\\"Ivana\\\", \\\"Jeremy\\\", \\\"Kyle\\\", \\\"Lucca\\\",\\n \\\"Max\\\", \\\"Nordic\\\", \\\"Oscar\\\", \\\"Paul\\\", \\\"Q\\\", \\\"Rodric\\\", \\\"Steve\\\", \\\"Trevor\\\", \\\"Ulfric\\\", \\\"Volcof\\\", \\\"Wilson\\\", \\\"Xena\\\", \\\"Yoril\\\", \\\"Z\\\"]\\nconst tasks = [\\\"Mug People\\\", \\\"Deal Drugs\\\", \\\"Strongarm Civilians\\\", \\\"Run a Con\\\", \\\"Armed Robbery\\\", \\\"Traffick Illegal Arms\\\", \\\"Threaten & Blackmail\\\", \\\"Human Trafficking\\\", \\\"Terrorism\\\"];\\nconst augs = [\\\"Bionic Arms\\\", \\\"Bionic Legs\\\", \\\"Bionic Spine\\\", \\\"BrachiBlades\\\", \\\"Nanofiber Weave\\\", \\\"Synthetic Heart\\\", \\\"Synfibril Muscle\\\", \\\"Graphene Bone Lacings\\\", \\\"BitWire\\\", \\\"Neuralstimulator\\\", \\\"DataJack\\\"]\\nconst weaps_new = [\\\"Baseball Bat\\\", \\\"Katana\\\", \\\"Malorian-3516\\\", \\\"Hansen-HA7\\\", \\\"Arasaka-HJSH18\\\", \\\"Militech-M251s\\\", \\\"Nokota-D5\\\", \\\"Techtronika-SPT32\\\"]\\nconst weaps_old = [\\\"Baseball Bat\\\", \\\"Katana\\\", \\\"Malorian-3516\\\", \\\"Hansen-HA7\\\", \\\"Arasaka-HJSH18\\\", \\\"Militech-M251s\\\", \\\"Nokota-D5\\\", \\\"Techtronika-SPT32\\\"]\\nconst armors = [\\\"Bulletproof Vest\\\", \\\"Full Body Armor\\\", \\\"Liquid Body Armor\\\", \\\"Graphene Plating Armor\\\"]\\nconst vehicles_new = [\\\"Herrera Outlaw GTS\\\", \\\"Yaiba ASM-R250 Muramasa\\\", \\\"Rayfield Caliburn\\\", \\\"Quadra Sport R-7\\\"]\\nconst vehicles_old = [\\\"Herrera Outlaw GTS\\\", \\\"Yaiba ASM-R250 Muramasa\\\", \\\"Rayfield Caliburn\\\", \\\"Quadra Sport R-7\\\"]\\nconst rootkits = [\\\"NUKE Rootkit\\\", \\\"Soulstealer Rootkit\\\", \\\"Demon Rootkit\\\", \\\"Hmap Node\\\", \\\"Jack the Ripper\\\"]\\nconst combatGangs = [\\\"Speakers for the Dead\\\", \\\"The Dark Army\\\", \\\"The Syndicate\\\", \\\"Tetrads\\\", \\\"Slum Snakes\\\"]\\nconst hackingGangs = [\\\"NiteSec\\\", \\\"The Black Hand\\\"]\""},{"filename":"SphyxOS/full/mystocks.js","file":"\"let SHORTS = false\\nlet S4DATA = false\\nlet QUIET = false\\nconst SNAPS = 16\\nconst BUY_THREASH = 60\\nconst SELL_THREASH = 52\\nconst SLEEPTM = 6000 // do not set it faster (lower). Will be too fast, updates will be duplicated, everything will fall apart\\nconst MSGTICKS = 3 // how many tics will messages stay in the logs for?\\nconst MSGTICKTM = SLEEPTM * MSGTICKS\\nconst MIN_TRANSACTION = 10000000 // 10m\\nconst TRANSACTION_COST = 100000 // Cost per transaction is 100k\\nconst RESERVE = 0\\nconst MIN_STOCKS = 100\\nconst HEIGHT = 970\\nconst WIDTH = 830\\nconst REPORT = 1000 * 60 * 60 // Every hour\\nlet SHOWBUYS = false\\nlet SHOWSELLS = true\\nlet HYBRIDFCAST = false\\nconst HYBRID_VOL = 1.0\\n// Weight is a multiplier on the forcast, where it is then added and averaged\\n// 4s=4 and reg=1 means if the 4s forcast is 62 and the reg forcast is 75, then\\n// the forcast is ((62 * 4) + (75 * 1)) / (4 + 1) = 64.6\\nconst HYBRID_WEIGHT_4S = 4\\nconst HYBRID_WEIGHT_REG = 1\\nlet printmsgs = []\\nlet startworth = 0\\nlet workingmoney = 0\\nlet FUNDSELF = false\\n\\nfunction newMsg(ns, msg) {\\n let record = {\\n \\\"msg\\\": msg,\\n \\\"time\\\": Date.now() + MSGTICKTM\\n }\\n printmsgs.push(record)\\n}\\n\\nfunction printLogs(ns, stocks) {\\n ns.clearLog()\\n //Clear the printmsgs queue so we just have fresh messages\\n while (printmsgs.length > 0 && printmsgs[0].time <= Date.now()) printmsgs.shift()\\n\\n for (const msg of printmsgs) {\\n ns.printf(\\\"%s\\\", msg.msg)\\n }\\n let totalpaid = 0\\n let totalvalue = 0\\n let totalshares = 0\\n let totalprofit = 0\\n //ns.printf(\\\"-----------------------------------------------------------------------\\\")\\n ns.printf(\\\"┌───────┬───────┬─────────┬─────────┬─────────┬──────────┬─────────┬────────┬──────┐\\\")\\n ns.printf(\\\"│ SYM │ TYPE │ SHARES │ PAID │ VALUE │ PROFIT │ %s │ FCAST │ VOLI │\\\", \\\"%\\\")\\n ns.printf(\\\"├───────┼───────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┼──────┤\\\")\\n\\n for (const stk of stocks) {\\n let paid = 0\\n let value = 0\\n let shares = 0\\n let profit = 0\\n let percentchange = 0\\n let type = \\\"-----\\\"\\n if (stk.posi[0] > 0) { // Long position\\n paid = stk.posi[0] * stk.posi[1] + TRANSACTION_COST\\n value = ns.stock.getSaleGain(stk.sym, stk.posi[0], \\\"long\\\")\\n shares = stk.posi[0]\\n profit = value - paid\\n percentchange = (profit > 0) ? (100 - value / paid * 100) * -1 : (100 - (value / paid * 100)) * -1\\n type = \\\"Long \\\"\\n }\\n else if (stk.posi[2] > 0) { // Short position\\n paid = stk.posi[2] * stk.posi[3] + TRANSACTION_COST\\n value = ns.stock.getSaleGain(stk.sym, stk.posi[2], \\\"short\\\")\\n shares = stk.posi[2]\\n profit = value - paid\\n percentchange = (profit > 0) ? (100 - value / paid * 100) * -1 : (100 - (value / paid * 100)) * -1\\n type = \\\"Short\\\"\\n }\\n totalpaid += paid\\n totalvalue += value\\n totalshares += shares\\n totalprofit += profit\\n\\n ns.printf(\\\"│ %5s │ %4s │ %7s │ %7s │ %7s │ %8s │ %7s │ %6s │ %4s │\\\", stk.sym, type, (shares > 0) ? ns.format.number(shares, 2) : \\\"-------\\\", (paid > 0) ? ns.format.number(paid, 2) : \\\"-------\\\", (value > 0) ? ns.format.number(value, 2) : \\\"-------\\\", (profit != 0) ? ns.format.number(profit, 2) : \\\"--------\\\", (percentchange != 0) ? ns.format.number(percentchange, 2) : \\\"-------\\\", ns.format.number(stk.forcast, 2), ns.format.number(stk.volitile, 2))\\n }\\n let totalpercentchange = (totalpaid > 0) ? (100 - totalvalue / totalpaid * 100) * -1 : 0\\n let worth = getWorth(ns, stocks)\\n // ns.printf(\\\"-----------------------------------------------------------------------\\\")\\n ns.printf(\\\"├───────┴───────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┴──────┤\\\")\\n ns.printf(\\\"│Start: %8s│ %7s │ %7s │ %7s │ %8s │ %7s │Gain: %7s%s │\\\", \\\"$\\\" + ns.format.number(startworth, 2), ns.format.number(totalshares, 2), ns.format.number(totalpaid, 2), ns.format.number(totalvalue, 2), ns.format.number(totalprofit, 2), ns.format.number(totalpercentchange, 2), ns.format.number(((worth / startworth) - 1) * 100, 2), \\\"%\\\")\\n ns.printf(\\\"└───────────────┴─────────┴─────────┴─────────┴──────────┴─────────┴───────────────┘\\\")\\n\\n}\\n\\nfunction buyItems(ns, stocks) {\\n //start off our buying spree\\n let stk = ns.stock\\n let topl = stocks.length - 1\\n let botl = 0\\n let top = stocks[topl]\\n let bot = stocks[botl]\\n\\n let running = true\\n while (running) { // Purchase loop\\n let cash = 0\\n if (FUNDSELF) cash = workingmoney\\n else cash = ns.getServerMoneyAvailable(\\\"home\\\")\\n let budget = 0\\n if (FUNDSELF) budget = cash - TRANSACTION_COST\\n else budget = cash - TRANSACTION_COST - RESERVE\\n\\n top = stocks[topl]\\n bot = stocks[botl]\\n\\n //Get the max shares of the stock and our position on the stock. Do we have all the shares? If so, skip it\\n let topposi = stk.getPosition(top.sym)\\n let botposi = stk.getPosition(bot.sym)\\n\\n while (topposi[0] == stk.getMaxShares(top.sym) || topposi[2] == stk.getMaxShares(top.sym)) {\\n topl--\\n top = stocks[topl]\\n topposi = stk.getPosition(top.sym)\\n }\\n while (botposi[0] == stk.getMaxShares(bot.sym) || botposi[2] == stk.getMaxShares(bot.sym)) {\\n botl++\\n bot = stocks[botl]\\n botposi = stk.getPosition(bot.sym)\\n }\\n top = stocks[topl]\\n bot = stocks[botl]\\n let max = false\\n if (SHORTS) {\\n if (bot.adjfcast >= top.forcast && bot.adjfcast >= BUY_THREASH) { //Bottom is the way to go right now\\n //buy shorts of bottom, get the next bottom\\n let price = stk.getBidPrice(bot.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + botposi[0] + botposi[2] > stk.getMaxShares(bot.sym)) {\\n buying = stk.getMaxShares(bot.sym) - botposi[0] - botposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Shorting: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n let bought = stk.buyShort(bot.sym, buying)\\n if (bought > 0) {\\n if (FUNDSELF) workingmoney -= (bought * buying) + TRANSACTION_COST\\n if (SHOWBUYS) ns.tprintf(\\\"Buying %s short of %s for $%s\\\", buying, bot.sym, ns.format.number(bought * buying, 2))\\n let msg = ns.sprintf(\\\"Buying %s short of %s for $%s\\\", buying, bot.sym, ns.format.number(bought * buying, 2))\\n newMsg(ns, msg)\\n botl++\\n }\\n else {\\n if (SHOWBUYS) ns.tprintf(\\\"Failed to buy %s Short of %s\\\", buying, bot.sym)\\n let msg = ns.sprintf(\\\"Failed to buy %s Short of %s\\\", buying, bot.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n else if (top.forcast >= BUY_THREASH) { // Top is the way to go\\n // Buy long of top, get the next top\\n let price = stk.getAskPrice(top.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + topposi[0] + topposi[2] > stk.getMaxShares(top.sym)) {\\n buying = stk.getMaxShares(top.sym) - topposi[0] - topposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Long within short: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n let bought = stk.buyStock(top.sym, buying)\\n if (bought > 0) {\\n if (FUNDSELF) workingmoney -= (bought * buying) + TRANSACTION_COST\\n if (SHOWBUYS) ns.tprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, ns.format.number(bought * buying, 2))\\n let msg = ns.sprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, ns.format.number(bought * buying, 2))\\n newMsg(ns, msg)\\n topl--\\n }\\n else {\\n if (SHOWBUYS) ns.tprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n let msg = ns.sprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n }\\n else if (top.forcast >= BUY_THREASH) { //check for long buy\\n let price = stk.getAskPrice(top.sym)\\n let buying = Math.floor(budget / price)\\n if (buying + topposi[0] + topposi[2] > stk.getMaxShares(top.sym)) {\\n buying = stk.getMaxShares(top.sym) - topposi[0] - topposi[2]\\n max = true\\n }\\n //ns.tprintf(\\\"Long: Price %s Buying %s Total %s\\\", price, buying, price * buying)\\n if ((buying >= MIN_STOCKS && price * buying >= MIN_TRANSACTION) || max) {\\n let bought = stk.buyStock(top.sym, buying)\\n if (bought > 0) {\\n if (FUNDSELF) workingmoney -= (bought * buying) + TRANSACTION_COST\\n if (SHOWBUYS) ns.tprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, ns.format.number(bought * buying, 2))\\n let msg = ns.sprintf(\\\"Buying %s long of %s for $%s\\\", buying, top.sym, ns.format.number(bought * buying, 2))\\n newMsg(ns, msg)\\n topl--\\n }\\n else {\\n if (SHOWBUYS) ns.tprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n let msg = ns.sprintf(\\\"Failed to buy %s long of %s\\\", buying, top.sym)\\n newMsg(ns, msg)\\n }\\n }\\n }\\n if (!max) {\\n running = false\\n }\\n }\\n if (FUNDSELF) workingmoney = 0 //We shave off the remainder so we don't have to worry about it not being there later\\n}\\n\\nfunction updateForcast(ns, stocks) {\\n // Cycle through our stocks and update the forcast\\n for (let stk of stocks) {\\n //Update 4S forcast\\n if (S4DATA) {\\n stk.s4forcast = ns.stock.getForecast(stk.sym) * 100\\n stk.s4adjfcast = (stk.s4forcast >= 50) ? stk.s4forcast : 100 - stk.s4forcast\\n stk.s4volitile = ns.stock.getVolatility(stk.sym) * 100\\n }\\n //Process the snapshot\\n //We are going to track 3 values and average them out. Price, AskPrice, BidPrice\\n let price = 0\\n let totalprice = 0\\n //-----------------\\n let ask = 0\\n let totalask = 0\\n //-----------------\\n let bid = 0\\n let totalbid = 0\\n //-----------------\\n let vol = 0\\n let bestvol = 0\\n //-----------------\\n for (let i = 0; i < stk.snaps.length - 1; i++) {\\n price += stk.snaps[i + 1].price - stk.snaps[i].price\\n totalprice += Math.abs(stk.snaps[i + 1].price - stk.snaps[i].price)\\n ask += stk.snaps[i + 1].askprice - stk.snaps[i].askprice\\n totalask += Math.abs(stk.snaps[i + 1].askprice - stk.snaps[i].askprice)\\n bid += stk.snaps[i + 1].bidprice - stk.snaps[i].bidprice\\n totalbid += Math.abs(stk.snaps[i + 1].bidprice - stk.snaps[i].bidprice)\\n vol = (stk.snaps[i + 1].price > stk.snaps[i].price) ? (stk.snaps[i + 1].price / stk.snaps[i].price) - 1 : (stk.snaps[i].price / stk.snaps[i + 1].price) - 1\\n vol *= 100\\n if (vol > bestvol) bestvol = vol\\n }\\n if (totalprice == 0) {\\n stk.regforcast = 50\\n stk.regadjfcast = 50\\n stk.regvolitile = 0\\n }\\n else {\\n let pfcast = (price / totalprice * 50) + 50\\n let afcast = (ask / totalask * 50) + 50\\n let bfcast = (bid / totalbid * 50) + 50\\n\\n stk.regforcast = (pfcast + afcast + bfcast) / 3\\n stk.regadjfcast = (stk.regforcast >= 50) ? stk.regforcast : 100 - stk.regforcast\\n stk.regvolitile = bestvol\\n }\\n\\n // Get the Hybrid forcast now\\n if (S4DATA) {\\n stk.hybridforcast = ((stk.regforcast * HYBRID_WEIGHT_REG) + (stk.s4forcast * HYBRID_WEIGHT_4S)) / (HYBRID_WEIGHT_4S + HYBRID_WEIGHT_REG)\\n stk.hybridadjfcast = (stk.hybridforcast >= 50) ? stk.hybridforcast : 100 - stk.hybridforcast\\n }\\n }\\n\\n // Assign the actual forcast\\n if (HYBRIDFCAST && S4DATA) {\\n for (const stk of stocks) {\\n stk.forcast = (stk.s4forcast > 50) ? stk.hybridforcast + stk.s4volitile - HYBRID_VOL : stk.hybridforcast - stk.s4volitile + HYBRID_VOL\\n stk.adjfcast = stk.hybridadjfcast\\n stk.volitile = stk.s4volitile\\n }\\n }\\n else if (S4DATA) {\\n for (const stk of stocks) {\\n stk.forcast = stk.s4forcast\\n stk.adjfcast = stk.s4adjfcast\\n stk.volitile = stk.s4volitile\\n }\\n }\\n else {\\n for (const stk of stocks) {\\n stk.forcast = stk.regforcast\\n stk.adjfcast = stk.regadjfcast\\n stk.volitile = stk.regvolitile\\n }\\n }\\n stocks.sort((a, b) => { return a.forcast - b.forcast })\\n}\\n\\nfunction sellItems(ns, stocks, arg) {\\n for (let obj of stocks) {\\n //if (obj.adjfcast > SELL_THREASH) continue // keep it\\n\\n let posi = ns.stock.getPosition(obj.sym)\\n\\n if (posi[0] > 0 && obj.forcast <= SELL_THREASH || (posi[0] > 0 && arg && arg == \\\"sell\\\")) { // We have Longs to sell\\n let sellprice = ns.stock.sellStock(obj.sym, posi[0])\\n if (FUNDSELF) workingmoney += (sellprice * posi[0]) - TRANSACTION_COST\\n if (sellprice >= posi[1]) { // Profit\\n let profit = (sellprice * posi[0]) - (posi[0] * posi[1])\\n if (SHOWSELLS) ns.tprintf(\\\"WARN: Selling %s long for $%s ($%s profit)\\\", obj.sym, ns.format.number(sellprice * posi[0], 2), ns.format.number(profit, 2))\\n let msg = ns.sprintf(\\\"WARN: Selling %s long for $%s ($%s profit)\\\", obj.sym, ns.format.number(sellprice * posi[0], 2), ns.format.number(profit, 2))\\n newMsg(ns, msg)\\n }\\n else {// Loss\\n let loss = (sellprice * posi[0]) - (posi[0] * posi[1])\\n if (SHOWSELLS) ns.tprintf(\\\"WARN: Selling %s long for $%s ($%s loss)\\\", obj.sym, ns.format.number(sellprice * posi[0], 2), ns.format.number(loss, 2))\\n let msg = ns.sprintf(\\\"WARN: Selling %s long for $%s ($%s loss)\\\", obj.sym, ns.format.number(sellprice * posi[0], 2), ns.format.number(loss, 2))\\n newMsg(ns, msg)\\n }\\n }\\n if (posi[2] > 0 && obj.forcast >= 100 - SELL_THREASH || (posi[2] > 0 && arg && arg == \\\"sell\\\")) { // We have shorts to sell\\n let shortsales = ns.stock.getSaleGain(obj.sym, posi[2], \\\"short\\\")\\n if (FUNDSELF) workingmoney += shortsales - TRANSACTION_COST\\n let paidshort = posi[2] * posi[3]\\n let sellprice = ns.stock.sellShort(obj.sym, posi[2])\\n if (shortsales >= paidshort) { // Profit\\n let profit = shortsales - paidshort// - (sellprice * posi[2])\\n if (SHOWSELLS) ns.tprintf(\\\"WARN: Selling %s short for $%s ($%s profit)\\\", obj.sym, ns.format.number(shortsales, 2), ns.format.number(profit, 2))\\n let msg = ns.sprintf(\\\"WARN: Selling %s short for $%s ($%s profit)\\\", obj.sym, ns.format.number(shortsales, 2), ns.format.number(profit, 2))\\n newMsg(ns, msg)\\n }\\n else {// Loss\\n let loss = shortsales - paidshort// - (sellprice * posi[2])\\n if (SHOWSELLS) ns.tprintf(\\\"WARN: Selling %s short for $%s ($%s loss)\\\", obj.sym, ns.format.number(shortsales, 2), ns.format.number(loss, 2))\\n let msg = ns.sprintf(\\\"WARN: Selling %s short for $%s ($%s loss)\\\", obj.sym, ns.format.number(shortsales, 2), ns.format.number(loss, 2))\\n newMsg(ns, msg)\\n }\\n }\\n }\\n}\\n\\nfunction getWorth(ns, stocks) {\\n let worth = ns.getServerMoneyAvailable(\\\"home\\\")\\n for (let obj of stocks) {\\n if (obj.posi[0] > 0) {\\n worth += ns.stock.getSaleGain(obj.sym, obj.posi[0], \\\"long\\\") //obj.posi[0] * stk.getPrice(obj.sym)//obj.posi[1]\\n }\\n if (obj.posi[2] > 0) {\\n worth += ns.stock.getSaleGain(obj.sym, obj.posi[2], \\\"short\\\")//obj.posi[2] * stk.getPrice(obj.sym)//obj.posi[3]\\n }\\n }\\n return worth\\n}\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n\\n let stks = ns.stock\\n\\n\\n if (ns.ui.getGameInfo()?.versionNumber >= 44 && (!stks.hasWseAccount() || !stks.hasTixApiAccess())) {\\n ns.tprintf(\\\"WSE and TIX API access are required to run this.\\\")\\n return\\n }\\n else if (ns.ui.getGameInfo()?.versionNumber === undefined && (!stks.hasWseAccount() || !stks.hasTixApiAccess())) {\\n ns.tprintf(\\\"WSE and TIX API access are required to run this.\\\")\\n return\\n }\\n if (ns.args.includes(\\\"help\\\")) {\\n ns.tprintf(\\\"Help activated.\\\")\\n ns.tprintf(\\\"Options to run with are (In any order):\\\")\\n ns.tprintf(\\\"no4s Disabled 4s data use\\\")\\n ns.tprintf(\\\"noshort Disables Shorts\\\")\\n ns.tprintf(\\\"hybrid Uses a hybrid forcast system\\\")\\n ns.tprintf(\\\"sell Sells all stocks\\\")\\n ns.tprintf(\\\"stop Stops all %s instances\\\", ns.getScriptName())\\n ns.tprintf(\\\"monitor Does not buy or sell, just watches\\\")\\n ns.tprintf(\\\"fundself Only purchase stocks with money from the sale of stocks\\\")\\n ns.tprintf(\\\"quiet Suppresses sales notifications\\\")\\n ns.tprintf(\\\"showbuy Display purchase notifications\\\")\\n ns.tprintf(\\\"help Activates the help menu (You are in it...)\\\")\\n return\\n }\\n\\n ns.args.includes(\\\"hybrid\\\") ? HYBRIDFCAST = true : HYBRIDFCAST = false\\n\\n // Initialize early so we can potentially sell without all the extra displays\\n let stocks = []\\n printmsgs = []\\n const syms = stks.getSymbols()\\n\\n //Initialize our stock list\\n for (const sym of syms) {\\n let record = {\\n \\\"sym\\\": sym,\\n \\\"snaps\\\": [],\\n \\\"s4forcast\\\": 50,\\n \\\"s4adjfcast\\\": 50,\\n \\\"hybridforcast\\\": 50,\\n \\\"hybridadjfcast\\\": 50,\\n \\\"forcast\\\": 50,\\n \\\"adjfcast\\\": 50,\\n \\\"regforcast\\\": 50,\\n \\\"regadjfcast\\\": 50,\\n \\\"posi\\\": stks.getPosition(sym),\\n \\\"s4volitile\\\": 0,\\n \\\"regvolitile\\\": 0,\\n \\\"volitile\\\": 0,\\n \\\"time\\\": Date.now()\\n }\\n stocks.push(record)\\n }\\n newMsg(ns, \\\"Just Initialized\\\")\\n printLogs(ns, stocks)\\n\\n if (ns.args.includes(\\\"stop\\\")) {\\n ns.tprintf(\\\"%s is being stopped. Don't forget to sell.\\\", ns.getScriptName())\\n if (ns.args.includes(\\\"sell\\\")) {\\n sellItems(ns, stocks, \\\"sell\\\")\\n }\\n UpdateHud(ns)\\n ns.scriptKill(ns.getScriptName(), ns.getHostname())\\n return\\n }\\n\\n if (ns.args.includes(\\\"sell\\\")) {\\n sellItems(ns, stocks, \\\"sell\\\")\\n UpdateHud(ns)\\n return\\n }\\n\\n\\n if (!ns.args.includes(\\\"noshorts\\\")) {\\n try {\\n stks.buyShort(\\\"ECP\\\", 0)\\n SHORTS = true\\n ns.tprintf(\\\"Shorts Active!\\\")\\n }\\n catch {\\n ns.tprintf(\\\"Shorts disabled\\\")\\n SHORTS = false\\n }\\n }\\n else {\\n ns.tprintf(\\\"Shorts disabled\\\")\\n SHORTS = false\\n }\\n\\n if (ns.ui.getGameInfo()?.versionNumber >= 44 && (stks.has4SDataTixApi() && !ns.args.includes(\\\"no4s\\\"))) {\\n S4DATA = true\\n ns.tprintf(\\\"4S data enabled!\\\")\\n if (HYBRIDFCAST) {\\n ns.tprintf(\\\"Hybrid Forcast enabled!\\\")\\n }\\n }\\n else if (ns.ui.getGameInfo()?.versionNumber === undefined && (stks.has4SDataTixApi() && !ns.args.includes(\\\"no4s\\\"))) {\\n S4DATA = true\\n ns.tprintf(\\\"4S data enabled!\\\")\\n if (HYBRIDFCAST) {\\n ns.tprintf(\\\"Hybrid Forcast enabled!\\\")\\n }\\n }\\n else {\\n ns.tprintf(\\\"4S Data disabled\\\")\\n S4DATA = false\\n }\\n if (ns.args.includes(\\\"monitor\\\")) {\\n ns.tprintf(\\\"Monitor Mode enabled!\\\")\\n }\\n if (ns.args.includes(\\\"fundself\\\") || ns.args.includes(\\\"selffund\\\")) {\\n ns.tprintf(\\\"Self Funding has been enabled!\\\")\\n FUNDSELF = true\\n workingmoney = 0\\n }\\n else FUNDSELF = false\\n\\n if (ns.args.includes(\\\"quiet\\\")) {\\n ns.tprintf(\\\"Quiet mode enabled. Will not show sales. Shhhh!!!\\\")\\n SHOWSELLS = false\\n }\\n else SHOWSELLS = true\\n\\n if (ns.args.includes(\\\"showbuy\\\")) {\\n ns.tprintf(\\\"Showing all purchases!\\\")\\n SHOWBUYS = true\\n }\\n else SHOWBUYS = false\\n\\n\\n let working = true\\n let count = 0\\n ns.ui.openTail()\\n\\n let starttime = Date.now()\\n startworth = getWorth(ns, stocks)\\n\\n // Are we relying only on the 4s Data and not a hybrid? Speed it up then!\\n if (S4DATA && !HYBRIDFCAST) count = SNAPS\\n\\n while (working) {\\n\\n ns.ui.resizeTail(WIDTH, HEIGHT);\\n if (count == SNAPS) {\\n printmsgs = []\\n newMsg(ns, \\\"Ready!\\\")\\n }\\n //Report if needed\\n if (Date.now() >= starttime + REPORT) {\\n starttime = Date.now()\\n let endworth = getWorth(ns, stocks)\\n\\n if (endworth > startworth) {\\n ns.tprintf(\\\"INFO: Success! After 1 hour %s turned into %s (%s%s)\\\", ns.format.number(startworth, 2), ns.format.number(endworth, 2), ns.format.number(endworth / startworth * 100, 2), \\\"%\\\")\\n //let msg = ns.sprintf(`INFO: Success! After 1 hour ${ns.format.number(startworth, 2)} turned into ${ns.format.number(endworth, 2)} (${ns.format.number(endworth / startworth * 100, 2)}\\\\%)`)\\n let msg = ns.sprintf(\\\"INFO: Success! After 1 hour %s turned into %s (%s%s)\\\", ns.format.number(startworth, 2), ns.format.number(endworth, 2), ns.format.number(endworth / startworth * 100, 2), \\\"%\\\")\\n newMsg(ns, msg)\\n }\\n else {\\n ns.tprintf(\\\"INFO: Fail! After 1 hour %s turned into %s (%s%s)\\\", ns.format.number(startworth, 2), ns.format.number(endworth, 2), ns.format.number(endworth / startworth * 100, 2), \\\"%\\\")\\n //let msg = ns.sprintf(`WARN: FAIL! After 1 hour ${ns.format.number(startworth, 2)} turned into ${ns.format.number(endworth, 2)} (${ns.format.number(endworth / startworth * 100, 2)}\\\\%)`)\\n let msg = ns.sprintf(\\\"INFO: Fail! After 1 hour %s turned into %s (%s%s)\\\", ns.format.number(startworth, 2), ns.format.number(endworth, 2), ns.format.number(endworth / startworth * 100, 2), \\\"%\\\")\\n newMsg(ns, msg)\\n }\\n startworth = endworth\\n }\\n\\n //Switch to 4S if we can\\n if (ns.ui.getGameInfo()?.versionNumber >= 44 && (stks.has4SDataTixApi() && !ns.args.includes(\\\"no4s\\\") && !S4DATA)) {\\n S4DATA = true\\n ns.tprintf(\\\"4S data enabled!\\\")\\n if (HYBRIDFCAST) {\\n ns.tprintf(\\\"Hybrid Forcast enabled!\\\")\\n }\\n }\\n else if (ns.ui.getGameInfo()?.versionNumber === undefined && (stks.has4SDataTixApi() && !ns.args.includes(\\\"no4s\\\") && !S4DATA)) {\\n S4DATA = true\\n ns.tprintf(\\\"4S data enabled!\\\")\\n if (HYBRIDFCAST) {\\n ns.tprintf(\\\"Hybrid Forcast enabled!\\\")\\n }\\n }\\n\\n //Snapshot\\n for (const obj of stocks) {\\n let record = {\\n \\\"bidprice\\\": stks.getBidPrice(obj.sym),\\n \\\"askprice\\\": stks.getAskPrice(obj.sym),\\n \\\"price\\\": stks.getPrice(obj.sym),\\n \\\"spread\\\": stks.getAskPrice(obj.sym) - stks.getBidPrice(obj.sym),\\n \\\"time\\\": Date.now()\\n }\\n obj.snaps.push(record)\\n obj.snaps.length > SNAPS ? obj.snaps.shift() : null\\n obj.posi = stks.getPosition(obj.sym)\\n }\\n\\n //Update the forcast\\n updateForcast(ns, stocks)\\n\\n //Sell stocks here\\n if (count > SNAPS || (S4DATA && !HYBRIDFCAST)) {\\n if (!ns.args.includes(\\\"monitor\\\")) sellItems(ns, stocks, \\\"none\\\")\\n }\\n //Buy Stocks here\\n if (count > SNAPS || (S4DATA && !HYBRIDFCAST)) {\\n if (!ns.args.includes(\\\"monitor\\\")) buyItems(ns, stocks)\\n }\\n // Update your position on everything\\n for (let obj of stocks) {\\n obj.posi = stks.getPosition(obj.sym)\\n }\\n\\n\\n if (count < SNAPS) {\\n let msg = ns.sprintf(\\\"Pre-total snaps %s/%s\\\", count, SNAPS)\\n newMsg(ns, msg)\\n printLogs(ns, stocks)\\n }\\n else {\\n printLogs(ns, stocks)\\n }\\n\\n let totalworth = getWorth(ns, stocks)\\n let printworth = ns.format.number(totalworth, 2)\\n UpdateHud(ns, printworth)\\n count++\\n await stks.nextUpdate()\\n }\\n}\\nfunction UpdateHud(ns, totalWorth) {\\n const doc = eval('document');\\n const hook0 = doc.getElementById('overview-extra-hook-0');\\n const hook1 = doc.getElementById('overview-extra-hook-1');\\n\\n try {\\n const headers = []\\n const values = [];\\n\\n if (totalWorth == undefined) {\\n hook0.innerText = '';\\n hook1.innerText = '';\\n return;\\n }\\n\\n headers.push('Total Worth: ');\\n values.push(totalWorth);\\n\\n hook0.innerText = headers.join(\\\" \\\\n\\\");\\n hook1.innerText = values.join(\\\"\\\\n\\\");\\n hook0.onclick = function () { getTail = true }\\n\\n } catch (err) {\\n ns.print(\\\"ERROR: Update Skipped: \\\" + String(err));\\n }\\n}\""},{"filename":"SphyxOS/full/puppetFull.js","file":"\"//Puppet2 by Sphyxis\\n/** @type {Server[]} baseServers */\\nlet baseServers;\\nlet servers; //Utilized by server run\\nlet batchServers; //Utilized by server run\\n//For the tail logs:\\n/** @type {Server} TARGET */\\nlet TARGET = \\\"\\\" //Who you are hacking\\n/** @type {Server} NEXTTARGET */\\nlet NEXTTARGET = \\\"\\\" //Whos next up\\nlet TARGETUPDATE = false\\nlet ZERGSTATUS = false\\nlet ZERGSENT = 0\\nlet ZERGREQUIRED = -1\\nlet RECALC_GOOD = false\\nlet RECALC_BAD = false\\nlet PORTS_OPEN = 0\\nlet BMODE = \\\"B\\\" //Batch mode: b is not batching, B is batching\\nlet THREADSLEFT = 0 //Total threads used\\nlet THREADSMAX = 0 //Total threads available\\nlet BATCHESTOTAL = 0 //Total batches done\\nlet BATCHESRUN = 0 //Actual batches run\\nlet PREPW1 = 0 //Prep wave\\nlet PREPG1 = 0\\nlet PREPW2 = 0\\nlet PREPH1 = 1\\nlet PREPW3 = 0\\nlet PREPG2 = 0\\nlet PREPW4 = 0\\nlet BATCHINFO;\\nlet STARTTIME = 0\\nlet ENDTIME = 0\\nlet BETWEENSTART = 0\\nlet BETWEENEND = 0\\nlet HACKTIME = 0\\nlet WEAKENTIME = 0\\nlet USEHACKNET = false\\nlet PURCHASE = true\\nlet AUTOHASH = false\\nlet AUTOBUYHACKNET = false\\nlet AUTOHASHTIMER = Number.POSITIVE_INFINITY\\nconst RESERVERAM = 32\\n\\n//Configuration\\nlet lastpid = 0\\nlet weakenStrength\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.ui.openTail()\\n USEHACKNET = ns.args.includes(\\\"usehacknet\\\")\\n PURCHASE = !ns.args.includes(\\\"nopurchase\\\")\\n AUTOHASH = ns.args.includes(\\\"autohash\\\") && hasBN(ns, 9)\\n AUTOBUYHACKNET = ns.args.includes(\\\"autobuyhacknet\\\")\\n if (AUTOBUYHACKNET) AUTOHASHTIMER = (1000 * 60 * 15) + performance.now()\\n virus(ns)\\n init(ns)\\n await writeFiles(ns)\\n /**@type {Player} player */\\n let player = ns.getPlayer()\\n const basicservers = getServersLight(ns)\\n if (ns.args[0] && basicservers.includes(ns.args[0]))\\n TARGET = ns.getServer(ns.args[0])\\n else if (player.skills.hacking < 10) TARGET = ns.getServer(\\\"n00dles\\\")\\n else TARGET = getOptimalTarget(ns)\\n NEXTTARGET = TARGET\\n\\n //Get the batch info. Contains: H1 W1 G1 W2 Type Take HackP\\n BATCHINFO = getHackP(ns, TARGET, -1, -1, 1)\\n let spending = true\\n let new_ports_open = 0\\n let overflowed = false\\n while (true) {\\n TARGET = ns.getServer(TARGET.hostname)\\n //Calc wave\\n const wavew1 = Math.ceil((TARGET.hackDifficulty - TARGET.minDifficulty) / weakenStrength)\\n const waveg1 = Math.ceil(getGrowThreads(ns, TARGET.hostname, TARGET.moneyAvailable, TARGET.minDifficulty))\\n\\n //Refresh times. Hack Time is the constant for that. 3.2x for Grow, 4x for Weaken\\n HACKTIME = ns.getHackTime(TARGET.hostname)\\n WEAKENTIME = HACKTIME * 4\\n //Refresh base servers\\n baseServers = getServers(ns)\\n //Get thread information\\n THREADSLEFT = 0 //Reserved?\\n for (const server of baseServers) {\\n if (server.hostname.startsWith(\\\"hacknet\\\") && !USEHACKNET) continue\\n if (server.hasAdminRights && server.maxRam > 0) {\\n let tmpramavailable = getServerAvailRam(ns, server.hostname)\\n if (server.hostname === \\\"home\\\") tmpramavailable = Math.max(tmpramavailable - RESERVERAM, 0)\\n let tmpthreads = Math.floor(tmpramavailable / 1.75)\\n THREADSLEFT += tmpthreads\\n }\\n }\\n THREADSMAX = THREADSLEFT\\n\\n //Figure out how many threads to assign to the wave, and where they will go for best usage.\\n //First weaken\\n if (wavew1 > THREADSLEFT) { //We need too many!\\n PREPW1 = THREADSLEFT\\n THREADSLEFT = 0\\n }\\n else { //Enough to fit\\n PREPW1 = wavew1\\n THREADSLEFT -= PREPW1 //Could be as low as 0 now\\n }\\n\\n // If we have threads left, move on to Grow/Weaken\\n PREPW2 = 0\\n PREPG1 = 0\\n if (waveg1 > THREADSLEFT) { //We need more grow than we can handle\\n PREPW2 = Math.ceil((THREADSLEFT * .004) / weakenStrength) //Figure out how many weaken threads we need to accomodate the highest\\n PREPG1 = THREADSLEFT - PREPW2 //Fill in as many grows as can fit now\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total grow threads, but can we handle it with weaken?\\n PREPW2 = Math.ceil((waveg1 * .004) / weakenStrength) //total weakens we need for a full grow\\n if (PREPW2 + waveg1 <= THREADSLEFT) {//We have enough for both grow and weaken!\\n PREPG1 = waveg1\\n THREADSLEFT -= PREPG1 + PREPW2 //Could be as low as 0 now\\n }\\n else { //We don't have enough. Calculate optimal\\n const growP = .004 / weakenStrength\\n const remainder = waveg1 + PREPW2 - THREADSLEFT\\n const weakremove = Math.floor(remainder * growP)\\n const growremove = remainder - weakremove\\n PREPG1 = waveg1 - growremove\\n PREPW2 -= weakremove\\n THREADSLEFT = 0\\n }\\n }\\n\\n //If we have threads left, move on to Hack/Weaken\\n PREPW3 = 0\\n PREPH1 = 0\\n if (BATCHINFO.H1 > THREADSLEFT) { //We don't have enough to fully hack!\\n PREPW3 = Math.floor((THREADSLEFT * .002) / weakenStrength)\\n PREPH1 = THREADSLEFT - PREPW3\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total hack threads, but what about the weakens it produces?\\n PREPW3 = Math.ceil((BATCHINFO.H1 * .002) / weakenStrength)\\n if (PREPW3 + BATCHINFO.H1 <= THREADSLEFT) { //We have enough for both hack and weaken\\n PREPH1 = BATCHINFO.H1\\n THREADSLEFT -= PREPH1 + PREPW3\\n }\\n else { //We don'thave enough. Calculate optimal\\n const hackP = .002 / weakenStrength\\n const remainder = BATCHINFO.H1 + PREPW3 - THREADSLEFT\\n const weakenremove = Math.floor(remainder * hackP)\\n const hackremove = remainder - weakenremove\\n PREPH1 = BATCHINFO.H1 - hackremove\\n PREPW3 -= weakenremove\\n THREADSLEFT = 0\\n }\\n }\\n\\n // If we have threads left, move on to Grow/Weaken\\n PREPW4 = 0\\n PREPG2 = 0\\n if (BATCHINFO.G1 > THREADSLEFT) { //We need more grow than we can handle\\n PREPW4 = Math.ceil((THREADSLEFT * .004) / weakenStrength) //Figure out how many weaken threads we need to accomodate the highest\\n PREPG2 = THREADSLEFT - PREPW4 //Fill in as many grows as can fit now\\n THREADSLEFT = 0\\n }\\n else { //We can handle the total grow threads, but can we handle it with weaken?\\n PREPW4 = Math.ceil((BATCHINFO.G1 * .004) / weakenStrength) //total weakens we need for a full grow\\n if (PREPW4 + BATCHINFO.G1 <= THREADSLEFT) {//We have enough for both grow and weaken!\\n PREPG2 = BATCHINFO.G1\\n THREADSLEFT -= PREPG2 + PREPW4 //Could be as low as 0 now\\n }\\n else { //We don't have enough. Calculate optimal\\n const growP = .004 / weakenStrength\\n const remainder = BATCHINFO.G1 + PREPW4 - THREADSLEFT\\n const weakremove = Math.floor(remainder * growP)\\n const growremove = remainder - weakremove\\n PREPG2 = BATCHINFO.G1 - growremove\\n PREPW4 -= weakremove\\n THREADSLEFT = 0\\n }\\n }\\n BATCHESTOTAL = Math.floor(THREADSLEFT / (BATCHINFO.H1 + BATCHINFO.W1 + BATCHINFO.G1 + BATCHINFO.W2))\\n if (ZERGSTATUS && ZERGREQUIRED !== ZERGSENT) BATCHESTOTAL = Math.max(BATCHESTOTAL - 2, 0) //Reserve a few batches to send as zerglings\\n\\n BETWEENEND = performance.now()\\n STARTTIME = performance.now()\\n //Start it all and get the results\\n const results = await serverRun(ns, TARGET.hostname, PREPW1, PREPG1, PREPW2, PREPH1, PREPW3, PREPG2, PREPW4, BATCHINFO.H1, BATCHINFO.W1, BATCHINFO.G1, BATCHINFO.W2, BATCHESTOTAL, !USEHACKNET)\\n ENDTIME = performance.now()\\n\\n lastpid = results.lastpid\\n RECALC_BAD = results.recalc\\n BATCHESRUN = results.batches\\n BMODE = results.batching ? \\\"B\\\" : \\\"b\\\"\\n THREADSLEFT -= (BATCHINFO.H1 + BATCHINFO.W1 + BATCHINFO.G1 + BATCHINFO.W2) * BATCHESRUN //Includes the wave as a batch\\n if (ZERGSTATUS && ZERGREQUIRED !== ZERGSENT) await zerglings(ns, THREADSLEFT) //If zerg is on, send the lings!\\n\\n //Now that we have the next batch ready, we wait...\\n while (ns.isRunning(lastpid)) {\\n await ns.sleep(20)\\n update_hud(ns)\\n }\\n update_hud(ns)\\n\\n BETWEENSTART = performance.now()\\n //If our hacking has gone up, recalculate\\n /**@type {Player} player2 */\\n const player2 = ns.getPlayer()\\n if (PORTS_OPEN < 5) new_ports_open = getPortOpeners(ns)\\n if (PURCHASE && spending) if (!serverPurchaser(ns)) spending = false\\n if (AUTOHASH) {\\n hashIt(ns, TARGET.hostname, \\\"max\\\")\\n hashIt(ns, TARGET.hostname, \\\"min\\\")\\n }\\n if (AUTOBUYHACKNET && AUTOHASHTIMER <= performance.now()) {\\n if (!hacknetPurchaser(ns)) AUTOHASHTIMER = Number.POSITIVE_INFINITY\\n else AUTOHASHTIMER = performance.now() + (1000 * 60 * 15)\\n }\\n if (player2.skills.hacking > player.skills.hacking || PORTS_OPEN !== new_ports_open) {\\n player = player2\\n RECALC_GOOD = true\\n TARGETUPDATE = true\\n if (PORTS_OPEN !== new_ports_open) {\\n PORTS_OPEN = new_ports_open\\n virus(ns)\\n }\\n }\\n\\n if (NEXTTARGET.hostname === TARGET.hostname && TARGETUPDATE) { //Nexttarget is target. We are open for a new target \\n /**@type {Server} upcoming */\\n const upcoming = getOptimalTarget(ns)\\n if (upcoming.hostname !== TARGET.hostname) { //We have an up and commer that's better. Start zerglings\\n NEXTTARGET = upcoming\\n ZERGSTATUS = true\\n }\\n TARGETUPDATE = false\\n }\\n else if (NEXTTARGET.hostname !== TARGET.hostname && ns.getServerSecurityLevel(NEXTTARGET.hostname) === ns.getServerMinSecurityLevel(NEXTTARGET.hostname)) { //Ready for the change over\\n TARGET = NEXTTARGET\\n ZERGSTATUS = false\\n ZERGSENT = 0\\n ZERGREQUIRED = -1\\n RECALC_BAD = false\\n RECALC_GOOD = false\\n //overflowed = false\\n //Get the batch info. Contains: H1 W1 G1 W2 Type Take HackP\\n BATCHINFO = getHackP(ns, TARGET, -1, -1, 1)\\n TARGETUPDATE = true\\n }\\n\\n if (RECALC_BAD) {\\n BATCHINFO = getHackP(ns, TARGET, BATCHESRUN, THREADSMAX, BATCHINFO.H1)\\n RECALC_BAD = false\\n overflowed = true\\n }\\n else if (RECALC_GOOD && !overflowed) {\\n BATCHINFO = getHackP(ns, TARGET, -1, -1, 1)\\n RECALC_GOOD = false\\n }\\n else BATCHINFO = getHackP(ns, TARGET, -1, -1, Math.max(BATCHINFO.H1 - 1, 1))\\n }//while (true) loop\\n}\\n\\n/** @param {NS} ns */\\nfunction update_hud(ns) {\\n ns.clearLog()\\n ns.printf(\\\"%s[%s] - (%s)\\\", TARGET.hostname, BMODE, BATCHINFO.Type)\\n if (TARGET.hostname !== NEXTTARGET.hostname) ns.printf(\\\"Next: %s Zerglings: %s/%s\\\", NEXTTARGET.hostname, ZERGSENT, ZERGREQUIRED)\\n if (!BATCHINFO.H1) debugger\\n ns.printf(\\\"%s/%s(%s) Batches: %s Take: $%s\\\", THREADSMAX - THREADSLEFT, THREADSMAX, THREADSLEFT, BATCHESRUN + 1, ns.format.number(BATCHINFO.Take * (BATCHESRUN + 1) * PREPH1 / BATCHINFO.H1))\\n ns.printf(\\\"HackP: %s%s ($%s/each) Chance: %s%s\\\", Math.round(BATCHINFO.HackP * 10000 * PREPH1) / 100, \\\"%\\\", ns.format.number(BATCHINFO.Take * PREPH1 / BATCHINFO.H1), ns.format.number(BATCHINFO.Chance * 100, 2), \\\"%\\\")\\n ns.printf(\\\"Prep Wave: W:%s G:%s W:%s H:%s W:%s G:%s W:%s\\\", PREPW1, PREPG1, PREPW2, PREPH1, PREPW3, PREPG2, PREPW4)\\n ns.printf(\\\"Batching Composition: H:%s W:%s G:%s W:%s\\\", BATCHINFO.H1, BATCHINFO.W1, BATCHINFO.G1, BATCHINFO.W2)\\n ns.printf(\\\"%s Countdown: %s\\\", \\\"$\\\" + profitPerSecond(ns, WEAKENTIME, BATCHINFO.Take * BATCHINFO.H1 / PREPH1, BATCHESRUN + 1), ns.format.time((WEAKENTIME + ENDTIME) - performance.now()))\\n ns.printf(\\\"Preptime : %s\\\", ns.format.time(BETWEENEND - BETWEENSTART, true))\\n ns.printf(\\\"Loadtime : %s\\\", ns.format.time(ENDTIME - STARTTIME, true))\\n ns.printf(\\\"Batchtime: %s\\\", ns.format.time(WEAKENTIME, true))\\n\\n if (AUTOBUYHACKNET) ns.printf(\\\"Auto Buy Hash: %s\\\", AUTOHASHTIMER - performance.now() > 0 ? ns.format.time(AUTOHASHTIMER - performance.now()) : \\\"Next Up\\\")\\n}\\n\\n/** @param {NS} ns */\\nasync function zerglings(ns, threads) {\\n if (ZERGREQUIRED <= 0) ZERGREQUIRED = Math.ceil((NEXTTARGET.hackDifficulty - NEXTTARGET.minDifficulty) / weakenStrength) + 1\\n if (ZERGSENT >= ZERGREQUIRED || threads === 0) return\\n const weakthreadsneeded = Math.ceil((NEXTTARGET.hackDifficulty - NEXTTARGET.minDifficulty) / weakenStrength) + 1 - ZERGSENT\\n const threadsthisround = weakthreadsneeded >= threads ? threads : weakthreadsneeded\\n\\n if (threadsthisround > 0) { //We are sending zerglings\\n ZERGSENT += threadsthisround\\n THREADSLEFT -= threadsthisround\\n await serverRun(ns, NEXTTARGET.hostname, threadsthisround, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, !ns.args.includes(\\\"usehacknet\\\"))\\n }\\n}\\n\\n/** @param {NS} ns **/\\nfunction virus(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try {\\n ns.nuke(server)\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n\\n }\\n catch { }\\n }\\n}\\n\\n/** @param {NS} ns */\\nfunction getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n const serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(server)\\n }\\n return serverDetails\\n}\\n\\n/** @param {NS} ns */\\nfunction getServers(ns, noHacknet = true) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n\\n const serverDetails = []\\n for (const server of serverList) {\\n serverDetails.push(ns.getServer(server))\\n }\\n serverDetails.sort((a, b) => { return (a.maxRam - a.ramUsed) - (b.maxRam - b.ramUsed) })\\n\\n return serverDetails\\n}\\n/** @param {NS} ns */\\nfunction getServersSorted(ns, nohacknet) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n\\n const serverDetails = []\\n for (const server of serverList) {\\n if (!ns.hasRootAccess(server)) continue\\n if (server.startsWith(\\\"hacknet\\\") && nohacknet) continue\\n serverDetails.push(server)\\n }\\n serverDetails.sort((a, b) => { return (ns.getServerMaxRam(a) - ns.getServerUsedRam(a)) - (ns.getServerMaxRam(b) - ns.getServerUsedRam(b)) })\\n\\n return serverDetails\\n}\\n/** @param {NS} ns */\\nfunction getPortOpeners(ns) {\\n let count = 0\\n if (ns.fileExists(\\\"BruteSSH.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"FTPCrack.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"relaySMTP.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"HTTPWorm.exe\\\", \\\"home\\\")) count++\\n if (ns.fileExists(\\\"SQLInject.exe\\\", \\\"home\\\")) count++\\n\\n return count\\n}\\n/** @param {NS} ns */\\nexport function getGrowThreads(ns, server, money, sec) {\\n const player = ns.getPlayer()\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n host.moneyAvailable = money\\n let gthreads = 0\\n try {\\n gthreads = ns.formulas.hacking.growThreads(host, player, host.moneyMax)\\n return gthreads\\n }\\n catch {\\n const server = host\\n const targetMoney = host.moneyMax\\n let startMoney = host.moneyAvailable\\n const cores = 1\\n const person = player\\n /*\\n if (!server.serverGrowth) {\\n gthreads = Infinity\\n }\\n */\\n const moneyMax = server.moneyMax ?? 1;\\n const hackDifficulty = server.hackDifficulty ?? 100;\\n\\n if (startMoney < 0) startMoney = 0; // servers \\\"can't\\\" have less than 0 dollars on them\\n if (targetMoney > moneyMax) targetMoney = moneyMax; // can't grow a server to more than its moneyMax\\n if (targetMoney <= startMoney) {\\n gthreads = 0; // no growth --> no threads\\n return gthreads\\n }\\n // exponential base adjusted by security\\n const adjGrowthRate = 1 + (1.03 - 1) / hackDifficulty;\\n const exponentialBase = Math.min(adjGrowthRate, 1.0035); // cap growth rate\\n\\n // total of all grow thread multipliers\\n const serverGrowthPercentage = server.serverGrowth / 100.0;\\n const coreMultiplier = 1 + (cores - 1) / 16\\n let threadMultiplier = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = getBNMults(ns)\\n threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier * mults.ServerGrowthRate\\n }\\n catch { threadMultiplier = serverGrowthPercentage * person.mults.hacking_grow * coreMultiplier }\\n\\n const x = threadMultiplier * Math.log(exponentialBase)\\n const y = startMoney * x + Math.log(targetMoney * x)\\n let w;\\n if (y < Math.log(2.5)) {\\n const ey = Math.exp(y);\\n w = (ey + (4 / 3) * ey * ey) / (1 + (7 / 3) * ey + (5 / 6) * ey * ey);\\n } else {\\n w = y;\\n if (y > 0) w -= Math.log(y);\\n }\\n let cycles = w / x - startMoney;\\n let bt = exponentialBase ** threadMultiplier;\\n if (bt == Infinity) bt = 1e300;\\n let corr = Infinity;\\n // Two sided error because we do not want to get stuck if the error stays on the wrong side\\n do {\\n // c should be above 0 so Halley's method can't be used, we have to stick to Newton-Raphson\\n let bct = bt ** cycles;\\n if (bct == Infinity) bct = 1e300;\\n const opc = startMoney + cycles;\\n let diff = opc * bct - targetMoney;\\n if (diff == Infinity) diff = 1e300;\\n corr = diff / (opc * x + 1.0) / bct;\\n cycles -= corr;\\n } while (Math.abs(corr) >= 1);\\n\\n const fca = Math.floor(cycles);\\n if (targetMoney <= (startMoney + fca) * Math.pow(exponentialBase, fca * threadMultiplier)) {\\n gthreads = fca;\\n return gthreads\\n }\\n const cca = Math.ceil(cycles);\\n if (targetMoney <= (startMoney + cca) * Math.pow(exponentialBase, cca * threadMultiplier)) {\\n gthreads = cca;\\n return gthreads\\n }\\n gthreads = cca + 1;\\n return gthreads\\n }\\n}\\n/** @param {NS} ns */\\nfunction getHackChance(ns, server, sec) {\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n try { return ns.formulas.hacking.hackChance(host, ns.getPlayer()) }\\n catch {\\n const person = ns.getPlayer()\\n const hackDifficulty = sec\\n const requiredHackingSkill = host.requiredHackingSkill\\n // Unrooted or unhackable server\\n if (!host.hasAdminRights || hackDifficulty >= 100 || host.minDifficulty >= 100) {\\n return 0\\n }\\n const hackFactor = 1.75;\\n const difficultyMult = (100 - hackDifficulty) / 100;\\n const skillMult = hackFactor * person.skills.hacking;\\n const skillChance = (skillMult - requiredHackingSkill) / skillMult;\\n let chance = 0\\n try {\\n chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance *\\n 1 + Math.pow(person.skills.intelligence, 0.8) / 600\\n }\\n catch {\\n chance =\\n skillChance *\\n difficultyMult *\\n person.mults.hacking_chance\\n }\\n return Math.min(1, Math.max(chance, 0));\\n }\\n}\\n/** @param {NS} ns */\\nfunction getHackPercent(ns, server, sec) {\\n const host = ns.getServer(server)\\n host.hackDifficulty = sec\\n const player = ns.getPlayer()\\n let hackperc = 0\\n try {\\n hackperc = ns.formulas.hacking.hackPercent(host, player)\\n return hackperc\\n }\\n catch {\\n const hackDifficulty = host.minDifficulty ?? 100\\n if (hackDifficulty >= 100) {\\n hackperc = 0\\n return hackperc\\n }\\n const requiredHackingSkill = host.requiredHackingSkill ?? 1e9\\n const balanceFactor = 240\\n const difficultyMult = (100 - hackDifficulty) / 100\\n const skillMult = (player.skills.hacking - (requiredHackingSkill - 1)) / player.skills.hacking\\n\\n let percentMoneyHacked = 0\\n try {\\n /** @type {BitNodeMultipliers} mults */\\n const mults = getBNMults(ns)\\n percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money * mults.ScriptHackMoney / balanceFactor\\n }\\n catch { percentMoneyHacked = difficultyMult * skillMult * player.mults.hacking_money / balanceFactor }\\n hackperc = Math.min(1, Math.max(percentMoneyHacked, 0))\\n }\\n return hackperc\\n}\\n\\n/** @param {NS} ns */\\nfunction getHackP(ns, server, batches, threads, starthacks) {\\n const hack_chance = getHackChance(ns, server.hostname, server.minDifficulty)\\n const hackperc = getHackPercent(ns, server.hostname, server.minDifficulty)\\n let moneytotake = 0\\n let hytotalbatches = 1\\n let hgwtotalbatches = 1\\n let hwgwtotalbatches = 1\\n let besttake = 0\\n let besth1threads = 0\\n let bestw1threads = 0\\n let bestg1threads = 0\\n let bestw2threads = 0\\n let besttype = \\\"HGW\\\"\\n let bestratio = 0\\n\\n //let testthreads = Math.min(Math.ceil(1 / hackperc), starthacks) - 1\\n for (let testthreads = Math.min(Math.ceil(1 / hackperc), starthacks); testthreads <= Math.max(Math.ceil(1 / hackperc), starthacks); testthreads++) {\\n //while (testthreads <= Math.max(Math.ceil(1 / hackperc))) {\\n //testthreads++\\n moneytotake = hackperc * testthreads >= 1 ? server.moneyMax - 1 : hackperc * server.moneyMax * testthreads\\n // Hybrid hacking threads and it's security threads\\n let hysechack = testthreads * .002 //Security added from hacking\\n const hyw1threads = Math.floor(hysechack / weakenStrength) //Take out the hybrid amount - just enough\\n hysechack -= hyw1threads * weakenStrength\\n // HGW hacking threads and it's security threads\\n const hgwsechack = testthreads * .002 //Security added from hacking which will carry over\\n // HWGW hacking threads and it's security threads\\n let hwgwsechack = testthreads * .002 //Security added from hacking\\n const hwgww1threads = Math.ceil(hwgwsechack / weakenStrength) //Take it all out \\n //Hybrid and HGW have some security left. HWGW does not\\n const hygthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty + hysechack)\\n const hgwgthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty + hgwsechack)\\n const hwgwgthreads = getGrowThreads(ns, server.hostname, server.moneyMax - moneytotake, server.minDifficulty)\\n\\n moneytotake *= hack_chance\\n //Last weaken threads for the grows and remaining from hacks\\n const hysecgrow = hygthreads * .004\\n const hgwsecgrow = hgwgthreads * .004\\n const hwgwsecgrow = hwgwgthreads * .004\\n\\n //Get weaken threads\\n const hyw2threads = Math.ceil((hysecgrow + hysechack) / weakenStrength)\\n const hgww2threads = Math.ceil((hgwsecgrow + hgwsechack) / weakenStrength)\\n const hwgww2threads = Math.ceil((hwgwsecgrow) / weakenStrength)\\n\\n //Get total thread count\\n const hytotalthreads = testthreads + hyw1threads + hygthreads + hyw2threads\\n const hgwtotalthreads = testthreads + hgwgthreads + hgww2threads\\n const hwgwtotalthreads = testthreads + hwgww1threads + hwgwgthreads + hwgww2threads\\n\\n if (threads > 0) {\\n hytotalbatches = Math.floor(threads / hytotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hytotalthreads)\\n hgwtotalbatches = Math.floor(threads / hgwtotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hgwtotalthreads)\\n hwgwtotalbatches = Math.floor(threads / hwgwtotalthreads) > batches || batches < 1 ? 0 : Math.floor(threads / hwgwtotalthreads)\\n }\\n\\n let VALIDTEST = false\\n let hyratio = 0\\n let hgwratio = 0\\n let hwgwratio = 0\\n\\n if (batches === -1 && threads === -1) { //Simply get the best. Assume unlimited batches/threads\\n hyratio = moneytotake / hytotalthreads\\n hgwratio = moneytotake / hgwtotalthreads\\n hwgwratio = moneytotake / hwgwtotalthreads\\n }\\n else {\\n hyratio = moneytotake / hytotalthreads * hytotalbatches\\n hgwratio = moneytotake / hgwtotalthreads * hgwtotalbatches\\n hwgwratio = moneytotake / hwgwtotalthreads * hwgwtotalbatches\\n }\\n if (hyratio || hgwratio || hwgwratio) VALIDTEST = true\\n\\n // Just cascade the possibilities\\n let failed = 0\\n //HGW\\n if (hgwratio > bestratio || (testthreads === Math.ceil(1 / hackperc) && bestratio === 0)) {\\n bestratio = hgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = 0\\n bestg1threads = hgwgthreads\\n bestw2threads = hgww2threads\\n besttype = \\\"HGW\\\"\\n }\\n else failed++\\n //Hybrid\\n if (hyratio > bestratio) {\\n bestratio = hyratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hyw1threads\\n bestg1threads = hygthreads\\n bestw2threads = hyw2threads\\n besttype = \\\"Hybrid\\\"\\n }\\n else failed++\\n //HWGW\\n if (hwgwratio > bestratio) {// || testthreads == Math.ceil(1 / hackperc)) { //Our default for the highest possible\\n bestratio = hwgwratio\\n besttake = moneytotake\\n besth1threads = testthreads\\n bestw1threads = hwgww1threads\\n bestg1threads = hwgwgthreads\\n bestw2threads = hwgww2threads\\n besttype = \\\"HWGW\\\"\\n }\\n else failed++\\n if (failed === 3 && VALIDTEST) break//We are done. Nothing better\\n } // for loop to max threads\\n\\n let takemult = 1\\n try {\\n const mults = getBNMults(ns)\\n takemult = mults.ScriptHackMoney\\n } catch { }\\n //Create return object\\n const record = {\\n \\\"H1\\\": besth1threads,\\n \\\"W1\\\": bestw1threads,\\n \\\"G1\\\": bestg1threads,\\n \\\"W2\\\": bestw2threads,\\n \\\"Type\\\": besttype,\\n \\\"Take\\\": besttake * takemult,\\n \\\"HackP\\\": hackperc,\\n \\\"Chance\\\": hack_chance\\n }\\n return record\\n}\\n/** @param {NS} ns */\\nfunction printProfit(ns, tm, take, batches, threads, chance) {\\n //tm is in milliseconds...\\n tm = tm / 1000\\n //Profit per second\\n let profit = (take / tm) * batches\\n profit = profit / threads * chance\\n return (profit === 0 || Number.isNaN(profit) || tm === Number.POSITIVE_INFINITY) ? 0 : profit\\n}\\n/** @param {NS} ns */\\nfunction profitPerSecond(ns, tm, take, batches) {\\n //tm is in milliseconds...\\n tm = tm / 1000\\n //Profit per second\\n let profit = (take / tm) * batches\\n return tm === 0 || isNaN(profit) ? 0 + \\\"/s\\\" : (ns.format.number(profit, 2) + \\\"/s\\\")\\n}\\n/** @param {NS} ns **/\\nfunction getOptimalTarget(ns) {\\n /** @type {Server[]} servers */\\n const servers = getServers(ns)\\n const player = ns.getPlayer()\\n let bestratio = 0\\n let bestserver;\\n for (const server of servers) {\\n if (server.minDifficulty === 100 || server.requiredHackingSkill > player.skills.hacking || !server.hasAdminRights || server.hostname === \\\"home\\\" || server.moneyMax === 0 || server.purchasedByPlayer) continue\\n const hchance = getHackChance(ns, server.hostname, server.minDifficulty)\\n if (hchance === 0) continue\\n const batchinfo = getHackP(ns, server, -1, -1, 1)\\n\\n const hackingTime = ns.getHackTime(server.hostname)\\n\\n //Weaken time at minimal difficulty\\n let weaktime = hackingTime * 4\\n weaktime = (weaktime === 0) ? 4 : weaktime\\n const totalthreads = (batchinfo.H1 + batchinfo.G1 + batchinfo.W2 + batchinfo.W1)\\n\\n const ratio = printProfit(ns, weaktime, batchinfo.Take, 1, totalthreads, hchance)\\n if (ratio > bestratio) {\\n bestratio = ratio\\n bestserver = server\\n }\\n\\n\\n }\\n return bestserver\\n}\\n/** @param {NS} ns */\\nasync function serverRun(ns, target, w1, g1, w2, h1, w3, g2, w4, batchh1, batchw1, batchg1, batchw2, batches, nohacknet) {\\n servers = getServersSorted(ns, nohacknet)\\n batchServers = getServersSorted(ns, nohacknet)\\n let results;\\n const hacktime = ns.getHackTime(target)\\n const growtime = ns.getGrowTime(target)\\n const weaktime = ns.getWeakenTime(target)\\n let recalc = false\\n let chunkswitch1 = false\\n let chunkswitch2 = false\\n\\n //Run the wave!\\n chunkswitch1 = check_batch(ns, w1, g1, w2, h1, w3, g2, w4, nohacknet)\\n const starttime = performance.now()\\n if (w1) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w1, false, nohacknet])\\n if (g1) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, weaktime - growtime, g1, chunkswitch1, nohacknet])\\n if (w2) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w2, false, nohacknet])\\n if (h1) results = runIt_Local(ns, \\\"SphyxOS/basic/hack.js\\\", [target, weaktime - hacktime, h1, chunkswitch1, nohacknet])\\n if (w3) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w3, false, nohacknet])\\n if (g2) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, weaktime - growtime, g2, chunkswitch1, nohacknet])\\n if (w4) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, w4, false, nohacknet])\\n\\n let batchesrun = 0\\n for (let i = 1; i <= Math.min(batches, 99999); i++) {\\n if (starttime + weaktime <= performance.now()) { //The performance wall\\n recalc = true\\n debugger\\n break\\n }\\n if (i === 99999) recalc = true\\n\\n batchesrun++\\n chunkswitch2 = check_batch(ns, 0, 0, 0, batchh1, batchw1, batchg1, batchw2, nohacknet)\\n if (batchh1) results = runIt_Local(ns, \\\"SphyxOS/basic/hack.js\\\", [target, weaktime - hacktime, batchh1, chunkswitch2, nohacknet])\\n if (batchw1) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, batchw1, false, nohacknet])\\n if (batchg1) results = runIt_Local(ns, \\\"SphyxOS/basic/grow.js\\\", [target, weaktime - growtime, batchg1, chunkswitch2, nohacknet])\\n if (batchw2) results = runIt_Local(ns, \\\"SphyxOS/basic/weaken.js\\\", [target, 0, batchw2, false, nohacknet])\\n\\n if (i % 2000 === 0) { // Reduce down for a smother experience\\n await ns.sleep(0)\\n }\\n }\\n const record = {\\n \\\"lastpid\\\": results,\\n \\\"recalc\\\": recalc,\\n \\\"batches\\\": batchesrun,\\n \\\"batching\\\": chunkswitch1 && chunkswitch2\\n }\\n return record\\n}\\n/** @param {NS} ns */\\nfunction runIt_Local(ns, script, argmts) {//target, sleeptm, threads, chunks, opt) {\\n const target = argmts[0]\\n const sleeptm = argmts[1]\\n let threads = argmts[2]\\n const chunks = argmts[3]\\n const nohacknet = argmts[4]\\n let thispid = 0\\n const serversRemove = []\\n for (const server of servers) {\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (server === \\\"hacknet\\\" && nohacknet) continue\\n if (server === \\\"home\\\") tmpramavailable = Math.max(tmpramavailable - RESERVERAM, 0) //Reserve home ram for smaller things\\n //Reserve our home threads\\n let threadsonserver = Math.floor(tmpramavailable / 1.75)\\n if (threadsonserver <= 0) {\\n serversRemove.push(server)\\n continue\\n }\\n //ns.scp([\\\"SphyxOS/basic/hack.js\\\", \\\"SphyxOS/basic/grow.js\\\", \\\"SphyxOS/basic/weaken.js\\\"], server, \\\"home\\\")\\n if (chunks) { //We NEED enough to finish the whole operation at once\\n if (threadsonserver >= threads) {\\n thispid = ns.exec(script, server, { threads: threads, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n threads = 0\\n break\\n }\\n } // chunks\\n else {\\n if (threadsonserver >= threads) { //We have enough to finish it off\\n thispid = ns.exec(script, server, { threads: threads, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n threads = 0\\n break\\n }\\n else { //We have threads but not enough \\n thispid = ns.exec(script, server, { threads: threadsonserver, temporary: true }, target, sleeptm, \\\"QUIET\\\")\\n if (thispid === 0) ns.tprintf(\\\"Failed to run: %s on %s threads:%s target:%s\\\", script, server, threads, target)\\n threads -= threadsonserver\\n threadsonserver = 0\\n serversRemove.push(server)\\n }\\n }//No chunks\\n }// All servers\\n if (threads > 0) ns.tprintf(\\\"Failed to allocate all %s threads. %s left. Chunk: %s Error!\\\", script, threads, chunks)\\n //servers = servers.filter((f) => !serversRemove.includes(f))\\n return thispid\\n}\\n/** @param {NS} ns */\\nfunction check_batch(ns, w1, g1, w2, h1, w3, g2, w4, noHacknet, checklist = []) {\\n //Nothing has been started up yet. Base servers have all the values we need.\\n //Our test cases. One for each possible worker type\\n let w1test = false\\n let g1test = false\\n let w2test = false\\n let h1test = false\\n let w3test = false\\n let g2test = false\\n let w4test = false\\n const startcount = w1 + g1 + w2 + h1 + w3 + g2 + w4\\n const remove = []\\n for (const server of batchServers) {\\n let tmpramavailable = ns.getServerMaxRam(server) - ns.getServerUsedRam(server)\\n if (server === \\\"home\\\") tmpramavailable = Math.max(tmpramavailable - RESERVERAM, 0) //Reserve home ram for smaller things\\n\\n let threadsonserver = Math.floor(tmpramavailable / 1.75)\\n //Reduce by our checklist\\n\\n if (checklist.length > 0) checklist.forEach((c) => c.name === server ? threadsonserver -= c.threads : null)\\n if (threadsonserver <= 0) {\\n remove.push(server)\\n continue\\n }\\n\\n //W1 testing\\n if (!w1test) { //No chunking\\n if (threadsonserver >= w1) { //We have enough to finish it off\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += w1\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": w1\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= w1\\n w1test = true\\n w1 = 0\\n }\\n else { //We have threads but not enough\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += threadsonserver\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": threadsonserver\\n }\\n checklist.push(record)\\n }\\n w1 -= threadsonserver\\n threadsonserver = 0\\n remove.push(server)\\n }\\n }\\n\\n //G1 testing\\n if (w1test && !g1test) { //Chunking\\n if (threadsonserver >= g1) {\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += g1\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": g1\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= g1\\n g1test = true\\n if (g1 !== 0) {\\n g1 = 0\\n break //Allows the next weaken cycle to start from the lowest server again\\n }\\n }\\n }\\n\\n //W2 testing\\n if (g1test && !w2test) { //No chunking\\n if (threadsonserver >= w2) { //We have enough to finish it off\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += w2\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": w2\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= w2\\n w2test = true\\n w2 = 0\\n }\\n else { //We have threads but not enough\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += threadsonserver\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": threadsonserver\\n }\\n checklist.push(record)\\n }\\n w2 -= threadsonserver\\n threadsonserver = 0\\n remove.push(server)\\n }\\n }\\n\\n //H1 testing\\n if (w2test && !h1test) { //Chunking\\n if (threadsonserver >= h1) {\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += h1\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": h1\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= h1\\n h1test = true\\n if (h1 !== 0) {\\n h1 = 0\\n break //Allows the next weaken cycle to start from the lowest server again\\n }\\n }\\n }\\n\\n //W3 testing\\n if (h1test && !w3test) { //No chunking\\n if (threadsonserver >= w3) { //We have enough to finish it off\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += w3\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": w3\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= w3\\n w3test = true\\n w3 = 0\\n }\\n else { //We have threads but not enough\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += threadsonserver\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": threadsonserver\\n }\\n checklist.push(record)\\n }\\n w3 -= threadsonserver\\n threadsonserver = 0\\n remove.push(server)\\n }\\n }\\n\\n //G2 testing\\n if (w3test && !g2test) { //Chunking\\n if (threadsonserver >= g2) {\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += g2\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": g2\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= g2\\n g2test = true\\n if (g2 !== 0) {\\n g2 = 0\\n break //Allows the next weaken cycle to start from the lowest server again\\n }\\n }\\n }\\n\\n //W4 testing\\n if (g2test && !w4test) { //No chunking\\n if (threadsonserver >= w4) { //We have enough to finish it off\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += w4\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": w4\\n }\\n checklist.push(record)\\n }\\n threadsonserver -= w4\\n w4test = true\\n w4 = 0\\n }\\n else { //We have threads but not enough\\n let found = false\\n for (let check of checklist) {\\n if (check.name === server) {\\n found = true\\n check.threads += threadsonserver\\n }\\n }\\n if (!found) {\\n let record = {\\n \\\"name\\\": server,\\n \\\"threads\\\": threadsonserver\\n }\\n checklist.push(record)\\n }\\n w4 -= threadsonserver\\n threadsonserver = 0\\n remove.push(server)\\n }\\n }\\n\\n //If this is true, it's all good\\n if (w4test) { //Success\\n return true\\n }\\n }//End of batchServers\\n const endcount = w1 + g1 + w2 + h1 + w3 + g2 + w4\\n batchServers = batchServers.filter((f) => !remove.includes(f))\\n //Did we make a change? If so, run it again!\\n if (startcount !== endcount) { // We processed something. Keep processing until we are done.\\n return check_batch(ns, w1, g1, w2, h1, w3, g2, w4, noHacknet, checklist)\\n }\\n else {\\n return false\\n }\\n}\\n/** @param {NS} ns */\\nfunction serverPurchaser(ns) {\\n let upgradecost = 1e150\\n const startRam = 2\\n // Iterator we'll use for our loop\\n let i = ns.cloud.getServerNames().length\\n if (ns.cloud.getServerLimit() === 0) return\\n\\n //Buy the base servers\\n while (i < ns.cloud.getServerLimit()) {\\n // Check if we have enough money to purchase a server\\n if (ns.getServerMoneyAvailable(\\\"home\\\") >= ns.cloud.getServerCost(startRam)) {\\n const server = i >= 10 ? ns.cloud.purchaseServer(\\\"pserv-\\\" + i, startRam) : ns.cloud.purchaseServer(\\\"pserv-0\\\" + i, startRam);\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n i++;\\n }\\n else {\\n upgradecost = ns.cloud.getServerCost(startRam)\\n return upgradecost\\n }\\n }\\n const servers = ns.cloud.getServerNames()\\n\\n //Cycle through every server. Check each attribute for cost of upgrade\\n //Upgrade the cheapest. Keep upgrading indefinitally\\n let upgradeitem = \\\"\\\"\\n let ramupgrade = 0\\n upgradecost = Number.POSITIVE_INFINITY\\n\\n //Check all servers\\n for (const server of servers) {\\n //Get the cheapest one and document it\\n if (ns.cloud.getServerUpgradeCost(server, ns.getServerMaxRam(server) * 2) < upgradecost) {\\n upgradecost = ns.cloud.getServerUpgradeCost(server, ns.getServerMaxRam(server) * 2)\\n upgradeitem = server\\n ramupgrade = ns.getServerMaxRam(server) * 2\\n }\\n }\\n //upgrade the server if we can\\n if (ns.getServerMoneyAvailable(\\\"home\\\") >= upgradecost) ns.cloud.upgradeServer(upgradeitem, ramupgrade)\\n else {\\n upgradecost = upgradecost === Number.POSITIVE_INFINITY ? 0 : upgradecost\\n }\\n return upgradecost\\n}\\n/** @param {NS} ns */\\nfunction hasBN(ns, bn, bnLvl = 1) {\\n const resetInfo = ns.getResetInfo()\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n if (resetInfo.currentNode === bn) {\\n return true\\n }\\n for (const sf of sourceFiles) if (sf.n === bn && sf.lvl >= bnLvl) {\\n return true\\n }\\n return false\\n}\\n/** @param {NS} ns */\\nfunction hashIt(ns, target, opt) {\\n //arg[0] is Type; money, corp, min, max, study, train, research, bbrank, bbsp, coding, favor, \\n //Target needs to be determined. peek(3) for current hacking target\\n //Will need to figure out Target for company favor - working for should do it but it's singularity\\n switch (opt) {\\n case \\\"min\\\":\\n if (ns.getServerMinSecurityLevel(target) === 1) break\\n while (ns.hacknet.spendHashes(\\\"Reduce Minimum Security\\\", target)) { if (ns.getServerMinSecurityLevel(target) === 1) break }\\n break\\n case \\\"max\\\":\\n while (ns.hacknet.spendHashes(\\\"Increase Maximum Money\\\", target)) { }\\n break\\n default:\\n break\\n }\\n}\\n/** @param {NS} ns */\\nfunction hacknetPurchaser(ns) {\\n let upgradeCost = -1\\n while (true) {\\n let upgradeType = 0\\n let upgradeItem = -1\\n upgradeCost = -1\\n if (ns.hacknet.numNodes() < ns.hacknet.maxNumNodes()) {\\n upgradeCost = ns.hacknet.getPurchaseNodeCost()\\n upgradeType = 5\\n }\\n for (let i = 0; i < ns.hacknet.numNodes(); i++) {\\n\\n if (upgradeCost == -1) { //Might be first one if we've purchased them all. We need to set the cost of something. Do so then move on\\n upgradeCost = ns.hacknet.getLevelUpgradeCost(i, 1)\\n upgradeType = 1\\n upgradeItem = i\\n }\\n if (ns.hacknet.getLevelUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getLevelUpgradeCost(i, 1)\\n upgradeType = 1\\n upgradeItem = i\\n }\\n if (ns.hacknet.getRamUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getRamUpgradeCost(i, 1)\\n upgradeType = 2\\n upgradeItem = i\\n }\\n if (ns.hacknet.getCoreUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getCoreUpgradeCost(i, 1)\\n upgradeType = 3\\n upgradeItem = i\\n }\\n if (ns.hacknet.getCacheUpgradeCost(i, 1) < upgradeCost) {\\n upgradeCost = ns.hacknet.getCacheUpgradeCost(i, 1)\\n upgradeType = 4\\n upgradeItem = i\\n }\\n }\\n\\n if (upgradeCost === Number.POSITIVE_INFINITY) {\\n upgradeCost = 0\\n return upgradeCost\\n } //We have no upgrade\\n else if (ns.getServerMoneyAvailable(\\\"home\\\") < upgradeCost) return upgradeCost//We don't have enough money to purchase\\n switch (upgradeType) {\\n case 1:\\n ns.hacknet.upgradeLevel(upgradeItem, 1)\\n break\\n case 2:\\n ns.hacknet.upgradeRam(upgradeItem, 1)\\n break\\n case 3:\\n ns.hacknet.upgradeCore(upgradeItem, 1)\\n break\\n case 4:\\n ns.hacknet.upgradeCache(upgradeItem, 1)\\n break\\n case 5:\\n ns.hacknet.purchaseNode()\\n break\\n default:\\n return upgradeCost\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction getServerAvailRam(ns, target) {\\n return ns.getServerMaxRam(target) - ns.getServerUsedRam(target)\\n}\\n/** @param {NS} ns */\\nfunction init(ns) {\\n baseServers = getServers(ns)\\n weakenStrength = ns.weakenAnalyze(1)\\n TARGET = \\\"\\\" //Who you are hacking\\n NEXTTARGET = \\\"\\\" //Whos next up\\n TARGETUPDATE = false\\n ZERGSTATUS = false\\n ZERGSENT = 0\\n ZERGREQUIRED = -1\\n RECALC_GOOD = false\\n RECALC_BAD = false\\n PORTS_OPEN = getPortOpeners(ns)\\n BMODE = \\\"B\\\" //Batching style. b is not batching, B is batching\\n THREADSMAX = 0 //Total threads available\\n BATCHESTOTAL = 0 //Total batches done\\n BATCHESRUN = 0 //Total batches actually run\\n PREPW1 = 0 //Prep wave\\n PREPG1 = 0\\n PREPW2 = 0\\n PREPH1 = 1\\n PREPW3 = 0\\n PREPG2 = 0\\n PREPW4 = 0\\n STARTTIME = 0\\n ENDTIME = 0\\n BETWEENSTART = performance.now()\\n BETWEENEND = 0\\n WEAKENTIME = 0\\n}\\n\\n/** @param {NS} ns */\\nasync function writeFiles(ns) {\\n const hfile = `\\n /** @param {NS} ns */\\nexport async function main(ns) {\\n await ns.hack(ns.args[0], { additionalMsec: ns.args[1] })\\n}`\\nconst gfile = `\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n await ns.grow(ns.args[0], { additionalMsec: ns.args[1] })\\n}`\\nconst wfile = `\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n await ns.weaken(ns.args[0], { additionalMsec: ns.args[1] })\\n}`\\n\\nns.write(\\\"SphyxOS/basic/hack.js\\\", hfile, \\\"w\\\")\\nns.write(\\\"SphyxOS/basic/grow.js\\\", gfile, \\\"w\\\")\\nns.write(\\\"SphyxOS/basic/weaken.js\\\", wfile, \\\"w\\\")\\n//Now, we get them ready\\nlet pidof = ns.exec(\\\"SphyxOS/basic/hack.js\\\", \\\"home\\\", 1, \\\"n00dles\\\")\\nawait ns.sleep(4)\\nns.kill(pidof)\\npidof = ns.exec(\\\"SphyxOS/basic/grow.js\\\", \\\"home\\\", 1, \\\"n00dles\\\")\\nawait ns.sleep(4)\\nns.kill(pidof)\\npidof = ns.exec(\\\"SphyxOS/basic/weaken.js\\\", \\\"home\\\", 1, \\\"n00dles\\\")\\nawait ns.sleep(4)\\nns.kill(pidof)\\n}\\n\\n/** @param {NS} ns */\\nfunction getBNMults(ns) {\\n let mults;\\n try { mults = ns.getBitNodeMultipliers() }\\n catch {\\n const resetInfo = ns.getResetInfo()\\n let record = {\\n \\\"AgilityLevelMultiplier\\\": 1,\\n \\\"AugmentationMoneyCost\\\": 1,\\n \\\"AugmentationRepCost\\\": 1,\\n \\\"BladeburnerRank\\\": 1,\\n \\\"BladeburnerSkillCost\\\": 1,\\n \\\"CharismaLevelMultiplier\\\": 1,\\n \\\"ClassGymExpGain\\\": 1,\\n \\\"CodingContractMoney\\\": 1,\\n \\\"CompanyWorkExpGain\\\": 1,\\n \\\"CompanyWorkMoney\\\": 1,\\n \\\"CompanyWorkRepGain\\\": 1,\\n \\\"CorporationValuation\\\": 1,\\n \\\"CrimeExpGain\\\": 1,\\n \\\"CrimeMoney\\\": 1,\\n \\\"CrimeSuccessRate\\\": 1,\\n \\\"DaedalusAugsRequirement\\\": 30,\\n \\\"DefenseLevelMultiplier\\\": 1,\\n \\\"DexterityLevelMultiplier\\\": 1,\\n \\\"FactionPassiveRepGain\\\": 1,\\n \\\"FactionWorkExpGain\\\": 1,\\n \\\"FactionWorkRepGain\\\": 1,\\n \\\"FourSigmaMarketDataApiCost\\\": 1,\\n \\\"FourSigmaMarketDataCost\\\": 1,\\n \\\"GangSoftcap\\\": 1,\\n \\\"GangUniqueAugs\\\": 1,\\n \\\"GoPower\\\": 1,\\n \\\"HackExpGain\\\": 1,\\n \\\"HackingLevelMultiplier\\\": 1,\\n \\\"HackingSpeedMultiplier\\\": 1,\\n \\\"HacknetNodeMoney\\\": 1,\\n \\\"HomeComputerRamCost\\\": 1,\\n \\\"InfiltrationMoney\\\": 1,\\n \\\"InfiltrationRep\\\": 1,\\n \\\"ManualHackMoney\\\": 1,\\n \\\"CloudServerCost\\\": 1,\\n \\\"CloudServerSoftcap\\\": 1,\\n \\\"CloudServerLimit\\\": 1,\\n \\\"CloudServerMaxRam\\\": 1,\\n \\\"FavorToDonateToFaction\\\": 1, //New\\n \\\"FavorToDonateToFaction\\\": 1, //Old\\n \\\"ScriptHackMoney\\\": 1,\\n \\\"ScriptHackMoneyGain\\\": 1,\\n \\\"ServerGrowthRate\\\": 1,\\n \\\"ServerMaxMoney\\\": 1,\\n \\\"ServerStartingMoney\\\": 1,\\n \\\"ServerStartingSecurity\\\": 1,\\n \\\"ServerWeakenRate\\\": 1,\\n \\\"StrengthLevelMultiplier\\\": 1,\\n \\\"StaneksGiftPowerMultiplier\\\": 1,\\n \\\"StaneksGiftExtraSize\\\": 0,\\n \\\"WorldDaemonDifficulty\\\": 1,\\n \\\"CorporationSoftcap\\\": 1,\\n \\\"CorporationDivisions\\\": 1\\n }\\n switch (resetInfo.currentNode) {\\n case 1:\\n break\\n case 2:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.8\\n record.ServerStartingMoney = 0.4\\n record.CloudServerSoftcap = 1.3\\n record.CrimeMoney = 3\\n record.FactionPassiveRepGain = 0\\n record.FactionWorkRepGain = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.InfiltrationMoney = 3\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = -6\\n record.WorldDaemonDifficulty = 5\\n break\\n case 3:\\n record.HackingLevelMultiplier = 0.8\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.04\\n record.ServerStartingMoney = 0.2\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 2\\n record.CloudServerSoftcap = 1.3\\n record.CompanyWorkMoney = 0.25\\n record.CrimeMoney = 0.25\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.2\\n record.FavorToDonateToFaction = 0.5 //New\\n record.FavorToDonateToFaction = 0.5 //Old\\n record.AugmentationMoneyCost = 3\\n record.AugmentationRepCost = 3\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 4:\\n record.ServerMaxMoney = 0.1125\\n record.ServerStartingMoney = 0.75\\n record.CloudServerSoftcap = 1.2\\n record.CompanyWorkMoney = 0.1\\n record.CrimeMoney = 0.2\\n record.HacknetNodeMoney = 0.05\\n record.ScriptHackMoney = 0.2\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.4\\n record.FactionWorkRepGain = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.5\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 3\\n break\\n case 5:\\n record.ServerStartingSecurity = 2\\n record.ServerStartingMoney = 0.5\\n record.CloudServerSoftcap = 1.2\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.15\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 1.5\\n record.InfiltrationRep = 1.5\\n record.CorporationValuation = 0.75\\n record.CorporationDivisions = 0.75\\n record.GangUniqueAugs = 0.5\\n record.StaneksGiftPowerMultiplier = 1.3\\n record.StaneksGiftExtraSize = 0\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 6:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.75\\n record.HackExpGain = 0.25\\n record.InfiltrationMoney = 0.75\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 7:\\n record.HackingLevelMultiplier = 0.35\\n record.ServerMaxMoney = 0.2\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.75\\n record.HacknetNodeMoney = 0.2\\n record.ScriptHackMoney = 0.5\\n record.HackExpGain = 0.25\\n record.AugmentationMoneyCost = 3\\n record.InfiltrationMoney = 0.75\\n record.FourSigmaMarketDataCost = 2\\n record.FourSigmaMarketDataApiCost = 2\\n record.CorporationValuation = 0.2\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.2\\n record.DaedalusAugsRequirement = 35\\n record.StaneksGiftPowerMultiplier = 0.9\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 2\\n break\\n case 8:\\n record.CloudServerSoftcap = 4\\n record.CompanyWorkMoney = 0\\n record.CrimeMoney = 0\\n record.HacknetNodeMoney = 0\\n record.ManualHackMoney = 0\\n record.ScriptHackMoney = 0.3\\n record.ScriptHackMoneyGain = 0\\n record.CodingContractMoney = 0\\n record.FavorToDonateToFaction = 0 //New\\n record.FavorToDonateToFaction = 0 //Old\\n record.InfiltrationMoney = 0\\n record.CorporationValuation = 0\\n record.CorporationSoftcap = 0\\n record.CorporationDivisions = 0\\n record.BladeburnerRank = 0\\n record.GangSoftcap = 0\\n record.GangUniqueAugs = 0\\n record.StaneksGiftExtraSize = -99\\n break\\n case 9:\\n record.HackingLevelMultiplier = 0.5\\n record.StrengthLevelMultiplier = 0.45\\n record.DefenseLevelMultiplier = 0.45\\n record.DexterityLevelMultiplier = 0.45\\n record.AgilityLevelMultiplier = 0.45\\n record.CharismaLevelMultiplier = 0.45\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerStartingSecurity = 2.5\\n record.HomeComputerRamCost = 5\\n record.CloudServerLimit = 0\\n record.CrimeMoney = 0.5\\n record.ScriptHackMoney = 0.1\\n record.HackExpGain = 0.05\\n record.FourSigmaMarketDataCost = 5\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.75\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.9\\n record.BladeburnerSkillCost = 1.2\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = 2\\n record.WorldDaemonDifficulty = 2\\n break\\n case 10:\\n record.HackingLevelMultiplier = 0.35\\n record.StrengthLevelMultiplier = 0.4\\n record.DefenseLevelMultiplier = 0.4\\n record.DexterityLevelMultiplier = 0.4\\n record.AgilityLevelMultiplier = 0.4\\n record.CharismaLevelMultiplier = 0.4\\n record.HomeComputerRamCost = 1.5\\n record.CloudServerCost = 5\\n record.CloudServerSoftcap = 1.1\\n record.CloudServerLimit = 0.6\\n record.CloudServerMaxRam = 0.5\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 0.5\\n record.HacknetNodeMoney = 0.5\\n record.ManualHackMoney = 0.5\\n record.ScriptHackMoney = 0.5\\n record.CodingContractMoney = 0.5\\n record.AugmentationMoneyCost = 5\\n record.AugmentationRepCost = 2\\n record.InfiltrationMoney = 0.5\\n record.CorporationValuation = 0.5\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.BladeburnerRank = 0.8\\n record.GangSoftcap = 0.9\\n record.GangUniqueAugs = 0.25\\n record.StaneksGiftPowerMultiplier = 0.75\\n record.StaneksGiftExtraSize = -3\\n record.WorldDaemonDifficulty = 2\\n break\\n case 11:\\n record.HackingLevelMultiplier = 0.6\\n record.ServerGrowthRate = 0.2\\n record.ServerMaxMoney = 0.01\\n record.ServerStartingMoney = 0.1\\n record.ServerWeakenRate = 2\\n record.CloudServerSoftcap = 2\\n record.CompanyWorkMoney = 0.5\\n record.CrimeMoney = 3\\n record.HacknetNodeMoney = 0.1\\n record.CodingContractMoney = 0.25\\n record.HackExpGain = 0.5\\n record.AugmentationMoneyCost = 2\\n record.InfiltrationMoney = 2.5\\n record.InfiltrationRep = 2.5\\n record.FourSigmaMarketDataCost = 4\\n record.FourSigmaMarketDataApiCost = 4\\n record.CorporationValuation = 0.1\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.9\\n record.GangUniqueAugs = 0.75\\n record.WorldDaemonDifficulty = 1.5\\n break\\n case 12:\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let SF12LVL = 1\\n for (const sf of sourceFiles) {\\n if (sf.n === 12) {\\n SF12LVL = sf.lvl + 1\\n break\\n }\\n }\\n const inc = Math.pow(1.02, SF12LVL)\\n const dec = 1 / inc\\n\\n record.DaedalusAugsRequirement = Math.floor(Math.min(record.DaedalusAugsRequirement + inc, 40))\\n record.HackingLevelMultiplier = dec\\n record.StrengthLevelMultiplier = dec\\n record.DefenseLevelMultiplier = dec\\n record.DexterityLevelMultiplier = dec\\n record.AgilityLevelMultiplier = dec\\n record.CharismaLevelMultiplier = dec\\n record.ServerGrowthRate = dec\\n record.ServerMaxMoney = dec * dec\\n record.ServerStartingMoney = dec\\n record.ServerWeakenRate = dec\\n record.ServerStartingSecurity = 1.5\\n record.HomeComputerRamCost = inc\\n record.CloudServerCost = inc\\n record.CloudServerSoftcap = inc\\n record.CloudServerLimit = dec\\n record.CloudServerMaxRam = dec\\n record.CompanyWorkMoney = dec\\n record.CrimeMoney = dec\\n record.HacknetNodeMoney = dec\\n record.ManualHackMoney = dec\\n record.ScriptHackMoney = dec\\n record.CodingContractMoney = dec\\n record.ClassGymExpGain = dec\\n record.CompanyWorkExpGain = dec\\n record.CrimeExpGain = dec\\n record.FactionWorkExpGain = dec\\n record.HackExpGain = dec\\n record.FactionPassiveRepGain = dec\\n record.FactionWorkRepGain = dec\\n record.FavorToDonateToFaction = inc\\n record.AugmentationMoneyCost = inc\\n record.AugmentationRepCost = inc\\n record.InfiltrationMoney = dec\\n record.InfiltrationRep = dec\\n record.FourSigmaMarketDataCost = inc\\n record.FourSigmaMarketDataApiCost = inc\\n record.CorporationValuation = dec\\n record.CorporationSoftcap = 0.8\\n record.CorporationDivisions = 0.5\\n record.BladeburnerRank = dec\\n record.BladeburnerSkillCost = inc\\n record.GangSoftcap = 0.8\\n record.GangUniqueAugs = dec\\n record.StaneksGiftPowerMultiplier = inc\\n record.StaneksGiftExtraSize = inc\\n record.WorldDaemonDifficulty = inc\\n break\\n case 13:\\n record.HackingLevelMultiplier = 0.25\\n record.StrengthLevelMultiplier = 0.7\\n record.DefenseLevelMultiplier = 0.7\\n record.DexterityLevelMultiplier = 0.7\\n record.AgilityLevelMultiplier = 0.7\\n record.CloudServerSoftcap = 1.6\\n record.ServerMaxMoney = 0.3375\\n record.ServerStartingMoney = 0.75\\n record.ServerStartingSecurity = 3\\n record.CompanyWorkMoney = 0.4\\n record.CrimeMoney = 0.4\\n record.HacknetNodeMoney = 0.4\\n record.ScriptHackMoney = 0.2\\n record.CodingContractMoney = 0.4\\n record.ClassGymExpGain = 0.5\\n record.CompanyWorkExpGain = 0.5\\n record.CrimeExpGain = 0.5\\n record.FactionWorkExpGain = 0.5\\n record.HackExpGain = 0.1\\n record.FactionWorkRepGain = 0.6\\n record.FourSigmaMarketDataCost = 10\\n record.FourSigmaMarketDataApiCost = 10\\n record.CorporationValuation = 0.001\\n record.CorporationSoftcap = 0.4\\n record.CorporationDivisions = 0.4\\n record.BladeburnerRank = 0.45\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.3\\n record.GangUniqueAugs = 0.1\\n record.StaneksGiftPowerMultiplier = 2\\n record.StaneksGiftExtraSize = 1\\n record.WorldDaemonDifficulty = 3\\n break\\n case 14:\\n record.GoPower = 4\\n record.HackingLevelMultiplier = 0.4\\n record.HackingSpeedMultiplier = 0.3\\n record.ServerMaxMoney = 0.7\\n record.ServerStartingMoney = 0.5\\n record.ServerStartingSecurity = 1.5\\n record.CrimeMoney = 0.75\\n record.CrimeSuccessRate = 0.4\\n record.HacknetNodeMoney = 0.25\\n record.ScriptHackMoney = 0.3\\n record.StrengthLevelMultiplier = 0.5\\n record.DexterityLevelMultiplier = 0.5\\n record.AgilityLevelMultiplier = 0.5\\n record.AugmentationMoneyCost = 1.5\\n record.InfiltrationMoney = 0.75\\n record.FactionWorkRepGain = 0.2\\n record.CompanyWorkRepGain = 0.2\\n record.CorporationValuation = 0.4\\n record.CorporationSoftcap = 0.9\\n record.CorporationDivisions = 0.8\\n record.BladeburnerRank = 0.6\\n record.BladeburnerSkillCost = 2\\n record.GangSoftcap = 0.7\\n record.GangUniqueAugs = 0.4\\n record.StaneksGiftPowerMultiplier = 0.5\\n record.StaneksGiftExtraSize = -1\\n record.WorldDaemonDifficulty = 5\\n break\\n }\\n mults = record\\n }\\n return mults\\n}\""},{"filename":"SphyxOS/full/sleevesFull.js","file":"\"let MODE = \\\"Recovery\\\" //Training, Money, Recovery, Sync, Karma, Int\\nconst IMODE = \\\"Training\\\" // Install Mode\\nlet HASBN5 = false\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n HASBN5 = hasBN(ns, 5, 1)\\n ns.ui.openTail()\\n //Read commands, set Mode\\n if (ns.args.length > 1) {\\n ns.printf(\\\"Only 1 argument.\\\\nmoney, karma, int, recovery, sync, training, install\\\")\\n ns.exit()\\n }\\n if (ns.args.includes(\\\"money\\\")) MODE = \\\"Money\\\"\\n if (ns.args.includes(\\\"karma\\\")) MODE = \\\"Karma\\\"\\n if (ns.args.includes(\\\"int\\\")) MODE = \\\"Int\\\"\\n if (ns.args.includes(\\\"recovery\\\")) MODE = \\\"Recovery\\\"\\n if (ns.args.includes(\\\"sync\\\")) MODE = \\\"Sync\\\"\\n if (ns.args.includes(\\\"training\\\")) MODE = \\\"Training\\\"\\n if (ns.args.includes(\\\"install\\\")) MODE = \\\"Install\\\"\\n\\n while (true) {\\n //me, num, task\\n const sleeves = getSleeveObject(ns)\\n if (MODE === \\\"Install\\\") installAugs(ns, sleeves)\\n displaySleeves(ns)\\n await ns.sleep(1000)\\n for (const slv of sleeves) {\\n \\n if (MODE === \\\"Recovery\\\") {\\n ns.sleeve.setToShockRecovery(slv.num)\\n continue\\n }\\n if (MODE === \\\"Sync\\\") {\\n ns.sleeve.setToSynchronize(slv.num)\\n continue\\n }\\n if (MODE === \\\"Training\\\") {\\n const skls = slv.me.skills\\n //Make sure we are in Sector-12\\n if (slv.me.city !== \\\"Sector-12\\\") {\\n if (!ns.sleeve.travel(slv.num, \\\"Sector-12\\\")) continue\\n }\\n if (skls.hacking === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"Computer Science\\\") {\\n ns.sleeve.setToUniversityCourse(slv.num, \\\"Rothman University\\\", \\\"Computer Science\\\")\\n }\\n continue\\n }\\n if (skls.strength === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"str\\\") {\\n ns.sleeve.setToGymWorkout(slv.num, \\\"Powerhouse Gym\\\", \\\"str\\\")\\n }\\n continue\\n }\\n if (skls.defense === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"def\\\") {\\n ns.sleeve.setToGymWorkout(slv.num, \\\"Powerhouse Gym\\\", \\\"def\\\")\\n }\\n continue\\n }\\n if (skls.dexterity === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"dexterity\\\") {\\n ns.sleeve.setToGymWorkout(slv.num, \\\"Powerhouse Gym\\\", \\\"dex\\\")\\n }\\n continue\\n }\\n if (skls.agility === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"agi\\\") {\\n ns.sleeve.setToGymWorkout(slv.num, \\\"Powerhouse Gym\\\", \\\"agi\\\")\\n }\\n continue\\n }\\n if (skls.charisma === Math.min(skls.hacking, skls.strength, skls.defense, skls.dexterity, skls.agility, skls.charisma)) {\\n if (slv.task === null || slv.task.classType !== \\\"Leadership\\\") {\\n ns.sleeve.setToUniversityCourse(slv.num, \\\"rothman university\\\", \\\"Leadership\\\")\\n }\\n continue\\n }\\n ns.tprintf(\\\"Error! Failed to train.\\\")\\n continue\\n }//End Training\\n if ([\\\"Money\\\", \\\"Karma\\\", \\\"Int\\\", \\\"Install\\\"].includes(MODE)) {\\n //Cycle our crimes and find the best for our mode.\\n const STYLE = MODE === \\\"Install\\\" ? IMODE : MODE\\n let bestRatio = 0\\n let bestCrime = \\\"Mug\\\"\\n for (const crime of crimes) {\\n const chance = getChance(ns, crime, slv.me)\\n const gain = STYLE === \\\"Money\\\" ? crime.money : STYLE === \\\"Install\\\" ? crime.money : STYLE === \\\"Karma\\\" ? crime.karma : crime.intelligence_exp\\n const ratio = gain * chance / crime.time\\n if (ratio > bestRatio) {\\n bestRatio = ratio\\n bestCrime = crime.name\\n }\\n }\\n\\n if (slv.task && slv.task.crimeType !== bestCrime) ns.sleeve.setToCommitCrime(slv.num, bestCrime)\\n continue\\n }\\n }//End of sleeves\\n }//End While True\\n}\\n/** @param {NS} ns */\\nfunction installAugs(ns, sleeves) {\\n for (const slv of sleeves) {\\n if (slv.me.shock !== 0) continue\\n const augs = ns.sleeve.getSleevePurchasableAugs(slv.num)\\n augs.forEach((a) => ns.sleeve.purchaseSleeveAug(slv.num, a.name))\\n }\\n}\\n/** @param {NS} ns */\\nfunction getSleeveObject(ns) {\\n const sleeves = []\\n for (let slv = 0; slv < ns.sleeve.getNumSleeves(); slv++) {\\n const record = {\\n \\\"num\\\": slv,\\n \\\"me\\\": ns.sleeve.getSleeve(slv),\\n \\\"task\\\": ns.sleeve.getTask(slv)\\n }\\n sleeves.push(record)\\n }\\n return sleeves\\n}\\n/** @param {NS} ns */\\nfunction hasBN(ns, bn, bnLvl = 1) {\\n const resetInfo = ns.getResetInfo()\\n const sourceFiles = []\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n if (resetInfo.currentNode === bn) {\\n return true\\n }\\n for (const sf of sourceFiles) if (sf.n === bn && sf.lvl >= bnLvl) {\\n return true\\n }\\n return false\\n}\\n/** @param {NS} ns */\\nasync function displaySleeves(ns) {\\n ns.clearLog()\\n ns.print(\\\"Sleeve Statistics:\\\")\\n if (HASBN5) ns.printf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s\\\", \\\"#\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Int\\\", \\\"Aug\\\", \\\"Shock\\\", \\\"Action\\\", \\\"Name\\\")\\n else ns.printf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s\\\", \\\"#\\\", \\\"Hack\\\", \\\"Str\\\", \\\"Def\\\", \\\"Dex\\\", \\\"Agi\\\", \\\"Cha\\\", \\\"Aug\\\", \\\"Shock\\\", \\\"Action\\\", \\\"Name\\\")\\n //num, me, task\\n const sleeves = getSleeveObject(ns)\\n for (const slv of sleeves) {\\n if (HASBN5) ns.printf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s %s\\\", slv.num, ns.format.number(slv.me.skills.hacking, 3), ns.format.number(slv.me.skills.strength, 3), ns.format.number(slv.me.skills.defense, 3), ns.format.number(slv.me.skills.dexterity, 3), ns.format.number(slv.me.skills.agility, 3), ns.format.number(slv.me.skills.charisma, 3), ns.format.number(slv.me.skills.intelligence), ns.sleeve.getSleeveAugmentations(slv.num).length, ns.format.number(slv.me.shock, 2), slv.task === null ? \\\"Shock Recovery\\\" : slv.task.type, slv.task.actionType || slv.task.classType || slv.task.crimeType || \\\"n/a\\\")\\n else ns.printf(\\\"%s: %8s %8s %8s %8s %8s %8s %8s %3s %5s %8s %s\\\", slv.num, ns.format.number(slv.me.skills.hacking, 3), ns.format.number(slv.me.skills.strength, 3), ns.format.number(slv.me.skills.defense, 3), ns.format.number(slv.me.skills.dexterity, 3), ns.format.number(slv.me.skills.agility, 3), ns.format.number(slv.me.skills.charisma, 3), ns.sleeve.getSleeveAugmentations(slv.num).length, ns.format.number(slv.me.shock, 2), slv.task === null ? \\\"Shock Recovery\\\" : slv.task.type, slv.task.actionType || slv.task.classType || slv.task.crimeType || \\\"n/a\\\")\\n }\\n}\\nfunction getChance(ns, crimestats, wsleeve) {\\n let hackweight = crimestats.hacking_success_weight * wsleeve.skills.hacking\\n let strweight = crimestats.strength_success_weight * wsleeve.skills.strength\\n let defweight = crimestats.defense_success_weight * wsleeve.skills.defense\\n let dexweight = crimestats.dexterity_success_weight * wsleeve.skills.dexterity\\n let agiweight = crimestats.agility_success_weight * wsleeve.skills.agility\\n let chaweight = crimestats.charisma_success_weight * wsleeve.skills.charisma\\n let intweight = HASBN5 ? 0.025 * wsleeve.skills.intelligence : 0\\n let chance = hackweight + strweight + defweight + dexweight + agiweight + chaweight + intweight\\n chance /= 975\\n chance /= crimestats.difficulty\\n chance *= wsleeve.mults.crime_success\\n if (HASBN5) chance *= 1 + (1 * Math.pow(wsleeve.skills.intelligence, 0.8)) / 600\\n chance *= 100\\n return Math.min(chance, 100)\\n}\\nconst crimes = [\\n {\\n \\\"name\\\": \\\"Shoplift\\\",\\n \\\"time\\\": 2e3,\\n \\\"money\\\": 15e3,\\n \\\"difficulty\\\": 1 / 20,\\n \\\"karma\\\": 0.1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Rob Store\\\",\\n \\\"time\\\": 60e3,\\n \\\"money\\\": 400e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.5,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 7.5 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Mug\\\",\\n \\\"time\\\": 4e3,\\n \\\"money\\\": 36e3,\\n \\\"difficulty\\\": 1 / 5,\\n \\\"karma\\\": 0.25,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1.5,\\n \\\"defense_success_weight\\\": 0.5,\\n \\\"dexterity_success_weight\\\": 1.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Larceny\\\",\\n \\\"time\\\": 90e3,\\n \\\"money\\\": 800e3,\\n \\\"difficulty\\\": 1 / 3,\\n \\\"karma\\\": 1.5,\\n \\\"hacking_success_weight\\\": 0.5,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 15 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Deal Drugs\\\",\\n \\\"time\\\": 10e3,\\n \\\"money\\\": 120e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 0.5,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 3,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Bond Forgery\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 4.5e6,\\n \\\"difficulty\\\": 1 / 2,\\n \\\"karma\\\": 0.1,\\n \\\"hacking_success_weight\\\": 0.05,\\n \\\"strength_success_weight\\\": 0,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1.25,\\n \\\"agility_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 60 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Traffick Arms\\\",\\n \\\"time\\\": 40e3,\\n \\\"money\\\": 600e3,\\n \\\"difficulty\\\": 2,\\n \\\"karma\\\": 1,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Homicide\\\",\\n \\\"time\\\": 3e3,\\n \\\"money\\\": 45e3,\\n \\\"difficulty\\\": 1,\\n \\\"karma\\\": 3,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 2,\\n \\\"defense_success_weight\\\": 2,\\n \\\"dexterity_success_weight\\\": 0.5,\\n \\\"agility_success_weight\\\": 0.5,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 0\\n },\\n {\\n \\\"name\\\": \\\"Grand Theft Auto\\\",\\n \\\"time\\\": 80e3,\\n \\\"money\\\": 1.6e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 5,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 4,\\n \\\"agility_success_weight\\\": 2,\\n \\\"charisma_success_weight\\\": 2,\\n \\\"intelligence_exp\\\": 16 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Kidnap\\\",\\n \\\"time\\\": 120e3,\\n \\\"money\\\": 3.6e6,\\n \\\"difficulty\\\": 5,\\n \\\"karma\\\": 6,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 26 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Assassination\\\",\\n \\\"time\\\": 300e3,\\n \\\"money\\\": 12e6,\\n \\\"difficulty\\\": 8,\\n \\\"karma\\\": 10,\\n \\\"hacking_success_weight\\\": 0,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 0,\\n \\\"dexterity_success_weight\\\": 2,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 0,\\n \\\"intelligence_exp\\\": 65 * 0.05\\n },\\n {\\n \\\"name\\\": \\\"Heist\\\",\\n \\\"time\\\": 600e3,\\n \\\"money\\\": 120e6,\\n \\\"difficulty\\\": 18,\\n \\\"karma\\\": 15,\\n \\\"hacking_success_weight\\\": 1,\\n \\\"strength_success_weight\\\": 1,\\n \\\"defense_success_weight\\\": 1,\\n \\\"dexterity_success_weight\\\": 1,\\n \\\"agility_success_weight\\\": 1,\\n \\\"charisma_success_weight\\\": 1,\\n \\\"intelligence_exp\\\": 130 * 0.05\\n }\\n]\""},{"filename":"SphyxOS/games/doom.jsx","file":"\"/**Author:\\n * Discord:\\n * - Sphyxis\\n */\\nconst DOOM_URL = \\\"https://raz0red.github.io/webprboom/\\\"\\nconst DEFAULT_WIDTH = 960\\nconst DEFAULT_HEIGHT = 760\\n\\nfunction getFrame() {\\n return globalThis[\\\"document\\\"]?.getElementById(\\\"bitburner-doom-frame\\\")\\n}\\n\\nfunction focusDoomFrame() {\\n const frame = getFrame()\\n if (!frame) return\\n\\n frame.focus({ preventScroll: true })\\n try {\\n frame.contentWindow?.focus()\\n } catch (_) {}\\n}\\n\\nfunction focusDoomFrameSoon() {\\n focusDoomFrame()\\n //If we still lose focus, enable these\\n //globalThis[\\\"setTimeout\\\"]?.(focusDoomFrame, 50)\\n //globalThis[\\\"setTimeout\\\"]?.(focusDoomFrame, 250)\\n}\\n\\nfunction DoomPlayer() {\\n return (\\n \\n \\n
\\n )\\n}\\n\\nconst styles = {\\n shell: {\\n width: \\\"100%\\\",\\n maxWidth: \\\"100%\\\",\\n aspectRatio: \\\"4 / 3\\\",\\n maxHeight: \\\"100vh\\\",\\n margin: 0,\\n padding: 0,\\n overflow: \\\"hidden\\\",\\n backgroundColor: \\\"#000000\\\",\\n },\\n frame: {\\n display: \\\"block\\\",\\n width: \\\"100%\\\",\\n height: \\\"100%\\\",\\n border: \\\"none\\\",\\n margin: 0,\\n padding: 0,\\n backgroundColor: \\\"#000000\\\",\\n outline: \\\"none\\\",\\n },\\n}\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.clearLog()\\n ns.ui.openTail()\\n ns.ui.setTailTitle(\\\"DOOM - BitBurner Edition - Click to Play\\\")\\n ns.ui.resizeTail(DEFAULT_WIDTH, DEFAULT_HEIGHT)\\n ns.printRaw( )\\n //await new Promise(() => { })\\n}\\n\""},{"filename":"SphyxOS/games/minesweeper.jsx","file":"\"/**Author:\\n * Discord:\\n * - goos\\n * \\n * Additional Contributers:\\n * Discord:\\n * - Sphyxis\\n */\\n\\n//Settings\\nconst SAVE_FILE = \\\"SphyxOSUserData/games/minesweeperHighScores.txt\\\"\\nconst START_HIGH_SCORE = 999000\\nconst DIFFICULTIES = {\\n Beginner: { boardRow: 9, boardCol: 9, maxNumberOfMines: 10 },\\n Intermediate: { boardRow: 16, boardCol: 16, maxNumberOfMines: 40 },\\n Expert: { boardRow: 16, boardCol: 30, maxNumberOfMines: 99 },\\n}\\nconst VISIT = {\\n unknown: 0,\\n known: 1,\\n flagged: 2,\\n}\\nconst CELL_SIZE = 28\\nconst BOARD_PADDING_X = 80\\nconst BOARD_PADDING_Y = 250\\nconst MIN_TAIL_WIDTH = 420\\nconst MIN_TAIL_HEIGHT = 420\\nconst NUMBER_COLORS = {\\n 1: \\\"#3b82f6\\\",\\n 2: \\\"#16a34a\\\",\\n 3: \\\"#dc2626\\\",\\n 4: \\\"#7c3aed\\\",\\n 5: \\\"#b45309\\\",\\n 6: \\\"#0891b2\\\",\\n 7: \\\"#334155\\\",\\n 8: \\\"#6b7280\\\",\\n}\\n\\nfunction generateGrid({ boardRow, boardCol }, value = 0) {\\n const grid = []\\n for (let row = 0; row < boardRow; row++) {\\n grid.push(Array(boardCol).fill(value))\\n }\\n return grid\\n}\\n\\nfunction getRandomInt(max) {\\n return Math.floor(Math.random() * max)\\n}\\n\\nfunction isValidCoordinates(row, col, { boardRow, boardCol }) {\\n return row >= 0 && row < boardRow && col >= 0 && col < boardCol\\n}\\n\\nfunction getSurroundingCoordinates([centerRow, centerCol], boardSize) {\\n const surroundingCoords = []\\n for (let rowOffset = -1; rowOffset <= 1; rowOffset++) {\\n for (let colOffset = -1; colOffset <= 1; colOffset++) {\\n const nearbyRow = centerRow + rowOffset\\n const nearbyCol = centerCol + colOffset\\n if (!isValidCoordinates(nearbyRow, nearbyCol, boardSize)) continue\\n surroundingCoords.push([nearbyRow, nearbyCol])\\n }\\n }\\n return surroundingCoords\\n}\\n\\nfunction firstTurnSafetyField(gridArea, currentPosition, boardSize) {\\n const safeGrid = gridArea.map((row) => [...row])\\n for (const [row, col] of getSurroundingCoordinates(currentPosition, boardSize)) {\\n safeGrid[row][col] -= 1\\n }\\n return safeGrid\\n}\\n\\nfunction generateMinefield(gridArea, boardSize, maxNumberOfMines) {\\n const nextGrid = gridArea.map((row) => [...row])\\n const selectableCoords = []\\n for (let row = 0; row < boardSize.boardRow; row++) {\\n for (let col = 0; col < boardSize.boardCol; col++) {\\n selectableCoords.push([row, col])\\n }\\n }\\n for (let mines = 0; mines < maxNumberOfMines;) {\\n const coordsIndex = getRandomInt(selectableCoords.length)\\n const [randomRow, randomCol] = selectableCoords[coordsIndex]\\n if (nextGrid[randomRow][randomCol] < 0) {\\n selectableCoords.splice(coordsIndex, 1)\\n continue\\n }\\n if (typeof nextGrid[randomRow][randomCol] !== \\\"string\\\") {\\n selectableCoords.splice(coordsIndex, 1)\\n nextGrid[randomRow][randomCol] = \\\"Mine\\\"\\n mines++\\n }\\n }\\n return nextGrid\\n}\\n\\nfunction countNearbyMine(gridArea, currentPosition, boardSize) {\\n let numOfMines = 0\\n for (const [row, col] of getSurroundingCoordinates(currentPosition, boardSize)) {\\n if (typeof gridArea[row][col] === \\\"string\\\") numOfMines += 1\\n }\\n return numOfMines\\n}\\n\\nfunction updateCellNearby(gridArea, boardSize) {\\n const nextGrid = gridArea.map((row) => [...row])\\n for (let row = 0; row < nextGrid.length; row++) {\\n for (let col = 0; col < nextGrid[row].length; col++) {\\n if (nextGrid[row][col] < 0) nextGrid[row][col] += 1\\n nextGrid[row][col] += countNearbyMine(nextGrid, [row, col], boardSize)\\n }\\n }\\n return nextGrid\\n}\\n\\nfunction createBoard(boardSize, maxNumberOfMines) {\\n return {\\n boardSize,\\n maxNumberOfMines,\\n gridArea: generateGrid(boardSize),\\n gridInfo: generateGrid(boardSize, VISIT.unknown),\\n isFirstTurn: true,\\n isGameOver: false,\\n isWin: false,\\n }\\n}\\n\\nfunction ensureBoardGenerated(state, currentPosition) {\\n if (!state.isFirstTurn) return state\\n let gridArea = firstTurnSafetyField(state.gridArea, currentPosition, state.boardSize)\\n gridArea = generateMinefield(gridArea, state.boardSize, state.maxNumberOfMines)\\n gridArea = updateCellNearby(gridArea, state.boardSize)\\n return {\\n ...state,\\n gridArea,\\n isFirstTurn: false,\\n }\\n}\\n\\nfunction floodDiscovery(gridArea, gridInfo, currentPosition, boardSize) {\\n const nextInfo = gridInfo.map((row) => [...row])\\n const [startRow, startCol] = currentPosition\\n if (gridArea[startRow][startCol] !== 0) return nextInfo\\n\\n const toVisit = [currentPosition]\\n for (let index = 0; index < toVisit.length; index++) {\\n const [row, col] = toVisit[index]\\n nextInfo[row][col] = VISIT.known\\n if (gridArea[row][col] !== 0) continue\\n\\n for (const [newRow, newCol] of getSurroundingCoordinates([row, col], boardSize)) {\\n const alreadyQueued = toVisit.some(([queuedRow, queuedCol]) => queuedRow === newRow && queuedCol === newCol)\\n if (alreadyQueued) continue\\n if (nextInfo[newRow][newCol] === VISIT.unknown) {\\n toVisit.push([newRow, newCol])\\n }\\n }\\n }\\n return nextInfo\\n}\\n\\nfunction chordingTile(gridArea, gridInfo, currentPosition, boardSize) {\\n const nextInfo = gridInfo.map((row) => [...row])\\n const [centerRow, centerCol] = currentPosition\\n const neededNum = gridArea[centerRow][centerCol]\\n let nearbyFlagged = 0\\n const surroundingCoords = getSurroundingCoordinates(currentPosition, boardSize)\\n\\n for (const [row, col] of surroundingCoords) {\\n if (nextInfo[row][col] === VISIT.flagged) nearbyFlagged += 1\\n }\\n if (neededNum !== nearbyFlagged) return nextInfo\\n\\n for (const [row, col] of surroundingCoords) {\\n if (nextInfo[row][col] === VISIT.flagged) continue\\n if (nextInfo[row][col] === VISIT.known) continue\\n nextInfo[row][col] = VISIT.known\\n const floodedInfo = floodDiscovery(gridArea, nextInfo, [row, col], boardSize)\\n for (let infoRow = 0; infoRow < nextInfo.length; infoRow++) {\\n nextInfo[infoRow] = [...floodedInfo[infoRow]]\\n }\\n }\\n return nextInfo\\n}\\n\\nfunction countFlags(gridInfo) {\\n let total = 0\\n for (const row of gridInfo) {\\n for (const cell of row) {\\n if (cell === VISIT.flagged) total++\\n }\\n }\\n return total\\n}\\n\\nfunction checkIfWin(gridArea, gridInfo, maxNumberOfMines) {\\n let correctFlags = 0\\n let totalFlags = 0\\n for (let row = 0; row < gridArea.length; row++) {\\n for (let col = 0; col < gridArea[row].length; col++) {\\n if (gridInfo[row][col] === VISIT.flagged) {\\n totalFlags++\\n if (typeof gridArea[row][col] === \\\"string\\\") correctFlags++\\n }\\n }\\n }\\n return correctFlags === maxNumberOfMines && totalFlags === maxNumberOfMines\\n}\\n\\nfunction revealBoardLossState(state) {\\n const nextState = { ...state }\\n nextState.isGameOver = true\\n return nextState\\n}\\n\\nfunction applyReveal(state, currentPosition) {\\n if (state.isGameOver || state.isWin) return state\\n const [row, col] = currentPosition\\n if (state.gridInfo[row][col] === VISIT.flagged) return state\\n\\n const preparedState = ensureBoardGenerated(state, currentPosition)\\n const nextState = {\\n ...preparedState,\\n gridInfo: preparedState.gridInfo.map((infoRow) => [...infoRow]),\\n }\\n\\n if (preparedState.gridArea[row][col] !== 0 && nextState.gridInfo[row][col] === VISIT.known) {\\n nextState.gridInfo = chordingTile(preparedState.gridArea, nextState.gridInfo, currentPosition, preparedState.boardSize)\\n } else {\\n nextState.gridInfo[row][col] = VISIT.known\\n nextState.gridInfo = floodDiscovery(preparedState.gridArea, nextState.gridInfo, currentPosition, preparedState.boardSize)\\n }\\n\\n for (let scanRow = 0; scanRow < nextState.gridInfo.length; scanRow++) {\\n for (let scanCol = 0; scanCol < nextState.gridInfo[scanRow].length; scanCol++) {\\n if (\\n nextState.gridInfo[scanRow][scanCol] === VISIT.known &&\\n typeof nextState.gridArea[scanRow][scanCol] === \\\"string\\\"\\n ) {\\n return revealBoardLossState(nextState)\\n }\\n }\\n }\\n\\n if (checkIfWin(nextState.gridArea, nextState.gridInfo, nextState.maxNumberOfMines)) {\\n nextState.isWin = true\\n }\\n return nextState\\n}\\n\\nfunction applyFlagToggle(state, currentPosition) {\\n if (state.isGameOver || state.isWin) return state\\n const [row, col] = currentPosition\\n const nextGridInfo = state.gridInfo.map((infoRow) => [...infoRow])\\n if (nextGridInfo[row][col] === VISIT.known) return state\\n\\n nextGridInfo[row][col] = nextGridInfo[row][col] === VISIT.flagged ? VISIT.unknown : VISIT.flagged\\n return {\\n ...state,\\n gridInfo: nextGridInfo,\\n isWin: checkIfWin(state.gridArea, nextGridInfo, state.maxNumberOfMines),\\n }\\n}\\n\\nfunction parseHighScores(ns) {\\n try {\\n ns.scp(SAVE_FILE, ns.self().server, \\\"home\\\")\\n const file = ns.read(SAVE_FILE)\\n if (!file) return new Map()\\n return new Map(JSON.parse(file))\\n } catch {\\n return new Map()\\n }\\n}\\n\\nfunction scoreKey(boardSize, maxNumberOfMines) {\\n return `${boardSize.boardRow}x${boardSize.boardCol}:${maxNumberOfMines}`\\n}\\n\\nfunction getHighScore(highScores, boardSize, maxNumberOfMines) {\\n return highScores.get(scoreKey(boardSize, maxNumberOfMines)) ?? START_HIGH_SCORE\\n}\\n\\nfunction formatTime(seconds) {\\n if (!Number.isFinite(seconds)) return \\\"--\\\"\\n return seconds.toFixed(1)\\n}\\n\\nfunction getTailSize(boardSize) {\\n return {\\n width: Math.max(MIN_TAIL_WIDTH, (boardSize.boardCol * CELL_SIZE) + BOARD_PADDING_X),\\n height: Math.max(MIN_TAIL_HEIGHT, (boardSize.boardRow * CELL_SIZE) + BOARD_PADDING_Y),\\n }\\n}\\n\\nfunction getCellLabel(cellState, infoState, isGameOver) {\\n if (isGameOver && typeof cellState === \\\"string\\\") return \\\"X\\\"\\n if (infoState === VISIT.flagged) return \\\"F\\\"\\n if (infoState === VISIT.unknown) return \\\"\\\"\\n if (typeof cellState === \\\"string\\\") return \\\"X\\\"\\n if (cellState === 0) return \\\"\\\"\\n return String(cellState)\\n}\\n\\nfunction getCellStyle(cellState, infoState, isGameOver) {\\n const isKnown = infoState === VISIT.known || (isGameOver && typeof cellState === \\\"string\\\")\\n const isMine = typeof cellState === \\\"string\\\" && (isGameOver || infoState === VISIT.known)\\n const baseStyle = {\\n width: CELL_SIZE,\\n height: CELL_SIZE,\\n border: \\\"1px solid #334155\\\",\\n fontSize: 14,\\n fontWeight: 700,\\n cursor: \\\"pointer\\\",\\n padding: 0,\\n userSelect: \\\"none\\\",\\n backgroundColor: isKnown ? \\\"#dbe4ee\\\" : \\\"#94a3b8\\\",\\n color: \\\"#0f172a\\\",\\n }\\n if (infoState === VISIT.flagged) {\\n baseStyle.backgroundColor = \\\"#f59e0b\\\"\\n baseStyle.color = \\\"#111827\\\"\\n } else if (isMine) {\\n baseStyle.backgroundColor = \\\"#ef4444\\\"\\n baseStyle.color = \\\"#ffffff\\\"\\n } else if (isKnown && typeof cellState === \\\"number\\\" && cellState > 0) {\\n baseStyle.color = NUMBER_COLORS[cellState] ?? \\\"#111827\\\"\\n }\\n return baseStyle\\n}\\n\\nfunction App({ ns, initialHighScores }) {\\n const React = globalThis[\\\"React\\\"] ?? globalThis[\\\"window\\\"]?.React\\n const [difficulty, setDifficulty] = React.useState(\\\"Beginner\\\")\\n const [customRows, setCustomRows] = React.useState(\\\"Rows\\\")\\n const [customCols, setCustomCols] = React.useState(\\\"Columns\\\")\\n const [customMines, setCustomMines] = React.useState(\\\"Mines\\\")\\n const [highScores, setHighScores] = React.useState(initialHighScores)\\n const [startMs, setStartMs] = React.useState(Date.now())\\n const [elapsedSeconds, setElapsedSeconds] = React.useState(0)\\n const [statusMessage, setStatusMessage] = React.useState(\\\"Left click to reveal. Right click to flag.\\\")\\n\\n function getConfig() {\\n if (difficulty !== \\\"Custom\\\") return DIFFICULTIES[difficulty]\\n const boardRow = Number(customRows)\\n const boardCol = Number(customCols)\\n const maxNumberOfMines = Number(customMines)\\n if (!Number.isInteger(boardRow) || !Number.isInteger(boardCol) || !Number.isInteger(maxNumberOfMines)) {\\n return null\\n }\\n if (boardRow < 3 || boardCol < 3 || maxNumberOfMines < 1) return null\\n if (maxNumberOfMines > (boardRow * boardCol) - 9) return null\\n return { boardRow, boardCol, maxNumberOfMines }\\n }\\n\\n const initialConfig = getConfig() ?? DIFFICULTIES.Beginner\\n const [gameState, setGameState] = React.useState(() => createBoard(initialConfig, initialConfig.maxNumberOfMines))\\n\\n const currentHighScore = getHighScore(highScores, gameState.boardSize, gameState.maxNumberOfMines)\\n const minesRemaining = gameState.maxNumberOfMines - countFlags(gameState.gridInfo)\\n\\n React.useEffect(() => {\\n if (gameState.isWin || gameState.isGameOver) {\\n setElapsedSeconds((Date.now() - startMs) / 1000)\\n return\\n }\\n const intervalId = globalThis[\\\"window\\\"]?.setInterval(() => {\\n setElapsedSeconds((Date.now() - startMs) / 1000)\\n }, 100)\\n return () => globalThis[\\\"window\\\"]?.clearInterval(intervalId)\\n }, [startMs, gameState.isWin, gameState.isGameOver])\\n\\n React.useEffect(() => {\\n if (!gameState.isWin) return\\n const finalTime = (Date.now() - startMs) / 1000\\n setElapsedSeconds(finalTime)\\n const key = scoreKey(gameState.boardSize, gameState.maxNumberOfMines)\\n const oldScore = highScores.get(key) ?? START_HIGH_SCORE\\n if (finalTime < oldScore) {\\n const nextScores = new Map(highScores)\\n nextScores.set(key, finalTime)\\n setHighScores(nextScores)\\n try {\\n ns.write(SAVE_FILE, JSON.stringify(Array.from(nextScores)), \\\"w\\\")\\n ns.scp(SAVE_FILE, \\\"home\\\")\\n setStatusMessage(`You won in ${formatTime(finalTime)}s. New high score.`)\\n }\\n catch { setStatusMessage(`Saving of highscores is disabled while the script is stopped.`) }\\n return\\n }\\n else setStatusMessage(`You won in ${formatTime(finalTime)}s.`)\\n }, [gameState.isWin, gameState.boardSize, gameState.maxNumberOfMines, highScores, ns, startMs])\\n\\n React.useEffect(() => {\\n if (!gameState.isGameOver) return\\n setStatusMessage(\\\"Game over. Press New Game to try again.\\\")\\n }, [gameState.isGameOver])\\n\\n React.useEffect(() => {\\n const { width, height } = getTailSize(gameState.boardSize)\\n try { ns.ui.resizeTail(width, height) } catch { }\\n }, [gameState.boardSize, ns])\\n\\n function resetGame(nextDifficulty = difficulty) {\\n const config = nextDifficulty === \\\"Custom\\\"\\n ? getConfig()\\n : DIFFICULTIES[nextDifficulty]\\n if (!config) {\\n setStatusMessage(\\\"Custom settings must be whole numbers, at least 3x3, with room for a safe first click.\\\")\\n return\\n }\\n setDifficulty(nextDifficulty)\\n setGameState(createBoard(config, config.maxNumberOfMines))\\n setStartMs(Date.now())\\n setElapsedSeconds(0)\\n setStatusMessage(\\\"Left click to reveal. Right click to flag.\\\")\\n }\\n\\n function handleReveal(row, col) {\\n setGameState((prevState) => applyReveal(prevState, [row, col]))\\n }\\n\\n function handleFlag(row, col) {\\n setGameState((prevState) => applyFlagToggle(prevState, [row, col]))\\n }\\n\\n return (\\n \\n
\\n
\\n
Minesweeper
\\n
Mouse controls: left click reveal, right click flag.
\\n
\\n
\\n
\\n\\n
\\n Time: {formatTime(gameState.isWin || gameState.isGameOver ? elapsedSeconds : elapsedSeconds)} \\n Mines: {minesRemaining} \\n Best: {currentHighScore >= START_HIGH_SCORE ? \\\"--\\\" : formatTime(currentHighScore)} \\n
\\n\\n
{statusMessage}
\\n\\n
\\n {gameState.gridArea.map((row, rowIndex) =>\\n row.map((cell, colIndex) => {\\n const infoState = gameState.gridInfo[rowIndex][colIndex]\\n const label = getCellLabel(cell, infoState, gameState.isGameOver)\\n return (\\n handleReveal(rowIndex, colIndex)}\\n onContextMenu={(event) => {\\n event.preventDefault()\\n handleFlag(rowIndex, colIndex)\\n }}\\n title={`Row ${rowIndex + 1}, Col ${colIndex + 1}`}\\n >\\n {label}\\n \\n )\\n })\\n )}\\n
\\n\\n
\\n Left click an opened number to chord when its surrounding flags match the number.\\n
\\n
\\n )\\n}\\n\\nconst styles = {\\n app: {\\n fontFamily: \\\"Verdana, sans-serif\\\",\\n color: \\\"#e2e8f0\\\",\\n backgroundColor: \\\"#0f172a\\\",\\n padding: 16,\\n minHeight: \\\"100%\\\",\\n },\\n header: {\\n display: \\\"flex\\\",\\n justifyContent: \\\"space-between\\\",\\n gap: 16,\\n alignItems: \\\"flex-start\\\",\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 12,\\n },\\n title: {\\n fontSize: 24,\\n fontWeight: 700,\\n },\\n subtitle: {\\n color: \\\"#94a3b8\\\",\\n marginTop: 4,\\n },\\n controls: {\\n display: \\\"flex\\\",\\n gap: 8,\\n alignItems: \\\"center\\\",\\n flexWrap: \\\"wrap\\\",\\n },\\n customControls: {\\n display: \\\"flex\\\",\\n gap: 8,\\n flexWrap: \\\"wrap\\\",\\n },\\n select: {\\n padding: \\\"6px 10px\\\",\\n backgroundColor: \\\"#1e293b\\\",\\n color: \\\"#e2e8f0\\\",\\n border: \\\"1px solid #475569\\\",\\n },\\n input: {\\n width: 70,\\n padding: \\\"6px 8px\\\",\\n backgroundColor: \\\"#1e293b\\\",\\n color: \\\"#e2e8f0\\\",\\n border: \\\"1px solid #475569\\\",\\n },\\n button: {\\n padding: \\\"6px 12px\\\",\\n backgroundColor: \\\"#22c55e\\\",\\n color: \\\"#052e16\\\",\\n fontWeight: 700,\\n border: \\\"none\\\",\\n cursor: \\\"pointer\\\",\\n },\\n stats: {\\n display: \\\"flex\\\",\\n gap: 16,\\n flexWrap: \\\"wrap\\\",\\n marginBottom: 8,\\n fontWeight: 700,\\n },\\n status: {\\n marginBottom: 12,\\n color: \\\"#cbd5e1\\\",\\n },\\n board: {\\n display: \\\"grid\\\",\\n gap: 0,\\n width: \\\"fit-content\\\",\\n border: \\\"2px solid #475569\\\",\\n backgroundColor: \\\"#475569\\\",\\n },\\n footer: {\\n marginTop: 12,\\n color: \\\"#94a3b8\\\",\\n maxWidth: 700,\\n },\\n}\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n ns.clearLog()\\n ns.ui.openTail()\\n const highScores = parseHighScores(ns)\\n ns.clearPort(27)\\n ns.writePort(27, ns.pid)\\n ns.atExit(() => { ns.clearPort(27) })\\n ns.printRaw( )\\n await new Promise(() => { })\\n}\\n\""},{"filename":"SphyxOS/games/timberman.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const React = globalThis[\\\"window\\\"].React\\n const doc = eval(\\\"document\\\");\\n const audioCtx = new globalThis[\\\"window\\\"].AudioContext();\\n let move\\n let stop\\n let handleKey\\n let ending = false\\n function TimberGame() {\\n const [branches, setBranches] = React.useState(Array(6).fill(0));\\n const [playerSide, setPlayerSide] = React.useState(1);\\n const [score, setScore] = React.useState(0);\\n const [highScore, setHighScore] = React.useState(0);\\n const [gameOver, setGameOver] = React.useState(false);\\n const [hasFocus, setHasFocus] = React.useState(false);\\n const [mode, setMode] = React.useState(null);\\n const [timeLeft, setTimeLeft] = React.useState(100);\\n const [pos, setPos] = React.useState({ x: globalThis[\\\"window\\\"].innerWidth / 2 - 110, y: 100 });\\n const [isDragging, setIsDragging] = React.useState(false);\\n\\n const playSound = (freq, type, duration, vol = 0.05) => {\\n if (audioCtx.state === 'suspended') audioCtx.resume();\\n const osc = audioCtx.createOscillator();\\n const gain = audioCtx.createGain();\\n osc.type = type; osc.frequency.setValueAtTime(freq, audioCtx.currentTime);\\n gain.gain.setValueAtTime(vol, audioCtx.currentTime);\\n gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);\\n osc[\\\"connect\\\"](gain); gain[\\\"connect\\\"](audioCtx.destination);\\n osc.start(); osc.stop(audioCtx.currentTime + duration);\\n };\\n\\n const chop = (side) => {\\n if (gameOver || !hasFocus || !mode) return;\\n\\n // 1. Move Player First\\n setPlayerSide(side);\\n\\n // 2. Process Tree Drop\\n const nextBranches = [...branches.slice(1)];\\n const rand = Math.random();\\n const newBranch = rand < 0.38 ? 1 : (rand < 0.76 ? 2 : 0);\\n nextBranches.push(newBranch);\\n\\n // 3. COLLISION CHECK: Check player side against the NEW bottom branch\\n if (nextBranches[0] === side) {\\n setGameOver(true);\\n playSound(120, 'sawtooth', 0.5, 0.1);\\n } else {\\n setBranches(nextBranches);\\n setScore(s => {\\n const ns = s + 1;\\n if (ns > highScore) setHighScore(ns);\\n return ns;\\n });\\n\\n if (mode === 'timber') {\\n setTimeLeft(p => {\\n // INCREASED REFILL: Minimum refill is now 5.5% \\n const bonus = Math.max(5.5, 12 - (score * 0.1));\\n return Math.min(100, p + bonus);\\n });\\n }\\n playSound(350 + (score * 2), 'square', 0.04);\\n }\\n };\\n\\n React.useEffect(() => {\\n if (mode !== 'timber' || gameOver || !hasFocus) return;\\n const timer = setInterval(() => {\\n setTimeLeft(prev => {\\n if (prev <= 0) { setGameOver(true); playSound(100, 'sawtooth', 0.4); return 0; }\\n // Slightly softened decay to match the better refill\\n const decay = Math.min(1.7, 0.5 + (score * 0.012));\\n return Math.max(0, prev - decay);\\n });\\n }, 50);\\n return () => clearInterval(timer);\\n }, [mode, gameOver, hasFocus, score]);\\n\\n React.useEffect(() => {\\n move = (e) => isDragging && setPos({ x: e.clientX - 110, y: e.clientY - 15 });\\n stop = () => setIsDragging(false);\\n handleKey = (e) => {\\n if (!hasFocus || gameOver) return;\\n if (e.key === \\\"ArrowLeft\\\" || e.key === \\\"ArrowRight\\\") {\\n e.preventDefault(); e.stopPropagation();\\n chop(e.key === \\\"ArrowLeft\\\" ? 1 : 2);\\n }\\n };\\n globalThis[\\\"window\\\"].addEventListener(\\\"mousemove\\\", move);\\n globalThis[\\\"window\\\"].addEventListener(\\\"mouseup\\\", stop);\\n globalThis[\\\"window\\\"].addEventListener(\\\"keydown\\\", handleKey, true);\\n return () => {\\n globalThis[\\\"window\\\"].removeEventListener(\\\"mousemove\\\", move);\\n globalThis[\\\"window\\\"].removeEventListener(\\\"mouseup\\\", stop);\\n globalThis[\\\"window\\\"].removeEventListener(\\\"keydown\\\", handleKey, true);\\n };\\n }, [isDragging, hasFocus, branches, gameOver, playerSide, mode, score, ending]);\\n\\n const reset = (m) => {\\n if (m === \\\"quit\\\") ending = true\\n else {\\n setMode(m); setGameOver(false); setScore(0); setBranches(Array(6).fill(0)); setTimeLeft(100);\\n if (audioCtx.state === 'suspended') audioCtx.resume();\\n }\\n };\\n\\n const shake = (mode === 'timber' && timeLeft < 20 && !gameOver) ? (Math.random() - 0.5) * 6 : 0;\\n return React.createElement(\\\"div\\\", {\\n onClick: () => { setHasFocus(true); if (audioCtx.state === 'suspended') audioCtx.resume(); },\\n onBlur: () => setHasFocus(false), tabIndex: \\\"0\\\",\\n style: {\\n position: \\\"fixed\\\", left: pos.x + shake, top: pos.y + shake, width: \\\"220px\\\", height: \\\"480px\\\",\\n backgroundColor: \\\"#111\\\", border: `2px solid ${hasFocus ? \\\"#00ff00\\\" : \\\"#444\\\"}`,\\n zIndex: \\\"1000\\\", fontFamily: \\\"monospace\\\", color: \\\"#00ff00\\\", outline: \\\"none\\\", userSelect: \\\"none\\\"\\n }\\n },\\n React.createElement(\\\"div\\\", { onMouseDown: () => setIsDragging(true), style: { padding: \\\"8px\\\", background: \\\"#222\\\", cursor: \\\"move\\\", fontSize: \\\"10px\\\", textAlign: \\\"center\\\" } },\\n hasFocus ? `● ${mode?.toUpperCase()}` : \\\"○ CLICK TO FOCUS\\\"),\\n\\n React.createElement(\\\"div\\\", { style: { textAlign: \\\"center\\\", padding: \\\"10px\\\" } }, `Score: ${score} | High: ${highScore}`),\\n\\n mode === 'timber' && React.createElement(\\\"div\\\", { style: { width: \\\"85%\\\", height: \\\"10px\\\", border: \\\"1px solid #0f0\\\", margin: \\\"0 auto 10px\\\", background: \\\"#000\\\" } },\\n React.createElement(\\\"div\\\", { style: { width: `${timeLeft}%`, height: \\\"100%\\\", background: timeLeft < 30 ? \\\"#f00\\\" : \\\"#0f0\\\" } })),\\n\\n React.createElement(\\\"div\\\", { style: { position: \\\"relative\\\", width: \\\"40px\\\", height: \\\"250px\\\", background: \\\"#5d4037\\\", margin: \\\"20px auto\\\", opacity: mode ? 1 : 0.2 } },\\n branches.map((b, i) => b !== 0 && React.createElement(\\\"div\\\", {\\n key: i, style: { position: \\\"absolute\\\", bottom: `${i * 50}px`, left: b === 1 ? \\\"-75px\\\" : \\\"40px\\\", width: \\\"75px\\\", height: \\\"18px\\\", background: \\\"#2e7d32\\\" }\\n })),\\n React.createElement(\\\"div\\\", { style: { position: \\\"absolute\\\", bottom: \\\"0\\\", left: playerSide === 1 ? \\\"-55px\\\" : \\\"55px\\\", fontSize: \\\"45px\\\" } }, gameOver ? \\\"💀\\\" : \\\"🪓\\\")\\n ),\\n\\n (!mode || gameOver) && React.createElement(\\\"div\\\", { style: { position: \\\"absolute\\\", top: 0, left: 0, width: \\\"100%\\\", height: \\\"100%\\\", background: \\\"rgba(0,0,0,0.9)\\\", display: \\\"flex\\\", flexDirection: \\\"column\\\", justifyContent: \\\"center\\\", alignItems: \\\"center\\\", gap: \\\"15px\\\" } },\\n gameOver && React.createElement(\\\"h2\\\", { style: { color: \\\"#f00\\\" } }, \\\"TIMBER!\\\"),\\n React.createElement(\\\"button\\\", { onClick: () => reset('casual'), style: { width: \\\"130px\\\", padding: \\\"12px\\\", cursor: \\\"pointer\\\", background: \\\"#111\\\", color: \\\"#0f0\\\", border: \\\"2px solid #0f0\\\" } }, \\\"CASUAL\\\"),\\n React.createElement(\\\"button\\\", { onClick: () => reset('timber'), style: { width: \\\"130px\\\", padding: \\\"12px\\\", cursor: \\\"pointer\\\", background: \\\"#111\\\", color: \\\"#f00\\\", border: \\\"2px solid #f00\\\" } }, \\\"TIMBER!\\\"),\\n React.createElement(\\\"button\\\", { onClick: () => reset('quit'), style: { width: \\\"130px\\\", padding: \\\"12px\\\", cursor: \\\"pointer\\\", background: \\\"#111\\\", color: \\\"#f00\\\", border: \\\"2px solid #f00\\\" } }, \\\"Quit\\\")\\n )\\n );\\n }\\n ns.writePort(29, ns.pid)\\n const container = doc.createElement(\\\"div\\\");\\n doc.getElementById(\\\"root\\\").appendChild(container);\\n eval(\\\"window.ReactDOM\\\").render(React.createElement(TimberGame), container);\\n ns.atExit(() => {\\n ns.clearPort(29)\\n container.remove(); audioCtx.close();\\n globalThis[\\\"window\\\"].removeEventListener(\\\"mousemove\\\", move);\\n globalThis[\\\"window\\\"].removeEventListener(\\\"mouseup\\\", stop);\\n globalThis[\\\"window\\\"].removeEventListener(\\\"keydown\\\", handleKey, true);\\n });\\n while (!ending) await ns.asleep(1000);\\n}\""},{"filename":"SphyxOS/gangs/ascend.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n let result = false\\n ns.atExit(() => port.write(result))\\n\\n for (let member of ns.gang.getMemberNames()) {\\n const memberAscensionResult = ns.gang.getAscensionResult(member)\\n if (memberAscensionResult !== undefined) {\\n const ascendRequirement = calculateAscendTreshold(ns, member)\\n const memberAscensionResultMultiplier = (memberAscensionResult.agi + memberAscensionResult.def + memberAscensionResult.dex + memberAscensionResult.str) / 4\\n if ((memberAscensionResultMultiplier > ascendRequirement || ns.args[0])) {\\n ns.gang.ascendMember(member)\\n result = true\\n }\\n }\\n }\\n}\\n/** @param {NS} ns */\\nfunction calculateAscendTreshold(ns, soldier) {\\n const member = ns.gang.getMemberInformation(soldier)\\n const mult = (member.agi_asc_mult + member.def_asc_mult + member.dex_asc_mult + member.str_asc_mult) / 4\\n if (mult < 1.632) return 1.6326\\n if (mult < 2.336) return 1.4315\\n if (mult < 2.999) return 1.284\\n if (mult < 3.363) return 1.2125\\n if (mult < 4.253) return 1.1698\\n if (mult < 4.860) return 1.1428\\n if (mult < 5.455) return 1.1225\\n if (mult < 5.977) return 1.0957\\n if (mult < 6.496) return 1.0869\\n if (mult < 7.008) return 1.0789\\n if (mult < 7.519) return 1.073\\n if (mult < 8.025) return 1.0673\\n if (mult < 8.513) return 1.0631\\n if (mult < 20) return 1.0591\\n return 1.04\\n}\\n\""},{"filename":"SphyxOS/gangs/createGang.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.createGang(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/equip.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\nconst port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(1))\\n const weaps = ns.ui.getGameInfo()?.versionNumber >= 44 ? weaps_new : weaps_old\\n const vehicles = ns.ui.getGameInfo()?.versionNumber >= 44 ? vehicles_new : vehicles_old\\n ns.gang.getMemberNames().forEach((m) => {\\n augs.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n weaps.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n armors.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n vehicles.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n //rootkits.forEach((a) => ns.gang.purchaseEquipment(m, a))\\n })\\n}\\n\\nconst augs = [\\\"Bionic Arms\\\", \\\"Bionic Legs\\\", \\\"Bionic Spine\\\", \\\"BrachiBlades\\\", \\\"Nanofiber Weave\\\", \\\"Synthetic Heart\\\", \\\"Synfibril Muscle\\\", \\\"Graphene Bone Lacings\\\", \\\"BitWire\\\", \\\"Neuralstimulator\\\", \\\"DataJack\\\"]\\nconst weaps_new = [\\\"Baseball Bat\\\", \\\"Katana\\\", \\\"Malorian-3516\\\", \\\"Hansen-HA7\\\", \\\"Arasaka-HJSH18\\\", \\\"Militech-M251s\\\", \\\"Nokota-D5\\\", \\\"Techtronika-SPT32\\\"]\\nconst weaps_old = [\\\"Baseball Bat\\\", \\\"Katana\\\", \\\"Malorian-3516\\\", \\\"Hansen-HA7\\\", \\\"Arasaka-HJSH18\\\", \\\"Militech-M251s\\\", \\\"Nokota-D5\\\", \\\"Techtronika-SPT32\\\"]\\nconst armors = [\\\"Bulletproof Vest\\\", \\\"Full Body Armor\\\", \\\"Liquid Body Armor\\\", \\\"Graphene Plating Armor\\\"]\\nconst vehicles_new = [\\\"Herrera Outlaw GTS\\\", \\\"Yaiba ASM-R250 Muramasa\\\", \\\"Rayfield Caliburn\\\", \\\"Quadra Sport R-7\\\"]\\nconst vehicles_old = [\\\"Herrera Outlaw GTS\\\", \\\"Yaiba ASM-R250 Muramasa\\\", \\\"Rayfield Caliburn\\\", \\\"Quadra Sport R-7\\\"]\\nconst rootkits = [\\\"NUKE Rootkit\\\", \\\"Soulstealer Rootkit\\\", \\\"Demon Rootkit\\\", \\\"Hmap Node\\\", \\\"Jack the Ripper\\\"]\\n\""},{"filename":"SphyxOS/gangs/getGangFaction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\nconst port = ns.getPortHandle(ns.pid)\\nlet gangFac = \\\"NOFACTION\\\"\\ntry { gangFac = ns.gang.getGangInformation().faction } catch { }\\n ns.atExit(() => port.write(gangFac))\\n}\""},{"filename":"SphyxOS/gangs/getGangInfo.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.getGangInformation()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/getMemberNames.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.getMemberNames()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/getMembersFull.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.getMemberNames().map((m) => ns.gang.getMemberInformation(m))\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/getOtherGangInfo.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n let result\\n if (ns.ui.getGameInfo()?.versionNumber >= 48) result = ns.gang.getAllGangInformation()\\n else result = ns.gang.getOtherGangInformation()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/inGang.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.inGang()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/recruit.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n let result = false\\n ns.atExit(() => port.write(result))\\n if (ns.gang.canRecruitMember()) {\\n let name = names[Math.floor(Math.random() * names.length)]\\n let membernames = ns.gang.getMemberNames()\\n while (membernames.includes(name)) name = names[Math.floor(Math.random() * names.length)]\\n //ns.printf(`INFO: Recruiting: ${name}`)\\n ns.gang.recruitMember(name)\\n result = true\\n }\\n}\\n\\nconst names = [\\\"Rocko\\\", \\\"Mike\\\", \\\"Jack\\\", \\\"Rudo\\\", \\\"Charmichal\\\", \\\"Percy\\\", \\\"Gloria\\\", \\\"Jessica\\\", \\\"Kelly\\\", \\\"Sam\\\", \\\"Gloria\\\", \\\"Sarah\\\",\\n \\\"Jackson\\\", \\\"Adam\\\", \\\"Bob\\\", \\\"Carl\\\", \\\"Dominique\\\", \\\"Enrique\\\", \\\"Falcon\\\", \\\"Garry\\\", \\\"Helen\\\", \\\"Ivana\\\", \\\"Jeremy\\\", \\\"Kyle\\\", \\\"Lucca\\\",\\n \\\"Max\\\", \\\"Nordic\\\", \\\"Oscar\\\", \\\"Paul\\\", \\\"Q\\\", \\\"Rodric\\\", \\\"Steve\\\", \\\"Trevor\\\", \\\"Ulfric\\\", \\\"Volcof\\\", \\\"Wilson\\\", \\\"Xena\\\", \\\"Yoril\\\", \\\"Z\\\"]\\n\""},{"filename":"SphyxOS/gangs/respectForNext.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.gang.respectForNextRecruit()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/gangs/setMemberTask.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(1))\\n ns.gang.setMemberTask(ns.args[0], ns.args[1])\\n}\""},{"filename":"SphyxOS/gangs/setTerritoryWarfare.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(1))\\n ns.gang.setTerritoryWarfare(ns.args[0])\\n}\""},{"filename":"SphyxOS/ipvgo/destroyNode.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const results = await ns.go.cheat.destroyNode(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(results))\\n}\""},{"filename":"SphyxOS/ipvgo/getbstate.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.getBoardState()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/ipvgo/getchains.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.analysis.getChains()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/ipvgo/getcontrolledemptynodes.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.analysis.getControlledEmptyNodes()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/ipvgo/getliberties.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.analysis.getLiberties()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/ipvgo/getvalidmoves.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.go.analysis.getValidMoves(undefined, undefined, ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/ipvgo/play2moves.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const results = await ns.go.cheat.playTwoMoves(ns.args[0], ns.args[1], ns.args[2], ns.args[3], ns.args[4])\\n ns.atExit(() => port.write(results))\\n}\""},{"filename":"SphyxOS/singularity/backdoor.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n try { await ns.singularity.installBackdoor() }\\n catch {}\\n await ns.sleep(100) //Give the other script time to set up the listener\\n ns.atExit(() => ns.writePort(ns.pid, true))\\n}\""},{"filename":"SphyxOS/singularity/commitCrime.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.commitCrime(ns.args[0], false)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/destroyWD.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const test = ns.singularity.destroyW0r1dD43m0n(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(test))\\n}\""},{"filename":"SphyxOS/singularity/donateToFaction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.donateToFaction(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/flume.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const tm = [...globalThis[\\\"document\\\"].querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n tm.filter(e => e.textContent === \\\"Terminal\\\")[0]?.click()\\n \\n await terminal(\\\"run b1t_flum3.exe\\\")\\n await ns.sleep(4)\\n const button = find(globalThis[\\\"document\\\"], \\\"//button[contains(text(), 'BitVerse')]\\\")\\n click(button)\\n}\\n\\n\\n//This will put something into the terminal and hit enter. You however, need to be on the terminal to do it or it won't work.\\nasync function terminal(text) {\\n const slp = ms => new Promise(r => setTimeout(r, ms))\\n //Capture the terminal button\\n const terminalButton = [...globalThis[\\\"document\\\"].querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n //Click it\\n terminalButton.filter(e => e.textContent === \\\"Terminal\\\")[0]?.click()\\n await slp(4)\\n //Get the terminal input field\\n const input = globalThis[\\\"document\\\"].getElementById('terminal-input');\\n //Get it's handler\\n const handler = Object.keys(input)[1];\\n //Set the change that will happen, ie: add it to the terminal\\n input[handler].onChange({ target: { value: text } });\\n //Click enter on the terminal\\n input[handler].onKeyDown({ key: 'Enter', preventDefault: () => null });\\n}\\n\\nfunction find(doc, xpath) { return doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; }\\n\\nfunction click(elem) {\\n elem[Object.keys(elem)[1]].onClick({ isTrusted: true });\\n}\""},{"filename":"SphyxOS/singularity/getAugsFromFaction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.getAugmentationsFromFaction(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getBestFavor.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const s = ns.singularity\\n const factions = ns.getPlayer().factions\\n let bestFac = \\\"none\\\"\\n let bestFav = -1\\n let gangFac = \\\"none\\\"\\n\\n try { gangFac = ns.gang.getGangInformation().faction } catch { }\\n //Best favor for purchasing Neuroflux. Filter out factions without it\\n for (const faction of factions) {\\n if (s.getFactionFavor(faction) > bestFav && faction !== gangFac && faction !== \\\"Bladeburners\\\" && faction !== \\\"Church of the Machine God\\\" && faction !== \\\"Shadows of Anarchy\\\") {\\n bestFac = faction\\n bestFav = s.getFactionFavor(faction)\\n }\\n }\\n let result = {\\n \\\"faction\\\": bestFac,\\n \\\"favor\\\": bestFav\\n }\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getBestRep.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const s = ns.singularity\\n const factions = ns.getPlayer().factions\\n let bestFac = \\\"none\\\"\\n let bestRep = -1\\n let gangFac = \\\"none\\\"\\n\\n try { gangFac = ns.gang.getGangInformation().faction } catch { }\\n //Best favor for purchasing Neuroflux. Filter out factions without it\\n for (const faction of factions) {\\n if (s.getFactionRep(faction) > bestRep && faction !== gangFac && faction != \\\"Bladeburners\\\" && faction != \\\"Church of the Machine God\\\") {\\n bestFac = faction\\n bestRep = s.getFactionRep(faction)\\n }\\n }\\n let result = {\\n \\\"faction\\\": bestFac,\\n \\\"rep\\\": bestRep\\n }\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getFactionFavor.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.getFactionFavor(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getFactionRep.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.getFactionRep(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getOwnedAugs.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.getOwnedAugmentations(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/getOwnedSF.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const collection = []\\n try {\\n for (const item of ns.getResetInfo().ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n collection.push(record)\\n }\\n }\\n catch {}\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(collection))\\n}\""},{"filename":"SphyxOS/singularity/goToLoc.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.goToLocation(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/joinFaction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.joinFaction(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/purchaseAug.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\nconst port = ns.getPortHandle(ns.pid)\\nconst result = ns.singularity.purchaseAugmentation(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/purchaseTor.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let result = 0\\n try {\\n ns.singularity.purchaseTor()\\n result = 1\\n }\\n catch {}\\n const port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(result))\\n}\\n\\nfunction dummy() { //for ram. try/catch doesn't always calculate it\\n ns.singularity.purchaseTor()\\n}\""},{"filename":"SphyxOS/singularity/restart.js","file":"\"import { runIt } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n virus(ns)\\n await runIt(ns, \\\"SphyxOS/bins/LoaderSphyxOS.jsx\\\", true, [\\\"autoPilot\\\"])\\n}\\n\\n/** @param {NS} ns **/\\nfunction virus(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try {\\n ns.nuke(server)\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n }\\n catch { }\\n }\\n}\\n\\n/** @param {NS} ns */\\nexport function getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n}\""},{"filename":"SphyxOS/singularity/setGym.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.gymWorkout(ns.args[0], ns.args[1], false)\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/stopAction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const test = ns.singularity.stopAction()\\n ns.atExit(() => port.write(test))\\n}\""},{"filename":"SphyxOS/singularity/travelToCity.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.travelToCity(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/singularity/upgradeHomeRam.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const port = ns.getPortHandle(ns.pid)\\n const result = ns.singularity.upgradeHomeRam()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/buyUpgradeSleeves.js","file":"\"import { proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.disableLog(\\\"ALL\\\")\\n await ns.sleep(4) //Let the main script establish it's wait timer\\n ns.atExit(() => ns.writePort(ns.pid, true))\\n const doc = globalThis[\\\"document\\\"]\\n const factions = [...doc.querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n factions.filter(e => e.textContent.includes(\\\"Factions\\\"))[0]?.click()\\n await ns.sleep(4)\\n const topButtons = [...doc.querySelectorAll(\\\"button\\\")]\\n let facButton = null\\n for (const btn of topButtons) {\\n if (!btn.innerText.includes(\\\"Details\\\")) continue\\n const gp = btn.parentElement?.parentElement\\n if (!gp) continue\\n if (gp.innerText.includes(\\\"Covenant\\\")) {\\n facButton = btn\\n break\\n }\\n }\\n if (!facButton) {\\n throw new Error(\\\"Covenant Details button not found\\\");\\n }\\n click(facButton)\\n await ns.sleep(4)\\n const sleeveButton = find(doc, \\\"//button[contains(text(), 'Sleeves')]\\\")\\n click(sleeveButton)\\n await ns.sleep(4)\\n const purchaseButton = Array.from(doc.querySelectorAll(\\\"button\\\")).filter(b => b.innerText.startsWith(\\\"Purchase -\\\"))\\n const maxS = await maxSleeves(ns)\\n const startingNum = maxS - await proxy(ns, \\\"sleeve.getNumSleeves\\\")\\n for (let x = startingNum; x > 0; x--) {\\n if (purchaseButton[0]) {\\n const money = await proxy(ns, \\\"getServerMoneyAvailable\\\", \\\"home\\\")\\n if (x === 5 && money >= 10e12) click(purchaseButton[0])\\n else if (x === 4 && money >= 100e12) click(purchaseButton[0])\\n else if (x === 3 && money >= 1e15) click(purchaseButton[0])\\n else if (x === 2 && money >= 10e15) click(purchaseButton[0])\\n else if (x === 1 && money >= 100e15) click(purchaseButton[0])\\n }\\n }\\n await ns.sleep(4)\\n const buttons = Array.from(doc.querySelectorAll(\\\"button\\\")).filter(b => b.innerText.startsWith(\\\"Purchase 1 memory\\\"))\\n doc.dispatchEvent(new KeyboardEvent(\\\"keydown\\\", { key: \\\"t\\\", altKey: true }))\\n for (let x = 0; x < 100; x++) {\\n for (const button of buttons) {\\n click(button)\\n }\\n }\\n}\\nfunction find(doc, xpath) { return doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; }\\nfunction click(elem) {\\n elem[Object.keys(elem)[1]].onClick({ isTrusted: true });\\n}\\n\\n/** @param {NS} ns */\\nasync function maxSleeves(ns) {\\n const resetInfo = await proxy(ns, \\\"getResetInfo\\\")\\n const sourceFiles = []\\n for (const item of resetInfo.ownedSF) {\\n const record = {\\n \\\"n\\\": item[0],\\n \\\"lvl\\\": item[1]\\n }\\n sourceFiles.push(record)\\n }\\n let result = 5\\n if (resetInfo.currentNode === 10) {\\n result++\\n }\\n for (const sf of sourceFiles) if (sf.n === 10) {\\n result += sf.lvl\\n }\\n return result > 8 ? 8 : result\\n}\""},{"filename":"SphyxOS/sleeves/getNumSlvs.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const slvs = ns.sleeve.getNumSleeves()\\n let port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(slvs))\\n}\""},{"filename":"SphyxOS/sleeves/getPurchasableAugs.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.getSleevePurchasableAugs(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/getSleeve.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const slv = ns.sleeve.getSleeve(ns.args[0])\\n let port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(slv))\\n}\""},{"filename":"SphyxOS/sleeves/getSleeveAugmentations.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.getSleeveAugmentations(ns.args[0]).length\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/getSleeveObject.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n const sleeves = []\\n for (let slv = 0; slv < ns.sleeve.getNumSleeves(); slv++) {\\n const task = ns.sleeve.getTask(slv)\\n if (task === null) {\\n const record = {\\n \\\"num\\\": slv,\\n \\\"me\\\": ns.sleeve.getSleeve(slv),\\n \\\"task\\\": null\\n }\\n sleeves.push(record)\\n }\\n else {\\n const {nextCompletion, ...tasks} = ns.sleeve.getTask(slv)\\n const record = {\\n \\\"num\\\": slv,\\n \\\"me\\\": ns.sleeve.getSleeve(slv),\\n \\\"task\\\": tasks\\n }\\n sleeves.push(record)\\n }\\n }\\n ns.atExit(() => ns.writePort(ns.pid, sleeves))\\n}\""},{"filename":"SphyxOS/sleeves/hasSleeves.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let sleeveAccess = false\\n try {\\n ns.sleeve.getNumSleeves()\\n sleeveAccess = true\\n }\\n catch { }\\n ns.atExit(() => port.write(sleeveAccess))\\n}\""},{"filename":"SphyxOS/sleeves/purchaseSleeveAug.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.purchaseSleeveAug(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToBBAction.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToBladeburnerAction(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToCrime.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToCommitCrime(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToGymWorkout.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToGymWorkout(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToIdle.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToIdle(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToShockRecovery.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToShockRecovery(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToSynchronize.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToSynchronize(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/setToUniversity.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.setToUniversityCourse(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/sleeves/sleeveInstallAugs.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n /** @param {NS} ns */\\n let port = ns.getPortHandle(ns.pid)\\n ns.atExit(() => port.write(1))\\n\\n for (let slv = 0; slv < ns.sleeve.getNumSleeves(); slv++) {\\n const augs = ns.sleeve.getSleevePurchasableAugs(slv)\\n augs.forEach((a) => {\\n try { ns.sleeve.purchaseSleeveAug(slv, a.name) } catch { }\\n })\\n }\\n}\""},{"filename":"SphyxOS/sleeves/sleeveTravel.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.sleeve.travel(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stanek/charge.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let frags = JSON.parse(ns.args[0]) //Send all current fragments as the arguments. Save exec cost\\n for (const frag of frags) {\\n if (frag.id < 100)\\n await ns.stanek.chargeFragment(frag.x, frag.y)\\n }\\n ns.writePort(ns.pid, true)\\n}\""},{"filename":"SphyxOS/stanek/deleteStanek.js","file":"\"import { proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n const fileLocation = \\\"/SphyxOSUserData/stanekLoadouts/\\\"\\n await proxy(ns, \\\"stanek.acceptGift\\\")\\n while (true) {\\n const files = ns.ls(\\\"home\\\", fileLocation).map(m => [m.substring(fileLocation.length - 1), fileLocation])\\n\\n let usableFiles = []\\n for (const testFile of files) {\\n //const testFile = file.substring(12)\\n const [width, hight, ...fileName] = testFile[0].substring(0, testFile[0].length - 4).split(\\\"x\\\")\\n usableFiles.push([width + \\\"x\\\" + hight + \\\"x\\\" + fileName.join(\\\"x\\\"), testFile[1]])\\n }\\n usableFiles = usableFiles.sort((a, b) => {\\n const [width, height] = a[0].split(\\\"x\\\")\\n const [width2, height2] = b[0].split(\\\"x\\\")\\n return (width2 + height2) - (width + height)\\n })\\n const selectable = []\\n for (const usableFile of usableFiles) {\\n selectable.push(usableFile[0])\\n }\\n if (selectable.length === 0) {\\n ns.toast(\\\"No more Stanek layouts to process.\\\", \\\"warning\\\", 3000)\\n ns.exit()\\n }\\n const chosen = await ns.prompt(\\\"Choose the loadout to delete:\\\", { type: \\\"select\\\", choices: selectable.sort((a, b) => b[0] > a[0]) })\\n if (chosen === \\\"\\\") {\\n //ns.toast(\\\"Exited out of Stanek removal script.\\\", \\\"error\\\", 3000)\\n ns.exit()\\n }\\n else {\\n let prefix = \\\"/SphyxOSUserData/stanekLoadouts/\\\"\\n for (const file of usableFiles) {\\n if (chosen === file[0]) {\\n prefix = file[1]\\n break\\n }\\n }\\n if (await proxy(ns, \\\"rm\\\", prefix + chosen + \\\".txt\\\", \\\"home\\\"))\\n ns.toast(\\\"SUCCESS: Delete Stanek \\\" + prefix + chosen + \\\".txt\\\", \\\"success\\\", 3000)\\n else ns.toast(\\\"FAILURE: Failed to delete Stanek \\\" + prefix + chosen + \\\".txt\\\", \\\"error\\\", 3000)\\n }\\n }\\n}\\n\""},{"filename":"SphyxOS/stanek/loadStanek.js","file":"\"import { proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n const fileLocation = \\\"/SphyxOSUserData/stanekLoadouts/\\\"\\n const defaultFileLocation = \\\"/SphyxOS/stanek/loadouts/\\\"\\n await proxy(ns, \\\"stanek.acceptGift\\\")\\n const useDefaults = ns.args.includes(\\\"default\\\") ? true : false\\n const files = ns.ls(\\\"home\\\", fileLocation).map(m => [m.substring(fileLocation.length - 1), fileLocation])\\n if (useDefaults) {\\n const defaultFiles = ns.ls(\\\"home\\\", defaultFileLocation).map(m => [m.substring(defaultFileLocation.length - 1), defaultFileLocation])\\n files.push(...defaultFiles)\\n }\\n let usableFiles = []\\n for (const testFile of files) {\\n //const testFile = file.substring(12)\\n const [width, hight, ...fileName] = testFile[0].substring(0, testFile[0].length - 4).split(\\\"x\\\")\\n if (width <= ns.stanek.giftWidth() && hight <= ns.stanek.giftHeight())\\n usableFiles.push([width + \\\"x\\\" + hight + \\\"x\\\" + fileName.join(\\\"x\\\"), testFile[1]])\\n }\\n usableFiles = usableFiles.sort((a, b) => {\\n const [width, height] = a[0].split(\\\"x\\\")\\n const [width2, height2] = b[0].split(\\\"x\\\")\\n return (width2 + height2) - (width + height)\\n })\\n const selectable = []\\n for (const usableFile of usableFiles) {\\n selectable.push(usableFile[0])\\n }\\n const chosen = await ns.prompt(\\\"Choose your loadout:\\\", { type: \\\"select\\\", choices: selectable.sort((a, b) => b[0] > a[0]) })\\n if (chosen === \\\"\\\") {\\n ns.toast(\\\"Canceled out. Nothing changed.\\\", \\\"error\\\", 3000)\\n ns.exit()\\n }\\n else {\\n ns.stanek.clearGift()\\n let prefix = \\\"/SphyxOSUserData/stanekLoadouts/\\\"\\n for (const file of usableFiles) {\\n if (chosen === file[0]) {\\n prefix = file[1]\\n break\\n }\\n }\\n await proxy(ns, \\\"scp\\\", prefix + chosen + \\\".txt\\\", ns.self().server, \\\"home\\\")\\n const file = JSON.parse(ns.read(prefix + chosen + \\\".txt\\\"))\\n for (const frag of file) {\\n //.x, .y, .rotation, .id\\n await proxy(ns, \\\"stanek.placeFragment\\\", frag.x, frag.y, frag.rotation, frag.id)\\n }\\n ns.toast(\\\"SUCCESS: Stanek loaded from \\\" + prefix + chosen + \\\".txt\\\", \\\"success\\\", 3000);\\n }\\n}\\n\""},{"filename":"SphyxOS/stanek/loadouts/3x3xautoPilot.txt","file":"\"[{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":1,\\\"id\\\":25},{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":2,\\\"id\\\":21}]\""},{"filename":"SphyxOS/stanek/loadouts/5x4xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":3,\\\"id\\\":101},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":1,\\\"id\\\":100}]\""},{"filename":"SphyxOS/stanek/loadouts/5x5xD-Hacking.txt","file":"\"[{\\\"x\\\":4,\\\"y\\\":0,\\\"rotation\\\":3,\\\"id\\\":6},{\\\"x\\\":2,\\\"y\\\":3,\\\"rotation\\\":0,\\\"id\\\":7},{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":0,\\\"y\\\":1,\\\"rotation\\\":3,\\\"id\\\":102},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":5}]\""},{"filename":"SphyxOS/stanek/loadouts/5x5xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":1,\\\"id\\\":105},{\\\"x\\\":3,\\\"y\\\":3,\\\"rotation\\\":1,\\\"id\\\":21}]\""},{"filename":"SphyxOS/stanek/loadouts/6x5xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":1,\\\"id\\\":105},{\\\"x\\\":2,\\\"y\\\":3,\\\"rotation\\\":2,\\\"id\\\":103},{\\\"x\\\":5,\\\"y\\\":0,\\\"rotation\\\":3,\\\"id\\\":6}]\""},{"filename":"SphyxOS/stanek/loadouts/6x6xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":3,\\\"id\\\":102},{\\\"x\\\":1,\\\"y\\\":3,\\\"rotation\\\":3,\\\"id\\\":105},{\\\"x\\\":3,\\\"y\\\":2,\\\"rotation\\\":2,\\\"id\\\":106}]\""},{"filename":"SphyxOS/stanek/loadouts/7x6xD-Hacking.txt","file":"\"[{\\\"x\\\":2,\\\"y\\\":1,\\\"rotation\\\":1,\\\"id\\\":104},{\\\"x\\\":3,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":1},{\\\"x\\\":5,\\\"y\\\":0,\\\"rotation\\\":1,\\\"id\\\":101},{\\\"x\\\":4,\\\"y\\\":2,\\\"rotation\\\":3,\\\"id\\\":7},{\\\"x\\\":2,\\\"y\\\":3,\\\"rotation\\\":3,\\\"id\\\":5},{\\\"x\\\":3,\\\"y\\\":4,\\\"rotation\\\":2,\\\"id\\\":101},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":0},{\\\"x\\\":1,\\\"y\\\":2,\\\"rotation\\\":3,\\\"id\\\":6}]\""},{"filename":"SphyxOS/stanek/loadouts/7x6xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":3,\\\"id\\\":102},{\\\"x\\\":1,\\\"y\\\":3,\\\"rotation\\\":3,\\\"id\\\":105},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":2,\\\"id\\\":101},{\\\"x\\\":4,\\\"y\\\":1,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":3,\\\"y\\\":3,\\\"rotation\\\":0,\\\"id\\\":103},{\\\"x\\\":4,\\\"y\\\":4,\\\"rotation\\\":0,\\\"id\\\":27}]\""},{"filename":"SphyxOS/stanek/loadouts/7x7xD-Hacking.txt","file":"\"[{\\\"x\\\":2,\\\"y\\\":2,\\\"rotation\\\":2,\\\"id\\\":107},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":2,\\\"id\\\":0},{\\\"x\\\":4,\\\"y\\\":2,\\\"rotation\\\":2,\\\"id\\\":1},{\\\"x\\\":4,\\\"y\\\":4,\\\"rotation\\\":0,\\\"id\\\":5},{\\\"x\\\":2,\\\"y\\\":4,\\\"rotation\\\":0,\\\"id\\\":7},{\\\"x\\\":3,\\\"y\\\":5,\\\"rotation\\\":2,\\\"id\\\":101},{\\\"x\\\":0,\\\"y\\\":4,\\\"rotation\\\":3,\\\"id\\\":106},{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":6},{\\\"x\\\":4,\\\"y\\\":0,\\\"rotation\\\":3,\\\"id\\\":105},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101}]\""},{"filename":"SphyxOS/stanek/loadouts/8x7xautoPilot.txt","file":"\"[{\\\"x\\\":1,\\\"y\\\":1,\\\"rotation\\\":0,\\\"id\\\":25},{\\\"x\\\":0,\\\"y\\\":0,\\\"rotation\\\":0,\\\"id\\\":101},{\\\"x\\\":0,\\\"y\\\":2,\\\"rotation\\\":3,\\\"id\\\":102},{\\\"x\\\":1,\\\"y\\\":3,\\\"rotation\\\":3,\\\"id\\\":105},{\\\"x\\\":2,\\\"y\\\":0,\\\"rotation\\\":2,\\\"id\\\":101},{\\\"x\\\":4,\\\"y\\\":1,\\\"rotation\\\":2,\\\"id\\\":106},{\\\"x\\\":3,\\\"y\\\":3,\\\"rotation\\\":0,\\\"id\\\":103},{\\\"x\\\":4,\\\"y\\\":4,\\\"rotation\\\":0,\\\"id\\\":27},{\\\"x\\\":4,\\\"y\\\":5,\\\"rotation\\\":2,\\\"id\\\":101}]\""},{"filename":"SphyxOS/stanek/saveStanek.js","file":"\"import { proxy } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n let frags = await proxy(ns, \\\"stanek.activeFragments\\\")\\n if (frags.length === 0) {\\n ns.toast(\\\"Please select a loadout first\\\", \\\"error\\\", 3000)\\n ns.exit()\\n }\\n const stanekLocation = \\\"/SphyxOSUserData/stanekLoadouts/\\\"\\n const defaultFileLocation = \\\"/SphyxOS/stanek/loadouts/\\\"\\n let file\\n let defaultFile\\n while (true) {\\n const name = await ns.prompt(\\\"Please name your loadout\\\", { type: \\\"text\\\" })\\n file = stanekLocation + ns.stanek.giftWidth() + \\\"x\\\" + ns.stanek.giftHeight() + 'x' + name + '.txt';\\n defaultFile = defaultFileLocation + ns.stanek.giftWidth() + \\\"x\\\" + ns.stanek.giftHeight() + 'x' + name + '.txt';\\n if (name === \\\"\\\") {\\n ns.toast(\\\"Canceled out. Save aborted.\\\", \\\"error\\\", 3000)\\n ns.exit()\\n }\\n else if (ns.fileExists(file, \\\"home\\\") || ns.fileExists(defaultFile, \\\"home\\\")) {\\n ns.toast(\\\"File exists. Please chose a new name\\\", \\\"error\\\", 3000)\\n }\\n else break\\n }\\n for (let i = 0; i < frags.length; ++i) {\\n let { x, y, rotation, id } = frags[i];\\n frags[i] = { x: x, y: y, rotation: rotation, id: id };\\n }\\n ns.write(file, JSON.stringify(frags), 'w');\\n ns.toast(\\\"SUCCESS: Stanek Loadout saved to \\\" + file, \\\"success\\\", 3000);\\n}\""},{"filename":"SphyxOS/stanek/startCharge.js","file":"\"import { getServersLight, proxy } from \\\"SphyxOS/util.js\\\"\\nconst chargeScript = \\\"SphyxOS/stanek/charge.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n ns.atExit(() => {\\n ns.clearPort(11)\\n })\\n ns.writePort(11, ns.pid)\\n const quietMode = ns.args.includes(\\\"quiet\\\")\\n const servers = await getServersLight(ns)\\n const promises = []\\n const fragments = await proxy(ns, \\\"stanek.activeFragments\\\")\\n let runningThreads = 0\\n for (const server of servers) {\\n if (!ns.hasRootAccess(server)) continue\\n const reserved = server === \\\"home\\\" ? 256 : 0\\n const threads = Math.floor((Math.max(0, ns.getServerMaxRam(server) - ns.getServerUsedRam(server) - reserved)) / 2)\\n runningThreads += threads\\n if (threads <= 0) continue\\n ns.scp(chargeScript, server, \\\"home\\\")\\n const scriptPid = ns.exec(chargeScript, server, threads, JSON.stringify(fragments))\\n promises.push(ns.nextPortWrite(scriptPid))\\n }\\n if (!quietMode) ns.toast(\\\"Awaiting \\\" + fragments.reduce((val, a) => a.id < 100 ? val += 1 : val = val, 0) + \\\" charges with \\\" + runningThreads + \\\" threads.\\\", \\\"success\\\", 3000)\\n await Promise.all(promises)\\n if (!quietMode) ns.toast(\\\"Done Charging\\\", \\\"success\\\", 2000)\\n \\n}\""},{"filename":"SphyxOS/stock/buyShort.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.buyShort(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/buyStock.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.buyStock(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getAskPrice.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getAskPrice(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getBidPrice.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getBidPrice(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getF-V.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let record = {\\n \\\"vol\\\": ns.stock.getVolatility(ns.args[0]),\\n \\\"forcast\\\": ns.stock.getForecast(ns.args[0])\\n }\\n ns.atExit(() => port.write(record))\\n}\""},{"filename":"SphyxOS/stock/getForcast.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getForecast(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getMaxShares.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getMaxShares(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getPosition.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getPosition(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getPrice.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getPrice(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getSaleGain.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getSaleGain(ns.args[0], ns.args[1], ns.args[2])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getSnap.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let record = {\\n \\\"bidp\\\": ns.stock.getBidPrice(ns.args[0]),\\n \\\"askp\\\": ns.stock.getAskPrice(ns.args[0]),\\n \\\"price\\\": ns.stock.getPrice(ns.args[0])\\n }\\n ns.atExit(() => port.write(record))\\n}\""},{"filename":"SphyxOS/stock/getSymbols.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getSymbols()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getVolatility.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.getVolatility(ns.args[0])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/getWorth.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let worth = 0\\n ns.atExit(() => port.write(worth > 0 ? worth : 1))\\n for (let sym of ns.stock.getSymbols()) {\\n const posi = ns.stock.getPosition(sym)\\n if (posi[0] > 0) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) worth += ns.stock.getSaleGain(sym, posi[0], \\\"L\\\")\\n else worth += ns.stock.getSaleGain(sym, posi[0], \\\"long\\\")\\n }\\n if (posi[2] > 0) {\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) worth += ns.stock.getSaleGain(sym, posi[2], \\\"S\\\")\\n else worth += ns.stock.getSaleGain(sym, posi[2], \\\"short\\\")\\n }\\n }\\n}\""},{"filename":"SphyxOS/stock/has4SDataTIXAPI.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let result\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) result = ns.stock.has4SDataTixApi()\\n else result = ns.stock.has4SDataTIXAPI()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/hasTIXAPIAccess.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let result\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) result = ns.stock.hasTixApiAccess()\\n else result = ns.stock.hasTIXAPIAccess()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/hasWSEAccount.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let result\\n if (ns.ui.getGameInfo()?.versionNumber >= 44) result = ns.stock.hasWseAccount()\\n else result = ns.stock.hasWSEAccount()\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/sellShort.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.sellShort(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/sellStock.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n const result = ns.stock.sellStock(ns.args[0], ns.args[1])\\n ns.atExit(() => port.write(result))\\n}\""},{"filename":"SphyxOS/stock/shortEnabled.js","file":"\"/** @param {NS} ns */\\nexport async function main(ns) {\\n let port = ns.getPortHandle(ns.pid)\\n let enabled = 0\\n try {\\n ns.stock.buyShort(\\\"ECP\\\", 0)\\n enabled = 1\\n }\\n catch {}\\n ns.atExit(() => port.write(enabled))\\n}\""},{"filename":"SphyxOS/util.js","file":"\"export const reservedRam = 256\\n/** @param {NS} ns */\\nexport async function ramDodge(ns, scriptName, persistent, argmts, stringifyArgs = false) {\\n const pidof = await runIt(ns, scriptName, persistent, argmts, 0, false, stringifyArgs)\\n if (pidof === 0) throw new Error(\\\"Failed to run \\\" + scriptName)\\n await ns.nextPortWrite(pidof)\\n return ns.readPort(pidof)\\n}\\n/** @param {NS} ns */\\nexport async function ramDodgeProxy(ns, script, func, argmts) {\\n //const pidof = ns.exec(\\\"SphyxOS/extras/runIt.js\\\", \\\"home\\\", { threads: 1, temporary: true }, script, false, ns.getFunctionRamCost(func) + 1.6, ...[func, ...argmts])\\n const pidof = await runIt(ns, script, false, [func, ...argmts], ns.getFunctionRamCost(func) + 1.6)\\n if (pidof === 0) throw new Error(\\\"Failed to run proxy \\\" + func)\\n await ns.nextPortWrite(pidof)\\n return ns.readPort(pidof)\\n}\\n/** @param {NS} ns */\\nexport async function ramDodgeLocal(ns, scriptName, argmts, stringifyArgs = false) {\\n let pidof\\n if (stringifyArgs) pidof = ns.exec(scriptName, \\\"home\\\", { threads: 1, temporary: true }, argmts)\\n else pidof = ns.exec(scriptName, \\\"home\\\", { threads: 1, temporary: true }, ...argmts)\\n if (pidof === 0) throw new Error(\\\"Failed to run \\\" + scriptName + \\\" locally\\\")\\n await ns.nextPortWrite(pidof)\\n return ns.readPort(pidof)\\n}\\n\\n/** @param {NS} ns */\\nexport async function runIt(ns, script, persistent, argmts, scriptOverride = 0, quiet = false, stringifyArgs = false) {\\n //Any runIt now has a persistent argument to pass along if it can run on hacknet servers.\\n //This way you can choose to run something like puppet on a hacknet server\\n let thispid = 0\\n let threads = 1\\n const scriptRam = scriptOverride === 0 ? await doGetScriptRam(ns, script) : scriptOverride\\n if (!persistent) {\\n if (stringifyArgs) thispid = ns.exec(script, \\\"home\\\", { ramOverride: scriptRam, threads: 1, temporary: true }, argmts)\\n else thispid = ns.exec(script, \\\"home\\\", { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmts)\\n if (thispid > 0)\\n threads--\\n }\\n if (threads >= 1) {\\n const servers = await getServersLight(ns)\\n let emergencyReserve = !persistent ? false : await getServerAvailRam(ns, \\\"home\\\") <= 16 ? true : false\\n const maxRam = !persistent ? 0 : await maxRun(ns, persistent)\\n const resRam = !persistent ? 0 : maxRam >= 256 ? 256 : maxRam >= 128 ? 128 : maxRam >= 64 ? 64 : maxRam >= 32 ? 32 : 16\\n for (const server of servers) {\\n if (!await getHasRootAccs(ns, server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = await getServerAvailRam(ns, server)\\n if (persistent && emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n }\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable <= 0) continue\\n const threadsonserver = Math.floor(tmpramavailable / scriptRam)\\n // How many threads can we run? If we can run something, do it\\n if (threadsonserver <= 0) continue\\n await doSCP(ns, script, server)\\n await doSCP(ns, \\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n await doSCP(ns, \\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n if (stringifyArgs) thispid = ns.exec(script, server, { ramOverride: scriptRam, threads: 1, temporary: true }, argmts)\\n else thispid = ns.exec(script, server, { ramOverride: scriptRam, threads: 1, temporary: true }, ...argmts)\\n if (thispid === 0) continue //ns.tprintf(\\\"Failed to run: %s on %s\\\", script, server)\\n threads--\\n break\\n }// All servers\\n }\\n if (threads >= 1 && !quiet) ns.tprintf(\\\"Failed to allocate all threads for script: %s\\\", script)\\n return thispid\\n}\\n/** @param {NS} ns */\\nexport async function maxRun(ns, persistent, useHacknet = false) {\\n //Any runIt now has a persistent argument to pass along if it can run on hacknet servers.\\n //This way you can choose to run something like puppet on a hacknet server\\n let highest = 0\\n /**@type {String[]} servers */\\n const servers = await getServersLight(ns)\\n let emergencyReserve = await getServerAvailRam(ns, \\\"home\\\") <= 16 ? true : false\\n for (const server of servers) {\\n if (!await getHasRootAccs(ns, server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && !useHacknet)) continue\\n let tmpramavailable = await getServerAvailRam(ns, server)\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest)\\n highest = tmpramavailable\\n }// All servers\\n if (!persistent) return highest\\n //Highest is now max run\\n const resRam = highest >= 256 ? 256 : highest >= 128 ? 128 : highest >= 64 ? 64 : highest >= 32 ? 32 : 16\\n //Now that we have the highest, we go again\\n let highest2 = 0\\n for (const server of servers) {\\n if (!await getHasRootAccs(ns, server)) continue\\n if ((server.startsWith(\\\"hacknet\\\") && persistent)) continue\\n let tmpramavailable = await getServerAvailRam(ns, server)\\n if (persistent && emergencyReserve && tmpramavailable >= resRam) {\\n emergencyReserve = false\\n tmpramavailable -= resRam\\n }\\n if (server === \\\"home\\\" && persistent) tmpramavailable = Math.max(tmpramavailable - reservedRam, 0)\\n if (tmpramavailable > highest2)\\n highest2 = tmpramavailable\\n }// All servers\\n return highest2\\n}\\nexport function printProfit(ns, tm, take, batches, threads, chance) {\\n //tm is in milliseconds...\\n tm = tm / 1000\\n //Profit per second\\n let profit = (take / tm) * batches\\n profit = profit / threads * chance\\n return tm === 0 || take === 0 || isNaN(profit) ? 0 : profit\\n}\\n/** @param {NS} ns */\\nexport function profitPerSecond(ns, tm, take, batches) {\\n //tm is in milliseconds...\\n tm = tm / 1000\\n //Profit per second\\n let profit = (take / tm) * batches\\n if (ns.ui.getGameInfo()?.versionNumber >= 44)\\n return tm === 0 || take === 0 || isNaN(profit) ? \\\"0\\\" + \\\"/s\\\" : (ns.format.number(profit, 2) + \\\"/s\\\")\\n else\\n return tm === 0 || take === 0 || isNaN(profit) ? \\\"0\\\" + \\\"/s\\\" : (ns.formatNumber(profit, 2) + \\\"/s\\\")\\n\\n}\\n//This will put something into the terminal and hit enter. You however, need to be on the terminal to do it or it won't work.\\nexport async function terminal(text) {\\n const slp = ms => new Promise(r => setTimeout(r, ms))\\n //Capture the terminal button\\n const terminalButton = [...globalThis[\\\"document\\\"].querySelectorAll(\\\"#root > div > div > div > ul > div > div > div > div\\\")]\\n //Click it\\n terminalButton.filter(e => e.textContent === \\\"Terminal\\\")[0]?.click()\\n //Wait for the screen to change to the Terminal\\n await slp(4)\\n //Get the terminal input field\\n const input = globalThis[\\\"document\\\"].getElementById('terminal-input');\\n //Get it's handler\\n const handler = Object.keys(input)[1];\\n //Set the change that will happen, ie: add it to the terminal\\n input[handler].onChange({ target: { value: text } });\\n //Click enter on the terminal\\n input[handler].onKeyDown({ key: 'Enter', preventDefault: () => null });\\n}\\n// Thanks to omuretsu, jeek and sphyxis\\nexport async function makeNewWindow(title = \\\"Default Window Title\\\", theme) {\\n let slp = ms => new Promise(r => setTimeout(r, ms));\\n // let win = open(\\\"\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n let win = open(\\\"main.bundle.js\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n let good = false;\\n let doc = 0;\\n while (!good) {\\n await slp(1000);\\n try {\\n doc = win[\\\"document\\\"];\\n doc.head.innerHTML = \\\"No.\\\";\\n good = true;\\n } catch {\\n good = false;\\n }\\n }\\n await slp(200);\\n doc.head.innerHTML = `\\n ${title} \\n `;\\n doc.body.innerHTML = `${title}
`;\\n win.clear = () => {\\n win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML = \\\"\\\";\\n }\\n win.header = (content) => {\\n win[\\\"document\\\"].body.innerHTML = `${content}
`;\\n }\\n win.update = (content) => {\\n win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML = win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innterHTML === \\\"\\\" ? content.replaceAll(\\\" \\\", \\\" \\\").replaceAll(\\\"\\\\r\\\", \\\" \\\").replaceAll(\\\"\\\\n\\\", \\\" \\\") : win[\\\"document\\\"].body.querySelector(\\\".logs\\\").innerHTML + ` ` + content.replaceAll(\\\" \\\", \\\" \\\").replaceAll(\\\"\\\\r\\\", \\\" \\\").replaceAll(\\\"\\\\n\\\", \\\" \\\");\\n }\\n win.reopen = () => open(\\\"\\\", title.replaceAll(\\\" \\\", \\\"_\\\"), \\\"popup=yes,height=200,width=500,left=100,top=100,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no\\\");\\n win.focus()\\n return win;\\n}\\nexport async function proxy(ns, func, ...argmnts) { return await ramDodgeProxy(ns, \\\"SphyxOS/extras/nsProxy.js\\\", func, argmnts) }\\nexport async function proxyTry(ns, func, ...argmnts) { return await ramDodgeProxy(ns, \\\"SphyxOS/extras/nsProxyTry.js\\\", func, argmnts) }\\nexport async function getServersLight(ns) { return await ramDodgeLocal(ns, \\\"SphyxOS/extras/getServersLight.js\\\", []) }\\nexport async function doSCP(ns, script, hostname) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/doSCP.js\\\", [script, hostname]) }\\nexport async function getHasRootAccs(ns, hostname) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/getHasRootAccs.js\\\", [hostname]) }\\nexport async function getServerAvailRam(ns, hostname) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/getServerAvailRam.js\\\", [hostname]) }\\nexport async function getMoneyAvail(ns, hostname) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/getMoneyAvail.js\\\", [hostname]) }\\nexport async function getIsRunning(ns, pidnumber) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/getIsRunning.js\\\", [pidnumber]) }\\nexport async function serverRun(ns, logging, target, w1, g1, w2, h1, w3, g2, w4, batchh1, batchw1, batchg1, batchw2, batches, nohacknet) { return await ramDodgeLocal(ns, \\\"SphyxOS/extras/serverRun.js\\\", [logging, target, w1, g1, w2, h1, w3, g2, w4, batchh1, batchw1, batchg1, batchw2, batches, nohacknet]) }\\nexport async function doGetScriptRam(ns, scriptname) { return await ramDodgeLocal(ns, \\\"SphyxOS/basic/getScriptRam.js\\\", [scriptname]) }\\nexport async function getSrvr(ns, hostname) { return await ramDodge(ns, \\\"SphyxOS/basic/getServer.js\\\", false, [hostname]) }\\nexport async function getHckTimeBasic(ns, hostname) { return await ramDodge(ns, \\\"SphyxOS/basic/getHackTime.js\\\", false, [hostname]) }\\nexport async function getServers(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/getServers.js\\\", false, []) }\\nexport async function doScriptKill(ns, script, server) { return await ramDodge(ns, \\\"SphyxOS/basic/scriptKill.js\\\", false, [script, server]) }\\nexport async function hasBN(ns, bn, lvl = 1, forced = false) { return await ramDodge(ns, \\\"SphyxOS/extras/hasBN.js\\\", false, [bn, lvl, forced]) }\\nexport async function currentBN(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/currentBN.js\\\", false, []) }\\nexport async function getBNMults(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/getbnmults.js\\\", false, []) }\\nexport async function getMoneySource(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/getMoneySources.js\\\", false, []) }\\nexport async function wastePids(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/wastePids.js\\\", false, []) }\\nexport async function getResetInf(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/getResetInfo.js\\\", false, []) }\\nexport async function getOptimalTarget(ns, first = false) { return await ramDodge(ns, \\\"SphyxOS/extras/getOptimalTarget.js\\\", false, [first]) }\\nexport async function getHackP(ns, target, batches, threadsavailable, starthack) { return await ramDodge(ns, \\\"SphyxOS/extras/getHackP.js\\\", false, [target, batches, threadsavailable, starthack]) }\\nexport async function getPlay(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/getPlay.js\\\", false, []) }\\nexport async function weakenStr(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/weakenStr.js\\\", false, []) }\\nexport async function getHackPercent(ns, hostname, minsecurity) { return await ramDodge(ns, \\\"SphyxOS/forms/getHackPercent.js\\\", false, [hostname, minsecurity]) }\\nexport async function getHackChance(ns, hostname, minsecurity) { return await ramDodge(ns, \\\"SphyxOS/forms/getHackChance.js\\\", false, [hostname, minsecurity]) }\\nexport async function getHckTime(ns, hostname, minsecurity) { return await ramDodge(ns, \\\"SphyxOS/forms/getHckTime.js\\\", false, [hostname, minsecurity]) }\\nexport async function getGrowThreads(ns, hostname, moneystate, minsecurity) { return await ramDodge(ns, \\\"SphyxOS/forms/getGrowThreads.js\\\", false, [hostname, moneystate, minsecurity]) }\\nexport async function getReputationFromDonation(ns, amount) { return await ramDodge(ns, \\\"SphyxOS/forms/getReputationFromDonation.js\\\", false, [amount]) }\\nexport async function doGetServerMinSec(ns, hostname) { return await ramDodge(ns, \\\"SphyxOS/basic/doGetServerMinSec.js\\\", false, [hostname]) }\\nexport async function doGetServerCurSec(ns, hostname) { return await ramDodge(ns, \\\"SphyxOS/basic/doGetServerCurSec.js\\\", false, [hostname]) }\\nexport async function doGetServerMaxMoney(ns, hostname) { return await ramDodge(ns, \\\"SphyxOS/basic/doGetServerMaxMoney.js\\\", false, [hostname]) }\\nexport async function doGetHostname(ns) { return await ramDodge(ns, \\\"SphyxOS/basic/getHostname.js\\\", false, []) }\\nexport async function hashIt(ns, type) { return await ramDodge(ns, \\\"SphyxOS/extras/hashIt.js\\\", false, [type]) }\\nexport async function virus(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/virus.js\\\", false, []) }\\nexport async function serverPurchaser(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/serverPurchaser.js\\\", false, []) }\\nexport async function hacknetPurchaser(ns) { return await ramDodge(ns, \\\"SphyxOS/bins/hacknetPurchaser.js\\\", false, []) }\\nexport async function getPortOpeners(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/getPortOpeners.js\\\", false, []) }\\nexport async function getPortOpenersSing(ns) { return await ramDodge(ns, \\\"SphyxOS/extras/getPortOpenersSing.js\\\", false, []) }\\nexport async function doKill(ns, pidnum) { return await ramDodge(ns, \\\"SphyxOS/basic/kill.js\\\", false, [pidnum]) }\\n//Singularity\\nexport async function destroyWD(ns, bn, script) { return await ramDodge(ns, \\\"SphyxOS/singularity/destroyWD.js\\\", false, [bn, script]) }\\nexport async function travelCity(ns, city) { return await ramDodge(ns, \\\"SphyxOS/singularity/travelToCity.js\\\", false, [city]) }\\nexport async function goToLoc(ns, city) { return await ramDodge(ns, \\\"SphyxOS/singularity/goToLoc.js\\\", false, [city]) }\\nexport async function setGym(ns, gym, workout) { return await ramDodge(ns, \\\"SphyxOS/singularity/setGym.js\\\", false, [gym, workout]) }\\nexport async function doCrime(ns, crime) { return await ramDodge(ns, \\\"SphyxOS/singularity/commitCrime.js\\\", false, [crime]) }\\nexport async function getBestFavor(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/getBestFavor.js\\\", false, []) }\\nexport async function getBestRep(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/getBestRep.js\\\", false, []) }\\nexport async function joinFac(ns, faction) { return await ramDodge(ns, \\\"SphyxOS/singularity/joinFaction.js\\\", false, [faction]) }\\nexport async function getAugsFromFaction(ns, faction) { return await ramDodge(ns, \\\"SphyxOS/singularity/getAugsFromFaction.js\\\", false, [faction]) }\\nexport async function getOwnedAugs(ns, queued) { return await ramDodge(ns, \\\"SphyxOS/singularity/getOwnedAugs.js\\\", false, [queued]) }\\nexport async function getOwnedSF(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/getOwnedSF.js\\\", false, []) }\\nexport async function purchaseAug(ns, faction, aug) { return await ramDodge(ns, \\\"SphyxOS/singularity/purchaseAug.js\\\", false, [faction, aug]) }\\nexport async function upgHomeRam(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/upgradeHomeRam.js\\\", false, []) }\\nexport async function getFactionFav(ns, faction) { return await ramDodge(ns, \\\"SphyxOS/singularity/getFactionFavor.js\\\", false, [faction]) }\\nexport async function getFacRep(ns, faction) { return await ramDodge(ns, \\\"SphyxOS/singularity/getFactionRep.js\\\", false, [faction]) }\\nexport async function donateToFac(ns, faction, amount) { return await ramDodge(ns, \\\"SphyxOS/singularity/donateToFaction.js\\\", false, [faction, amount]) }\\nexport async function purchTor(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/purchaseTor.js\\\", false, []) }\\nexport async function stopAct(ns) { return await ramDodge(ns, \\\"SphyxOS/singularity/stopAction.js\\\", false, []) }\\n//Coding Contracts\\nexport async function getCType(ns, filename, host) { return await ramDodge(ns, \\\"SphyxOS/codingContracts/getContractType.js\\\", false, [filename, host]) }\\nexport async function getCData(ns, filename, host) { return await ramDodge(ns, \\\"SphyxOS/codingContracts/getContractData.js\\\", false, [filename, host]) }\\nexport async function cctAttempt(ns, answer, filename, host) { return await ramDodge(ns, \\\"SphyxOS/codingContracts/attemptCCT.js\\\", false, JSON.stringify([answer, filename, host]), true) }\\n\\n//Stocks\\nexport async function hasWSEAcct(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/hasWSEAccount.js\\\", false, []) }\\nexport async function hasTIXAPIAccs(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/hasTIXAPIAccess.js\\\", false, []) }\\nexport async function getSyms(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/getSymbols.js\\\", false, []) }\\nexport async function shortEnabled(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/shortEnabled.js\\\", false, []) }\\nexport async function getSalesGain(ns, sym, shares, type) { return await ramDodge(ns, \\\"SphyxOS/stock/getSaleGain.js\\\", false, [sym, shares, type]) }\\nexport async function has4SAPI(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/has4SDataTIXAPI.js\\\", false, []) }\\nexport async function getBidP(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getBidPrice.js\\\", false, [sym]) }\\nexport async function getAskP(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getAskPrice.js\\\", false, [sym]) }\\nexport async function getPrices(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getPrice.js\\\", false, [sym]) }\\nexport async function getPosi(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getPosition.js\\\", false, [sym]) }\\nexport async function getFCast(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getForcast.js\\\", false, [sym]) }\\nexport async function getVol(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getVolatility.js\\\", false, [sym]) }\\nexport async function sellstock(ns, sym, shares) { return await ramDodge(ns, \\\"SphyxOS/stock/sellStock.js\\\", false, [sym, shares]) }\\nexport async function sellshort(ns, sym, shares) { return await ramDodge(ns, \\\"SphyxOS/stock/sellShort.js\\\", false, [sym, shares]) }\\nexport async function getmaxshares(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getMaxShares.js\\\", false, [sym]) }\\nexport async function buyshort(ns, sym, shares) { return await ramDodge(ns, \\\"SphyxOS/stock/buyShort.js\\\", false, [sym, shares]) }\\nexport async function buystock(ns, sym, shares) { return await ramDodge(ns, \\\"SphyxOS/stock/buyStock.js\\\", false, [sym, shares]) }\\nexport async function getfv(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getF-V.js\\\", false, [sym]) }\\nexport async function getSnap(ns, sym) { return await ramDodge(ns, \\\"SphyxOS/stock/getSnap.js\\\", false, [sym]) }\\nexport async function getWorth(ns) { return await ramDodge(ns, \\\"SphyxOS/stock/getWorth.js\\\", false, []) }\\n//IPvGo\\nexport async function getBState(ns) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/getbstate.js\\\", false, []) }\\nexport async function getCEmptyNodes(ns) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/getcontrolledemptynodes.js\\\", false, []) }\\nexport async function getLibs(ns) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/getliberties.js\\\", false, []) }\\nexport async function getValMoves(ns, playAsWhite) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/getvalidmoves.js\\\", false, [playAsWhite]) }\\nexport async function getChain(ns) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/getchains.js\\\", false, []) }\\nexport async function play2moves(ns, x1, y1, x2, y2, playAsWhite) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/play2moves.js\\\", false, [x1, y1, x2, y2, playAsWhite]) }\\nexport async function destroyND(ns, x1, y1, playAsWhite) { return await ramDodge(ns, \\\"SphyxOS/ipvgo/destroyNode.js\\\", false, [x1, y1, playAsWhite]) }\\n//Gangs\\nexport async function gangRecruit(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/recruit.js\\\", false, []) }\\nexport async function getGangFaction(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/getGangFaction.js\\\", false, []) }\\nexport async function gangAscend(ns, forced = false) { return await ramDodge(ns, \\\"SphyxOS/gangs/ascend.js\\\", false, [forced]) }\\nexport async function gangEquip(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/equip.js\\\", false, []) }\\nexport async function setWar(ns, setting) { return await ramDodge(ns, \\\"SphyxOS/gangs/setTerritoryWarfare.js\\\", false, [setting]) }\\nexport async function gangCreate(ns, name) { return await ramDodge(ns, \\\"SphyxOS/gangs/createGang.js\\\", false, [name]) }\\nexport async function gangGetMembers(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/getMemberNames.js\\\", false, []) }\\nexport async function gangGetMembersFull(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/getMembersFull.js\\\", false, []) }\\nexport async function gangGetGangInfo(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/getGangInfo.js\\\", false, []) }\\nexport async function gangGetOtherGangInfo(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/getOtherGangInfo.js\\\", false, []) }\\nexport async function gangRespectForNext(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/respectForNext.js\\\", false, []) }\\nexport async function gangInGang(ns) { return await ramDodge(ns, \\\"SphyxOS/gangs/inGang.js\\\", false, []) }\\nexport async function gangSetMemberTask(ns, name, task) { return await ramDodge(ns, \\\"SphyxOS/gangs/setMemberTask.js\\\", false, [name, task]) }\\n//Sleeves\\nexport async function hasSleeves(ns) { return await ramDodge(ns, \\\"SphyxOS/sleeves/hasSleeves.js\\\", false, []) }\\nexport async function sleeveShockRecovery(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToShockRecovery.js\\\", false, [slv]) }\\nexport async function sleeveIdle(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToIdle.js\\\", false, [slv]) }\\nexport async function sleeveSync(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToSynchronize.js\\\", false, [slv]) }\\nexport async function sleeveTravel(ns, slv, location) { return await ramDodge(ns, \\\"SphyxOS/sleeves/sleeveTravel.js\\\", false, [slv, location]) }\\nexport async function sleeveSetToGym(ns, slv, gym, type) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToGymWorkout.js\\\", false, [slv, gym, type]) }\\nexport async function sleeveSetToCrime(ns, slv, crime) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToCrime.js\\\", false, [slv, crime]) }\\nexport async function sleeveSetToUniversity(ns, slv, uni, course) { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToUniversity.js\\\", false, [slv, uni, course]) }\\nexport async function sleeveSetToBBAction(ns, slv, type, contract = \\\"\\\") { return await ramDodge(ns, \\\"SphyxOS/sleeves/setToBBAction.js\\\", false, [slv, type, contract]) }\\nexport async function getSleeveObject(ns) { return await ramDodge(ns, \\\"SphyxOS/sleeves/getSleeveObject.js\\\", false, []) }\\nexport async function sleeveGetNum(ns) { return await ramDodge(ns, \\\"SphyxOS/sleeves/getNumSlvs.js\\\", false, []) }\\nexport async function sleeveGet(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/getSleeve.js\\\", false, [slv]) }\\nexport async function sleeveGetAugs(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/getSleeveAugmentations.js\\\", false, [slv]) }\\nexport async function sleeveGetPurchasableAugs(ns, slv) { return await ramDodge(ns, \\\"SphyxOS/sleeves/getPurchasableAugs.js\\\", false, [slv]) }\\nexport async function sleevePurchaseAug(ns, slv, aug) { return await ramDodge(ns, \\\"SphyxOS/sleeves/purchaseSleeveAug.js\\\", false, [slv, aug]) }\\nexport async function sleeveInstallAugs(ns) { return await ramDodge(ns, \\\"SphyxOS/sleeves/sleeveInstallAugs.js\\\", false, []) }\\n//BladeBurner\\nexport async function bbJoinBBFac(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/joinBBFac.js\\\", false, []) }\\nexport async function bbJoinBBDiv(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/joinBBdiv.js\\\", false, []) }\\nexport async function bbGetStam(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getStam.js\\\", false, []) }\\nexport async function bbGetCity(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getCity.js\\\", false, []) }\\nexport async function bbGetCityChaos(ns, city) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getCityChaos.js\\\", false, [city]) }\\nexport async function bbGetActionEstSuccessChance(ns, type, name, slv = undefined) {\\n return slv === undefined ? await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionEstSuccessChance.js\\\", false, [type, name]) :\\n await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionEstSuccessChance.js\\\", false, [type, name, slv])\\n}\\nexport async function bbSetActionAutoLvl(ns, type, name, setting) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/setActionAutoLevel.js\\\", false, [type, name, setting]) }\\nexport async function bbGetSkillLevel(ns, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getSkillLevel.js\\\", false, [name]) }\\nexport async function bbGetActionMaxLvl(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionMaxLevel.js\\\", false, [type, name]) }\\nexport async function bbGetActionCountRemain(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionCountRemain.js\\\", false, [type, name]) }\\nexport async function bbGetCurrentAction(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getCurrentAction.js\\\", false, []) }\\nexport async function bbGetSkillPoints(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getSkillPoints.js\\\", false, []) }\\nexport async function bbUpgradeSkill(ns, name, level) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/upgradeSkill.js\\\", false, [name, level]) }\\nexport async function bbGetSkillUpgradeCost(ns, name, level = 1) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getSkillUpgradeCost.js\\\", false, [name, level]) }\\nexport async function bbSwitchCity(ns, city) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/switchCity.js\\\", false, [city]) }\\nexport async function bbSetActionLevel(ns, type, name, level) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/setActionLevel.js\\\", false, [type, name, level]) }\\nexport async function bbGetActionTime(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionTime.js\\\", false, [type, name]) }\\nexport async function bbStartAction(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/startAction.js\\\", false, [type, name]) }\\nexport async function bbGetActionCurTime(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionCurrentTime.js\\\", false, []) }\\nexport async function bbGetRank(ns) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getRank.js\\\", false, []) }\\nexport async function bbGetCityEstPop(ns, city) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getCityEstPop.js\\\", false, [city]) }\\nexport async function bbGetCityComms(ns, city) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getCityComms.js\\\", false, [city]) }\\nexport async function bbGetActionRepGain(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionRepGain.js\\\", false, [type, name]) }\\nexport async function bbGetBlackOpRank(ns, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getBlackOpRank.js\\\", false, [name]) }\\nexport async function bbGetActionCurLvl(ns, type, name) { return await ramDodge(ns, \\\"SphyxOS/bladeBurner/getActionCurLevel.js\\\", false, [type, name]) }\\n//Corp\\nexport async function divExist(ns, div) { return await ramDodge(ns, \\\"SphyxOS/corp/divExist.js\\\", false, [div]) }\\n\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n}\""},{"filename":"Loader.js","file":"\"import { runIt } from \\\"SphyxOS/util.js\\\"\\n/** @param {NS} ns */\\nexport async function main(ns) {\\n virus(ns)\\n await runIt(ns, \\\"SphyxOS/bins/LoaderSphyxOS.jsx\\\", true, [])\\n}\\n\\n/** @param {NS} ns **/\\nfunction virus(ns) {\\n const servers = getServersLight(ns)\\n for (const server of servers) {\\n try { ns.brutessh(server) } catch { }\\n try { ns.ftpcrack(server) } catch { }\\n try { ns.relaysmtp(server) } catch { }\\n try { ns.httpworm(server) } catch { }\\n try { ns.sqlinject(server) } catch { }\\n try {\\n ns.nuke(server)\\n ns.scp(\\\"SphyxOS/basic/weaken.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/grow.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/basic/hack.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/util.js\\\", server, \\\"home\\\")\\n ns.scp(\\\"SphyxOS/forms.js\\\", server, \\\"home\\\")\\n }\\n catch { }\\n }\\n}\\n\\n/** @param {NS} ns */\\nexport function getServersLight(ns) {\\n const serverList = new Set([\\\"home\\\"])\\n for (const server of serverList) {\\n for (const connection of ns.scan(server)) {\\n serverList.add(connection)\\n }\\n }\\n return Array.from(serverList)\\n}\""},{"filename":"SphyxOS/special/hashKey.txt","file":"\"izkx88nk4n\""}]