From 3213032427d19e294b63bd59cafb02b244bf40f0 Mon Sep 17 00:00:00 2001 From: danielyxie Date: Mon, 2 Jul 2018 22:35:12 -0500 Subject: [PATCH] Fixed incompatibility issues with Edge (due to spread syntax). Fixed issue with Terminal autocomplete and capitalized commands. Script ram is now rounded to 2 decimal places --- dist/engine.bundle.js | 91 +++++++++++++++++++++++++++++++-------- src/ActiveScriptsUI.js | 4 +- src/Constants.js | 7 +-- src/NetscriptEvaluator.js | 2 +- src/NetscriptFunctions.js | 22 +++++++++- src/NetscriptWorker.js | 3 +- src/Script.js | 38 ++++++++++++++-- src/Terminal.js | 10 ++--- src/engine.js | 2 +- utils/HelperFunctions.js | 30 ++++++++++--- 10 files changed, 169 insertions(+), 40 deletions(-) diff --git a/dist/engine.bundle.js b/dist/engine.bundle.js index 1e9aef6a5..c66bbf021 100644 --- a/dist/engine.bundle.js +++ b/dist/engine.bundle.js @@ -2531,6 +2531,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compareArrays", function() { return compareArrays; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "printArray", function() { return printArray; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "powerOfTwo", function() { return powerOfTwo; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "roundToTwo", function() { return roundToTwo; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clearEventListenersEl", function() { return clearEventListenersEl; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeElementById", function() { return removeElementById; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeElement", function() { return removeElement; }); @@ -2791,6 +2792,11 @@ function powerOfTwo(n) { return n && (n & (n-1)) === 0; } +//Rounds a number to two decimal places +function roundToTwo(n) { + return +(Math.round(n + "e+2") + "e-2"); +} + function exceptionAlert(e) { Object(_DialogBox__WEBPACK_IMPORTED_MODULE_1__["dialogBoxCreate"])("Caught an exception: " + e + "

" + "Filename: " + e.fileName + "

