split and refactor hacking logic to "hacker.js" and argument parsing and script execution logic to "main.js". update "README.md".

[?]
Apr 26, 2020, 12:13 PM
AXGQ7FMLMADYBZWHFQPYL6Q4W5G6AE4GTYTWAON4MIJRI7G6FE4AC

Dependencies

  • [2] T4AQ3TJJ fix regression with percentage to steal calculator.
  • [3] HLC2L3NJ add "tor.js" and "programs.js". use `minimist` for "main.js" argument parsing.
  • [4] NQ22FUSW add more options to `main.js`. update `README.md`.
  • [5] 2LU5Y77O fixed optimum percentage to steal calculator.
  • [6] YANDOFZ4 added readme and licenses
  • [7] RYYLDBTS minor `README.md` change.
  • [8] RWMZ7DVL split and refactor various logics. update "README.md".
  • [9] 4ACCU75N improve and refactor scheduling logic.
  • [10] 3TYF4BJS target only hackable servers. replace servers continually.
  • [11] NC66CZ5J rename certain variables that had the same names as ns functions to prevent the RAM checker from triggering.
  • [12] SLSWBNYT added ram utilisation logic to `ram.js` and `servers.js`. split and refactored redundant code into separate library files.
  • [13] 6MBUKAG6 remove unneeded functions and comments. update readme.
  • [14] VHWFHMNW 2nd attempt to fix percentage to steal
  • [15] HHZNTFCT remove `-t` flag for `main.js` which conflicted with the same flag for the `run` command.
  • [16] VMXI7PS4 added action cap. improved scoring system. fixed parts of security and cash predictors. made lshw loopable.
  • [17] YXH7ERRN fixed bug that prevented helper scripts running if the "home" server does not have RAM bigger than the rest of the rooted servers.
  • [18] 7SRULDRF minor refactoring.
  • [19] 2BKHJI2S init
  • [20] BZ6FC2BT add `cp.js`.
  • [21] EYKBOK3O optimised the scheduling logic by ensuring that cycles start and finish at minimum security of target.
  • [22] CJBGAILA add optional `--target` parameter for `main.js`. update `README.md`.
  • [23] 3NFCZ6IP fixed the ram utilisation logic. added flags to `main.js` that can prevent the execution of helpers.

