diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 0000000..468a823 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,3 @@ +sonar.issue.ignore.multicriteria=e1 +sonar.issue.ignore.multicriteria.e1.ruleKey=javascript:S3504 +sonar.issue.ignore.multicriteria.e1.resourceKey=** diff --git a/app/index.js b/app/index.js index e8fd7ef..e69fafb 100644 --- a/app/index.js +++ b/app/index.js @@ -55,8 +55,10 @@ Router.add('/', function(render) { // test Router.add('/test', function(render) { + var test_profile_filepath = "data/test-oss-korea-2023.json"; + window.test_start = function(test_id) { - SHELL.show(["cscript", "app.js", "testloader", test_id]); + SHELL.show(["cscript", "app.js", "testloader", test_id, test_profile_filepath]); }; window.gui_check = function() { @@ -69,7 +71,7 @@ Router.add('/test', function(render) { alert("모든 메시지가 정상적으로 보였다면 테스트에 성공한 것입니다."); }; - var content = FILE.readFile("data/test-oss-20231030.json", FILE.CdoCharset.CdoUTF_8); + var content = FILE.readFile(test_profile_filepath, FILE.CdoCharset.CdoUTF_8); var data = JSON.parse(content); render("app/test.html", { "data": data @@ -100,7 +102,7 @@ Router.add('/notepad', function(render) { return $.summernote; }); - document.getElementById("useragent").innerHTML = window.navigator.userAgent; + document.getElementById("useragent").innerHTML = window.navigator.userAgent; }); // go diff --git a/build.bat b/build_native_libraries.bat similarity index 100% rename from build.bat rename to build_native_libraries.bat diff --git a/lib/adb.js b/lib/adb.js index 711d348..6c8845a 100644 --- a/lib/adb.js +++ b/lib/adb.js @@ -1,22 +1,22 @@ -//////////////////////////////////////////////////////////////////////// // Android Debug Bridge API -/////////////////////////////////////////////////////////////////////// - +// Namhyeon Go (Catswords Research) +// https://github.com/gnh1201/welsonjs var SHELL = require("lib/shell"); var SYS = require("lib/system"); // A common Android devices function ADBObject() { - this.binPath = "bin\\platform-tools_r33.0.0-windows\\platform-tools\\adb.exe"; + this._interface = SHELL.create(); this.setBinPath = function(binPath) { this.binPath = binPath; + this._interface.setPrefix(this.binPath); return this; }; this.getDevices = function() { var devices = []; - var result = SHELL.exec([this.binPath, "devices"]); + var result = this._interface.exec(["devices"]); splitLn(result).forEach(function(line) { var row = line.split(/\s+/); @@ -63,28 +63,32 @@ function ADBObject() { // download a file from target device this.pull = function(id, path) { - return SHELL.exec([this.binPath, "-s", id, "pull", path, "data\\"]); + return this._interface.exec(["-s", id, "pull", path, "data\\"]); }; // upload a file to target device this.push = function(id, filename, path) { - return SHELL.exec([this.binPath, "-s", id, "push", "data\\" + filename, path]); + return this._interface.exec(["-s", id, "push", "data\\" + filename, path]); }; // install APK file this.install = function(id, filename) { - return SHELL.exec([this.binPath, "-s", id, "install", "data\\" + filename]); + return this._interface.exec(["-s", id, "install", "data\\" + filename]); }; // Uninstall the App this.uninstall = function(id, appname) { - return SHELL.exec([this.binPath, "-s", id, "uninstall", appname]); + return this._interface.exec(["-s", id, "uninstall", appname]); }; // reboot device this.reboot = function(id) { - return SHELL.exec([this.binPath, "-s", id, "reboot"]); + return this._interface.exec(["-s", id, "reboot"]); }; + + // set the binary path + this.binPath = "bin\\platform-tools_r33.0.0-windows\\platform-tools\\adb.exe"; + this._interface.setPrefix(this.binPath); } // An Android Emulator @@ -125,7 +129,7 @@ exports.createEmulator = function(binPath) { return new EmulatorObject(binPath); }; -exports.VERSIONINFO = "Android Debug Bridge Interface (adb.js) version 0.2.1"; +exports.VERSIONINFO = "Android Debug Bridge Interface (adb.js) version 0.2.2"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/autoit.js b/lib/autoit.js index ef47feb..82122bf 100644 --- a/lib/autoit.js +++ b/lib/autoit.js @@ -1,13 +1,13 @@ -//////////////////////////////////////////////////////////////////////// -// AutoIt (AutoIt3, AutoItX) API -//////////////////////////////////////////////////////////////////////// - +// autoit.js +// AutoIt (AutoIt3, AutoItX) API interface for WelsonJS framework +// Namhyeon Go (Catswords Research) +// https://github.com/gnh1201/welsonjs function AutoItObject() { - this.interface = null; + this._interface = null; this.create = function() { try { - this.interface = CreateObject("AutoItX3.Control"); + this._interface = CreateObject("AutoItX3.Control"); } catch (e) { console.error("AutoIt_CreateObject() ->", e.message); } @@ -37,10 +37,10 @@ function AutoItObject() { this.callFunction = function(functionName, args) { console.log("Calling AutoItX function...", functionName); - if (this.interface != null) { + if (this._interface != null) { try { - //this.interface[functionName].apply(null, args); - eval("this.interface." + functionName + "(\"" + args.map(addslashes).join("\", \"") + "\")"); + //this._interface[functionName].apply(null, args); + eval("this._interface." + functionName + "(\"" + args.map(addslashes).join("\", \"") + "\")"); sleep(300); } catch (e) { console.error("AutoItObject.callFunction() ->", e.message); @@ -55,4 +55,8 @@ function AutoItObject() { exports.create = function() { return new AutoItObject(); -}; \ No newline at end of file +}; + +exports.VERSIONINFO = "AutoIt API interface version 0.1.3"; +exports.global = global; +exports.require = global.require; diff --git a/lib/chrome.js b/lib/chrome.js index f6848f8..f432183 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -1,6 +1,6 @@ // chrome.js +// Chrome Web Browser Debugging Interface for WelsonJS framework // Namhyeon Go -// This code is part of WelsonJS framework // https://github.com/gnh1201/welsonjs var STD = require("lib/std"); @@ -17,10 +17,9 @@ var ExtraMath = require("lib/extramath"); // for remote debugging var pageEventId = 0; -var ChromeObject = function(interfaces) { +var ChromeObject = function() { STD.EventTarget.apply(this, arguments); // Set event-attachable object - this.interfaces = (typeof interfaces !== "undefined" ? interfaces : []); this.vendor = "Chrome"; this.workingDirectory = SYS.getEnvString("PROGRAMFILES") + "\\Google\\:installedDir\\Application"; this.binPath = SYS.getEnvString("PROGRAMFILES") + "\\Google\\:installedDir\\Application\\chrome.exe"; @@ -1406,7 +1405,7 @@ exports.startDebugInPrivate = function(url, proxy, profileName, debuggingPort, i ; }; -exports.VERSIONINFO = "Chrome Web Browser Debugging Interface (chrome.js) version 0.4.8"; +exports.VERSIONINFO = "Chrome Web Browser Debugging Interface (chrome.js) version 0.4.9"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/http.js b/lib/http.js index c6f3112..0ad245b 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1,4 +1,5 @@ // http.js +// HTTP client module for WelsonJS framework // Namhyeon Go // https://github.com/gnh1201/welsonjs var SYS = require("lib/system"); @@ -16,7 +17,8 @@ var PROCESS_VERSION = SYS.getProcessVersion(); var DEFAULT_USER_AGENT = "WelsonJS/0.2.7 (" + OS_NAME + "; " + OS_ARCH + "; " + PROCESS_VERSION + "; " + DEVICE_UUID + "; abuse@catswords.net)"; var HTTPObject = function(engine) { - this.interface = null; + this._interface = null; + this.contentType = "application/x-www-form-urlencoded"; this.requestBody = ""; this.responseBody = null; @@ -36,7 +38,7 @@ var HTTPObject = function(engine) { this.engine = (typeof(engine) !== "undefined" ? engine : "MSXML"); this.cookie = null; - this.storedCookie = PipeIPC.create("volatile"); + this.storedCookie = PipeIPC.connect("volatile"); this.states = []; this.variables = { "uuidv4": RAND.uuidv4, @@ -78,7 +80,7 @@ var HTTPObject = function(engine) { this.create = function() { if (this.engine == "MSXML") { - this.interface = CreateObject([ + this._interface = typeof XMLHttpRequest !== "undefined" ? new XMLHttpRequest() : CreateObject([ "Microsoft.XMLHTTP", "WinHttp.WinHttpRequest.5.1", "Msxml3.XMLHTTP", @@ -96,9 +98,13 @@ var HTTPObject = function(engine) { "Msxml2.ServerXMLHTTP.3.0" ]); } else if (this.engine == "CURL") { - this.interface = SHELL.create(); - this.interface.setPrefix("bin\\curl"); // the location of cURL binary + this._interface = SHELL.create(); + this._interface.setPrefix("bin\\curl.exe"); // the location of cURL binary + } else if (this.engine == "BITS") { + this._interface = SHELL.create(); + this._interface.setPrefix("bitsadmin.exe"); // the location of BITS binary } + return this; }; @@ -152,11 +158,8 @@ var HTTPObject = function(engine) { }; this.setEngine = function(engine) { - if (typeof(engine) == "string") { - this.engine = engine.toUpperCase(); - } else { - this.engine = engine; - } + this.engine = String(engine).toUpperCase(); + this.create(); return this; }; @@ -233,7 +236,7 @@ var HTTPObject = function(engine) { this.getHeader = function(key) { try { - return this.interface.getResponseHeader(key); + return this._interface.getResponseHeader(key); } catch (e) { console.error("HTTPObject.getHeader() -> ", e.message); } @@ -241,7 +244,7 @@ var HTTPObject = function(engine) { this.getHeaders = function() { try { - var raw = this.interface.getAllResponseHeaders(); + var raw = this._interface.getAllResponseHeaders(); return raw.split(/[\r\n]+/).filter(function(s) { return s.trim().length > 0; @@ -372,11 +375,11 @@ var HTTPObject = function(engine) { // Open switch (this.method) { case "POST": - this.interface.open(method, url, this.isAsynchronous); + this._interface.open(method, url, this.isAsynchronous); break; case "GET": - this.interface.open(method, url, this.isAsynchronous); + this._interface.open(method, url, this.isAsynchronous); break; default: @@ -429,28 +432,28 @@ var HTTPObject = function(engine) { try { if (this.engine == "MSXML") { for (var key in this.headers) { - this.interface.setRequestHeader(key, this.evaluate(this.headers[key])); + this._interface.setRequestHeader(key, this.evaluate(this.headers[key])); } switch (this.method) { case "GET": - this.interface.send(); + this._interface.send(); break; default: - this.interface.send(this.serialize()); + this._interface.send(this.serialize()); } // Waiting a response - while (this.interface.readyState < 4) sleep(100); + while (this._interface.readyState < 4) sleep(100); // Get response text - responseText = this.interface.responseText; + responseText = this._interface.responseText; } else if (this.engine == "CURL") { if (this.states.length > 0) { // Make CURL context var state = this.states[this.states.length - 1]; - var cmd = []; + var cmd = ["bin\\curl"]; var url = state.url; if (this.isDebugging) { @@ -567,7 +570,7 @@ var HTTPObject = function(engine) { cmd.push(state.url); // Get response text - responseText = this.interface.setCharset(this.charset).exec(cmd); + responseText = this._interface.setCharset(this.charset).exec(cmd); // Reload a cookie in the pipe if (this.isLoggingCookie) { @@ -587,7 +590,26 @@ var HTTPObject = function(engine) { } // Get debuging text - debuggingText = this.interface.stderr.read(); + debuggingText = this._interface.stderr.read(); + } + } else if (this.engine == "BITS") { + var job_name = "welsonjs_" + PipeIPC.UUIDv4.create().substring(0, 8); + var job_priority = "normal"; + var state = this.states[this.states.length - 1]; + var cmd = ["/transfer", job_name]; + var url = state.url; + var out = PipeIPC.connect("volatile"); + + if (this.method == "GET") { + cmd = cmd.concat(["/download", "/priority", job_priority, url, SYS.getCurrentScriptDirectory() + "\\" + out.path]); // build a BITS command + this._interface.exec(cmd); // launch the download job + out.reload(); // read the downloaded data + responseText = out.read() // set the downloaded data to response text + + var err = this._interface.exec(["/geterror", job_name]); // get error information + debuggingText = err.stdout.read(); // set the error information to debugging text + + out.destroy(); // destroy the downloaded data } } @@ -1049,7 +1071,7 @@ exports.parseURL = parseURL; exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT; exports.defaultUserAgent = DEFAULT_USER_AGENT; // compatible with the specific case -exports.VERSIONINFO = "HTTP request module (http.js) version 0.7.19"; +exports.VERSIONINFO = "HTTP client module (http.js) version 0.7.22"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/pipe-ipc.js b/lib/pipe-ipc.js index 957d3d7..7fa50c8 100644 --- a/lib/pipe-ipc.js +++ b/lib/pipe-ipc.js @@ -1,6 +1,7 @@ // pipe-ipc.js +// Pipe based IPC implementation for WelsonJS framework +// Namhyeon Go (Catswords Research) // https://github.com/gnh1201/welsonjs - var STD = require("lib/std"); // https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/opentextfile-method @@ -437,7 +438,7 @@ function PipeIPC() { }; // Fixed bug: broken GUI sample #86, Reported by @eogloblin, in 2023-10-26 - // Reference #1: https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d + // https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d this._read = function(fh) { try { return (function(s) { diff --git a/lib/powershell.js b/lib/powershell.js index 5efafca..faf2052 100644 --- a/lib/powershell.js +++ b/lib/powershell.js @@ -1,10 +1,11 @@ -//////////////////////////////////////////////////////////////////////// // Powershell Interface API -/////////////////////////////////////////////////////////////////////// - +// Namhyeon Go (Catswords Research) +// https://github.com/gnh1201/welsonjs var SHELL = require("lib/shell"); var PowershellObject = function() { + var _interface = SHELL.create(); + this.execType = "ps1"; this.dataType = -1; this.target = null; @@ -75,7 +76,6 @@ var PowershellObject = function() { } var cmd = [ - "powershell.exe", "-NoProfile", "-ExecutionPolicy", "ByPass", @@ -117,12 +117,15 @@ var PowershellObject = function() { }; this.exec = function(args) { - return SHELL.exec(this.build(args)); + return _interface.exec(this.build(args)); }; this.runAs = function(args) { return this.exec("Start-Process cmd \"/q /c " + SHELL.addslashes(this.build(args)) + "\" -Verb RunAs"); }; + + // set the location of PowerShell runtime + _interface.setPrefix("powershell.exe"); } function create() { @@ -145,7 +148,7 @@ exports.execScript = execScript; exports.execCommand = execCommand; exports.runAs = runAs; -exports.VERSIONINFO = "Powershell Interface (powershell.js) version 0.1.3"; +exports.VERSIONINFO = "Powershell Interface (powershell.js) version 0.1.4"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/shell.js b/lib/shell.js index ec9e4db..bfb76aa 100644 --- a/lib/shell.js +++ b/lib/shell.js @@ -1,11 +1,11 @@ -//////////////////////////////////////////////////////////////////////// -// Shell API with PIPE-IPC -//////////////////////////////////////////////////////////////////////// +// Windows Shell Interface with WelsonJS Pipe-IPC module +// Namhyeon Go (Catswords Research) +// https://github.com/gnh1201/welsonjs var FILE = require("lib/file"); var PipeIPC = require("lib/pipe-ipc"); var ShellObject = function() { - this.interface = null; + this._interface = null; this.currentDirectory = null; this.workingDirectory = null; @@ -20,8 +20,8 @@ var ShellObject = function() { this.create = function() { try { - this.interface = CreateObject("WScript.Shell"); - this.currentDirectory = this.interface.CurrentDirectory; + this._interface = CreateObject("WScript.Shell"); + this.currentDirectory = this._interface.CurrentDirectory; this.workingDirectory = this.currentDirectory; } catch (e) { console.error("ShellObject.create() ->", e.message); @@ -31,6 +31,7 @@ var ShellObject = function() { this.setPrefix = function(prefix) { this.prefix = prefix; + return this; }; this.setCharset = function(charset) { @@ -41,7 +42,7 @@ var ShellObject = function() { this.setWorkingDirectory = function(dirname) { if (typeof(dirname) === "string") { this.workingDirectory = dirname; - this.interface.CurrentDirectory = this.workingDirectory; + this._interface.CurrentDirectory = this.workingDirectory; console.log("ShellObject.workingDirectory ->", this.workingDirectory); } return this; @@ -54,7 +55,7 @@ var ShellObject = function() { this.build = function(cmd) { var wrap = function(s) { - return this.target != null ? [this.target, s].join(' ') : s; + return this.prefix != null ? [this.prefix, s].join(' ') : s; }; if (typeof(cmd) === "string") { @@ -78,7 +79,7 @@ var ShellObject = function() { try { var c = this.build(cmd); console.log("ShellObject.createProcess() ->", c); - return this.interface.Exec(c); + return this._interface.Exec(c); } catch (e) { console.error("ShellObject.createProcess() ->", e.message); } @@ -101,7 +102,7 @@ var ShellObject = function() { var c = "%comspec% /c (" + this.build(cmd) + ") 1> " + this.stdout.path; //c += " 2>&1"; c += " 2> " + this.stderr.path; - this.interface.Run(c, 0, true); + this._interface.Run(c, 0, true); console.log("ShellObject.exec() ->", c); sleep(1); @@ -126,7 +127,7 @@ var ShellObject = function() { var fork = (typeof(fork) !== "undefined") ? fork : true; var c = "%comspec% /q /c (" + this.build(cmd) + ")"; console.log("ShellObject.run() ->", c); - this.interface.Run(c, (!this.isVisibleWindow ? 0 : 1), !fork); + this._interface.Run(c, (!this.isVisibleWindow ? 0 : 1), !fork); }; this.runAs = function(FN, args) { @@ -141,11 +142,11 @@ var ShellObject = function() { }; this.createShoutcut = function(shoutcutName, cmd) { - var desktopPath = this.interface.SpecialFolders("Desktop"); + var desktopPath = this._interface.SpecialFolders("Desktop"); var path = desktopPath + "\\" + shoutcutName + ".lnk"; if (!FILE.fileExists(path)) { - var link = this.interface.CreateShortcut(path); + var link = this._interface.CreateShortcut(path); //link.TargetPath = "cmd"; //link.Arguments = "/q /c " + this.build(cmd); link.TargetPath = "wscript"; @@ -160,13 +161,13 @@ var ShellObject = function() { }; this.getPathOfMyDocuments = function() { - return this.interface.SpecialFolders("MyDocuments"); + return this._interface.SpecialFolders("MyDocuments"); }; this.release = function() { console.log("ShellObject.release() ->", this.currentDirectory); - this.interface.CurrentDirectory = this.currentDirectory; - this.interface = null; + this._interface.CurrentDirectory = this.currentDirectory; + this._interface = null; }; this.create(); @@ -220,7 +221,7 @@ exports.getPathOfMyDocuments = function() { exports.CdoCharset = PipeIPC.CdoCharset; -exports.VERSIONINFO = "Shell interface (shell.js) version 0.3.9"; +exports.VERSIONINFO = "Windows Shell Interface (shell.js) version 0.3.12"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/toolkit.js b/lib/toolkit.js index d6f8f2c..8cdcd14 100644 --- a/lib/toolkit.js +++ b/lib/toolkit.js @@ -1,13 +1,14 @@ // toolkit.js +// WelsonJS native component interface for WelsonJS framework // Namhyeon Go // https://github.com/gnh1201/welsonjs function ToolkitObject() { - this.interface = null; + this._interface = null; this.create = function() { try { - this.interface = CreateObject("WelsonJS.Toolkit"); + this._interface = CreateObject("WelsonJS.Toolkit"); } catch (e) { console.info("WelsonJS.Toolkit not installed"); console.info("It could be download from https://github.com/gnh1201/welsonjs"); @@ -17,7 +18,7 @@ function ToolkitObject() { }; this.getInterface = function() { - return this.interface; + return this._interface; }; this.create(); @@ -114,7 +115,7 @@ exports.closeProcess = closeProcess; exports.encryptStringHIGHT = encryptStringHIGHT; exports.decryptStringHIGHT = decryptStringHIGHT; -exports.VERSIONINFO = "WelsonJS native component (WelsonJS.Toolkit) version 0.3.5"; +exports.VERSIONINFO = "WelsonJS native component interface (WelsonJS.Toolkit) version 0.3.6"; exports.AUTHOR = "abuse@catswords.net"; exports.global = global; exports.require = global.require; diff --git a/lib/wmi.js b/lib/wmi.js index 1f09847..d986465 100644 --- a/lib/wmi.js +++ b/lib/wmi.js @@ -1,24 +1,24 @@ -//////////////////////////////////////////////////////////////////////// -// WMI(Windows Management Instrumentation) API -//////////////////////////////////////////////////////////////////////// - +// wmi.js +// WMI(Windows Management Instrumentation) API interface for WelsonJS framework +// Namhyeon Go (Catswords Research) +// https://github.com/gnh1201/welsonjs var WMIQueryObject = function() { var wbemFlagReturnImmediately = 0x10; var wbemFlagForwardOnly = 0x20; this.computer = "."; this.namespace = "root\\cimv2"; - this.interface = null; + this._interface = null; this.cursor = {}; this.current = {}; this.create = function() { try { if (typeof(GetObject) === "function") { - this.interface = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\" + this.computer + "\\" + this.namespace); + this._interface = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\" + this.computer + "\\" + this.namespace); } else { var objLocator = CreateObject("WbemScripting.SWbemLocator"); - this.interface = objLocator.ConnectServer(this.computer, this.namespace); + this._interface = objLocator.ConnectServer(this.computer, this.namespace); } } catch (e) { console.error(e.message); @@ -38,7 +38,7 @@ var WMIQueryObject = function() { this.execQuery = function(query) { try { - var result = this.interface.ExecQuery(query, "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly); + var result = this._interface.ExecQuery(query, "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly); this.cursor = new Enumerator(result); } catch (e) { console.error(e.message); @@ -70,7 +70,7 @@ var WMIQueryObject = function() { }; var WMIClassObject = function() { - this.interface = (new WMIQueryObject()).interface; + this._interface = (new WMIQueryObject()).interface; this.classObject = null; this.className = ""; this.instance = null; @@ -82,7 +82,7 @@ var WMIClassObject = function() { // Instance this.setClass = function(className) { this.className = className; - this.classObject = this.interface.Get(className); + this.classObject = this._interface.Get(className); return this; }; diff --git a/start.bat b/start.bat deleted file mode 100644 index 8a9ee90..0000000 --- a/start.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -pushd "%~dp0" -cscript app.js bootstrap diff --git a/testloader.js b/testloader.js index 0f1578a..e9c0026 100644 --- a/testloader.js +++ b/testloader.js @@ -420,6 +420,13 @@ var test_implements = { console.log("응답 시간: " + SYS.ping("1.1.1.1") + "ms"); }, + "network_bitsadmin_test": function() { + var HTTP = require("lib/http"); + var bits = HTTP.create("BITS"); + var response = bits.open("GET", "https://httpbin.org/get").send().responseText; + console.log(response); + }, + "extramath_dtm": function() { var ExtraMath = require("lib/extramath"); @@ -991,7 +998,7 @@ var test_implements = { }; function main(args) { - // EXAMPLE: cscript app.js testloader + // EXAMPLE: cscript app.js testloader if (args.length > 0) { var test_id = args[0]; var profilefile = args[1];