" + @@ -3079,8 +3085,6 @@ let CONSTANTS = { ScriptBladeburnerApiBaseRamCost: 4, - MultithreadingRAMCost: 1, - NumNetscriptPorts: 20, //Server constants @@ -3487,6 +3491,7 @@ let CONSTANTS = { "v0.39.1
" + "* Bladeburner Rank gain in BN-7 is now reduced by 40% instead of 50%
" + "* Quadrupled the amount of money gained from Bladeburner contracts
" + + "* Added joinBladeburnerDivision() Netscript function to Bladeburner API
" + "* Doubled the effects of Source-File 5. Now gives 8%, 12%, and 14% increase to all hacking multipliers " + "at levels 1, 2, and 3, respectively (increased from 4%/6%, 7%)
" + "* Increased the effect of Source-File 8. It now gives a 12%, 18% and 21% to your hacking growth multiplier " + @@ -3498,7 +3503,9 @@ let CONSTANTS = { "* When an Infiltration is finished, you will now return back to the company's page, rather than the city
" + "* Infiltration faction reputation selector now remembers your last choice
" + "* Bug Fix: Copying a NetscriptJS script to another server using scp now properly takes into account " + - "the script's changes.
" + "the script's changes.
" + + "* Bug Fix: Fixed an issue where game would not load in Edge due to incompatible features
" + + "* travelToCity() Singularity function no longer grants Intelligence exp" } @@ -6800,7 +6807,7 @@ let Engine = { if (Engine.currentPage === Engine.Page.ActiveScripts) { Engine.Counters.updateActiveScriptsDisplay = 5; } else { - Engine.Counters.updateActiveScriptsDisplay = 15; + Engine.Counters.updateActiveScriptsDisplay = 10; } } @@ -8719,7 +8726,7 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1) var script = server.scripts[i]; var ramUsage = script.ramUsage; threads = Math.round(Number(threads)); //Convert to number and round - ramUsage = ramUsage * threads * Math.pow(_Constants__WEBPACK_IMPORTED_MODULE_1__["CONSTANTS"].MultithreadingRAMCost, threads-1); + ramUsage = ramUsage * threads; var ramAvailable = server.maxRam - server.ramUsed; if (server.hasAdminRights == false) { @@ -15769,8 +15776,7 @@ function addWorkerScript(runningScriptObj, server) { } else { runningScriptObj.threads = 1; } - var ramUsage = runningScriptObj.scriptRef.ramUsage * threads - * Math.pow(_Constants__WEBPACK_IMPORTED_MODULE_1__["CONSTANTS"].MultithreadingRAMCost, threads-1); + var ramUsage = runningScriptObj.scriptRef.ramUsage * threads; var ramAvailable = server.maxRam - server.ramUsed; if (ramUsage > ramAvailable) { Object(_utils_DialogBox__WEBPACK_IMPORTED_MODULE_10__["dialogBoxCreate"])("Not enough RAM to run script " + runningScriptObj.filename + " with args " + @@ -17681,9 +17687,9 @@ function tabCompletion(command, arg, allPossibilities, index=0) { if (!(allPossibilities.constructor === Array)) {return;} if (!Object(_utils_StringHelperFunctions__WEBPACK_IMPORTED_MODULE_20__["containsAllStrings"])(allPossibilities)) {return;} - if (!command.startsWith("./")) { - command = command.toLowerCase(); - } + //if (!command.startsWith("./")) { + //command = command.toLowerCase(); + //} //Remove all options in allPossibilities that do not match the current string //that we are attempting to autocomplete @@ -18582,7 +18588,7 @@ let Terminal = { for (var i = 0; i < currServ.scripts.length; ++i) { if (scriptName == currServ.scripts[i].filename) { var scriptBaseRamUsage = currServ.scripts[i].ramUsage; - var ramUsage = scriptBaseRamUsage * numThreads * Math.pow(_Constants__WEBPACK_IMPORTED_MODULE_1__["CONSTANTS"].MultithreadingRAMCost, numThreads-1); + var ramUsage = scriptBaseRamUsage * numThreads; post("This script requires " + Object(_utils_StringHelperFunctions__WEBPACK_IMPORTED_MODULE_20__["formatNumber"])(ramUsage, 2) + "GB of RAM to run for " + numThreads + " thread(s)"); return; @@ -19388,7 +19394,7 @@ let Terminal = { if (server.scripts[i].filename == scriptName) { //Check for admin rights and that there is enough RAM availble to run var script = server.scripts[i]; - var ramUsage = script.ramUsage * numThreads * Math.pow(_Constants__WEBPACK_IMPORTED_MODULE_1__["CONSTANTS"].MultithreadingRAMCost, numThreads-1); + var ramUsage = script.ramUsage * numThreads; var ramAvailable = server.maxRam - server.ramUsed; if (server.hasAdminRights == false) { @@ -25305,7 +25311,7 @@ Script.prototype.updateRamUsage = function() { var codeCopy = this.code.repeat(1); var res = calculateRamUsage(codeCopy); if (res !== -1) { - this.ramUsage = res; + this.ramUsage = Object(_utils_HelperFunctions__WEBPACK_IMPORTED_MODULE_15__["roundToTwo"])(res); } } @@ -25352,7 +25358,9 @@ function parseOnlyRamCalculate(server, code, workerScript) { } // Splice all the references in. - dependencyMap = {...dependencyMap, ...result.dependencyMap}; + //Spread syntax not supported in edge, use Object.assign instead + //dependencyMap = {...dependencyMap, ...result.dependencyMap}; + dependencyMap = Object.assign(dependencyMap, result.dependencyMap); } const initialModule = "__SPECIAL_INITIAL_MODULE__"; @@ -25513,6 +25521,8 @@ function parseOnlyCalculateDeps(code, currentModule) { } } + //Spread syntax not supported in Edge yet, use Object.assign + /* walk.recursive(ast, {key: globalKey}, { ImportDeclaration: (node, st, walkDeeper) => { const importModuleName = node.source.value; @@ -25540,6 +25550,33 @@ function parseOnlyCalculateDeps(code, currentModule) { }, ...commonVisitors() }); + */ + walk.recursive(ast, {key: globalKey}, Object.assign({ + ImportDeclaration: (node, st, walkDeeper) => { + const importModuleName = node.source.value; + additionalModules.push(importModuleName); + + // This module's global scope refers to that module's global scope, no matter how we + // import it. + dependencyMap[st.key].add(importModuleName + memCheckGlobalKey); + + for (let i = 0; i < node.specifiers.length; ++i) { + const spec = node.specifiers[i]; + if (spec.imported !== undefined && spec.local !== undefined) { + // We depend on specific things. + internalToExternal[spec.local.name] = importModuleName + "." + spec.imported.name; + } else { + // We depend on everything. + dependencyMap[st.key].add(importModuleName + ".*"); + } + } + }, + FunctionDeclaration: (node, st, walkDeeper) => { + // Don't use walkDeeper, because we are changing the visitor set. + const key = currentModule + "." + node.id.name; + walk.recursive(node, {key: key}, commonVisitors()); + }, + }, commonVisitors())); return {dependencyMap: dependencyMap, additionalModules: additionalModules}; } @@ -32963,7 +33000,6 @@ function NetscriptFunctions(workerScript) { } _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].loseMoney(_Constants__WEBPACK_IMPORTED_MODULE_6__["CONSTANTS"].TravelCost); _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].city = cityname; - _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].gainIntelligenceExp(_Constants__WEBPACK_IMPORTED_MODULE_6__["CONSTANTS"].IntelligenceSingFnBaseExpGain); if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.travelToCity == null) { workerScript.scriptRef.log("Traveled to " + cityname); } @@ -34161,6 +34197,27 @@ function NetscriptFunctions(workerScript) { throw Object(_NetscriptEvaluator__WEBPACK_IMPORTED_MODULE_25__["makeRuntimeRejectMsg"])(workerScript, "joinBladeburnerFaction() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " + "at the Bladeburner division or because you do not have Source-File 7"); }, + joinBladeburnerDivision : function() { + if (workerScript.checkingRam) { + return updateStaticRam("joinBladeburnerDivision", _Constants__WEBPACK_IMPORTED_MODULE_6__["CONSTANTS"].ScriptBladeburnerApiBaseRamCost); + } + updateDynamicRam("joinBladeburnerDivision", _Constants__WEBPACK_IMPORTED_MODULE_6__["CONSTANTS"].ScriptBladeburnerApiBaseRamCost); + if ((_Player__WEBPACK_IMPORTED_MODULE_16__["Player"].bitNodeN === 7 || hasBladeburner2079SF)) { + if (_Player__WEBPACK_IMPORTED_MODULE_16__["Player"].bladeburner instanceof _Bladeburner__WEBPACK_IMPORTED_MODULE_4__["Bladeburner"]) { + return true; //Already member + } else if (_Player__WEBPACK_IMPORTED_MODULE_16__["Player"].strength >= 100 && _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].defense >= 100 && + _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].dexterity >= 100 && _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].agility >= 100) { + _Player__WEBPACK_IMPORTED_MODULE_16__["Player"].bladeburner = new _Bladeburner__WEBPACK_IMPORTED_MODULE_4__["Bladeburner"]({new:true}); + workerScript.log("You have been accepted into the Bladeburner division"); + return true; + } else { + workerScript.log("You do not meet the requirements for joining the Bladeburner division"); + return false; + } + } + throw Object(_NetscriptEvaluator__WEBPACK_IMPORTED_MODULE_25__["makeRuntimeRejectMsg"])(workerScript, "joinBladeburnerDivision() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " + + "at the Bladeburner division or because you do not have Source-File 7"); + } } } //End return } //End NetscriptFunction() @@ -53603,9 +53660,9 @@ function deleteActiveScriptsItem(workerscript) { } //Update the ActiveScriptsItems array -function updateActiveScriptsItems(maxTasks=100) { +function updateActiveScriptsItems(maxTasks=150) { //Run tasks that need to be done sequentially (adding items, creating/deleting server panels) - //We'll limit this to 50 at a time in case someone decides to start a bunch of scripts all at once... + //We'll limit this to 150 at a time in case someone decides to start a bunch of scripts all at once... let numTasks = Math.min(maxTasks, ActiveScriptsTasks.length); for (let i = 0; i < numTasks; ++i) { let task = ActiveScriptsTasks.shift(); diff --git a/src/ActiveScriptsUI.js b/src/ActiveScriptsUI.js index f2e03e8ad..54b48dc0f 100644 --- a/src/ActiveScriptsUI.js +++ b/src/ActiveScriptsUI.js @@ -179,9 +179,9 @@ function deleteActiveScriptsItem(workerscript) { } //Update the ActiveScriptsItems array -function updateActiveScriptsItems(maxTasks=100) { +function updateActiveScriptsItems(maxTasks=150) { //Run tasks that need to be done sequentially (adding items, creating/deleting server panels) - //We'll limit this to 50 at a time in case someone decides to start a bunch of scripts all at once... + //We'll limit this to 150 at a time in case someone decides to start a bunch of scripts all at once... let numTasks = Math.min(maxTasks, ActiveScriptsTasks.length); for (let i = 0; i < numTasks; ++i) { let task = ActiveScriptsTasks.shift(); diff --git a/src/Constants.js b/src/Constants.js index 76d09a6a3..11ae10f07 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -84,8 +84,6 @@ let CONSTANTS = { ScriptBladeburnerApiBaseRamCost: 4, - MultithreadingRAMCost: 1, - NumNetscriptPorts: 20, //Server constants @@ -492,6 +490,7 @@ let CONSTANTS = { "v0.39.1
" + "* Bladeburner Rank gain in BN-7 is now reduced by 40% instead of 50%
" + "* Quadrupled the amount of money gained from Bladeburner contracts
" + + "* Added joinBladeburnerDivision() Netscript function to Bladeburner API
" + "* Doubled the effects of Source-File 5. Now gives 8%, 12%, and 14% increase to all hacking multipliers " + "at levels 1, 2, and 3, respectively (increased from 4%/6%, 7%)
" + "* Increased the effect of Source-File 8. It now gives a 12%, 18% and 21% to your hacking growth multiplier " + @@ -503,7 +502,9 @@ let CONSTANTS = { "* When an Infiltration is finished, you will now return back to the company's page, rather than the city
" + "* Infiltration faction reputation selector now remembers your last choice
" + "* Bug Fix: Copying a NetscriptJS script to another server using scp now properly takes into account " + - "the script's changes.
" + "the script's changes.
" + + "* Bug Fix: Fixed an issue where game would not load in Edge due to incompatible features
" + + "* travelToCity() Singularity function no longer grants Intelligence exp" } diff --git a/src/NetscriptEvaluator.js b/src/NetscriptEvaluator.js index 74521f242..08070dd1f 100644 --- a/src/NetscriptEvaluator.js +++ b/src/NetscriptEvaluator.js @@ -860,7 +860,7 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1) var script = server.scripts[i]; var ramUsage = script.ramUsage; threads = Math.round(Number(threads)); //Convert to number and round - ramUsage = ramUsage * threads * Math.pow(CONSTANTS.MultithreadingRAMCost, threads-1); + ramUsage = ramUsage * threads; var ramAvailable = server.maxRam - server.ramUsed; if (server.hasAdminRights == false) { diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 934062ee5..7994962c3 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -2264,7 +2264,6 @@ function NetscriptFunctions(workerScript) { } Player.loseMoney(CONSTANTS.TravelCost); Player.city = cityname; - Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.travelToCity == null) { workerScript.scriptRef.log("Traveled to " + cityname); } @@ -3462,6 +3461,27 @@ function NetscriptFunctions(workerScript) { throw makeRuntimeRejectMsg(workerScript, "joinBladeburnerFaction() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " + "at the Bladeburner division or because you do not have Source-File 7"); }, + joinBladeburnerDivision : function() { + if (workerScript.checkingRam) { + return updateStaticRam("joinBladeburnerDivision", CONSTANTS.ScriptBladeburnerApiBaseRamCost); + } + updateDynamicRam("joinBladeburnerDivision", CONSTANTS.ScriptBladeburnerApiBaseRamCost); + if ((Player.bitNodeN === 7 || hasBladeburner2079SF)) { + if (Player.bladeburner instanceof Bladeburner) { + return true; //Already member + } else if (Player.strength >= 100 && Player.defense >= 100 && + Player.dexterity >= 100 && Player.agility >= 100) { + Player.bladeburner = new Bladeburner({new:true}); + workerScript.log("You have been accepted into the Bladeburner division"); + return true; + } else { + workerScript.log("You do not meet the requirements for joining the Bladeburner division"); + return false; + } + } + throw makeRuntimeRejectMsg(workerScript, "joinBladeburnerDivision() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " + + "at the Bladeburner division or because you do not have Source-File 7"); + } } } //End return } //End NetscriptFunction() diff --git a/src/NetscriptWorker.js b/src/NetscriptWorker.js index c00a5c9b7..590992b54 100644 --- a/src/NetscriptWorker.js +++ b/src/NetscriptWorker.js @@ -292,8 +292,7 @@ function addWorkerScript(runningScriptObj, server) { } else { runningScriptObj.threads = 1; } - var ramUsage = runningScriptObj.scriptRef.ramUsage * threads - * Math.pow(CONSTANTS.MultithreadingRAMCost, threads-1); + var ramUsage = runningScriptObj.scriptRef.ramUsage * threads; var ramAvailable = server.maxRam - server.ramUsed; if (ramUsage > ramAvailable) { dialogBoxCreate("Not enough RAM to run script " + runningScriptObj.filename + " with args " + diff --git a/src/Script.js b/src/Script.js index e833cc3c9..bfae75a67 100644 --- a/src/Script.js +++ b/src/Script.js @@ -36,7 +36,8 @@ import {parse, Node} from "../utils/acorn"; import {dialogBoxCreate} from "../utils/DialogBox"; import {Reviver, Generic_toJSON, Generic_fromJSON} from "../utils/JSONReviver"; -import {compareArrays, createElement} from "../utils/HelperFunctions"; +import {compareArrays, createElement, + roundToTwo} from "../utils/HelperFunctions"; import {formatNumber, numOccurrences, numNetscriptOperators} from "../utils/StringHelperFunctions"; @@ -373,7 +374,7 @@ Script.prototype.updateRamUsage = function() { var codeCopy = this.code.repeat(1); var res = calculateRamUsage(codeCopy); if (res !== -1) { - this.ramUsage = res; + this.ramUsage = roundToTwo(res); } } @@ -420,7 +421,9 @@ function parseOnlyRamCalculate(server, code, workerScript) { } // Splice all the references in. - dependencyMap = {...dependencyMap, ...result.dependencyMap}; + //Spread syntax not supported in edge, use Object.assign instead + //dependencyMap = {...dependencyMap, ...result.dependencyMap}; + dependencyMap = Object.assign(dependencyMap, result.dependencyMap); } const initialModule = "__SPECIAL_INITIAL_MODULE__"; @@ -581,6 +584,8 @@ function parseOnlyCalculateDeps(code, currentModule) { } } + //Spread syntax not supported in Edge yet, use Object.assign + /* walk.recursive(ast, {key: globalKey}, { ImportDeclaration: (node, st, walkDeeper) => { const importModuleName = node.source.value; @@ -608,6 +613,33 @@ function parseOnlyCalculateDeps(code, currentModule) { }, ...commonVisitors() }); + */ + walk.recursive(ast, {key: globalKey}, Object.assign({ + ImportDeclaration: (node, st, walkDeeper) => { + const importModuleName = node.source.value; + additionalModules.push(importModuleName); + + // This module's global scope refers to that module's global scope, no matter how we + // import it. + dependencyMap[st.key].add(importModuleName + memCheckGlobalKey); + + for (let i = 0; i < node.specifiers.length; ++i) { + const spec = node.specifiers[i]; + if (spec.imported !== undefined && spec.local !== undefined) { + // We depend on specific things. + internalToExternal[spec.local.name] = importModuleName + "." + spec.imported.name; + } else { + // We depend on everything. + dependencyMap[st.key].add(importModuleName + ".*"); + } + } + }, + FunctionDeclaration: (node, st, walkDeeper) => { + // Don't use walkDeeper, because we are changing the visitor set. + const key = currentModule + "." + node.id.name; + walk.recursive(node, {key: key}, commonVisitors()); + }, + }, commonVisitors())); return {dependencyMap: dependencyMap, additionalModules: additionalModules}; } diff --git a/src/Terminal.js b/src/Terminal.js index 1fe175872..ccb2f9d35 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -314,9 +314,9 @@ function tabCompletion(command, arg, allPossibilities, index=0) { if (!(allPossibilities.constructor === Array)) {return;} if (!containsAllStrings(allPossibilities)) {return;} - if (!command.startsWith("./")) { - command = command.toLowerCase(); - } + //if (!command.startsWith("./")) { + //command = command.toLowerCase(); + //} //Remove all options in allPossibilities that do not match the current string //that we are attempting to autocomplete @@ -1215,7 +1215,7 @@ let Terminal = { for (var i = 0; i < currServ.scripts.length; ++i) { if (scriptName == currServ.scripts[i].filename) { var scriptBaseRamUsage = currServ.scripts[i].ramUsage; - var ramUsage = scriptBaseRamUsage * numThreads * Math.pow(CONSTANTS.MultithreadingRAMCost, numThreads-1); + var ramUsage = scriptBaseRamUsage * numThreads; post("This script requires " + formatNumber(ramUsage, 2) + "GB of RAM to run for " + numThreads + " thread(s)"); return; @@ -2021,7 +2021,7 @@ let Terminal = { if (server.scripts[i].filename == scriptName) { //Check for admin rights and that there is enough RAM availble to run var script = server.scripts[i]; - var ramUsage = script.ramUsage * numThreads * Math.pow(CONSTANTS.MultithreadingRAMCost, numThreads-1); + var ramUsage = script.ramUsage * numThreads; var ramAvailable = server.maxRam - server.ramUsed; if (server.hasAdminRights == false) { diff --git a/src/engine.js b/src/engine.js index 066184c87..f92ef8047 100644 --- a/src/engine.js +++ b/src/engine.js @@ -1044,7 +1044,7 @@ let Engine = { if (Engine.currentPage === Engine.Page.ActiveScripts) { Engine.Counters.updateActiveScriptsDisplay = 5; } else { - Engine.Counters.updateActiveScriptsDisplay = 15; + Engine.Counters.updateActiveScriptsDisplay = 10; } } diff --git a/utils/HelperFunctions.js b/utils/HelperFunctions.js index 6231cf78b..68ee19d12 100644 --- a/utils/HelperFunctions.js +++ b/utils/HelperFunctions.js @@ -243,6 +243,11 @@ function powerOfTwo(n) { return n && (n & (n-1)) === 0; } +//Rounds a number to two decimal places +function roundToTwo(n) { + return +(Math.round(n + "e+2") + "e-2"); +} + function exceptionAlert(e) { dialogBoxCreate("Caught an exception: " + e + "

" + "Filename: " + e.fileName + "

" + @@ -270,9 +275,24 @@ function createProgressBarText(params={}) { return "[" + Array(numTicks+1).join("|") + Array(numDashes+1).join("-") + "]"; } -export {sizeOfObject, clearObject, addOffset, clearEventListeners, getRandomInt, - compareArrays, printArray, powerOfTwo, clearEventListenersEl, - removeElementById, removeElement, createElement, createAccordionElement, +export {sizeOfObject, + clearObject, + addOffset, + clearEventListeners, + getRandomInt, + compareArrays, + printArray, + powerOfTwo, + roundToTwo, + clearEventListenersEl, + removeElementById, + removeElement, + createElement, + createAccordionElement, appendLineBreaks, - removeChildrenFromElement, createPopup, clearSelector, exceptionAlert, - createProgressBarText, getElementById}; + removeChildrenFromElement, + createPopup, + clearSelector, + exceptionAlert, + createProgressBarText, + getElementById};