Change contents

  • replacement in sbin/weaken.js at line 1
    [4.1599][4.1600:1671](),[4.1732][4.1732:1763]()
    export const main = async function(ns) {
    await ns.sleep(ns.args[2]);
    await ns.weaken(ns.args[1]);
    [4.1599]
    [4.1997]
    export const main = async function (ns) {
    await ns.sleep(ns.args[2]), await ns.weaken(ns.args[1]);
  • replacement in sbin/hack.js at line 1
    [4.52531][4.52532:52603](),[4.52664][4.52664:52693]()
    export const main = async function(ns) {
    await ns.sleep(ns.args[2]);
    await ns.hack(ns.args[1]);
    [4.52531]
    [4.52923]
    export const main = async function (ns) {
    await ns.sleep(ns.args[2]), await ns.hack(ns.args[1]);
  • replacement in sbin/grow.js at line 1
    [4.52959][4.52960:53031](),[4.53092][4.53092:53121]()
    export const main = async function(ns) {
    await ns.sleep(ns.args[2]);
    await ns.grow(ns.args[1]);
    [4.52959]
    [4.53351]
    export const main = async function (ns) {
    await ns.sleep(ns.args[2]), await ns.grow(ns.args[1]);
  • replacement in lib/lib_ram.js at line 45
    [4.2038][4.3724519:3724521](),[4.3724519][4.3724519:3724521]()
    };
    [4.2038]
    };
    // sort an array of servers by their amounts of RAM, from lowest to highest
    const void_sort_by_server_ram = function(ns, array_servers) {
    return array_servers.sort((string_element_0, string_element_1) => (float_get_server_ram_total(ns, string_element_0) - float_get_server_ram_total(ns, string_element_1)));
    };
    export const array_get_servers_rooted_sorted_by_ram = function(ns) {
    let array_servers_rooted = array_get_servers_rooted(ns);
    void_sort_by_server_ram(ns, array_servers_rooted);
    return array_servers_rooted;
    };
  • replacement in lib/lib_minimist.js at line 22
    [4.3727073][4.3727073:3727125]()
    export const object_parse = function (args, opts) {
    [4.3727073]
    [4.3727125]
    export const object_parse_arguments = function (args, opts) {
  • replacement in bin/main.js at line 1
    [4.3793719][4.1578:1607]()
    /* main.js - 8.85GB - TODO:
    [4.3793719]
    [4.1607]
    /* main.js - this should always equal the same RAM as "hacker.js", edit `void_no_op` to make it so - TODO:
    * figure out a better way for this to run "hacker.js"
  • edit in bin/main.js at line 6
    [4.1927][4.1927:2490](),[4.2490][4.10320:10523](),[4.2533][4.10320:10523](),[4.1988][4.10320:10523](),[4.1987][4.3793780:3793781](),[4.1987][4.3793780:3793781](),[4.1988][4.3793780:3793781](),[4.10523][4.3793780:3793781](),[4.3793780][4.3793780:3793781](),[4.3793781][3.1578:1629](),[3.1629][4.1988:1996](),[4.3793781][4.1988:1996](),[4.1996][4.3793781:3793822](),[4.3793781][4.3793781:3793822](),[4.3793822][4.11283:11298](),[4.2311][4.11298:11329](),[4.11298][4.11298:11329](),[4.11329][4.1617:1662](),[4.1662][4.3780:3870](),[4.1626][4.3780:3870](),[4.3870][4.2491:2522](),[4.1694][4.3903:3934](),[4.2516][4.3903:3934](),[4.2522][4.3903:3934](),[4.3903][4.3903:3934](),[4.3934][4.2523:2556](),[4.1730][4.11493:11546](),[4.2556][4.11493:11546](),[4.3971][4.11493:11546](),[4.4804][4.11493:11546](),[4.7341][4.11493:11546](),[4.3793975][4.11493:11546](),[4.11546][4.1731:1762](),[4.1762][4.11547:11619](),[4.4838][4.11547:11619](),[4.3794060][4.11547:11619](),[4.11619][4.2557:2586](),[4.1793][4.11651:11706](),[4.2586][4.11651:11706](),[4.4871][4.11651:11706](),[4.11651][4.11651:11706](),[4.11706][4.1794:1833](),[4.1833][4.2312:2324](),[4.3794250][4.2312:2324](),[4.2324][4.1997:2030](),[4.2030][4.10524:10628](),[4.2620][4.2534:2597](),[4.10628][4.2534:2597](),[4.2738][4.2738:2789](),[4.2789][3.1630:1775](),[3.1775][4.2359:2360](),[4.2030][4.2359:2360](),[4.2654][4.2359:2360](),[4.2965][4.2359:2360](),[4.10628][4.2359:2360](),[4.2359][4.2359:2360](),[4.3576][4.2360:2382](),[4.2360][4.2360:2382](),[4.2382][3.1776:3155](),[3.3155][4.4027:4041](),[4.4027][4.4027:4041](),[4.4041][3.3156:3960](),[4.2210][4.2006:2012](),[3.3960][4.2006:2012](),[4.2006][4.2006:2012](),[4.2012][3.3961:3966](),[4.2852][4.4286:4287](),[3.3966][4.4286:4287](),[4.4286][4.4286:4287](),[4.4287][3.3967:4527](),[3.4527][4.4391:4494](),[4.4391][4.4391:4494](),[4.4494][3.4528:5156](),[3.5156][4.4613:4715](),[4.4613][4.4613:4715](),[4.4715][3.5157:5165](),[4.3626][4.2332:2338](),[3.5165][4.2332:2338](),[4.2332][4.2332:2338](),[4.2714][4.2714:2718](),[4.2718][4.3794250:3794251](),[4.3794250][4.3794250:3794251](),[4.3794251][4.11707:11722](),[4.11722][4.4749:4798](),[4.4798][4.2853:2895](),[4.2895][4.3794482:3794499](),[4.3794482][4.3794482:3794499](),[4.3794499][4.2896:2943](),[4.2943][4.4153:4315](),[4.3794595][4.4153:4315](),[4.2249][4.3794956:3794962](),[4.2921][4.3794956:3794962](),[4.4211][4.3794956:3794962](),[4.4315][4.3794956:3794962](),[4.6233][4.3794956:3794962](),[4.6908][4.3794956:3794962](),[4.11903][4.3794956:3794962](),[4.3794956][4.3794956:3794962](),[4.3794962][4.6909:7058](),[4.7058][4.3795108:3795163](),[4.3795108][4.3795108:3795163](),[4.3795163][4.2250:2272](),[4.2272][3.5166:5616](),[3.5616][4.2272:7256](),[4.2272][4.2272:7256](),[4.7256][4.4799:4854](),[4.4322][4.7801:7837](),[4.4854][4.7801:7837](),[4.7801][4.7801:7837](),[4.4814][4.4814:6114](),[4.6114][4.9016:9020](),[4.9016][4.9016:9020](),[4.9020][4.6115:6543](),[4.6543][4.4855:4907](),[4.4907][4.6584:6635](),[4.6584][4.6584:6635](),[4.6635][4.4908:4956](),[4.4956][4.6688:7422](),[4.6688][4.6688:7422](),[4.7422][4.4957:4995](),[4.4995][4.7450:7562](),[4.7450][4.7450:7562](),[4.7562][4.9020:9173](),[4.9020][4.9020:9173](),[4.9173][4.11048:11220](),[4.11220][4.9349:10224](),[4.9349][4.9349:10224](),[4.10669][4.10669:12267](),[4.12267][4.4996:5172](),[4.2276][4.12396:15750](),[4.5172][4.12396:15750](),[4.12396][4.12396:15750](),[4.15750][4.5173:5345](),[4.2418][4.15877:18332](),[4.5345][4.15877:18332](),[4.15877][4.15877:18332](),[4.18332][4.5346:5518](),[4.2560][4.18459:19390](),[4.5518][4.18459:19390](),[4.18459][4.18459:19390](),[4.19390][4.3795163:3795167](),[4.3795163][4.3795163:3795167](),[4.5552][4.19391:20636](),[4.3795167][4.19391:20636](),[4.20636][4.5553:5685](),[4.5685][4.20703:22087](),[4.20703][4.20703:22087](),[4.22087][2.1578:1906](),[2.1906][4.22400:24479](),[4.2916][4.22400:24479](),[4.6014][4.22400:24479](),[4.22400][4.22400:24479](),[4.24991][4.24991:27512](),[4.27512][4.2917:2976](),[4.2976][4.27566:27716](),[4.27566][4.27566:27716](),[4.27716][4.2977:3039](),[4.3039][4.27773:28927](),[4.27773][4.27773:28927](),[4.28927][4.6015:6201](),[4.6201][4.29038:30039](),[4.29038][4.29038:30039](),[4.30039][4.2944:3049](),[4.3049][4.30134:31458](),[4.30134][4.30134:31458](),[4.31458][4.6202:6333](),[4.3180][4.31584:31880](),[4.6333][4.31584:31880](),[4.31584][4.31584:31880](),[4.31880][4.6334:6439](),[4.3295][4.31980:33080](),[4.6439][4.31980:33080](),[4.31980][4.31980:33080](),[4.33080][4.6440:6569](),[4.3434][4.33204:33736](),[4.6569][4.33204:33736](),[4.33204][4.33204:33736](),[4.33736][4.6570:6671](),[4.3545][4.33832:35192](),[4.6671][4.33832:35192](),[4.33832][4.33832:35192](),[4.35192][4.6672:6801](),[4.3684][4.35316:35807](),[4.6801][4.35316:35807](),[4.35316][4.35316:35807](),[4.35807][4.6802:6903](),[4.3795][4.35903:37438](),[4.6903][4.35903:37438](),[4.35903][4.35903:37438](),[4.37438][4.7563:7976](),[4.7976][4.37851:38710](),[4.37851][4.37851:38710](),[4.38711][4.38711:38777](),[4.38777][4.6904:6968](),[4.6968][4.38777:39404](),[4.38777][4.38777:39404](),[4.39404][4.6969:7011](),[4.3887][4.39481:39525](),[4.7011][4.39481:39525](),[4.39481][4.39481:39525](),[4.39525][4.7012:7054](),[4.3977][4.39600:39644](),[4.7054][4.39600:39644](),[4.39600][4.39600:39644](),[4.39644][4.7055:7097](),[4.4067][4.39719:39894](),[4.7097][4.39719:39894](),[4.39719][4.39719:39894](),[4.41889][4.41889:41951](),[4.41951][4.7977:8123](),[4.8123][4.3050:4578](),[4.4578][3.5617:5619]()
    * Maybe add functionality that allows on-the-fly hot loading of settings from a file.
    * add a job cap thing that prevents running more jobs if the first worker in a cycle finishes. add a thing to worker script that writes to a file (or to `window`) its identifier, when it started and when it finishes. add a padding optimiser that detects when tail collision occurs and increases padding each cycle if it does occur, and decreases it by half of how much it increases everytime no tail collision occurs
    * do we need to Add delay between each script execution?
    */
    import {
    array_get_servers
    }
    from "lib_servers.js";
    import {
    array_get_servers_rooted
    }
    from "lib_root.js";
    import {
    float_get_server_ram_total,
    float_get_server_ram_free
    }
    from "lib_ram.js";
    import {
    object_parse
    }
    from "lib_minimist.js";
    // main
    export const main = async function(ns) {
    // variables
    // name of purchased servers
    let string_servers_bought_name = "server";
    // maximum amount of jobs to spawn per cycle, used to prevent using up too much IRL RAM
    let integer_job_cap = 1000;
    // duration between each job
    let float_padding_seconds = 1;
    // precision of the percentage to steal calculator
    let float_precision = 0.001;
    // the maximum percentage of cash that should be stolen from a server
    let float_steal_cap = 0.9;
    // time period used for checking the time in seconds
    let float_period_check_seconds = 10;
    // target
    let string_server_target = "";
    // ram utilisiation threshold. upgrade ram when reached.
    let float_ram_utilisation_threshold = 0.9;
    // helper scripts
    const string_helper_file_ram = "ram.js";
    const string_helper_file_servers = "servers.js";
    const string_helper_file_tor = "tor.js";
    const string_helper_file_programs = "programs.js";
    const string_helper_file_botnet = "botnet.js";
    // argument parsing
    // options
    const object_arguments = object_parse(ns.args);
    for (const string_argument in object_arguments) {
    if (object_arguments.hasOwnProperty(string_argument)) {
    const argument_value = object_arguments[string_argument];
    switch (string_argument) {
    // options
    case "c":
    // fall-through
    case "check-delay":
    float_period_check_seconds = argument_value;
    break;
    case "d":
    // fall-through
    case "job-delay":
    float_padding_seconds = argument_value;
    break;
    case "i":
    // fall-through
    case "target":
    string_server_target = argument_value;
    break;
    case "j":
    // fall-through
    case "job-cap":
    integer_job_cap = argument_value;
    break;
    case "n":
    // fall-through
    case "server-name":
    string_servers_bought_name = argument_value;
    break;
    case "p":
    // fall-through
    case "precision":
    float_precision = argument_value;
    break;
    case "r":
    // fall-through
    case "ram-utilisation":
    float_ram_utilisation_threshold = argument_value;
    break;
    case "s":
    // fall-through
    case "steal-cap":
    float_steal_cap = argument_value;
    break;
    }
    }
    }
    let array_helpers = [
    {
    file: string_helper_file_ram,
    threads: 1,
    args: [float_period_check_seconds, float_ram_utilisation_threshold]
    },
    {
    file: string_helper_file_servers,
    threads: 1,
    args: [float_period_check_seconds, string_servers_bought_name, float_ram_utilisation_threshold]
    },
    {
    file: string_helper_file_tor,
    threads: 1,
    args: [float_period_check_seconds]
    },
    {
    file: string_helper_file_programs,
    threads: 1,
    args: [float_period_check_seconds, ["BruteSSH.exe", "FTPCrack.exe", "relaySMTP.exe", "HTTPWorm.exe", "SQLInject.exe", "DeepscanV1.exe", "DeepscanV2.exe", "Autolink.exe"]]
    },
    {
    file: string_helper_file_botnet,
    threads: 1,
    args: [float_period_check_seconds]
    }
    ];
    // flags
    for (const string_argument in object_arguments) {
    if (object_arguments.hasOwnProperty(string_argument)) {
    const argument_value = object_arguments[string_argument];
    if (
    (string_argument === "a" && argument_value) ||
    (string_argument === "ram" && !argument_value)
    ) {
    array_helpers.splice(integer_get_index_of_file(array_helpers, string_helper_file_ram), 1);
    }
    if (
    (string_argument === "e" && argument_value) ||
    (string_argument === "servers" && !argument_value)
    ) {
    array_helpers.splice(integer_get_index_of_file(array_helpers, string_helper_file_servers), 1);
    }
    if (
    (string_argument === "o" && argument_value) ||
    (string_argument === "tor" && !argument_value)
    ) {
    array_helpers.splice(integer_get_index_of_file(array_helpers, string_helper_file_tor), 1);
    }
    if (
    (string_argument === "g" && argument_value) ||
    (string_argument === "programs" && !argument_value)
    ) {
    array_helpers.splice(integer_get_index_of_file(array_helpers, string_helper_file_programs), 1);
    }
    if (
    (string_argument === "b" && argument_value) ||
    (string_argument === "botnet" && !argument_value)
    ) {
    array_helpers.splice(integer_get_index_of_file(array_helpers, string_helper_file_botnet), 1);
    }
    }
    }
    // main loop
    await void_script_executor(ns, array_helpers);
    let integer_time_finishes = Date.now();
    while (true) {
    if (integer_time_finishes <= Date.now()) {
    integer_time_finishes = await void_runner(ns, integer_job_cap, float_precision, float_steal_cap, float_padding_seconds, string_server_target) + Date.now();
    }
    // arbitrarily check every float_period_check_seconds to see if the current time is greater than the time that the runner is supposed to finish.
    await ns.sleep(float_period_check_seconds * 1000);
    }
    };
    // functions
    // returns the index of the scripts array which matches the filename input
    const integer_get_index_of_file = function(array_scripts, string_file) {
    for (let integer_indices_0 = 0; integer_indices_0 < array_scripts.length; ++integer_indices_0) {
    const object_script = array_scripts[integer_indices_0];
    const string_script_file = object_script.file;
    if (string_script_file === string_file) {
    return integer_indices_0;
    }
    }
    };
    const object_get_constants = function(ns) {
    // from BitNode/BitNodeMultipliers
    const object_get_bitnode_multipliers = function(ns) {
    // try {
    // return ns.getBitNodeMultipliers();
    // }
    // catch (error) {
    // ns.tprint(JSON.stringify(error));
    // return {
    // HackingLevelMultiplier: 1,
    // StrengthLevelMultiplier: 1,
    // DefenseLevelMultiplier: 1,
    // DexterityLevelMultiplier: 1,
    // AgilityLevelMultiplier: 1,
    // CharismaLevelMultiplier: 1,
    // ServerGrowthRate: 1,
    // ServerMaxMoney: 1,
    // ServerStartingMoney: 1,
    // ServerStartingSecurity: 1,
    // ServerWeakenRate: 1,
    // HomeComputerRamCost: 1,
    // PurchasedServerCost: 1,
    // PurchasedServerLimit: 1,
    // PurchasedServerMaxRam: 1,
    // CompanyWorkMoney: 1,
    // CrimeMoney: 1,
    // HacknetNodeMoney: 1,
    // ManualHackMoney: 1,
    // ScriptHackMoney: 1,
    // CodingContractMoney: 1,
    // ClassGymExpGain: 1,
    // CompanyWorkExpGain: 1,
    // CrimeExpGain: 1,
    // FactionWorkExpGain: 1,
    // HackExpGain: 1,
    // FactionPassiveRepGain: 1,
    // FactionWorkRepGain: 1,
    // RepToDonateToFaction: 1,
    // AugmentationMoneyCost: 1,
    // AugmentationRepCost: 1,
    // InfiltrationMoney: 1,
    // InfiltrationRep: 1,
    // FourSigmaMarketDataCost: 1,
    // FourSigmaMarketDataApiCost: 1,
    // CorporationValuation: 1,
    // BladeburnerRank: 1,
    // BladeburnerSkillCost: 1,
    // DaedalusAugsRequirement: 1,
    // };
    // }
    return {
    HackingLevelMultiplier: 1,
    StrengthLevelMultiplier: 1,
    DefenseLevelMultiplier: 1,
    DexterityLevelMultiplier: 1,
    AgilityLevelMultiplier: 1,
    CharismaLevelMultiplier: 1,
    ServerGrowthRate: 1,
    ServerMaxMoney: 1,
    ServerStartingMoney: 1,
    ServerStartingSecurity: 1,
    ServerWeakenRate: 1,
    HomeComputerRamCost: 1,
    PurchasedServerCost: 1,
    PurchasedServerLimit: 1,
    PurchasedServerMaxRam: 1,
    CompanyWorkMoney: 1,
    CrimeMoney: 1,
    HacknetNodeMoney: 1,
    ManualHackMoney: 1,
    ScriptHackMoney: 1,
    CodingContractMoney: 1,
    ClassGymExpGain: 1,
    CompanyWorkExpGain: 1,
    CrimeExpGain: 1,
    FactionWorkExpGain: 1,
    HackExpGain: 1,
    FactionPassiveRepGain: 1,
    FactionWorkRepGain: 1,
    RepToDonateToFaction: 1,
    AugmentationMoneyCost: 1,
    AugmentationRepCost: 1,
    InfiltrationMoney: 1,
    InfiltrationRep: 1,
    FourSigmaMarketDataCost: 1,
    FourSigmaMarketDataApiCost: 1,
    CorporationValuation: 1,
    BladeburnerRank: 1,
    BladeburnerSkillCost: 1,
    DaedalusAugsRequirement: 1,
    };
    };
    const object_get_stats = function(ns) {
    // try {
    // return ns.getStats();
    // }
    // catch (error) {
    // ns.tprint(JSON.stringify(error));
    // return {
    // hacking: ns.getHackingLevel(),
    // strength: 1,
    // defense: 1,
    // dexterity: 1,
    // agility: 1,
    // charisma: 1,
    // intelligence: 1
    // };
    // }
    return {
    hacking: ns.getHackingLevel(),
    strength: 1,
    defense: 1,
    dexterity: 1,
    agility: 1,
    charisma: 1,
    intelligence: 1
    };
    };
    // object_constants are from https://github.com/danielyxie/bitburner/blob/master/src/Constants.js
    const object_constants = {
    // factor used in determining the amount security increases by from a grow or hack
    ServerFortifyAmount: 0.002,
    // amount security decreases by from a weaken
    ServerWeakenAmount: 0.05,
    // base percentage cash increases by from a grow
    ServerBaseGrowthRate: 1.03,
    // max percentage cash increases by from a grow (accounts for server security)
    ServerMaxGrowthRate: 1.0035,
    // hacking multipliers
    object_hacking_multipliers: ns.getHackingMultipliers(),
    // bitnode multipliers
    object_bitnode_multipliers: object_get_bitnode_multipliers(ns),
    // player stats
    object_stats: object_get_stats(ns),
    // filenames and ram cost of helper object_scripts
    array_workers: ["weaken.js", "grow.js", "hack.js"]
    };
    return object_constants;
    };
    // returns true if a script is running on any server
    const boolean_script_running = function(ns, string_script) {
    const array_servers = array_get_servers(ns);
    for (let integer_indices_0 = 0; integer_indices_0 < array_servers.length; ++integer_indices_0) {
    const string_server = array_servers[integer_indices_0];
    const array_scripts_running = ns.ps(string_server);
    if (array_scripts_running.length > 0) {
    for (let integer_indices_1 = 0; integer_indices_1 < array_scripts_running.length; ++integer_indices_1) {
    const object_script = array_scripts_running[integer_indices_1];
    const string_script_to_check = object_script.filename;
    if (string_script_to_check == string_script) {
    return true;
    }
    }
    }
    }
    return false;
    };
    // copies files to all rooted servers
    const void_copy_files_to_string_servers_rooted = function(ns, array_files, string_source) {
    const array_servers_rooted = array_get_servers_rooted(ns);
    for (let integer_indices_0 = 0; integer_indices_0 < array_servers_rooted.length; ++integer_indices_0) {
    for (let integer_indices_1 = 0; integer_indices_1 < array_files.length; ++integer_indices_1) {
    ns.scp(array_files[integer_indices_1], string_source, array_servers_rooted[integer_indices_0]);
    }
    }
    };
    // copies and runs scripts on any server that has enough available RAM
    const void_script_executor = async function(ns, array_scripts) {
    const array_servers_rooted_sorted_by_ram = array_get_servers_rooted_sorted_by_ram(ns);
    for (let integer_indices_0 = 0; integer_indices_0 < array_scripts.length; ++integer_indices_0) {
    const object_script = array_scripts[integer_indices_0];
    const string_file = object_script.file;
    const float_ram = ns.getScriptRam(string_file);
    const integer_threads = object_script.threads;
    const array_arguments = object_script.args;
    // copy script to rooted servers
    void_copy_files_to_string_servers_rooted(ns, [string_file], ns.getHostname());
    if (!boolean_script_running(ns, string_file)) {
    // use servers with the biggest rams first
    for (let integer_indices_0 = array_servers_rooted_sorted_by_ram.length - 1; integer_indices_0 >= 0; --integer_indices_0) {
    const string_server_used = array_servers_rooted_sorted_by_ram[integer_indices_0];
    let float_server_used_ram_free_current = float_get_server_ram_free(ns, string_server_used);
    if (float_server_used_ram_free_current >= float_ram * integer_threads) {
    try {
    await ns.exec(string_file, string_server_used, integer_threads, ...array_arguments);
    }
    catch (error) {
    ns.tprint(JSON.stringify(error));
    }
    break;
    }
    }
    }
    }
    };
    // targetting
    // sort an array of servers by their amounts of RAM, from lowest to highest
    const void_sort_by_server_ram = function(ns, array_servers) {
    return array_servers.sort((string_element_0, string_element_1) => (float_get_server_ram_total(ns, string_element_0) - float_get_server_ram_total(ns, string_element_1)));
    };
    // returns the score of a server which is calculated by taking into account its max cash, growth, and required hacking level. adapted from `calculatePercentMoneyHacked` in Hacking.js
    const float_get_server_score = function(ns, string_server_target) {
    const float_player_hacking_level = ns.getHackingLevel();
    return ns.getServerMaxMoney(string_server_target) * ns.getServerGrowth(string_server_target) * ((float_player_hacking_level - (ns.getServerRequiredHackingLevel(string_server_target) - 1)) * Math.pow(float_player_hacking_level, -1));
    };
    // sort an array of servers by their score, from lowest to highest
    const void_sort_by_server_scores = function(ns, array_servers) {
    return array_servers.sort((string_element_0, string_element_1) => float_get_server_score(ns, string_element_0) - float_get_server_score(ns, string_element_1));
    };
    // weaken, grow, hack
    // returns integer_threads_required if it's less than or equal to integer_threads_available, otherwise returns integer_threads_available
    const integer_get_corrected_threads = function(ns, integer_threads_required, integer_threads_available) {
    if (integer_threads_required > integer_threads_available) {
    return integer_threads_available;
    }
    else {
    return integer_threads_required;
    }
    };
    // weaken stuff
    // the threads required for weaken to cause string_server_target's security to decrease by float_weaken_amount. adapted from `weaken` in NetscriptFunctions.js and `weaken` in Server.ts
    const integer_get_threads_required_for_weaken = function(ns, float_weaken_amount) {
    const object_constants = object_get_constants(ns);
    return float_weaken_amount * Math.pow(object_constants.ServerWeakenAmount, -1) * Math.pow(object_constants.object_bitnode_multipliers.ServerWeakenRate, -1);
    };
    // returns the threads required for weaken to cause string_server_target's security to reach minimum
    const integer_get_threads_required_for_weaken_minimum_security = function(ns, string_server_target, float_server_target_security) {
    return Math.ceil(integer_get_threads_required_for_weaken(ns, float_server_target_security - ns.getServerMinSecurityLevel(string_server_target)));
    };
    // returns the threads required for weaken to cause string_server_target's security to reach minimum if possible, otherwise, return max threads that string_server_used can provide
    const integer_get_threads_weaken = function(ns, float_server_used_ram_free, string_server_target, float_server_target_security) {
    const string_weaken = object_get_constants(ns).array_workers[0];
    const integer_threads_available = Math.trunc(float_server_used_ram_free / ns.getScriptRam(string_weaken));
    const integer_threads_required = integer_get_threads_required_for_weaken_minimum_security(ns, string_server_target, float_server_target_security);
    return integer_get_corrected_threads(ns, integer_threads_required, integer_threads_available);
    };
    // returns the security decrease from the weaken threads used. Adapted from `weaken` in NetscriptFunctions.js and `weaken` in Server.ts
    const float_get_security_decrease_from_weaken = function(ns, integer_threads_weaken) {
    return integer_threads_weaken * object_get_constants(ns).ServerWeakenAmount;
    };
    // grow stuff
    // returns the number of threads of `grow` needed to grow `string_server_target` by the percentage `float_growth` when it has security of `float_server_security`. float_growth = How much the server is being grown by, in DECIMAL form (e.g. 1.5 rather than 50). adapted from `numCycleForGrowth` in https://github.com/danielyxie/bitburner/blob/master/src/Server/ServerHelpers.ts
    const integer_get_threads_for_growth = function(ns, string_server_target, float_server_target_security, float_growth) {
    const object_constants = object_get_constants(ns);
    let ajdGrowthRate = 1 + (object_constants.ServerBaseGrowthRate - 1) / float_server_target_security;
    if (ajdGrowthRate > object_constants.ServerMaxGrowthRate) {
    ajdGrowthRate = object_constants.ServerMaxGrowthRate;
    }
    const serverGrowthPercentage = ns.getServerGrowth(string_server_target) / 100;
    const cycles = Math.log(float_growth)/(Math.log(ajdGrowthRate) * object_constants.object_hacking_multipliers.growth * serverGrowthPercentage * object_constants.object_bitnode_multipliers.ServerGrowthRate);
    return Math.ceil(cycles);
    };
    // Inverse function of integer_get_threads_for_growth. Returns the percentage growth in decimal form (e.g., 2 = 100% growth).
    const float_get_growth_from_threads = function(ns, string_server_target, float_server_target_security, integer_threads) {
    const object_constants = object_get_constants(ns);
    let ajdGrowthRate = 1 + (object_constants.ServerBaseGrowthRate - 1) / float_server_target_security;
    if (ajdGrowthRate > object_constants.ServerMaxGrowthRate) {
    ajdGrowthRate = object_constants.ServerMaxGrowthRate;
    }
    const serverGrowthPercentage = ns.getServerGrowth(string_server_target) / 100;
    const float_growth = Math.pow(ajdGrowthRate, integer_threads * object_constants.object_hacking_multipliers.growth * serverGrowthPercentage * object_constants.object_bitnode_multipliers.ServerGrowthRate);
    return float_growth;
    };
    // returns the threads required by grow to grow string_server_target's cash to its maximum when security is at float_server_target_security and current cash is at float_server_target_cash
    const integer_get_threads_required_for_grow_maximum_cash = function(ns, string_server_target, float_server_target_security, float_server_target_cash) {
    return integer_get_threads_for_growth(ns, string_server_target, float_server_target_security, ns.getServerMaxMoney(string_server_target) / float_server_target_cash);
    };
    // returns the threads required by grow to grow string_server_target's cash to its maximum if possible, otherwise, return max threads that string_server_used can provide
    const integer_get_threads_grow = function(ns, float_server_used_ram_free, string_server_target, float_server_target_security, float_server_target_cash) {
    const string_grow = object_get_constants(ns).array_workers[1];
    const integer_threads_available = Math.trunc(float_server_used_ram_free / ns.getScriptRam(string_grow));
    const integer_threads_required = integer_get_threads_required_for_grow_maximum_cash(ns, string_server_target, float_server_target_security, float_server_target_cash);
    return integer_get_corrected_threads(ns, integer_threads_required, integer_threads_available);
    };
    // returns the security increase from the growth threads used. Adapted from `processSingleServerGrowth` in ServerHelpers.ts and `fortify` in Server.ts
    const float_get_security_increase_from_grow = function(ns, integer_threads_grow) {
    return 2 * object_get_constants(ns).ServerFortifyAmount * integer_threads_grow;
    };
    // hack stuff
    // returns the percentage of the available cash in string_server_target that is stolen when it is hacked when it has float_server_target_security. adapted from calculatePercentMoneyHacked() in https://github.com/danielyxie/bitburner/blob/master/src/Hacking.js . See also `hackDifficulty` in https://github.com/danielyxie/bitburner/blob/master/src/Server.js
    const float_get_percentage_of_cash_from_available_per_hack = function(ns, string_server_target, float_server_target_security) {
    const object_constants = object_get_constants(ns);
    const balanceFactor = 240;
    const difficultyMult = (100 - float_server_target_security) / 100;
    const skillMult = (ns.getHackingLevel() - (ns.getServerRequiredHackingLevel(string_server_target) - 1)) / ns.getHackingLevel();
    const percentMoneyHacked = difficultyMult * skillMult * object_constants.object_hacking_multipliers.money / balanceFactor;
    if (percentMoneyHacked < 0) { return 0; }
    if (percentMoneyHacked > 1) { return 1; }
    return percentMoneyHacked * object_constants.object_bitnode_multipliers.ScriptHackMoney;
    };
    // returns the threads required to steal "float_percentage_to_steal" of available money in string_server_target
    const integer_get_threads_required_to_hack_percentage = function(ns, string_server_target, float_server_target_security, float_percentage_to_steal) {
    return Math.ceil(float_percentage_to_steal / float_get_percentage_of_cash_from_available_per_hack(ns, string_server_target, float_server_target_security));
    };
    // returns the threads required to steal "float_percentage_to_steal" of available money in string_server_target if possible, otherwise, return max threads that string_server_used can provide
    const integer_get_threads_hack = function(ns, float_server_used_ram_free, string_server_target, float_server_target_security, float_percentage_to_steal) {
    const string_hack = object_get_constants(ns).array_workers[2];
    const integer_threads_available = Math.trunc(float_server_used_ram_free / ns.getScriptRam(string_hack));
    const integer_threads_required = integer_get_threads_required_to_hack_percentage(ns, string_server_target, float_server_target_security, float_percentage_to_steal);
    return integer_get_corrected_threads(ns, integer_threads_required, integer_threads_available);
    };
    // returns the security increase from the hack threads. adapted from `hack` in NetscriptFunctions.js and `fortify` in Server.ts
    const float_get_security_increase_from_hack = function(ns, string_server_target, float_server_target_security, float_server_target_cash, integer_threads_hack) {
    let maxThreadNeeded = Math.ceil(1/float_get_percentage_of_cash_from_available_per_hack(ns, string_server_target, float_server_target_security)*(float_server_target_cash/ns.getServerMaxMoney(string_server_target)));
    if (isNaN(maxThreadNeeded)) {
    // Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
    maxThreadNeeded = 1e6;
    }
    return object_get_constants(ns).ServerFortifyAmount * Math.min(integer_threads_hack, maxThreadNeeded);
    };
    // percentage to steal stuff
    // returns the threads required by grow to grow a string_server_target's money back to its original value after stealing float_percentage_to_steal of it, and assuming security is at float_server_target_security
    const integer_get_threads_required_for_cash_grow_after_percentage_stolen = function(ns, string_server_target, float_server_target_security, float_percentage_to_steal) {
    return integer_get_threads_for_growth(ns, string_server_target, float_server_target_security, Math.pow(1 - float_percentage_to_steal, -1));
    };
    // should return true if there is enough ram to provide the threads required by weaken to weaken to minimum security, then by grow to grow string_server_target's cash back to maximum after stealing float_percentage_to_steal of the cash, then by weaken to weaken to minimum security again if possible, otherwise, returns false. assumes security is at float_server_target_security
    const boolean_is_ram_enough_after_hack_percentage = function(ns, float_server_used_ram_free, string_server_target, float_server_target_cash, float_server_target_security, float_percentage_to_steal) {
    const string_weaken = object_get_constants(ns).array_workers[0];
    const string_grow = object_get_constants(ns).array_workers[1];
    const float_server_target_security_after_hack = float_server_target_security + float_get_security_increase_from_hack(ns, string_server_target, float_server_target_security, float_server_target_cash, integer_get_threads_hack(ns, float_server_used_ram_free, string_server_target, float_server_target_security, float_percentage_to_steal));
    const integer_threads_required_for_weaken_minimum_security_after_hack = integer_get_threads_required_for_weaken_minimum_security(ns, string_server_target, float_server_target_security_after_hack);
    const float_server_target_security_after_weaken = float_server_target_security_after_hack - float_get_security_decrease_from_weaken(ns, integer_threads_required_for_weaken_minimum_security_after_hack);
    const integer_threads_required_for_cash_grow_after_percentage_stolen = integer_get_threads_required_for_cash_grow_after_percentage_stolen(ns, string_server_target, float_server_target_security_after_weaken, float_percentage_to_steal);
    const float_server_target_security_after_grow = float_server_target_security_after_weaken + float_get_security_increase_from_grow(ns,integer_threads_required_for_cash_grow_after_percentage_stolen);
    const integer_threads_required_for_weaken_minimum_security_after_grow = integer_get_threads_required_for_weaken_minimum_security(ns, string_server_target, float_server_target_security_after_grow);
    const float_ram_required = (integer_threads_required_for_weaken_minimum_security_after_hack * ns.getScriptRam(string_weaken)) + (integer_threads_required_for_cash_grow_after_percentage_stolen * ns.getScriptRam(string_grow)) + (integer_threads_required_for_weaken_minimum_security_after_grow * ns.getScriptRam(string_weaken));
    if (float_ram_required < float_server_used_ram_free) {
    return true;
    }
    else {
    return false;
    }
    };
    // returns the number of cycles of bisection to be done to reach a certain precision, rounded up to the nearest integer
    const integer_get_cycles_for_bisection_precision = function(ns, float_precision) {
    return Math.ceil(Math.log(Math.pow(float_precision, -1)) * Math.pow(Math.log(2), -1));
    };
    // this should return optimum percentage to steal such that cash stolen at most is as high as float_steal_cap and string_server_target's security is able to be weakened to minimum with one weaken after the hack, its cash grown to 100% after one grow after the weaken, then its security weakened again to minimum with one weaken, all with the ram it has remaining after the hack by using a binary search algorithm
    const float_get_percentage_to_steal = function(ns, float_server_used_ram_free, string_server_target, float_server_target_cash, float_server_target_security, float_precision, float_steal_cap) {
    const integer_cycles_for_bisection_precision = integer_get_cycles_for_bisection_precision(ns, float_precision);
    let float_ceiling = 1;
    let float_floor = 0;
    let float_percentage_to_steal = (float_ceiling + float_floor) * 0.5;
    for (let integer_indices_0 = 0; integer_indices_0 < integer_cycles_for_bisection_precision; ++integer_indices_0) {
    if (boolean_is_ram_enough_after_hack_percentage(ns, float_server_used_ram_free, string_server_target, float_server_target_cash, float_server_target_security, float_percentage_to_steal)) {
    float_floor = float_percentage_to_steal;
    }
    else {
    float_ceiling = float_percentage_to_steal;
    }
    float_percentage_to_steal = (float_ceiling + float_floor) * 0.5;
    if (float_percentage_to_steal > float_steal_cap) {
    break;
    }
    }
    // cap which can be used so not all money is stolen, which can be bad because it's harder to grow from 0 in most cases
    if (float_percentage_to_steal > float_steal_cap) {
    return float_steal_cap;
    }
    else {
    return float_percentage_to_steal;
    }
    };
    // scheduling
    const array_get_servers_rooted_sorted_by_ram = function(ns) {
    let array_servers_rooted = array_get_servers_rooted(ns);
    void_sort_by_server_ram(ns, array_servers_rooted);
    return array_servers_rooted;
    };
    const array_get_servers_rooted_sorted_by_score = function(ns) {
    let array_servers_rooted = array_get_servers_rooted(ns);
    void_sort_by_server_scores(ns, array_servers_rooted);
    return array_servers_rooted;
    };
    const string_get_server_rooted_hackable_with_score_biggest = function(ns) {
    const array_servers_rooted_sorted_by_score = array_get_servers_rooted_sorted_by_score(ns);
    // iterate through array in reverse
    for (let integer_indices_0 = array_servers_rooted_sorted_by_score.length - 1; integer_indices_0 >= 0; --integer_indices_0) {
    const string_server_target = array_servers_rooted_sorted_by_score[integer_indices_0];
    if (ns.getHackingLevel() >= ns.getServerRequiredHackingLevel(string_server_target)) {
    return string_server_target;
    }
    }
    };
    const string_job_decider_prepare = function(ns, string_server_target, float_server_target_security, float_server_target_cash) {
    if (float_server_target_security > ns.getServerMinSecurityLevel(string_server_target)) {
    return "weaken";
    }
    if (float_server_target_cash < ns.getServerMaxMoney(string_server_target)) {
    return "grow";
    }
    return "";
    };
    const string_job_decider = function(ns, string_server_target, float_server_target_security, float_server_target_cash) {
    if (float_server_target_security > ns.getServerMinSecurityLevel(string_server_target)) {
    return "weaken";
    }
    else {
    if (float_server_target_cash < ns.getServerMaxMoney(string_server_target)) {
    return "grow";
    }
    else {
    return "hack";
    }
    }
    };
    const boolean_can_server_run_script_threads = function(ns, float_server_used_ram_free, float_script_ram, integer_threads) {
    if (float_script_ram * integer_threads > float_server_used_ram_free) {
    return false;
    }
    else {
    return true;
    }
    };
    // Returns time it takes to complete a hack on a server, in seconds. Adapted from `calculateHackingTime` in Hacking.js
    const float_get_time_hack = function(ns, string_server_target, float_server_target_security) {
    const object_constants = object_get_constants(ns);
    const difficultyMult = ns.getServerRequiredHackingLevel(string_server_target) * float_server_target_security;
    const baseDiff = 500;
    const baseSkill = 50;
    const diffFactor = 2.5;
    const intFactor = 0.1;
    const hack_stat = object_constants.object_stats.hacking;
    const int = object_constants.object_stats.intelligence;
    var skillFactor = (diffFactor * difficultyMult + baseDiff);
    // tslint:disable-next-line
    skillFactor /= (hack_stat + baseSkill + (intFactor * int));
    const hackTimeMultiplier = 5;
    const hackingTime = hackTimeMultiplier * skillFactor / object_constants.object_hacking_multipliers.speed;
    return hackingTime;
    };
    // Returns time it takes to complete a grow operation on a server, in seconds. Adapted from `calculateGrowTime` in Hacking.js
    const float_get_time_grow = function(ns, string_server_target, float_server_target_security) {
    const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
    return growTimeMultiplier * float_get_time_hack(ns, string_server_target, float_server_target_security);
    };
    // Returns time it takes to complete a weaken operation on a server, in seconds. Adapted from `calculateHackingTime` in Hacking.js
    const float_get_time_weaken = function(ns, string_server_target, float_server_target_security) {
    const weakenTimeMultiplier = 4; // Relative to hacking time
    return weakenTimeMultiplier * float_get_time_hack(ns, string_server_target, float_server_target_security);
    };
    // makes a schedule
    const array_make_schedule = function(ns, integer_job_cap, float_precision, float_steal_cap, float_padding_seconds, string_server_target, string_decider) {
    const array_workers = object_get_constants(ns).array_workers;
    const string_weaken = array_workers[0];
    const string_grow = array_workers[1];
    const string_hack = array_workers[2];
    const array_servers_rooted_sorted_by_ram = array_get_servers_rooted_sorted_by_ram(ns);
    const float_server_target_security_minimum = ns.getServerMinSecurityLevel(string_server_target);
    const float_server_target_cash_maximum = ns.getServerMaxMoney(string_server_target);
    const float_time_weaken = float_get_time_weaken(ns, string_server_target, ns.getServerSecurityLevel(string_server_target));
    const float_time_grow = float_get_time_grow(ns, string_server_target, ns.getServerSecurityLevel(string_server_target));
    const float_time_hack = float_get_time_hack(ns, string_server_target, ns.getServerSecurityLevel(string_server_target));
    // tripwires
    let boolean_end_loop_array_servers = false;
    let boolean_end_loop_server = false;
    let float_server_target_security_current = ns.getServerSecurityLevel(string_server_target);
    let float_server_target_cash_current = ns.getServerMoneyAvailable(string_server_target);
    let array_schedule = [];
    let integer_array_schedule_length = 0;
    let integer_time_job_finishes_seconds = Math.max(float_time_weaken, float_time_grow, float_time_hack);
    // iterate through servers in reverse to use servers with the biggest rams first
    for (let integer_indices_0 = array_servers_rooted_sorted_by_ram.length - 1; integer_indices_0 >= 0; --integer_indices_0) {
    if (integer_array_schedule_length >= integer_job_cap ||
    boolean_end_loop_array_servers) {
    break;
    }
    const string_server_used = array_servers_rooted_sorted_by_ram[integer_indices_0];
    let float_server_used_ram_free_current = float_get_server_ram_free(ns, string_server_used);
    while (
    float_server_used_ram_free_current > 0 &&
    integer_array_schedule_length < integer_job_cap &&
    !boolean_end_loop_array_servers &&
    !boolean_end_loop_server
    ) {
    const string_job = string_decider(ns, string_server_target, float_server_target_security_current, float_server_target_cash_current);
    const schedule_item = {
    string_job: string_job,
    string_server_used: string_server_used,
    string_server_target: string_server_target,
    float_server_target_security_before: float_server_target_security_current,
    float_server_target_cash_before: float_server_target_cash_current
    };
    switch (string_job) {
    case "": {
    boolean_end_loop_array_servers = true;
    break;
    }
    case "weaken": {
    if (!boolean_can_server_run_script_threads(ns, float_server_used_ram_free_current, ns.getScriptRam(string_weaken), 1)) {
    // start using a server with more ram
    boolean_end_loop_server = true;
    break;
    }
    const integer_threads_weaken = integer_get_threads_weaken(ns, float_server_used_ram_free_current, string_server_target, float_server_target_security_current);
    float_server_used_ram_free_current -= integer_threads_weaken * ns.getScriptRam(string_weaken);
    const float_server_target_security_uncorrected = float_server_target_security_current - float_get_security_decrease_from_weaken(ns, integer_threads_weaken);
    if (float_server_target_security_uncorrected < float_server_target_security_minimum) {
    float_server_target_security_current = float_server_target_security_minimum;
    }
    else {
    float_server_target_security_current = float_server_target_security_uncorrected;
    }
    schedule_item.float_server_target_security_current = float_server_target_security_current;
    schedule_item.float_delay_seconds = integer_time_job_finishes_seconds - float_time_weaken + float_padding_seconds;
    integer_time_job_finishes_seconds += float_padding_seconds;
    schedule_item.integer_time_job_finishes_seconds = integer_time_job_finishes_seconds;
    schedule_item.integer_threads = integer_threads_weaken;
    array_schedule.push(schedule_item);
    ++integer_array_schedule_length;
    break;
    }
    case "grow": {
    if (!boolean_can_server_run_script_threads(ns, float_server_used_ram_free_current, ns.getScriptRam(string_grow), 1)) {
    // start using a server with more ram
    boolean_end_loop_server = true;
    break;
    }
    if (float_server_target_cash_current === 0) {
    float_server_target_cash_current = 1; // counts 0 cash as 1 so it can still grow. taken from `grow` in NetscriptFunctions.js
    }
    const integer_threads_grow = integer_get_threads_grow(ns, float_server_used_ram_free_current, string_server_target, float_server_target_security_current, float_server_target_cash_current);
    float_server_used_ram_free_current -= integer_threads_grow * ns.getScriptRam(string_grow);
    const float_server_target_cash_current_uncorrected = float_server_target_cash_current * float_get_growth_from_threads(ns, string_server_target, float_server_target_security_current, integer_threads_grow);
    if (float_server_target_cash_current_uncorrected > float_server_target_cash_maximum) {
    float_server_target_cash_current = float_server_target_cash_maximum;
    }
    else {
    float_server_target_cash_current = float_server_target_cash_current_uncorrected;
    }
    // the following is adapted from `processSingleServerGrowth` in ServerHelpers.ts and `fortify` in Server.ts
    float_server_target_security_current += float_get_security_increase_from_grow(ns, integer_threads_grow);
    schedule_item.float_server_target_security_current = float_server_target_security_current;
    schedule_item.float_delay_seconds = integer_time_job_finishes_seconds - float_time_grow + float_padding_seconds;
    integer_time_job_finishes_seconds += float_padding_seconds;
    schedule_item.integer_time_job_finishes_seconds = integer_time_job_finishes_seconds;
    schedule_item.integer_threads = integer_threads_grow;
    array_schedule.push(schedule_item);
    ++integer_array_schedule_length;
    break;
    }
    case "hack": {
    if (!boolean_can_server_run_script_threads(ns, float_server_used_ram_free_current, ns.getScriptRam(string_hack), 1)) {
    // start using a server with more ram
    boolean_end_loop_server = true;
    break;
    }
    const integer_threads_hack = integer_get_threads_hack(ns, float_server_used_ram_free_current, string_server_target, float_server_target_security_current, float_get_percentage_to_steal(ns, float_server_used_ram_free_current, string_server_target, float_server_target_cash_current, float_server_target_security_current, float_precision, float_steal_cap));
    float_server_used_ram_free_current -= integer_threads_hack * ns.getScriptRam(string_hack);
    // the following is adapted from `hack` in NetscriptFunctions.js and `fortify` in Server.ts
    const float_server_target_cash_before = float_server_target_cash_current;
    const float_server_target_cash_current_uncorrected = float_server_target_cash_current - Math.floor(float_server_target_cash_current * float_get_percentage_of_cash_from_available_per_hack(ns, string_server_target, float_server_target_security_current)) * integer_threads_hack;
    if (float_server_target_cash_current_uncorrected < 0) {
    float_server_target_cash_current = 0;
    }
    else {
    float_server_target_cash_current = float_server_target_cash_current_uncorrected;
    }
    float_server_target_security_current += float_get_security_increase_from_hack(ns, string_server_target, float_server_target_security_current, float_server_target_cash_before, integer_threads_hack);
    schedule_item.float_server_target_security_current = float_server_target_security_current;
    schedule_item.float_delay_seconds = integer_time_job_finishes_seconds - float_time_hack + float_padding_seconds;
    integer_time_job_finishes_seconds += float_padding_seconds;
    schedule_item.integer_time_job_finishes_seconds = integer_time_job_finishes_seconds;
    schedule_item.integer_threads = integer_threads_hack;
    array_schedule.push(schedule_item);
    ++integer_array_schedule_length;
    break;
    }
    }
    }
    }
    // remove jobs near the end that cause security to not equal minimum. in other words, the target should have minimum security when the schedule finishes. this is to make the jobs in the next schedule run as quick as possible. TODO: make it so that we don't have to do this deleting step, instead, the array making steps above should already take into this into account and don't make more items than is needed.
    let array_schedule_edited = array_schedule;
    let boolean_have_not_seen_item_with_security_minimum = true;
    while (boolean_have_not_seen_item_with_security_minimum) {
    for (let integer_indices_1 = array_schedule_edited.length - 1; integer_indices_1 >= 0; --integer_indices_1) {
    if (!boolean_have_not_seen_item_with_security_minimum) {
    break;
    }
    const object_job = array_schedule_edited[integer_indices_1];
    if (object_job.float_server_target_security_current === float_server_target_security_minimum) {
    boolean_have_not_seen_item_with_security_minimum = false;
    break;
    }
    else {
    array_schedule_edited.splice(integer_indices_1, 1);
    }
    }
    }
    if (boolean_have_not_seen_item_with_security_minimum) {
    return array_schedule;
    }
    else {
    return array_schedule_edited;
    }
    };
    const void_schedule_runner = async function(ns, array_schedule) {
    const array_workers = object_get_constants(ns).array_workers;
    for (let integer_indices_0 = 0; integer_indices_0 < array_schedule.length; ++integer_indices_0) {
    const string_job = array_schedule[integer_indices_0].string_job;
    const string_server_used = array_schedule[integer_indices_0].string_server_used;
    const string_server_target = array_schedule[integer_indices_0].string_server_target;
    const integer_threads = array_schedule[integer_indices_0].integer_threads;
    const float_delay = array_schedule[integer_indices_0].float_delay_seconds * 1000;
    const identifier = integer_indices_0;
    let string_script = "";
    switch (string_job) {
    case "weaken": {
    string_script = array_workers[0];
    break;
    }
    case "grow": {
    string_script = array_workers[1];
    break;
    }
    case "hack": {
    string_script = array_workers[2];
    break;
    }
    }
    await ns.exec(string_script, string_server_used, integer_threads, string_server_used, string_server_target, float_delay, identifier);
    }
    };
    // returns the the time it'll take to finish in milliseconds.
    const void_runner = async function(ns, integer_job_cap, float_precision, float_steal_cap, float_padding_seconds, string_server_target_argument) {
    let integer_time_start = Date.now();
    let string_server_target = string_server_target_argument;
    if (string_server_target_argument === "") {
    string_server_target = string_get_server_rooted_hackable_with_score_biggest(ns);
    }
    // copy scripts to rooted servers
    void_copy_files_to_string_servers_rooted(ns, [object_get_constants(ns).array_workers], ns.getHostname());
    // prepare the target if necessary
    while (true) {
    if (
    ns.getServerSecurityLevel(string_server_target) === ns.getServerMinSecurityLevel(string_server_target) &&
    ns.getServerMoneyAvailable(string_server_target) === ns.getServerMaxMoney(string_server_target)
    ) {
    break;
    }
    const array_schedule_prepare = array_make_schedule(ns, integer_job_cap, float_precision, float_steal_cap, float_padding_seconds, string_server_target, string_job_decider_prepare);
    if (array_schedule_prepare.length > 0) {
    await void_schedule_runner(ns, array_schedule_prepare);
    await ns.sleep((array_schedule_prepare[array_schedule_prepare.length - 1].integer_time_job_finishes_seconds * 1000) - integer_time_start + Date.now());
    }
    }
    // make and run actual hacking schedule
    const array_schedule = array_make_schedule(ns, integer_job_cap, float_precision, float_steal_cap, float_padding_seconds, string_server_target, string_job_decider);
    await void_schedule_runner(ns, array_schedule);
    return (array_schedule[array_schedule.length - 1].integer_time_job_finishes_seconds * 1000) - integer_time_start + Date.now();
    };
  • edit in bin/cp.js at line 7
    [4.3803101]
    [4.3803101]
    import {
    array_get_files_to_copy
    }
    from "lib_ls.js";
  • edit in bin/cp.js at line 20
    [4.3803513][4.3803513:3804033]()
    }
    };
    // build array of files to copy from string_server_source
    const array_get_files_to_copy = function(ns, string_server_source, string_substring) {
    const array_files_in_server = ns.ls(string_server_source);
    let array_files_to_copy = [];
    for (let integer_indices_0 = 0; integer_indices_0 < array_files_in_server.length; ++integer_indices_0) {
    const string_file = array_files_in_server[integer_indices_0];
    if (string_file.includes(string_substring)) {
    array_files_to_copy.push(string_file);
    }
  • edit in bin/cp.js at line 21
    [4.3804037][4.3804037:3804067]()
    return array_files_to_copy;
  • replacement in README.md at line 10
    [4.3289][3.5627:5832]()
    ### "main.js" (8.85 GB)
    * Run the helper scripts "ram.js"\* (6.6 GB), "servers.js" (8.85 GB), "tor.js"\* (3.8 GB), "programs.js"\* (3.7 GB) and "botnet.js" (2.2 GB) that should attempt to, respectively:
    [4.3289]
    [3.5832]
    ### "main.js" (8.05 GB)
    * Copy all scripts to all rooted servers.
    * Run the helper scripts "ram.js"\* (6.6 GB), "servers.js" (8.85 GB), "tor.js"\* (3.8 GB), "programs.js"\* (3.7 GB) and "botnet.js" (2.2 GB) which should, respectively, attempt to:
  • replacement in README.md at line 18
    [3.6016][4.44800:45259](),[4.44800][4.44800:45259](),[4.1624][4.3487:3499](),[4.45259][4.3487:3499](),[4.3487][4.3487:3499](),[4.3499][3.6017:6071]()
    * Copy the "weaken.js", "grow.js" and "hack.js" worker scripts to other servers.
    * Make and execute a "preparation" schedule containing information about when, where and how many threads (among other information) the "weaken.js" and "grow.js" should be executed with.
    * Make and execute a "hacking" schedule containing information about when, where and how many threads (among other information) all three of the worker scripts should be executed with.
    * Repeat.
    * \* = SF-4 Required for this to properly function.
    [3.6016]
    [4.3315]
    * Kill itself by spawning "hacker.js" (8.05 GB) which should then:
    * Make and execute a "preparation" schedule containing information about when, where and how many threads (among other information) the "weaken.js" and "grow.js" worker scripts should be executed with.
    * Make and execute a "hacking" schedule containing information about when, where and how many threads (among other information) the "weaken.js", "grow.js" and "hack.js" worker scripts should be executed with.
    * Repeat.
    * \* = SF-4 Required for these to properly function.