diff --git a/gulpfile.js b/gulpfile.js index 0b3487a896..87b678f008 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -74,6 +74,11 @@ * copyright * * Updates the copyright year in all project files to match the year contained in package.json. + * + * Options + * + * --rebuild will force the "compile" task to recompile the code for any or all the machines, even if the + * compiled code is up-to-date. */ "use strict"; @@ -84,14 +89,17 @@ var gulpConcat = require("gulp-concat"); var gulpForEach = require("gulp-foreach"); var gulpHeader = require("gulp-header"); var gulpReplace = require("gulp-replace"); -var gulpClosureCompiler = require('google-closure-compiler-js').gulp(); +var gulpClosureCompiler = require('google-closure-compiler').gulp(); var gulpSourceMaps = require('gulp-sourcemaps'); -var merge = require('merge-stream'); var fs = require("fs"); var path = require("path"); var pkg = require("./package.json"); +var proc = require("./modules/shared/lib/proclib.js"); +var args = proc.getArgs(); +var argv = args.argv; + /** * @typedef {Object} MachineConfig * @property {string} name @@ -112,27 +120,11 @@ var pkg = require("./package.json"); * @type {Object.} */ var machines = require("./_data/machines.json"); - -var sExterns = ""; - -for (let i = 0; i < machines.shared.externs.length; i++) { - let sContents = ""; - try { - sContents = fs.readFileSync(machines.shared.externs[i], "utf8"); - } catch(err) { - console.log(err.message); - } - if (sContents) { - if (sExterns) sExterns += '\n'; - sExterns += sContents; - } -} - -var sSiteHost = "https://www.pcjs.org"; +var siteHost = "https://www.pcjs.org"; if (pkg.homepage) { let match = pkg.homepage.match(/^(https?:\/\/[^/]*)(.*)/); - if (match) sSiteHost = match[1]; + if (match) siteHost = match[1]; } var aMachines = Object.keys(machines); @@ -152,34 +144,35 @@ aMachines.forEach(function(machineType) { machineConfig = machines[machineConfig.alias]; } + let machineDefines = []; let machineVersion = machineConfig.version || machines.shared.version; let machineReleaseDir = "./versions/" + machineConfig['folder'] + "/" + machineVersion; let machineReleaseFile = machineType + ".js"; let machineUncompiledFile = machineType + "-uncompiled.js"; - let machineDefines = {}; if (machineConfig.defines) { for (let i = 0; i < machineConfig.defines.length; i++) { - let define = machineConfig.defines[i]; + let define = machineConfig.defines[i], value = undefined; switch(define) { case "APPVERSION": case "VERSION": - machineDefines[define] = machineVersion; + value = machineVersion; break; case "SITEURL": - machineDefines[define] = sSiteHost; + value = siteHost; break; case "BACKTRACK": case "DEBUG": - machineDefines[define] = false; + value = false; break; case "COMPILED": case "DEBUGGER": case "I386": default: - machineDefines[define] = true; + value = true; break; } + machineDefines.push(define + '=' + value); } } @@ -204,7 +197,7 @@ aMachines.forEach(function(machineType) { let dstStat = fs.statSync(dstFile); let srcTime = new Date(srcStat.mtime); let dstTime = new Date(dstStat.mtime); - if (dstTime < srcTime) aMachinesOutdated.push(machineType); + if (dstTime < srcTime || argv['rebuild']) aMachinesOutdated.push(machineType); } catch(err) { // console.log(err.message); } @@ -224,7 +217,7 @@ aMachines.forEach(function(machineType) { .pipe(gulpReplace(/^[ \t]*(if\s+\(NODE\)\s*|)module\.exports\s*=\s*[^;]*;/gm, "")) .pipe(gulpReplace(/\/\*\*\s*\*\s*@fileoverview[\s\S]*?\*\/\s*/g, "")) .pipe(gulpReplace(/[ \t]*if\s*\(NODE\)\s*({[^}]*}|[^\n]*)(\n|$)/gm, "")) - .pipe(gulpReplace(/[ \t]*if\s*\(typeof\s+module\s*!==\s*(['"])undefined\1\)\s*({[^}]*}|[^\n]*)(\n|$)/gm, "")) + .pipe(gulpReplace(/[ \t]*if\s*\(typeof\s+module\s*!==?\s*(['"])undefined\1\)\s*({[^}]*}|[^\n]*)(\n|$)/gm, "")) .pipe(gulpReplace(/\/\*\*[^@]*@typedef\s*{([A-Z][A-Za-z0-9_<>.]+)}\s*(\S+)\s*([\s\S]*?)\*\//g, function(match, def, type, props) { let sType = "/** @typedef {", sProps = ""; let reProps = /@property\s*{([^}]*)}\s*(\[|)([^\s\]]+)]?/g, matchProps; @@ -254,16 +247,16 @@ aMachines.forEach(function(machineType) { if (aMachinesOutdated.indexOf(machineType) >= 0) { stream.pipe(gulpSourceMaps.init()) .pipe(gulpClosureCompiler({ - assumeFunctionWrapper: true, - compilationLevel: 'ADVANCED', - defines: machineDefines, - externs: [{src: sExterns}], - warningLevel: 'VERBOSE', - languageIn: "ES6", // this is now the default, just documenting our requirements - languageOut: "ES5", // this is also the default - outputWrapper: '(function(){%output%})()', - jsOutputFile: machineReleaseFile, // NOTE: if we go back to doing debugger/non-debugger releases, this must be updated - createSourceMap: true + assume_function_wrapper: true, + compilation_level: 'ADVANCED', + define: machineDefines, + externs: machines.shared.externs, + warning_level: 'VERBOSE', + language_in: 'ES6', // this is now the default, just documenting our requirements + language_out: 'ES5', // this is also the default + output_wrapper: '(function(){%output%})()', + js_output_file: machineReleaseFile, // NOTE: if we go back to doing debugger/non-debugger releases, this must be updated + create_source_map: true })) .pipe(gulpSourceMaps.write('./')) // gulp-sourcemaps automatically adds the sourcemap url comment .pipe(gulp.dest(machineReleaseDir)); diff --git a/modules/c1pjs/lib/computer.js b/modules/c1pjs/lib/computer.js index 73193e7abe..6c38b1a466 100644 --- a/modules/c1pjs/lib/computer.js +++ b/modules/c1pjs/lib/computer.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); } diff --git a/modules/c1pjs/lib/cpu.js b/modules/c1pjs/lib/cpu.js index 400fb3b967..4f26a0f0da 100644 --- a/modules/c1pjs/lib/cpu.js +++ b/modules/c1pjs/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); diff --git a/modules/c1pjs/lib/debugger.js b/modules/c1pjs/lib/debugger.js index 5ba27f525d..430f4a26ce 100644 --- a/modules/c1pjs/lib/debugger.js +++ b/modules/c1pjs/lib/debugger.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); diff --git a/modules/c1pjs/lib/disk.js b/modules/c1pjs/lib/disk.js index 7f87c98044..d15d538675 100644 --- a/modules/c1pjs/lib/disk.js +++ b/modules/c1pjs/lib/disk.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); diff --git a/modules/c1pjs/lib/keyboard.js b/modules/c1pjs/lib/keyboard.js index c6fdf2169f..6ab7a6af26 100644 --- a/modules/c1pjs/lib/keyboard.js +++ b/modules/c1pjs/lib/keyboard.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); diff --git a/modules/c1pjs/lib/panel.js b/modules/c1pjs/lib/panel.js index 2be91bba9c..a83250cb0a 100644 --- a/modules/c1pjs/lib/panel.js +++ b/modules/c1pjs/lib/panel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); } diff --git a/modules/c1pjs/lib/ram.js b/modules/c1pjs/lib/ram.js index 4bd4ba12c3..4b0564a1c7 100644 --- a/modules/c1pjs/lib/ram.js +++ b/modules/c1pjs/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); } diff --git a/modules/c1pjs/lib/rom.js b/modules/c1pjs/lib/rom.js index 3d80762ede..6cff144453 100644 --- a/modules/c1pjs/lib/rom.js +++ b/modules/c1pjs/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); diff --git a/modules/c1pjs/lib/serial.js b/modules/c1pjs/lib/serial.js index d3342f3855..7cb0ac3149 100644 --- a/modules/c1pjs/lib/serial.js +++ b/modules/c1pjs/lib/serial.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); diff --git a/modules/c1pjs/lib/video.js b/modules/c1pjs/lib/video.js index 96ec631ec1..cab4469321 100644 --- a/modules/c1pjs/lib/video.js +++ b/modules/c1pjs/lib/video.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); } diff --git a/modules/diskdump/lib/diskdump.js b/modules/diskdump/lib/diskdump.js index e61bca5b37..1d7061a1a0 100644 --- a/modules/diskdump/lib/diskdump.js +++ b/modules/diskdump/lib/diskdump.js @@ -33,6 +33,7 @@ "use strict"; if (typeof module != "undefined") { // we can't simply test for NODE, since defines.js hasn't been loaded yet + var NODE = true; var fs = require("fs"); var path = require("path"); var glob = require("glob"); diff --git a/modules/htmlout/lib/htmlout.js b/modules/htmlout/lib/htmlout.js index 8024074444..7bd58034eb 100644 --- a/modules/htmlout/lib/htmlout.js +++ b/modules/htmlout/lib/htmlout.js @@ -227,9 +227,9 @@ var asFilesNonServed = [ ]; /* - * Maximum blog entries increased from 20 to 100 for the new blog format. + * Maximum blog entries increased from 20 to 200 for the new blog format. */ -var nBlogExcerpts = 100; +var nBlogExcerpts = 200; /** * HTMLOut() @@ -488,6 +488,7 @@ HTMLOut.filter = function(req, res, next) sData = sData.replace(/^([ \t]*export\s+default\s+\S+;)/gm, "// $1"); sData = sData.replace(/^([ \t]*var\s+\S+\s*=\s*require\(['"].*?['"]\)[^;]*;)/gm, "// $1"); sData = sData.replace(/^([ \t]*(if\s+\(NODE\)\s*|)module\.exports\s*=\s*[^;]*;)/gm, "// $1"); + sData = sData.replace(/^([ \t]*(if\s+\(typeof\s+module\s*!==?\s*['"]undefined['"]\)\s*|)module\.exports\s*=\s*[^;]*;)/gm, "// $1"); res.set("Content-Type", "application/javascript"); res.status(200).send(sData); } diff --git a/modules/pc6502/lib/bus.js b/modules/pc6502/lib/bus.js index 5ffa480f28..a1ed05f8f1 100644 --- a/modules/pc6502/lib/bus.js +++ b/modules/pc6502/lib/bus.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -714,4 +714,4 @@ Bus.prototype.reportError = function(op, addr, size, fQuiet) return false; }; -if (NODE) module.exports = Bus; +if (typeof module !== "undefined") module.exports = Bus; diff --git a/modules/pc6502/lib/computer.js b/modules/pc6502/lib/computer.js index 3f292ae645..c1834a8c81 100644 --- a/modules/pc6502/lib/computer.js +++ b/modules/pc6502/lib/computer.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var usr = require("../../shared/lib/usrlib"); var web = require("../../shared/lib/weblib"); @@ -1630,4 +1630,4 @@ web.onInit(Computer.init); web.onShow(Computer.show); web.onExit(Computer.exit); -if (NODE) module.exports = Computer; +if (typeof module !== "undefined") module.exports = Computer; diff --git a/modules/pc6502/lib/cpu.js b/modules/pc6502/lib/cpu.js index 379c335d06..80fef9d471 100644 --- a/modules/pc6502/lib/cpu.js +++ b/modules/pc6502/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -1121,4 +1121,4 @@ CPU.prototype.yieldCPU = function() this.updateCPU(); }; -if (NODE) module.exports = CPU; +if (typeof module !== "undefined") module.exports = CPU; diff --git a/modules/pc6502/lib/cpudef.js b/modules/pc6502/lib/cpudef.js index b45e172431..5015fa850d 100644 --- a/modules/pc6502/lib/cpudef.js +++ b/modules/pc6502/lib/cpudef.js @@ -85,4 +85,4 @@ var CPUDef = { } }; -if (NODE) module.exports = CPUDef; +if (typeof module !== "undefined") module.exports = CPUDef; diff --git a/modules/pc6502/lib/cpuops.js b/modules/pc6502/lib/cpuops.js index 485e5d49d5..6aecf1c946 100644 --- a/modules/pc6502/lib/cpuops.js +++ b/modules/pc6502/lib/cpuops.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var Messages = require("./messages"); var CPUDef = require("./CPUDef"); diff --git a/modules/pc6502/lib/cpustate.js b/modules/pc6502/lib/cpustate.js index 1681123cce..c648329bfd 100644 --- a/modules/pc6502/lib/cpustate.js +++ b/modules/pc6502/lib/cpustate.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1427,4 +1427,4 @@ CPUState.init = function() */ web.onInit(CPUState.init); -if (NODE) module.exports = CPUState; +if (typeof module !== "undefined") module.exports = CPUState; diff --git a/modules/pc6502/lib/debugger.js b/modules/pc6502/lib/debugger.js index a4c7fbabda..72deb5e893 100644 --- a/modules/pc6502/lib/debugger.js +++ b/modules/pc6502/lib/debugger.js @@ -29,7 +29,7 @@ "use strict"; if (DEBUGGER) { - if (NODE) { + if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var usr = require("../../shared/lib/usrlib"); var web = require("../../shared/lib/weblib"); @@ -4371,4 +4371,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = Debugger; +if (typeof module !== "undefined") module.exports = Debugger; diff --git a/modules/pc6502/lib/defines.js b/modules/pc6502/lib/defines.js index d9a00eb134..fe3dd50434 100644 --- a/modules/pc6502/lib/defines.js +++ b/modules/pc6502/lib/defines.js @@ -91,7 +91,7 @@ var PC6502 = { XMLVERSION: XMLVERSION // shared }; -if (NODE) { +if (typeof module !== "undefined") { global.APPCLASS = APPCLASS; global.DEBUGGER = DEBUGGER; global.BYTEARRAYS = BYTEARRAYS; diff --git a/modules/pc6502/lib/keyboard.js b/modules/pc6502/lib/keyboard.js index c40703093d..cd1fb7bc58 100644 --- a/modules/pc6502/lib/keyboard.js +++ b/modules/pc6502/lib/keyboard.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -78,4 +78,4 @@ Keyboard.init = function() */ web.onInit(Keyboard.init); -if (NODE) module.exports = Keyboard; +if (typeof module !== "undefined") module.exports = Keyboard; diff --git a/modules/pc6502/lib/memory.js b/modules/pc6502/lib/memory.js index bdd540922a..c697d75722 100644 --- a/modules/pc6502/lib/memory.js +++ b/modules/pc6502/lib/memory.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var Messages = require("./messages"); @@ -845,4 +845,4 @@ if (TYPEDARRAYS) { ]; } -if (NODE) module.exports = Memory; +if (typeof module !== "undefined") module.exports = Memory; diff --git a/modules/pc6502/lib/messages.js b/modules/pc6502/lib/messages.js index 35059e95a8..ef4cf875ef 100644 --- a/modules/pc6502/lib/messages.js +++ b/modules/pc6502/lib/messages.js @@ -47,4 +47,4 @@ var Messages = { HALT: 0x80000000|0 }; -if (NODE) module.exports = Messages; +if (typeof module !== "undefined") module.exports = Messages; diff --git a/modules/pc6502/lib/panel.js b/modules/pc6502/lib/panel.js index 86eb9d7e9c..a43470196c 100644 --- a/modules/pc6502/lib/panel.js +++ b/modules/pc6502/lib/panel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var usr = require("../../shared/lib/usrlib"); var web = require("../../shared/lib/weblib"); @@ -178,4 +178,4 @@ Panel.init = function() */ web.onInit(Panel.init); -if (NODE) module.exports = Panel; +if (typeof module !== "undefined") module.exports = Panel; diff --git a/modules/pc6502/lib/ram.js b/modules/pc6502/lib/ram.js index 1a97573bea..a3f2e75679 100644 --- a/modules/pc6502/lib/ram.js +++ b/modules/pc6502/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -190,4 +190,4 @@ RAM.init = function() */ web.onInit(RAM.init); -if (NODE) module.exports = RAM; +if (typeof module !== "undefined") module.exports = RAM; diff --git a/modules/pc6502/lib/rom.js b/modules/pc6502/lib/rom.js index 424f868c76..4b6008e630 100644 --- a/modules/pc6502/lib/rom.js +++ b/modules/pc6502/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -385,4 +385,4 @@ ROM.init = function() */ web.onInit(ROM.init); -if (NODE) module.exports = ROM; +if (typeof module !== "undefined") module.exports = ROM; diff --git a/modules/pc6502/lib/state.js b/modules/pc6502/lib/state.js index 0e938da7af..54319c89c6 100644 --- a/modules/pc6502/lib/state.js +++ b/modules/pc6502/lib/state.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var web = require("./../../shared/lib/weblib"); var Component = require("./../../shared/lib/component"); var Messages = require("./messages"); @@ -390,4 +390,4 @@ State.prototype = { } }; -if (NODE) module.exports = State; +if (typeof module !== "undefined") module.exports = State; diff --git a/modules/pc6502/lib/video.js b/modules/pc6502/lib/video.js index 0820d4bfbc..5fff91ecb8 100644 --- a/modules/pc6502/lib/video.js +++ b/modules/pc6502/lib/video.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -712,4 +712,4 @@ Video.init = function() */ web.onInit(Video.init); -if (NODE) module.exports = Video; +if (typeof module !== "undefined") module.exports = Video; diff --git a/modules/pc8080/lib/bus.js b/modules/pc8080/lib/bus.js index b4fff6890a..d5af7efe15 100644 --- a/modules/pc8080/lib/bus.js +++ b/modules/pc8080/lib/bus.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -1061,4 +1061,4 @@ Bus8080.BlockInfo = Usr.defineBitFields({num:20, count:8, btmod:1, type:3}); */ var BusInfo8080; -if (NODE) module.exports = Bus8080; +if (typeof module !== "undefined") module.exports = Bus8080; diff --git a/modules/pc8080/lib/chipset.js b/modules/pc8080/lib/chipset.js index 3f20608e8c..5029d1f408 100644 --- a/modules/pc8080/lib/chipset.js +++ b/modules/pc8080/lib/chipset.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -1137,4 +1137,4 @@ ChipSet8080.VT100.portsOutput = { */ Web.onInit(ChipSet8080.init); -if (NODE) module.exports = ChipSet8080; +if (typeof module !== "undefined") module.exports = ChipSet8080; diff --git a/modules/pc8080/lib/computer.js b/modules/pc8080/lib/computer.js index fcdb018807..7012961db7 100644 --- a/modules/pc8080/lib/computer.js +++ b/modules/pc8080/lib/computer.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -234,8 +234,12 @@ class Computer8080 extends Component { * OVERRIDES everything; it overrides any 'state' Computer parameter AND it disables resume of any saved state in * localStorage (in other words, it prevents fAllowResume from being true, and forcing resume off). */ - var fAllowResume; - var sState = this.getMachineParm('state') || (fAllowResume = true) && parmsComputer['state']; + var fAllowResume = false; + var sState = this.getMachineParm('state'); + if (!sState) { + fAllowResume = true; + sState = parmsComputer['state']; + } if (sState) { sStatePath = this.sStatePath = sState; @@ -266,7 +270,7 @@ class Computer8080 extends Component { this.setReady(); } else { var cmp = this; - Web.getResource(sStatePath, null, true, function(sURL, sResource, nErrorCode) { + Web.getResource(/** @type {string} */ (sStatePath), null, true, function(sURL, sResource, nErrorCode) { cmp.doneLoad(sURL, sResource, nErrorCode); }); } @@ -1669,4 +1673,4 @@ Web.onInit(Computer8080.init); Web.onShow(Computer8080.show); Web.onExit(Computer8080.exit); -if (NODE) module.exports = Computer8080; +if (typeof module !== "undefined") module.exports = Computer8080; diff --git a/modules/pc8080/lib/cpu.js b/modules/pc8080/lib/cpu.js index 115e08d560..17d2f32396 100644 --- a/modules/pc8080/lib/cpu.js +++ b/modules/pc8080/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var Messages8080 = require("./messages"); @@ -1280,4 +1280,4 @@ CPU8080.YIELDS_PER_STATUS = 15; // every 15 yields (ie, twice pe CPU8080.BUTTONS = ["power", "reset"]; -if (NODE) module.exports = CPU8080; +if (typeof module !== "undefined") module.exports = CPU8080; diff --git a/modules/pc8080/lib/cpudef.js b/modules/pc8080/lib/cpudef.js index 8019ae6f96..3150abb4ae 100644 --- a/modules/pc8080/lib/cpudef.js +++ b/modules/pc8080/lib/cpudef.js @@ -124,4 +124,4 @@ CPUDef8080.PS.RESULT = (CPUDef8080.PS.CF | CPUDef8080.PS.PF | CPUDef8080.PS */ CPUDef8080.PS.SET = (CPUDef8080.PS.BIT1); -if (NODE) module.exports = CPUDef8080; +if (typeof module !== "undefined") module.exports = CPUDef8080; diff --git a/modules/pc8080/lib/cpuops.js b/modules/pc8080/lib/cpuops.js index 46bd40ef3b..e151c33bf5 100644 --- a/modules/pc8080/lib/cpuops.js +++ b/modules/pc8080/lib/cpuops.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var CPUDef8080 = require("./CPUDef"); var Messages8080 = require("./messages"); } diff --git a/modules/pc8080/lib/cpustate.js b/modules/pc8080/lib/cpustate.js index b44c2ab3bd..35c422e478 100644 --- a/modules/pc8080/lib/cpustate.js +++ b/modules/pc8080/lib/cpustate.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); var State = require("../../shared/lib/state"); @@ -1176,4 +1176,4 @@ class CPUState8080 extends CPU8080 { */ Web.onInit(CPUState8080.init); -if (NODE) module.exports = CPUState8080; +if (typeof module !== "undefined") module.exports = CPUState8080; diff --git a/modules/pc8080/lib/debugger.js b/modules/pc8080/lib/debugger.js index 2616f9c3cd..005f8bc701 100644 --- a/modules/pc8080/lib/debugger.js +++ b/modules/pc8080/lib/debugger.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -4364,4 +4364,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = Debugger8080; +if (typeof module !== "undefined") module.exports = Debugger8080; diff --git a/modules/pc8080/lib/defines.js b/modules/pc8080/lib/defines.js index b9fa3c153a..09960a5196 100644 --- a/modules/pc8080/lib/defines.js +++ b/modules/pc8080/lib/defines.js @@ -91,7 +91,7 @@ var PC8080 = { XMLVERSION: XMLVERSION // shared }; -if (NODE) { +if (typeof module !== "undefined") { global.APPCLASS = APPCLASS; global.APPNAME = APPNAME; global.DEBUGGER = DEBUGGER; diff --git a/modules/pc8080/lib/keyboard.js b/modules/pc8080/lib/keyboard.js index f164a43126..9ada3d2cb6 100644 --- a/modules/pc8080/lib/keyboard.js +++ b/modules/pc8080/lib/keyboard.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1467,4 +1467,4 @@ Keyboard8080.VT100.portsOutput = { */ Web.onInit(Keyboard8080.init); -if (NODE) module.exports = Keyboard8080; +if (typeof module !== "undefined") module.exports = Keyboard8080; diff --git a/modules/pc8080/lib/memory.js b/modules/pc8080/lib/memory.js index 2e3d7c7b1d..9ad919c35c 100644 --- a/modules/pc8080/lib/memory.js +++ b/modules/pc8080/lib/memory.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var CPUDef8080 = require("./cpudef"); @@ -917,4 +917,4 @@ if (TYPEDARRAYS) { ]; } -if (NODE) module.exports = Memory8080; +if (typeof module !== "undefined") module.exports = Memory8080; diff --git a/modules/pc8080/lib/messages.js b/modules/pc8080/lib/messages.js index c5768ec33c..11c493b90c 100644 --- a/modules/pc8080/lib/messages.js +++ b/modules/pc8080/lib/messages.js @@ -89,4 +89,4 @@ Messages8080.CATEGORIES = { "halt": Messages8080.HALT }; -if (NODE) module.exports = Messages8080; +if (typeof module !== "undefined") module.exports = Messages8080; diff --git a/modules/pc8080/lib/panel.js b/modules/pc8080/lib/panel.js index e6d198abda..972e1b1e00 100644 --- a/modules/pc8080/lib/panel.js +++ b/modules/pc8080/lib/panel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); var PC8080 = require("./defines"); @@ -183,4 +183,4 @@ class Panel8080 extends Component { */ Web.onInit(Panel8080.init); -if (NODE) module.exports = Panel8080; +if (typeof module !== "undefined") module.exports = Panel8080; diff --git a/modules/pc8080/lib/ram.js b/modules/pc8080/lib/ram.js index 53d61af8b1..1921832a17 100644 --- a/modules/pc8080/lib/ram.js +++ b/modules/pc8080/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -394,4 +394,4 @@ RAM8080.CPM.VECTORS = [RAM8080.CPM.BIOS.VECTOR, RAM8080.CPM.BDOS.VECTOR]; */ Web.onInit(RAM8080.init); -if (NODE) module.exports = RAM8080; +if (typeof module !== "undefined") module.exports = RAM8080; diff --git a/modules/pc8080/lib/rom.js b/modules/pc8080/lib/rom.js index 49b864404c..0b5cabe3e3 100644 --- a/modules/pc8080/lib/rom.js +++ b/modules/pc8080/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -383,4 +383,4 @@ class ROM8080 extends Component { */ Web.onInit(ROM8080.init); -if (NODE) module.exports = ROM8080; +if (typeof module !== "undefined") module.exports = ROM8080; diff --git a/modules/pc8080/lib/serial.js b/modules/pc8080/lib/serial.js index 6b109d790b..c07d7c6b13 100644 --- a/modules/pc8080/lib/serial.js +++ b/modules/pc8080/lib/serial.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -956,4 +956,4 @@ SerialPort8080.aPortOutput = { */ Web.onInit(SerialPort8080.init); -if (NODE) module.exports = SerialPort8080; +if (typeof module !== "undefined") module.exports = SerialPort8080; diff --git a/modules/pc8080/lib/video.js b/modules/pc8080/lib/video.js index a669c917e4..96458e6ac6 100644 --- a/modules/pc8080/lib/video.js +++ b/modules/pc8080/lib/video.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -1565,4 +1565,4 @@ Video8080.VT100 = { */ Web.onInit(Video8080.init); -if (NODE) module.exports = Video8080; +if (typeof module !== "undefined") module.exports = Video8080; diff --git a/modules/pcx86/lib/bus.js b/modules/pcx86/lib/bus.js index 26fa53889c..7abed37f4d 100644 --- a/modules/pcx86/lib/bus.js +++ b/modules/pcx86/lib/bus.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -1765,4 +1765,4 @@ Bus.ERROR = { REM_MEM_BADRANGE: 5 }; -if (NODE) module.exports = {Bus, Controller}; +if (typeof module !== "undefined") module.exports = {Bus, Controller}; diff --git a/modules/pcx86/lib/chipset.js b/modules/pcx86/lib/chipset.js index e010e118e8..e456672523 100644 --- a/modules/pcx86/lib/chipset.js +++ b/modules/pcx86/lib/chipset.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -6269,4 +6269,4 @@ if (DESKPRO386) { */ Web.onInit(ChipSet.init); -if (NODE) module.exports = ChipSet; +if (typeof module !== "undefined") module.exports = ChipSet; diff --git a/modules/pcx86/lib/computer.js b/modules/pcx86/lib/computer.js index 322fbc490e..07aee45929 100644 --- a/modules/pcx86/lib/computer.js +++ b/modules/pcx86/lib/computer.js @@ -57,7 +57,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -1969,4 +1969,4 @@ Web.onInit(Computer.init); Web.onShow(Computer.show); Web.onExit(Computer.exit); -if (NODE) module.exports = Computer; +if (typeof module !== "undefined") module.exports = Computer; diff --git a/modules/pcx86/lib/cpu.js b/modules/pcx86/lib/cpu.js index 56dddff857..9cfc35da7f 100644 --- a/modules/pcx86/lib/cpu.js +++ b/modules/pcx86/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -1397,4 +1397,4 @@ CPU.YIELDS_PER_SECOND = 60; CPU.BUTTONS = ["power", "reset"]; -if (NODE) module.exports = CPU; +if (typeof module !== "undefined") module.exports = CPU; diff --git a/modules/pcx86/lib/cpux86.js b/modules/pcx86/lib/cpux86.js index b7792b62b7..d642152af4 100644 --- a/modules/pcx86/lib/cpux86.js +++ b/modules/pcx86/lib/cpux86.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -4600,4 +4600,4 @@ CPUX86.PAGEBLOCKS_CACHE = 512; // TODO: This seems adequate for 4Mb of RAM, */ Web.onInit(CPUX86.init); -if (NODE) module.exports = CPUX86; +if (typeof module !== "undefined") module.exports = CPUX86; diff --git a/modules/pcx86/lib/debugger.js b/modules/pcx86/lib/debugger.js index a00d87c65a..665cdbe964 100644 --- a/modules/pcx86/lib/debugger.js +++ b/modules/pcx86/lib/debugger.js @@ -29,7 +29,7 @@ "use strict"; if (DEBUGGER) { - if (NODE) { + if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -7949,4 +7949,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = DebuggerX86; +if (typeof module !== "undefined") module.exports = DebuggerX86; diff --git a/modules/pcx86/lib/defines.js b/modules/pcx86/lib/defines.js index a96de47672..d1aed5e5e2 100644 --- a/modules/pcx86/lib/defines.js +++ b/modules/pcx86/lib/defines.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); } @@ -192,7 +192,7 @@ var PCX86 = { XMLVERSION: XMLVERSION // shared }; -if (NODE) { +if (typeof module !== "undefined") { global.APPCLASS = APPCLASS; global.APPNAME = APPNAME; global.DEBUGGER = DEBUGGER; diff --git a/modules/pcx86/lib/disk.js b/modules/pcx86/lib/disk.js index 93e8e5c859..b0b4dbfc01 100644 --- a/modules/pcx86/lib/disk.js +++ b/modules/pcx86/lib/disk.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -2957,4 +2957,4 @@ FileInfo.NE = { * @property {number} offFile */ -if (NODE) module.exports = Disk; +if (typeof module !== "undefined") module.exports = Disk; diff --git a/modules/pcx86/lib/fdc.js b/modules/pcx86/lib/fdc.js index f28fe5106b..3cc2bd4e80 100644 --- a/modules/pcx86/lib/fdc.js +++ b/modules/pcx86/lib/fdc.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DiskAPI = require("../../shared/lib/diskapi"); @@ -3087,4 +3087,4 @@ FDC.aPortOutput = { */ Web.onInit(FDC.init); -if (NODE) module.exports = FDC; +if (typeof module !== "undefined") module.exports = FDC; diff --git a/modules/pcx86/lib/fpux86.js b/modules/pcx86/lib/fpux86.js index 785b0185e8..27b9842292 100644 --- a/modules/pcx86/lib/fpux86.js +++ b/modules/pcx86/lib/fpux86.js @@ -31,7 +31,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -3373,4 +3373,4 @@ FPUX86.afnPreserveExceptions = [ */ Web.onInit(FPUX86.init); -if (NODE) module.exports = FPUX86; +if (typeof module !== "undefined") module.exports = FPUX86; diff --git a/modules/pcx86/lib/hdc.js b/modules/pcx86/lib/hdc.js index 1048fa13d0..8cc86c41a3 100644 --- a/modules/pcx86/lib/hdc.js +++ b/modules/pcx86/lib/hdc.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DiskAPI = require("../../shared/lib/diskapi"); @@ -123,7 +123,7 @@ class HDC extends Component { this.fATAPI = (this.sType == "ATAPI"); } this.nInterface = (this.fATAPI? 1 : 0); // default to the secondary interface if type is "ATAPI" - let nInterface = this.sType.slice(-1); + let nInterface = this.sType.slice(-1); // but if an interface is specified (eg, "AT2", "ATAPI1"), honor it if (nInterface == '1') { this.nInterface = 0; } else if (nInterface == '2') { @@ -265,20 +265,21 @@ class HDC extends Component { if (!this.fATC) { bus.addPortInputTable(this, HDC.aXTCPortInput); bus.addPortOutputTable(this, HDC.aXTCPortOutput); - } else if (!this.nInterface) { - bus.addPortInputTable(this, HDC.aATCPortInputPrimary); - bus.addPortOutputTable(this, HDC.aATCPortOutputPrimary); } else { - bus.addPortInputTable(this, HDC.aATCPortInputSecondary); - bus.addPortOutputTable(this, HDC.aATCPortOutputSecondary); - } - - if (this.fATC) { + if (!this.nInterface) { + bus.addPortInputTable(this, HDC.aATCPortInputPrimary); + bus.addPortOutputTable(this, HDC.aATCPortOutputPrimary); + bus.addPortInputWidth(HDC.ATC.DATA.PORT1, 2); + bus.addPortOutputWidth(HDC.ATC.DATA.PORT1, 2); + } else { + bus.addPortInputTable(this, HDC.aATCPortInputSecondary); + bus.addPortOutputTable(this, HDC.aATCPortOutputSecondary); + bus.addPortInputWidth(HDC.ATC.DATA.PORT2, 2); + bus.addPortOutputWidth(HDC.ATC.DATA.PORT2, 2); + } this.iDriveTable++; if (this.chipset && this.chipset.model == ChipSet.MODEL_COMPAQ_DESKPRO386) this.iDriveTable++; this.iDriveTypeDefault = 2; - bus.addPortInputWidth(HDC.ATC.DATA.PORT, 2); - bus.addPortOutputWidth(HDC.ATC.DATA.PORT, 2); } cpu.addIntNotify(Interrupts.DISK, this.intBIOSDisk.bind(this)); @@ -1241,7 +1242,7 @@ class HDC extends Component { /** * inATCData(port, addrFrom) * - * Wrapper around inATCByte() to treat this as a 16-bit port; see addPortInputWidth(HDC.ATC.DATA.PORT, 2). + * Wrapper around inATCByte() to treat this as a 16-bit port; see addPortInputWidth(HDC.ATC.DATA.PORT1, 2). * * @this {HDC} * @param {number} port (0x1F0,0x170) @@ -1321,7 +1322,7 @@ class HDC extends Component { /** * outATCData(port, data, addrFrom) * - * Wrapper around outATCByte() to treat this as a 16-bit port; see addPortOutputWidth(HDC.ATC.DATA.PORT, 2) + * Wrapper around outATCByte() to treat this as a 16-bit port; see addPortOutputWidth(HDC.ATC.DATA.PORT1, 2) * * @this {HDC} * @param {number} port (0x1F0,0x170) @@ -1828,7 +1829,7 @@ class HDC extends Component { let b3 = this.popCmd(); let wCylinder = ((b2 << 2) & 0x300) | b3; let bSector = b2 & 0x3f; - let bCount = this.popCmd(); // block count or interleave count, depending on the command + let bCount = this.popCmd(); // block count or interleave count, depending on the command let bControl = this.popCmd(); let bParm, bDataStatus; @@ -2547,17 +2548,16 @@ class HDC extends Component { * * @this {HDC} * @param {number} iDrive - * - unloadDrive(iDrive) - { - this.aDrives[iDrive].disk = null; - // - // WARNING: This conversion of drive number to drive letter, starting with "C:" (0x43), is very simplistic - // and is not guaranteed to match the drive mapping that DOS ultimately uses. - // - this.notice("Drive " + String.fromCharCode(0x43 + iDrive) + " unloaded"); - } */ + // unloadDrive(iDrive) + // { + // this.aDrives[iDrive].disk = null; + // // + // // WARNING: This conversion of drive number to drive letter, starting with "C:" (0x43), is very simplistic + // // and is not guaranteed to match the drive mapping that DOS ultimately uses. + // // + // this.notice("Drive " + String.fromCharCode(0x43 + iDrive) + " unloaded"); + // } /** * doFormat(drive, done) @@ -2576,45 +2576,44 @@ class HDC extends Component { * @this {HDC} * @param {Object} drive * @param {function(number)} done (dataStatus is XTC.DATA.STATUS.OK or XTC.DATA.STATUS.ERROR; if error, then drive.errorCode should be set as well) - * - doFormat(drive, done) - { - drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - - if (drive.disk) { - drive.sector = null; - if (this.chipset) { - drive.cbFormat = 0; - drive.abFormat = new Array(4); - drive.bFormatting = true; - drive.cSectorsFormatted = 0; - // - // We need to reverse the original logic, and default to success unless/until an actual error occurs; - // otherwise doDMAWriteFormat() will bail on us. The original approach would work because requestDMA() - // would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked; - // now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished. - // - drive.errorCode = HDC.XTC.DATA.ERR.NONE; - this.chipset.connectDMA(ChipSet.DMA_HDC, this, 'dmaWriteFormat', drive); - this.chipset.requestDMA(ChipSet.DMA_HDC, function onDMAFormat(fComplete) { - if (!fComplete) { - // - // If an incomplete request wasn't triggered by an explicit error, then let's make explicit - // (ie, revert to the default failure code that we originally set above). - // - if (drive.errorCode == HDC.XTC.DATA.ERR.NONE) { - drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; - } - } - drive.bFormatting = false; - done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK); - }); - return; - } - } - done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK); - } */ + // doFormat(drive, done) + // { + // drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; + // + // if (drive.disk) { + // drive.sector = null; + // if (this.chipset) { + // drive.cbFormat = 0; + // drive.abFormat = new Array(4); + // drive.bFormatting = true; + // drive.cSectorsFormatted = 0; + // // + // // We need to reverse the original logic, and default to success unless/until an actual error occurs; + // // otherwise doDMAWriteFormat() will bail on us. The original approach would work because requestDMA() + // // would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked; + // // now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished. + // // + // drive.errorCode = HDC.XTC.DATA.ERR.NONE; + // this.chipset.connectDMA(ChipSet.DMA_HDC, this, 'dmaWriteFormat', drive); + // this.chipset.requestDMA(ChipSet.DMA_HDC, function onDMAFormat(fComplete) { + // if (!fComplete) { + // // + // // If an incomplete request wasn't triggered by an explicit error, then let's make explicit + // // (ie, revert to the default failure code that we originally set above). + // // + // if (drive.errorCode == HDC.XTC.DATA.ERR.NONE) { + // drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; + // } + // } + // drive.bFormatting = false; + // done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK); + // }); + // return; + // } + // } + // done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK); + // } /** * HDC.init() @@ -2888,9 +2887,13 @@ HDC.aDriveTypes = [ * diskette drives, because if none of the "MULTIPLE DATA RATE" tests succeed, a "601-Diskette Error" always occurs. */ HDC.ATC = { - DATA: { PORT: 0x1F0}, // no register (read-write) + DATA: { // no register (read-write) + PORT1: 0x1F0, // data port address for primary interface + PORT2: 0x170 // data port address for secondary interface + }, DIAG: { // this.regError (read-only) - PORT: 0x1F1, + PORT1: 0x1F1, + PORT2: 0x171, NO_ERROR: 0x01, CTRL_ERROR: 0x02, SEC_ERROR: 0x03, @@ -2898,7 +2901,8 @@ HDC.ATC = { PROC_ERROR: 0x05 }, ERROR: { // this.regError (read-only) - PORT: 0x1F1, + PORT1: 0x1F1, + PORT2: 0x171, NONE: 0x00, NO_DAM: 0x01, // Data Address Mark (DAM) not found NO_TRK0: 0x02, // Track 0 not detected @@ -2907,23 +2911,38 @@ HDC.ATC = { ECC_ERR: 0x40, // Data ECC Error BAD_BLOCK: 0x80 // Bad Block Detect }, - WPREC: { PORT: 0x1F1}, // this.regWPreC (write-only) - SECCNT: { PORT: 0x1F2}, // this.regSecCnt (read-write; 0 implies a 256-sector request) - SECNUM: { PORT: 0x1F3}, // this.regSecNum (read-write) - CYLLO: { PORT: 0x1F4}, // this.regCylLo (read-write; all 8 bits are used) + WPREC: { // this.regWPreC (write-only) + PORT1: 0x1F1, + PORT2: 0x171 + }, + SECCNT: { // this.regSecCnt (read-write; 0 implies a 256-sector request) + PORT1: 0x1F2, + PORT2: 0x172 + }, + SECNUM: { // this.regSecNum (read-write) + PORT1: 0x1F3, + PORT2: 0x173 + }, + CYLLO: { // this.regCylLo (read-write; all 8 bits are used) + PORT1: 0x1F4, + PORT2: 0x174 + }, CYLHI: { // this.regCylHi (read-write; only bits 0-1 are used, for a total of 10 bits, or 1024 max cylinders) - PORT: 0x1F5, + PORT1: 0x1F5, + PORT2: 0x175, MASK: 0x03 }, DRVHD: { // this.regDrvHd (read-write) - PORT: 0x1F6, + PORT1: 0x1F6, + PORT2: 0x176, HEAD_MASK: 0x0F, // set this to the max number of heads before issuing a SET PARAMETERS command DRIVE_MASK: 0x10, SET_MASK: 0xE0, SET_BITS: 0xA0 // for whatever reason, these bits must always be set }, STATUS: { // this.regStatus (read-only; reading clears IRQ.ATC1) - PORT: 0x1F7, + PORT1: 0x1F7, + PORT2: 0x177, ERROR: 0x01, // set when the previous command ended in an error; one or more bits are set in the ERROR register (the next command to the controller resets the ERROR bit) INDEX: 0x02, // set once for every revolution of the disk CORRECTED: 0x04, @@ -2934,21 +2953,33 @@ HDC.ATC = { BUSY: 0x80 // if this is set, no other STATUS bits are valid }, COMMAND: { // this.regCommand (write-only) - PORT: 0x1F7, - RESTORE: 0x10, // low nibble x 500us equal stepping rate (except for 0, which corresponds to 35us) (aka RECALIBRATE) - READ_DATA: 0x20, // also supports NO_RETRIES and WITH_ECC - WRITE_DATA: 0x30, // also supports NO_RETRIES and WITH_ECC - READ_VERF: 0x40, // also supports NO_RETRIES + PORT1: 0x1F7, + PORT2: 0x177, + NO_RETRY: 0x01, // optional bit for READ_DATA, WRITE_DATA, and READ_VERF commands + WITH_ECC: 0x02, // optional bit for READ_DATA and WRITE_DATA commands + /* + * The following 8 commands comprised the original PC AT command set. You may see other later command set + * definitions that show "mandatory" commands, such as READ_MULT (0xC4) or WRITE_MULT (0xC5), but those didn't + * exist until the introduction of later enhancements (eg, "IDE", "ATA", "EIDE", "ATAPI", etc). + */ + RESTORE: 0x10, // aka RECALIBRATE: low nibble x 500us equal stepping rate (except for 0, which corresponds to 35us) + READ_DATA: 0x20, // also supports NO_RETRY and/or WITH_ECC + WRITE_DATA: 0x30, // also supports NO_RETRY and/or WITH_ECC + READ_VERF: 0x40, // also supports NO_RETRY FORMAT_TRK: 0x50, // TODO SEEK: 0x70, // low nibble x 500us equal stepping rate (except for 0, which corresponds to 35us) DIAGNOSE: 0x90, SETPARMS: 0x91, - NO_RETRIES: 0x01, - WITH_ECC: 0x02, - MASK: 0xF0 + MASK: 0xF0, + /* + * Additional IDE/ATA/ATAPI commands go here. As for which command(s) were introduced as part of + * which enhancement, or when, is not something I'm going to try to get into here (as least not yet). + */ + IDENTIFY: 0xEC }, FDR: { // this.regFDR - PORT: 0x3F6, + PORT1: 0x3F6, + PORT2: 0x376, INT_DISABLE: 0x02, // a logical 0 enables fixed disk interrupts RESET: 0x04, // a logical 1 enables reset fixed disk function HS3: 0x08, // a logical 1 enables head select 3 (a logical 0 enables reduced write current) @@ -2956,6 +2987,83 @@ HDC.ATC = { } }; +/* + * Much of the following IDENTIFY structure information comes from a Seagate ATA Reference Manual, + * 36111-001, Rev. C, dated 21 May 1993 (111-1c.pdf). All words are stored little-endian; also note + * some definitions of CUR_CAPACITY define it as two 16-bit words, since as a 32-bit dword, it would + * be misaligned if the structure began on a dword boundary (and, of course, if it did NOT begin on + * a dword boundary, then LBA_CAPACITY would be misaligned). Alignment considerations are of no + * particular concern here, however. + */ +HDC.ATC.IDENTIFY = { + CONFIG: { // WORD: GENERAL_CONFIG + OFFSET: 0x00, + ATA_RESERVED: 0x0001, // always clear (ATA reserved) + HARD_SECTORED: 0x0002, // set if hard sectored + SOFT_SECTORED: 0x0004, // set if soft sectored + NOT_MFM: 0x0008, // set if not MFM encoded + HDSW_15MS: 0x0010, // set if head switch time > 15usec + SPINDLE_OPT: 0x0020, // set if spindle motor control option implemented + FIXED: 0x0040, // set if fixed drive + REMOVABLE: 0x0080, // set if removable cartridge drive + RATE_5MBIT: 0x0100, // set if disk transfer rate <= 5Mbit/sec + RATE_10MBIT: 0x0200, // set if disk transfer rate <= 10Mbit/sec and > 5Mbit/sec + RATE_FASTER: 0x0400, // set if disk transfer rate > 10Mbit/sec + ROT_TOLERANCE: 0x0800, // set if rotational speed tolerance is > 0.5% + STROBE_OPT: 0x1000, // set if data strobe offset option available + TRACK_OPT: 0x2000, // set if track offset option available + FMT_TOLERANCE: 0x4000, // set if format speed tolerance gap required + NM_RESERVED: 0x8000 // always clear (reserved for non-magnetic drives) + }, + CYLS: 0x02, // WORD: number of physical cylinders + CONFIG2: 0x04, // WORD: SPECIFIC_CONFIG + HEADS: 0x06, // WORD: number of physical heads + TRACK_BYTES: 0x08, // WORD: bytes per track + SECTOR_BYTES: 0x0A, // WORD: bytes per sector + SECTORS: 0x0C, // WORD: sectors per track + // (reserved words at 0x0E, 0x10, and 0x12) + SERIAL_NUMBER: 0x14, // CHAR: 20 ASCII characters + BUFFER_TYPE: 0x28, // WORD: 0=unspecified, 1=single, 2=dual, 3=caching + BUFFER_SIZE: 0x2A, // WORD: 512-byte increments + ECC_BYTES: 0x2C, // WORD: number of ECC bytes on read/write long commands + FIRMWARE_REV: 0x2E, // CHAR: 8 ASCII characters + MODEL_NUMBER: 0x36, // CHAR: 40 ASCII characters + MAX_MULTISEC: 0x5E, // BYTE: if non-zero, number of transferable sectors per interrupt + // (reserved byte at 0x5F) + DWORD_IO: 0x60, // WORD: 0x0001 if double-word I/O supported, 0x0000 if not + // (reserved byte at 0x62) + CAPABILITY: 0x63, // BYTE: bit0=DMA, bit1=LBA, bit2=IORDYsw, bit3=IORDYsup + // (reserved word at 0x64; reserved byte at 0x66) + PIO_TIMING: 0x67, // BYTE: 0=slow, 1=medium, 2=fast + // (reserved byte at 0x68) + DMA_TIMING: 0x69, // BYTE: 0=slow, 1=medium, 2=fast + NEXT5_VALID: 0x6A, // WORD: bit0=1 if next 5 words are valid, 0 if not + CUR_CYLS: 0x6C, // WORD: number of logical cylinders + CUR_HEADS: 0x6E, // WORD: number of logical heads + CUR_SECTORS: 0x70, // WORD: number of logical sectors per track + CUR_CAPACITY: 0x72, // LONG: logical capacity in sectors + MULTISECT: 0x76, // BYTE: current mutiple sector count + MULTISECT_VALID: 0x77, // BYTE: bit0=1 if MULTSECT is valid, 0 if not + LBA_CAPACITY: 0x78, // LONG: total number of sectors + DMA_SINGLE: 0x7C, // BYTE + DMA_SINGLE_ACTIVE: 0x7D, // BYTE + DMA_MULTI: 0x7E, // BYTE + DMA_MULTI_ACTIVE: 0x7F, // BYTE + /* + * The rest of this 512-byte structure (words 64 through 255) was reserved at the time of the + * aforementioned Seagate 1993 specification, so I will not delve any deeper into this structure now. + * + * Further details can be found at: + * + * https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ata/ns-ata-_identify_device_data + * https://chromium.googlesource.com/chromiumos/third_party/u-boot-next/+/master/include/ata.h + * + * Regrettably, most modern documents don't bother mentioning at what point any fields were added + * to the specification, and they treat some of the fields as too old to warrant any explanation at all, + * calling them simply "Retired" or "Obsolete". Not particularly helpful. + */ +}; + /* * XTC (XT Controller) Registers */ @@ -3003,7 +3111,7 @@ HDC.XTC = { * maximum ECC data burst length * * Note that the 3 word values above are stored in "big-endian" format (high byte followed by low byte), - * rather than the more typical "little-endian" format (low byte followed by high byte). + * rather than the "little-endian" format (low byte followed by high byte) you typically find on Intel machines. */ CMD: { TEST_READY: 0x00, // Test Drive Ready @@ -3212,4 +3320,4 @@ HDC.aATCPortOutputSecondary = { */ Web.onInit(HDC.init); -if (NODE) module.exports = HDC; +if (typeof module !== "undefined") module.exports = HDC; diff --git a/modules/pcx86/lib/interrupts.js b/modules/pcx86/lib/interrupts.js index dd0e30cabf..b1bbde8ac6 100644 --- a/modules/pcx86/lib/interrupts.js +++ b/modules/pcx86/lib/interrupts.js @@ -2132,4 +2132,4 @@ if (DEBUGGER) { * entries for 16 segments. */ -if (NODE) module.exports = Interrupts; +if (typeof module !== "undefined") module.exports = Interrupts; diff --git a/modules/pcx86/lib/keyboard.js b/modules/pcx86/lib/keyboard.js index 11efa7659c..1e0ce8be14 100644 --- a/modules/pcx86/lib/keyboard.js +++ b/modules/pcx86/lib/keyboard.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -3076,4 +3076,4 @@ Keyboard.INJECTION = { */ Web.onInit(Keyboard.init); -if (NODE) module.exports = Keyboard; +if (typeof module !== "undefined") module.exports = Keyboard; diff --git a/modules/pcx86/lib/memory.js b/modules/pcx86/lib/memory.js index c60608f661..c8c10b0351 100644 --- a/modules/pcx86/lib/memory.js +++ b/modules/pcx86/lib/memory.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var Messages = require("./messages"); @@ -1786,4 +1786,4 @@ if (TYPEDARRAYS) { ]; } -if (NODE) module.exports = Memory; +if (typeof module !== "undefined") module.exports = Memory; diff --git a/modules/pcx86/lib/messages.js b/modules/pcx86/lib/messages.js index 48da6d8298..51c4b4b1eb 100644 --- a/modules/pcx86/lib/messages.js +++ b/modules/pcx86/lib/messages.js @@ -130,4 +130,4 @@ Messages.CATEGORIES = { "buffer": Messages.BUFFER }; -if (NODE) module.exports = Messages; +if (typeof module !== "undefined") module.exports = Messages; diff --git a/modules/pcx86/lib/mouse.js b/modules/pcx86/lib/mouse.js index c0143fa16b..3e8e5ae916 100644 --- a/modules/pcx86/lib/mouse.js +++ b/modules/pcx86/lib/mouse.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -987,4 +987,4 @@ Mouse.SERIAL = { */ Web.onInit(Mouse.init); -if (NODE) module.exports = Mouse; +if (typeof module !== "undefined") module.exports = Mouse; diff --git a/modules/pcx86/lib/panel.js b/modules/pcx86/lib/panel.js index ac4c2a7e83..9f85f89cf2 100644 --- a/modules/pcx86/lib/panel.js +++ b/modules/pcx86/lib/panel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -1121,4 +1121,4 @@ Panel.UPDATES_PER_SECOND = 10; */ Web.onInit(Panel.init); -if (NODE) module.exports = Panel; +if (typeof module !== "undefined") module.exports = Panel; diff --git a/modules/pcx86/lib/parallel.js b/modules/pcx86/lib/parallel.js index 77fc0b6871..6f8049ef66 100644 --- a/modules/pcx86/lib/parallel.js +++ b/modules/pcx86/lib/parallel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -557,4 +557,4 @@ ParallelPort.aPortOutput = { */ Web.onInit(ParallelPort.init); -if (NODE) module.exports = ParallelPort; +if (typeof module !== "undefined") module.exports = ParallelPort; diff --git a/modules/pcx86/lib/ram.js b/modules/pcx86/lib/ram.js index 33cd844087..8e3fa752f5 100644 --- a/modules/pcx86/lib/ram.js +++ b/modules/pcx86/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -601,4 +601,4 @@ CompaqController.ACCESS = [CompaqController.readByte, null, null, CompaqControll */ Web.onInit(RAM.init); -if (NODE) module.exports = RAM; +if (typeof module !== "undefined") module.exports = RAM; diff --git a/modules/pcx86/lib/rom.js b/modules/pcx86/lib/rom.js index 396af94d01..6e94e48eeb 100644 --- a/modules/pcx86/lib/rom.js +++ b/modules/pcx86/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -668,4 +668,4 @@ ROMX86.BIOS = { */ Web.onInit(ROMX86.init); -if (NODE) module.exports = ROMX86; +if (typeof module !== "undefined") module.exports = ROMX86; diff --git a/modules/pcx86/lib/segx86.js b/modules/pcx86/lib/segx86.js index c6c8493218..662269b0bc 100644 --- a/modules/pcx86/lib/segx86.js +++ b/modules/pcx86/lib/segx86.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Messages = require("./messages"); var X86 = require("./x86"); @@ -1701,4 +1701,4 @@ SegX86.ID = { SegX86.CALLBREAK_SEL = 0x0001; -if (NODE) module.exports = SegX86; +if (typeof module !== "undefined") module.exports = SegX86; diff --git a/modules/pcx86/lib/serial.js b/modules/pcx86/lib/serial.js index e60b532303..da3e49e817 100644 --- a/modules/pcx86/lib/serial.js +++ b/modules/pcx86/lib/serial.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1195,4 +1195,4 @@ SerialPort.aPortOutput = { */ Web.onInit(SerialPort.init); -if (NODE) module.exports = SerialPort; +if (typeof module !== "undefined") module.exports = SerialPort; diff --git a/modules/pcx86/lib/testctl.js b/modules/pcx86/lib/testctl.js index 9ae7f46406..3e62af2436 100644 --- a/modules/pcx86/lib/testctl.js +++ b/modules/pcx86/lib/testctl.js @@ -33,7 +33,7 @@ * our 'binding' property indicates, if any. */ -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -347,4 +347,4 @@ class TestController extends Component { */ Web.onInit(TestController.init); -if (NODE) module.exports = TestController; +if (typeof module !== "undefined") module.exports = TestController; diff --git a/modules/pcx86/lib/testmon.js b/modules/pcx86/lib/testmon.js index 0d07899eef..1f608dd3ae 100644 --- a/modules/pcx86/lib/testmon.js +++ b/modules/pcx86/lib/testmon.js @@ -47,7 +47,7 @@ * commands, and if a match is found, the corresponding request is sent to the SerialPort. */ -if (NODE) { +if (typeof module !== "undefined") { var Keys = require("../../shared/lib/keys"); var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); @@ -483,4 +483,4 @@ TestMonitor.COMMANDS = [ TestMonitor.COMMAND.WAIT ]; -if (NODE) module.exports = TestMonitor; +if (typeof module !== "undefined") module.exports = TestMonitor; diff --git a/modules/pcx86/lib/video.js b/modules/pcx86/lib/video.js index aed1b139d3..723a4baf61 100644 --- a/modules/pcx86/lib/video.js +++ b/modules/pcx86/lib/video.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -8629,4 +8629,4 @@ Video.aVGAPortOutput = { */ Web.onInit(Video.init); -if (NODE) module.exports = Video; +if (typeof module !== "undefined") module.exports = Video; diff --git a/modules/pcx86/lib/x86.js b/modules/pcx86/lib/x86.js index df7fd12843..78782685c1 100644 --- a/modules/pcx86/lib/x86.js +++ b/modules/pcx86/lib/x86.js @@ -892,4 +892,4 @@ X86.PS_SAHF = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF); */ X86.OPFLAG_PREFIXES = (X86.OPFLAG.SEG | X86.OPFLAG.LOCK | X86.OPFLAG.REPZ | X86.OPFLAG.REPNZ | X86.OPFLAG.DATASIZE | X86.OPFLAG.ADDRSIZE); -if (NODE) module.exports = X86; +if (typeof module !== "undefined") module.exports = X86; diff --git a/modules/pcx86/lib/x86func.js b/modules/pcx86/lib/x86func.js index 0d1334aa07..d45a2c815e 100644 --- a/modules/pcx86/lib/x86func.js +++ b/modules/pcx86/lib/x86func.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Messages = require("./messages"); var X86 = require("./x86"); } diff --git a/modules/pcx86/lib/x86help.js b/modules/pcx86/lib/x86help.js index 74feb6be1c..31a034a6e5 100644 --- a/modules/pcx86/lib/x86help.js +++ b/modules/pcx86/lib/x86help.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Messages = require("./messages"); var X86 = require("./x86"); diff --git a/modules/pcx86/lib/x86mods.js b/modules/pcx86/lib/x86mods.js index 6b6c09db3a..a4cacd5223 100644 --- a/modules/pcx86/lib/x86mods.js +++ b/modules/pcx86/lib/x86mods.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var X86 = require("./x86"); } diff --git a/modules/pcx86/lib/x86op0f.js b/modules/pcx86/lib/x86op0f.js index 226976d961..7dc0798cd1 100644 --- a/modules/pcx86/lib/x86op0f.js +++ b/modules/pcx86/lib/x86op0f.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var X86 = require("./x86"); } diff --git a/modules/pcx86/lib/x86ops.js b/modules/pcx86/lib/x86ops.js index 65782b850d..a716994755 100644 --- a/modules/pcx86/lib/x86ops.js +++ b/modules/pcx86/lib/x86ops.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Messages = require("./messages"); var X86 = require("./x86"); diff --git a/modules/pdp10/lib/bus.js b/modules/pdp10/lib/bus.js index 1116b21212..091dffadaa 100644 --- a/modules/pdp10/lib/bus.js +++ b/modules/pdp10/lib/bus.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -759,4 +759,4 @@ BusPDP10.ERROR = { RANGE_INVALID: 2 }; -if (NODE) module.exports = BusPDP10; +if (typeof module !== "undefined") module.exports = BusPDP10; diff --git a/modules/pdp10/lib/computer.js b/modules/pdp10/lib/computer.js index 0fbcab092f..a4d18d3594 100644 --- a/modules/pdp10/lib/computer.js +++ b/modules/pdp10/lib/computer.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -220,8 +220,12 @@ class ComputerPDP10 extends Component { * OVERRIDES everything; it overrides any 'state' Computer parameter AND it disables resume of any saved state in * localStorage (in other words, it prevents fAllowResume from being true, and forcing resume off). */ - var fAllowResume; - var sState = this.getMachineParm('state') || (fAllowResume = true) && parmsComputer['state']; + var fAllowResume = false; + var sState = this.getMachineParm('state'); + if (!sState) { + fAllowResume = true; + sState = parmsComputer['state']; + } if (sState) { this.sStatePath = sStatePath = sState; @@ -252,7 +256,7 @@ class ComputerPDP10 extends Component { this.setReady(); } else { var cmp = this; - Web.getResource(sStatePath, null, true, function doneStateLoad(sURL, sResource, nErrorCode) { + Web.getResource(/** @type {string} */ (sStatePath), null, true, function doneStateLoad(sURL, sResource, nErrorCode) { cmp.finishStateLoad(sURL, sResource, nErrorCode); }); } @@ -1673,4 +1677,4 @@ Web.onInit(ComputerPDP10.init); Web.onShow(ComputerPDP10.show); Web.onExit(ComputerPDP10.exit); -if (NODE) module.exports = ComputerPDP10; +if (typeof module !== "undefined") module.exports = ComputerPDP10; diff --git a/modules/pdp10/lib/cpu.js b/modules/pdp10/lib/cpu.js index e6703948e6..5f09b6a22e 100644 --- a/modules/pdp10/lib/cpu.js +++ b/modules/pdp10/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var MessagesPDP10 = require("./messages"); @@ -1237,4 +1237,4 @@ CPUPDP10.YIELDS_PER_STATUS = 15; // every 15 yields (ie, twice pe CPUPDP10.BUTTONS = ["power", "reset"]; -if (NODE) module.exports = CPUPDP10; +if (typeof module !== "undefined") module.exports = CPUPDP10; diff --git a/modules/pdp10/lib/cpuops.js b/modules/pdp10/lib/cpuops.js index 072e81ba25..5beb582ed9 100644 --- a/modules/pdp10/lib/cpuops.js +++ b/modules/pdp10/lib/cpuops.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var PDP10 = require("./defines"); diff --git a/modules/pdp10/lib/cpustate.js b/modules/pdp10/lib/cpustate.js index 41eab829c2..1671be89c0 100644 --- a/modules/pdp10/lib/cpustate.js +++ b/modules/pdp10/lib/cpustate.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -986,4 +986,4 @@ class CPUStatePDP10 extends CPUPDP10 { */ Web.onInit(CPUStatePDP10.init); -if (NODE) module.exports = CPUStatePDP10; +if (typeof module !== "undefined") module.exports = CPUStatePDP10; diff --git a/modules/pdp10/lib/debugger.js b/modules/pdp10/lib/debugger.js index 906d4a1eb2..172a2bc712 100644 --- a/modules/pdp10/lib/debugger.js +++ b/modules/pdp10/lib/debugger.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -1761,7 +1761,7 @@ class DebuggerPDP10 extends Debugger { for (var i = 0; i < aOperands.length; i++) { - var sOperand = aOperands[i].trim(); + var operand, sOperand = aOperands[i].trim(); if (!sOperand) continue; var match = sOperand.match(/(@?)([^(]*)\(?([^)]*)\)?/); @@ -1821,7 +1821,7 @@ class DebuggerPDP10 extends Debugger { } } - var operand = this.parseExpression(sOperand, aUndefined); + operand = this.parseExpression(sOperand, aUndefined); if (operand == undefined) { opCode = -1; break; @@ -4336,4 +4336,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = DebuggerPDP10; +if (typeof module !== "undefined") module.exports = DebuggerPDP10; diff --git a/modules/pdp10/lib/defines.js b/modules/pdp10/lib/defines.js index e03ff6423a..bfa0df3832 100644 --- a/modules/pdp10/lib/defines.js +++ b/modules/pdp10/lib/defines.js @@ -283,7 +283,7 @@ PDP10.APPNAME = APPNAME; PDP10.DEBUGGER = DEBUGGER; PDP10.SIMH = SIMH; -if (NODE) { +if (typeof module !== "undefined") { global.APPCLASS = APPCLASS; global.APPNAME = APPNAME; global.DEBUGGER = DEBUGGER; diff --git a/modules/pdp10/lib/device.js b/modules/pdp10/lib/device.js index 1b62eb7123..c0a18d189e 100644 --- a/modules/pdp10/lib/device.js +++ b/modules/pdp10/lib/device.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -169,4 +169,4 @@ class DevicePDP10 extends Component { */ Web.onInit(DevicePDP10.init); -if (NODE) module.exports = DevicePDP10; +if (typeof module !== "undefined") module.exports = DevicePDP10; diff --git a/modules/pdp10/lib/macro10.js b/modules/pdp10/lib/macro10.js index b264f6bc0d..cd99f92a9a 100644 --- a/modules/pdp10/lib/macro10.js +++ b/modules/pdp10/lib/macro10.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Debugger = require("../../shared/lib/debugger"); diff --git a/modules/pdp10/lib/memory.js b/modules/pdp10/lib/memory.js index b48e8e6a60..1e87364286 100644 --- a/modules/pdp10/lib/memory.js +++ b/modules/pdp10/lib/memory.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Component = require("../../shared/lib/component"); var PDP10 = require("./defines"); var MessagesPDP10 = require("./messages"); @@ -538,4 +538,4 @@ MemoryPDP10.afnChecked = [ MemoryPDP10.prototype.writeWordChecked ]; -if (NODE) module.exports = MemoryPDP10; +if (typeof module !== "undefined") module.exports = MemoryPDP10; diff --git a/modules/pdp10/lib/messages.js b/modules/pdp10/lib/messages.js index e537b6387b..482392516c 100644 --- a/modules/pdp10/lib/messages.js +++ b/modules/pdp10/lib/messages.js @@ -101,4 +101,4 @@ MessagesPDP10.CATEGORIES = { "halt": MessagesPDP10.HALT }; -if (NODE) module.exports = MessagesPDP10; +if (typeof module !== "undefined") module.exports = MessagesPDP10; diff --git a/modules/pdp10/lib/panel.js b/modules/pdp10/lib/panel.js index 6d0c18a319..fa8a3481da 100644 --- a/modules/pdp10/lib/panel.js +++ b/modules/pdp10/lib/panel.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1245,4 +1245,4 @@ PanelPDP10.SWITCH = { */ Web.onInit(PanelPDP10.init); -if (NODE) module.exports = PanelPDP10; +if (typeof module !== "undefined") module.exports = PanelPDP10; diff --git a/modules/pdp10/lib/ram.js b/modules/pdp10/lib/ram.js index 142b8a4ff8..7ca616ab96 100644 --- a/modules/pdp10/lib/ram.js +++ b/modules/pdp10/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -331,4 +331,4 @@ class RAMPDP10 extends Component { */ Web.onInit(RAMPDP10.init); -if (NODE) module.exports = RAMPDP10; +if (typeof module !== "undefined") module.exports = RAMPDP10; diff --git a/modules/pdp10/lib/rom.js b/modules/pdp10/lib/rom.js index 4f85dca9b3..35027f4215 100644 --- a/modules/pdp10/lib/rom.js +++ b/modules/pdp10/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -336,4 +336,4 @@ class ROMPDP10 extends Component { */ Web.onInit(ROMPDP10.init); -if (NODE) module.exports = ROMPDP10; +if (typeof module !== "undefined") module.exports = ROMPDP10; diff --git a/modules/pdp10/lib/serial.js b/modules/pdp10/lib/serial.js index f049dd60a9..c0bcbb4a2d 100644 --- a/modules/pdp10/lib/serial.js +++ b/modules/pdp10/lib/serial.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -659,4 +659,4 @@ class SerialPortPDP10 extends Component { */ Web.onInit(SerialPortPDP10.init); -if (NODE) module.exports = SerialPortPDP10; +if (typeof module !== "undefined") module.exports = SerialPortPDP10; diff --git a/modules/pdp11/lib/bus.js b/modules/pdp11/lib/bus.js index f0afbd9d9e..fece37948d 100644 --- a/modules/pdp11/lib/bus.js +++ b/modules/pdp11/lib/bus.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Component = require("../../shared/lib/component"); @@ -1461,4 +1461,4 @@ BusPDP11.IOController = { } }; -if (NODE) module.exports = BusPDP11; +if (typeof module !== "undefined") module.exports = BusPDP11; diff --git a/modules/pdp11/lib/computer.js b/modules/pdp11/lib/computer.js index b64d13b6de..6a159fc804 100644 --- a/modules/pdp11/lib/computer.js +++ b/modules/pdp11/lib/computer.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -224,8 +224,12 @@ class ComputerPDP11 extends Component { * OVERRIDES everything; it overrides any 'state' Computer parameter AND it disables resume of any saved state in * localStorage (in other words, it prevents fAllowResume from being true, and forcing resume off). */ - var fAllowResume; - var sState = this.getMachineParm('state') || (fAllowResume = true) && parmsComputer['state']; + var fAllowResume = false; + var sState = this.getMachineParm('state'); + if (!sState) { + fAllowResume = true; + sState = parmsComputer['state']; + } if (sState) { this.sStatePath = sStatePath = sState; @@ -256,7 +260,7 @@ class ComputerPDP11 extends Component { this.setReady(); } else { var cmp = this; - Web.getResource(sStatePath, null, true, function doneStateLoad(sURL, sResource, nErrorCode) { + Web.getResource(/** @type {string} */ (sStatePath), null, true, function doneStateLoad(sURL, sResource, nErrorCode) { cmp.finishStateLoad(sURL, sResource, nErrorCode); }); } @@ -1679,4 +1683,4 @@ Web.onInit(ComputerPDP11.init); Web.onShow(ComputerPDP11.show); Web.onExit(ComputerPDP11.exit); -if (NODE) module.exports = ComputerPDP11; +if (typeof module !== "undefined") module.exports = ComputerPDP11; diff --git a/modules/pdp11/lib/cpu.js b/modules/pdp11/lib/cpu.js index 6ccfc0de95..99f03934f3 100644 --- a/modules/pdp11/lib/cpu.js +++ b/modules/pdp11/lib/cpu.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); var MessagesPDP11 = require("./messages"); @@ -1232,4 +1232,4 @@ CPUPDP11.YIELDS_PER_STATUS = 15; // every 15 yields (ie, twice pe CPUPDP11.BUTTONS = ["power", "reset"]; -if (NODE) module.exports = CPUPDP11; +if (typeof module !== "undefined") module.exports = CPUPDP11; diff --git a/modules/pdp11/lib/cpuops.js b/modules/pdp11/lib/cpuops.js index 0c83906682..dca3f0ba99 100644 --- a/modules/pdp11/lib/cpuops.js +++ b/modules/pdp11/lib/cpuops.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var PDP11 = require("./defines"); } diff --git a/modules/pdp11/lib/cpustate.js b/modules/pdp11/lib/cpustate.js index e9605316c4..600847657b 100644 --- a/modules/pdp11/lib/cpustate.js +++ b/modules/pdp11/lib/cpustate.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -3089,4 +3089,4 @@ class CPUStatePDP11 extends CPUPDP11 { */ Web.onInit(CPUStatePDP11.init); -if (NODE) module.exports = CPUStatePDP11; +if (typeof module !== "undefined") module.exports = CPUStatePDP11; diff --git a/modules/pdp11/lib/debugger.js b/modules/pdp11/lib/debugger.js index ffa4271482..1adb0bbe23 100644 --- a/modules/pdp11/lib/debugger.js +++ b/modules/pdp11/lib/debugger.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Usr = require("../../shared/lib/usrlib"); var Web = require("../../shared/lib/weblib"); @@ -4336,4 +4336,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = DebuggerPDP11; +if (typeof module !== "undefined") module.exports = DebuggerPDP11; diff --git a/modules/pdp11/lib/defines.js b/modules/pdp11/lib/defines.js index 5dbffececd..e1935258d8 100644 --- a/modules/pdp11/lib/defines.js +++ b/modules/pdp11/lib/defines.js @@ -994,7 +994,7 @@ PDP11.TYPEDARRAYS = TYPEDARRAYS; PDP11.MEMFAULT = MEMFAULT; PDP11.WORDBUS = WORDBUS; -if (NODE) { +if (typeof module !== "undefined") { global.APPCLASS = APPCLASS; global.APPNAME = APPNAME; global.DEBUGGER = DEBUGGER; diff --git a/modules/pdp11/lib/device.js b/modules/pdp11/lib/device.js index 5f83c58d25..009f5d0168 100644 --- a/modules/pdp11/lib/device.js +++ b/modules/pdp11/lib/device.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1268,4 +1268,4 @@ DevicePDP11.UNIBUS_IOTABLE = { */ Web.onInit(DevicePDP11.init); -if (NODE) module.exports = DevicePDP11; +if (typeof module !== "undefined") module.exports = DevicePDP11; diff --git a/modules/pdp11/lib/disk.js b/modules/pdp11/lib/disk.js index cf6503b64e..3614598fc0 100644 --- a/modules/pdp11/lib/disk.js +++ b/modules/pdp11/lib/disk.js @@ -45,7 +45,7 @@ * to further reduce some of the duplication between them, but the above functionality is a good start. */ -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DiskAPI = require("../../shared/lib/diskapi"); @@ -1242,4 +1242,4 @@ class DiskPDP11 extends Component { */ DiskPDP11.nDisks = 0; -if (NODE) module.exports = DiskPDP11; +if (typeof module !== "undefined") module.exports = DiskPDP11; diff --git a/modules/pdp11/lib/drive.js b/modules/pdp11/lib/drive.js index 184b0b7faf..3491393541 100644 --- a/modules/pdp11/lib/drive.js +++ b/modules/pdp11/lib/drive.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DiskAPI = require("../../shared/lib/diskapi"); @@ -1362,4 +1362,4 @@ DriveController.SOURCE = { REMOTE: "??" }; -if (NODE) module.exports = DriveController; +if (typeof module !== "undefined") module.exports = DriveController; diff --git a/modules/pdp11/lib/keyboard.js b/modules/pdp11/lib/keyboard.js index 4b6339356c..756b1b406f 100644 --- a/modules/pdp11/lib/keyboard.js +++ b/modules/pdp11/lib/keyboard.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); var PDP11 = require("./defines"); @@ -106,4 +106,4 @@ KeyboardPDP11.MINPRESSTIME = 100; // 100ms */ Web.onInit(KeyboardPDP11.init); -if (NODE) module.exports = KeyboardPDP11; +if (typeof module !== "undefined") module.exports = KeyboardPDP11; diff --git a/modules/pdp11/lib/memory.js b/modules/pdp11/lib/memory.js index beb94af091..ce0726c951 100644 --- a/modules/pdp11/lib/memory.js +++ b/modules/pdp11/lib/memory.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Component = require("../../shared/lib/component"); var PDP11 = require("./defines"); var MessagesPDP11 = require("./messages"); @@ -1014,4 +1014,4 @@ var littleEndian = (TYPEDARRAYS? (function() { return new Uint16Array(buffer)[0] === 256; })() : false); -if (NODE) module.exports = MemoryPDP11; +if (typeof module !== "undefined") module.exports = MemoryPDP11; diff --git a/modules/pdp11/lib/messages.js b/modules/pdp11/lib/messages.js index 28dc64b025..0e9a7b782a 100644 --- a/modules/pdp11/lib/messages.js +++ b/modules/pdp11/lib/messages.js @@ -113,4 +113,4 @@ MessagesPDP11.CATEGORIES = { "halt": MessagesPDP11.HALT }; -if (NODE) module.exports = MessagesPDP11; +if (typeof module !== "undefined") module.exports = MessagesPDP11; diff --git a/modules/pdp11/lib/panel.js b/modules/pdp11/lib/panel.js index ea43977111..33807afc34 100644 --- a/modules/pdp11/lib/panel.js +++ b/modules/pdp11/lib/panel.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -1338,4 +1338,4 @@ PanelPDP11.UNIBUS_IOTABLE = { */ Web.onInit(PanelPDP11.init); -if (NODE) module.exports = PanelPDP11; +if (typeof module !== "undefined") module.exports = PanelPDP11; diff --git a/modules/pdp11/lib/pc11.js b/modules/pdp11/lib/pc11.js index bc25d0b74f..a61bfaf48f 100644 --- a/modules/pdp11/lib/pc11.js +++ b/modules/pdp11/lib/pc11.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -1021,4 +1021,4 @@ PC11.UNIBUS_IOTABLE = { [PDP11.UNIBUS.PPB]: /* 177556 */ [null, null, PC11.prototype.readPPB, PC11.prototype.writePPB, "PPB"] }; -if (NODE) module.exports = PC11; +if (typeof module !== "undefined") module.exports = PC11; diff --git a/modules/pdp11/lib/ram.js b/modules/pdp11/lib/ram.js index 49218762ca..99f4ea5f36 100644 --- a/modules/pdp11/lib/ram.js +++ b/modules/pdp11/lib/ram.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -417,4 +417,4 @@ class RAMPDP11 extends Component { */ Web.onInit(RAMPDP11.init); -if (NODE) module.exports = RAMPDP11; +if (typeof module !== "undefined") module.exports = RAMPDP11; diff --git a/modules/pdp11/lib/rk11.js b/modules/pdp11/lib/rk11.js index 779c9d038c..cd8d5cef72 100644 --- a/modules/pdp11/lib/rk11.js +++ b/modules/pdp11/lib/rk11.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var PDP11 = require("./defines"); var MessagesPDP11 = require("./messages"); @@ -620,4 +620,4 @@ RK11.UNIBUS_IOTABLE = { [PDP11.UNIBUS.RKDB]: /* 177416 */ [null, null, RK11.prototype.readRKDB, RK11.prototype.writeRKDB, "RKDB"] }; -if (NODE) module.exports = RK11; +if (typeof module !== "undefined") module.exports = RK11; diff --git a/modules/pdp11/lib/rl11.js b/modules/pdp11/lib/rl11.js index 85e1fb0867..e0d831e038 100644 --- a/modules/pdp11/lib/rl11.js +++ b/modules/pdp11/lib/rl11.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var PDP11 = require("./defines"); var MessagesPDP11 = require("./messages"); @@ -557,4 +557,4 @@ RL11.UNIBUS_IOTABLE = { [PDP11.UNIBUS.RLBE]: /* 174410 */ [null, null, RL11.prototype.readRLBE, RL11.prototype.writeRLBE, "RLBE"] }; -if (NODE) module.exports = RL11; +if (typeof module !== "undefined") module.exports = RL11; diff --git a/modules/pdp11/lib/rom.js b/modules/pdp11/lib/rom.js index d2ddab6921..8a7889452d 100644 --- a/modules/pdp11/lib/rom.js +++ b/modules/pdp11/lib/rom.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var DumpAPI = require("../../shared/lib/dumpapi"); @@ -387,4 +387,4 @@ class ROMPDP11 extends Component { */ Web.onInit(ROMPDP11.init); -if (NODE) module.exports = ROMPDP11; +if (typeof module !== "undefined") module.exports = ROMPDP11; diff --git a/modules/pdp11/lib/rx11.js b/modules/pdp11/lib/rx11.js index 8611de1bc1..f41ff10c08 100644 --- a/modules/pdp11/lib/rx11.js +++ b/modules/pdp11/lib/rx11.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var PDP11 = require("./defines"); var MessagesPDP11 = require("./messages"); @@ -590,4 +590,4 @@ RX11.UNIBUS_IOTABLE = { [PDP11.UNIBUS.RXDB]: /* 177172 */ [null, null, RX11.prototype.readRXDB, RX11.prototype.writeRXDB, "RXDB"] }; -if (NODE) module.exports = RX11; +if (typeof module !== "undefined") module.exports = RX11; diff --git a/modules/pdp11/lib/serial.js b/modules/pdp11/lib/serial.js index cff39db347..2ca42a0c3f 100644 --- a/modules/pdp11/lib/serial.js +++ b/modules/pdp11/lib/serial.js @@ -32,7 +32,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); @@ -915,4 +915,4 @@ SerialPortPDP11.UNIBUS_IOTABLE = { */ Web.onInit(SerialPortPDP11.init); -if (NODE) module.exports = SerialPortPDP11; +if (typeof module !== "undefined") module.exports = SerialPortPDP11; diff --git a/modules/shared/lib/component.js b/modules/shared/lib/component.js index eaedc03f2a..081d7a8466 100644 --- a/modules/shared/lib/component.js +++ b/modules/shared/lib/component.js @@ -49,7 +49,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); } @@ -1549,4 +1549,4 @@ if (!Function.prototype.bind) { }; } -if (NODE) module.exports = Component; +if (typeof module !== "undefined") module.exports = Component; diff --git a/modules/shared/lib/debugger.js b/modules/shared/lib/debugger.js index cd456706bb..fb22e639f0 100644 --- a/modules/shared/lib/debugger.js +++ b/modules/shared/lib/debugger.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Component = require("../../shared/lib/component"); } @@ -1354,4 +1354,4 @@ if (DEBUGGER) { } // endif DEBUGGER -if (NODE) module.exports = Debugger; +if (typeof module !== "undefined") module.exports = Debugger; diff --git a/modules/shared/lib/defines.js b/modules/shared/lib/defines.js index 7dab0ae6b6..3e66d18791 100644 --- a/modules/shared/lib/defines.js +++ b/modules/shared/lib/defines.js @@ -111,15 +111,7 @@ var RS232 = { } }; -/* - * NODE should be true if we're running under NodeJS (eg, command-line), false if not (eg, web browser) - */ -var NODE = false; -if (typeof module !== 'undefined') { - NODE = true; -} - -if (NODE) { +if (typeof module !== "undefined") { global.window = false; // provides an alternative "if (typeof window === 'undefined')" (ie, "if (window) ...") global.APPVERSION = APPVERSION; global.XMLVERSION = XMLVERSION; @@ -132,7 +124,6 @@ if (NODE) { global.MAXDEBUG = MAXDEBUG; global.PRIVATE = PRIVATE; global.RS232 = RS232; - global.NODE = NODE; /* * TODO: When we're "required" by Node, should we return anything via module.exports? */ diff --git a/modules/shared/lib/diskapi.js b/modules/shared/lib/diskapi.js index 15e2289f11..9c7726a491 100644 --- a/modules/shared/lib/diskapi.js +++ b/modules/shared/lib/diskapi.js @@ -250,4 +250,4 @@ DiskAPI.ATTR = { ARCHIVE: 0x20 // PC-DOS 2.0 and up }; -if (NODE) module.exports = DiskAPI; +if (typeof module !== "undefined") module.exports = DiskAPI; diff --git a/modules/shared/lib/dumpapi.js b/modules/shared/lib/dumpapi.js index f70888d28c..ef04174f5c 100644 --- a/modules/shared/lib/dumpapi.js +++ b/modules/shared/lib/dumpapi.js @@ -83,4 +83,4 @@ var DumpAPI = { DumpAPI.asDiskCommands = [DumpAPI.QUERY.DIR, DumpAPI.QUERY.DISK, DumpAPI.QUERY.PATH]; DumpAPI.asFileCommands = [DumpAPI.QUERY.FILE]; -if (NODE) module.exports = DumpAPI; +if (typeof module !== "undefined") module.exports = DumpAPI; diff --git a/modules/shared/lib/embed.js b/modules/shared/lib/embed.js index 26e59f0188..b6ef8bed25 100644 --- a/modules/shared/lib/embed.js +++ b/modules/shared/lib/embed.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); diff --git a/modules/shared/lib/int36.js b/modules/shared/lib/int36.js index a0bb8eb708..bb6b145e87 100644 --- a/modules/shared/lib/int36.js +++ b/modules/shared/lib/int36.js @@ -1379,4 +1379,4 @@ Int36.INT_LIMIT = Math.pow(2, 35); // 34,359,738,368 (400000 000000): si Int36.WORD_MASK = Math.pow(2, 36) - 1; // 68,719,476,735 (777777 777777): unsigned word mask Int36.WORD_LIMIT = Math.pow(2, 36); // 68,719,476,736 (1 000000 000000): unsigned word limit -if (NODE) module.exports = Int36; +if (typeof module !== "undefined") module.exports = Int36; diff --git a/modules/shared/lib/keys.js b/modules/shared/lib/keys.js index 8858f4deae..de1df46ccb 100644 --- a/modules/shared/lib/keys.js +++ b/modules/shared/lib/keys.js @@ -269,4 +269,4 @@ Keys.SHIFTED_KEYCODES[Keys.KEYCODE.FF_DASH] = Keys.ASCII['_']; Keys.SHIFTED_KEYCODES[Keys.KEYCODE.FF_EQUALS] = Keys.ASCII['+']; Keys.SHIFTED_KEYCODES[Keys.KEYCODE.FF_SEMI] = Keys.ASCII[':']; -if (NODE) module.exports = Keys; +if (typeof module !== "undefined") module.exports = Keys; diff --git a/modules/shared/lib/netlib.js b/modules/shared/lib/netlib.js index b0a4b0bc28..9663009867 100644 --- a/modules/shared/lib/netlib.js +++ b/modules/shared/lib/netlib.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var fs = require("fs"); var http = require("http"); var path = require("path"); @@ -399,4 +399,4 @@ Net.REVEAL_PDFS = "pdfs"; Net.asPropagate = [Net.GORT_COMMAND, "autostart"]; Net.sServerRoot = null; -if (NODE) module.exports = Net; +if (typeof module !== "undefined") module.exports = Net; diff --git a/modules/shared/lib/proclib.js b/modules/shared/lib/proclib.js index df71976d9e..e8be6547c0 100644 --- a/modules/shared/lib/proclib.js +++ b/modules/shared/lib/proclib.js @@ -86,4 +86,4 @@ class Proc { } } -if (NODE) module.exports = Proc; +if (typeof module !== "undefined") module.exports = Proc; diff --git a/modules/shared/lib/reportapi.js b/modules/shared/lib/reportapi.js index 13049dc59c..2bdc2e2fa4 100644 --- a/modules/shared/lib/reportapi.js +++ b/modules/shared/lib/reportapi.js @@ -46,4 +46,4 @@ var ReportAPI = { } }; -if (NODE) module.exports = ReportAPI; +if (typeof module !== "undefined") module.exports = ReportAPI; diff --git a/modules/shared/lib/save.js b/modules/shared/lib/save.js index 302e57f2c5..34efe38fee 100644 --- a/modules/shared/lib/save.js +++ b/modules/shared/lib/save.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); diff --git a/modules/shared/lib/state.js b/modules/shared/lib/state.js index 24e2146330..9c7e77b3bb 100644 --- a/modules/shared/lib/state.js +++ b/modules/shared/lib/state.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); } @@ -392,4 +392,4 @@ class State { } } -if (NODE) module.exports = State; +if (typeof module !== "undefined") module.exports = State; diff --git a/modules/shared/lib/strlib.js b/modules/shared/lib/strlib.js index 03b6a1a875..d2d40adee7 100644 --- a/modules/shared/lib/strlib.js +++ b/modules/shared/lib/strlib.js @@ -1120,4 +1120,4 @@ Str.HexUpperCase = "0123456789ABCDEF"; Str.NamesOfDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; Str.NamesOfMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; -if (NODE) module.exports = Str; +if (typeof module !== "undefined") module.exports = Str; diff --git a/modules/shared/lib/userapi.js b/modules/shared/lib/userapi.js index 6a91381b7c..788b029fec 100644 --- a/modules/shared/lib/userapi.js +++ b/modules/shared/lib/userapi.js @@ -65,4 +65,4 @@ var UserAPI = { } }; -if (NODE) module.exports = UserAPI; +if (typeof module !== "undefined") module.exports = UserAPI; diff --git a/modules/shared/lib/usrlib.js b/modules/shared/lib/usrlib.js index 46943b6b8c..537df91001 100644 --- a/modules/shared/lib/usrlib.js +++ b/modules/shared/lib/usrlib.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Str = require("../../shared/lib/strlib"); } @@ -282,4 +282,4 @@ Usr.aMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; */ Usr.getTime = Date.now || function() { return +new Date(); }; -if (NODE) module.exports = Usr; +if (typeof module !== "undefined") module.exports = Usr; diff --git a/modules/shared/lib/weblib.js b/modules/shared/lib/weblib.js index 0ad31e718d..170382597b 100644 --- a/modules/shared/lib/weblib.js +++ b/modules/shared/lib/weblib.js @@ -28,7 +28,7 @@ "use strict"; -if (NODE) { +if (typeof module !== "undefined") { var Component = require("../../shared/lib/component"); var ReportAPI = require("../../shared/lib/reportapi"); } @@ -199,7 +199,7 @@ class Web { } let sURLRedirect = sURL; - if (Web.getHost() == "pcjs:8088" || NODE) { + if (Web.getHost() == "pcjs:8088" || typeof module !== "undefined") { /* * The larger resources that I've put on archive.pcjs.org are assumed to also be available locally * whenever the hostname is "pcjs" (or NODE is true); otherwise, use "localhost" when debugging locally. @@ -217,7 +217,7 @@ class Web { sURLRedirect = sURL.replace(/^\/disks-([a-z0-9]+)\//, "https://$1-disks.pcjs.org/"); } - if (NODE) { + if (typeof module !== "undefined") { /* * We don't even need to load Component, because we can't use any of the code below * within Node anyway. Instead, we must hand this request off to our network library. @@ -1203,4 +1203,4 @@ if (DEBUG && window) { } } -if (NODE) module.exports = Web; +if (typeof module !== "undefined") module.exports = Web; diff --git a/package.json b/package.json index cf1dc80115..367971e3f4 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "async": "^0.6.2", "editorconfig": "^0.15.2", "eslint": "^4.19.1", - "google-closure-compiler-js": "^20180506.0.0", - "gulp": "^4.0.0", + "google-closure-compiler": "^20190415.0.0", + "gulp": "^4.0.2", "gulp-concat": "^2.6.1", "gulp-foreach": "^0.1.0", "gulp-header": "^1.8.12", @@ -80,7 +80,7 @@ "merge-stream": "^1.0.1", "replace": "^0.3.0", "serialport": "^6.2.2", - "unzip": "^0.1.9", + "unzip": "^0.1.11", "xml2js": "^0.4.19" } } diff --git a/versions/c1pjs/1.75.2/c1p-uncompiled.js b/versions/c1pjs/1.75.2/c1p-uncompiled.js index 84c2171d56..7805412ebe 100644 --- a/versions/c1pjs/1.75.2/c1p-uncompiled.js +++ b/versions/c1pjs/1.75.2/c1p-uncompiled.js @@ -87,11 +87,6 @@ var RS232 = { } }; -/* - * NODE should be true if we're running under NodeJS (eg, command-line), false if not (eg, web browser) - */ -var NODE = false; - /** * @copyright https://www.pcjs.org/modules/shared/lib/dumpapi.js (C) Jeff Parsons 2012-2019 @@ -153,7 +148,6 @@ DumpAPI.asDiskCommands = [DumpAPI.QUERY.DIR, DumpAPI.QUERY.DISK, DumpAPI.QUERY.P DumpAPI.asFileCommands = [DumpAPI.QUERY.FILE]; - /** * @copyright https://www.pcjs.org/modules/shared/lib/reportapi.js (C) Jeff Parsons 2012-2019 */ @@ -177,7 +171,6 @@ var ReportAPI = { }; - /** * @copyright https://www.pcjs.org/modules/shared/lib/strlib.js (C) Jeff Parsons 2012-2019 */ @@ -1275,7 +1268,6 @@ Str.NamesOfDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Frid Str.NamesOfMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; - /** * @copyright https://www.pcjs.org/modules/shared/lib/usrlib.js (C) Jeff Parsons 2012-2019 */ @@ -1528,7 +1520,6 @@ Usr.aMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; Usr.getTime = Date.now || function() { return +new Date(); }; - /** * @copyright https://www.pcjs.org/modules/shared/lib/weblib.js (C) Jeff Parsons 2012-2019 */ @@ -1700,7 +1691,7 @@ class Web { } let sURLRedirect = sURL; - if (Web.getHost() == "pcjs:8088" || NODE) { + if (Web.getHost() == "pcjs:8088" || typeof module !== "undefined") { /* * The larger resources that I've put on archive.pcjs.org are assumed to also be available locally * whenever the hostname is "pcjs" (or NODE is true); otherwise, use "localhost" when debugging locally. @@ -2695,7 +2686,6 @@ if (DEBUG && window) { } - /** * @copyright https://www.pcjs.org/modules/shared/lib/component.js (C) Jeff Parsons 2012-2019 */ @@ -4220,7 +4210,6 @@ if (!Function.prototype.bind) { } - /** * @copyright https://www.pcjs.org/modules/c1pjs/lib/defines.js (C) Jeff Parsons 2012-2019 */ diff --git a/versions/c1pjs/1.75.2/c1p.js b/versions/c1pjs/1.75.2/c1p.js index d1274f2ff3..c5cdfbe68b 100644 --- a/versions/c1pjs/1.75.2/c1p.js +++ b/versions/c1pjs/1.75.2/c1p.js @@ -19,197 +19,196 @@ https://www.pcjs.org/modules/c1pjs/lib/debugger.js (C) Jeff Parsons 2012-2019 https://www.pcjs.org/modules/c1pjs/lib/computer.js (C) Jeff Parsons 2012-2019 */ -var f,aa="function"==typeof Object.create?Object.create:function(a){function b(){}b.prototype=a;return new b},ba;if("function"==typeof Object.setPrototypeOf)ba=Object.setPrototypeOf;else{var ca;a:{var da={Nb:!0},ea={};try{ea.__proto__=da;ca=ea.Nb;break a}catch(a){}ca=!1}ba=ca?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var fa=ba; -function t(a,b){a.prototype=aa(b.prototype);a.prototype.constructor=a;if(fa)fa(a,b);else for(var c in b)if("prototype"!=c)if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.We=b.prototype}var ha="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)},u="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this; -function ja(){ja=function(){};u.Symbol||(u.Symbol=ka)}var ka=function(){var a=0;return function(b){return"jscomp_symbol_"+(b||"")+a++}}();function la(){ja();var a=u.Symbol.iterator;a||(a=u.Symbol.iterator=u.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&ha(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ma(this)}});la=function(){}}function ma(a){var b=0;return na(function(){return ba?-b:b}});qa("Number.parseInt",function(a){return a||parseInt});function ra(){} -function v(a,b,c){b?9=b?4:4294967295>=b?8:9);c=c?"0x":"";var d=void 0===d?0:d;var e="";isNaN(a)||"number"!=typeof a?a=null:(0>a&&-1a&&(a+=Math.pow(16,b)),a>=Math.pow(16,b)&&(b=Math.ceil(Math.log(a)/Math.log(16))));for(var g=d||-1;0=l?48:55;e=String.fromCharCode(l)+e;a=Math.trunc(a/16)}g--}return(void 0===c?"":c)+e}function w(a){return v(a,2,!0)}function x(a){return v(a,4,!0)} -function sa(a){var b=a,c=a.lastIndexOf("/");0<=c&&(b=a.substr(c+1));c=b.indexOf("\x26");0"'$]/g,function(a){return va[a]})} -function wa(a){for(var b=[],c=0;ch)d+="%"+e[l+1]+e[l+2]+e[l+3]+e[l+4]+k;else{if(gh&&"object"!=typeof m?wa(m):m;switch(k){case "C":m=q?"#":"";d+=isNaN(h.getTime())?void 0:y(y("%%%sW, %%%sF %%%sD, %%%sY",m),h);continue;case "D":m=q?h.getUTCDate():h.getDate();k="d";break;case "A":case "H":case "I":m=q?h.getUTCHours():h.getHours();"A"==k?(m=12>m?"am":"pm",k="s"):("I"==k&&(m=m?12m&&p--,k=("0000000000"+Math.abs(m)).slice(-p),0>m&&(k="-"+k)):k=(" "+k).slice(-p));0>>=16==Y?4:3,0<=n.indexOf("0")||""==k||q||m?k=ia[q]+k:p&&(G?(k=G.slice(-1)+k,G=G.slice(0,-1)):k=" "+k);while(0<--p||m);d+=r+k;break;case "%":d+="%";break;default:d+="(unimplemented printf type %"+k+")"}}}return d+=e[l]} -var va={"\x26":"\x26amp;","\x3c":"\x26lt;","\x3e":"\x26gt;",'"':"\x26quot;","'":"\x26apos;",$:"\x26dollar;"},Aa="0123456789abcdef",za="0123456789ABCDEF",ya="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),xa="January February March April May June July August September October November December".split(" "),Ba=Date.now||function(){return+new Date}; -function z(a,b){var c=null,d=!0;c=void 0===c?"text":c;d=void 0===d?!1:d;var e=0,g=null;if("object"==typeof resources&&(g=resources[a]))b&&b(a,g,e);else if(d&&"function"==typeof resources)resources(a,function(c,d){b&&b(a,c,d)});else{var l=a;"pcjs:8088"==(window?window.location.host:"localhost")?(l=a.replace(/^(http:\/\/archive\.pcjs\.org\/|https:\/\/[a-z0-9-]+\.amazonaws\.com\/archive\.pcjs\.org\/)([^/]*)\/(.*?)\/([^/]*)$/,"/$2-demo/$3/archive/$4"),l=l.replace(/^https:\/\/([a-z0-9]+)-disks\.pcjs\.org\/(.*)$/, -"/disks-$1/$2")):l=a.replace(/^\/disks-([a-z0-9]+)\//,"https://$1-disks.pcjs.org/");var k=window.XMLHttpRequest?new window.XMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP"),h=!1,m="string"===typeof k.responseType,n=function(){if(4!==k.readyState)return null;try{g=h?k.response:k.responseText}catch(q){}if(null==g||200!=k.status&&(k.status||!g.length||"file:"!=(window?window.location.protocol:"file:")))if(e=k.status||-1,!k.status&&!Ca){var c=l.match(/(^https?:\/\/[^/]+)(.*)/);c&&(Ca=!0,A("PCjs was unable to perform a cross-origin resource request to '"+ -c[1]+"'.\n\nIf you're running an ad blocker, try adding '"+Da()+"' to your whitelist (or find a smarter ad blocker)."))}b&&b(a,g,e);return[g,e]};d&&(k.onreadystatechange=n);if(c&&"object"==typeof c){m="";for(var p in c)c.hasOwnProperty(p)&&(m&&(m+="\x26"),m+=p+"\x3d"+encodeURIComponent(c[p]));m=m.replace(/%20/g,"+");k.open("POST",l,d);k.setRequestHeader("Content-type","application/x-www-form-urlencoded");k.send(m)}else k.open("GET",l,d),"arraybuffer"==c&&(m?(h=!0,k.responseType=c):k.overrideMimeType("text/plain; charset\x3dx-user-defined")), -k.send();d||(k.readyState=4,n())}}function Da(){return window?window.location.protocol+"//"+window.location.host:"https://www.pcjs.org"}function B(a){if(window){var b=window?window.navigator.userAgent:"";return"iOS"==a&&!!b.match(/(iPod|iPhone|iPad)/)&&!!b.match(/AppleWebKit/)||"MSIE"==a&&!!b.match(/(MSIE|Trident)/)||0<=b.indexOf(a)}return!1}function Ea(){var a,b=Fa("mobile");if(b)return"true"==b;if(B("Mobi")){if(!a)return!0;(b="!"==a[0])&&(a=a.substr(1));return B(a)!=b}return!1} -function Fa(a){if(!Ga){var b,c={};if(window){b||(b=window.location.search.substr(1));for(var d,e=/\+/g,g=/([^&=]+)=?([^&]*)/g;d=g.exec(b);)c[decodeURIComponent(d[1].replace(e," "))]=decodeURIComponent(d[2].replace(e," "))}Ga=c}return Ga[a]||Ga[a.toLowerCase()]}function Ha(a,b,c){function d(){--a;0<=a&&(b()||(a=0));0a?this.eb="PCjs":this.eb=this.id.substr(0,a);this.D={ready:!1,Ka:!1,ab:!1,Ve:!1,N:!1,Oe:!1,error:!1};this.cb=null;this.D.error=!1;this.ma=c||0;this.v=this.u=this.U=null;F.push(this)}function A(a){window&&window.alert(a)} -function Qa(a,b){a.value+=b;b=a.value;8192d?c+=a+"\n":c=c.substr(0,d)+(a+".")+ -c.substr(d+a.length);8192b?-c:c}});ma("Number.parseInt",function(a){return a||parseInt});function na(){} +function u(a,b,c){b?9=b?4:4294967295>=b?8:9);c=c?"0x":"";var d=void 0===d?0:d;var e="";isNaN(a)||"number"!=typeof a?a=null:(0>a&&-1a&&(a+=Math.pow(16,b)),a>=Math.pow(16,b)&&(b=Math.ceil(Math.log(a)/Math.log(16))));for(var g=d||-1;0=h?48:55;e=String.fromCharCode(h)+e;a=Math.trunc(a/16)}g--}return(void 0===c?"":c)+e}function v(a){return u(a,2,!0)}function z(a){return u(a,4,!0)} +function oa(a){var b=a,c=a.lastIndexOf("/");0<=c&&(b=a.substr(c+1));c=b.indexOf("&");0"'$]/g,function(b){return ra[b]})} +function ta(a){for(var b=[],c=0;ck)d+="%"+e[h+1]+e[h+2]+e[h+3]+e[h+4]+l;else{if(gk&&"object"!=typeof m?ta(m):m;switch(l){case "C":m=q?"#":"";d+=isNaN(k.getTime())?void 0:A(A("%%%sW, %%%sF %%%sD, %%%sY",m),k);continue;case "D":m=q?k.getUTCDate():k.getDate();l="d";break;case "A":case "H":case "I":m=q?k.getUTCHours():k.getHours();"A"==l?(m=12>m?"am":"pm",l="s"):("I"==l&&(m=m?12m&&p--,l=("0000000000"+Math.abs(m)).slice(-p),0>m&&(l="-"+l)):l=(" "+l).slice(-p));0>>=16==y?4:3,0<=n.indexOf("0")||""==l||q||m?l=x[q]+l:p&&(w?(l=w.slice(-1)+l,w=w.slice(0,-1)):l=" "+l);while(0<--p||m);d+=r+l;break;case "%":d+="%";break;default:d+="(unimplemented printf type %"+l+")"}}}return d+=e[h]} +var ra={"&":"&","<":"<",">":">",'"':""","'":"'",$:"$"},xa="0123456789abcdef",wa="0123456789ABCDEF",va="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ua="January February March April May June July August September October November December".split(" "),ya=Date.now||function(){return+new Date}; +function B(a,b){var c=null,d=!0;c=void 0===c?"text":c;d=void 0===d?!1:d;var e=0,g=null;if("object"==typeof resources&&(g=resources[a]))b&&b(a,g,e);else if(d&&"function"==typeof resources)resources(a,function(r,q){b&&b(a,r,q)});else{var h=a;"pcjs:8088"==(window?window.location.host:"localhost")||"undefined"!==typeof module?(h=a.replace(/^(http:\/\/archive\.pcjs\.org\/|https:\/\/[a-z0-9-]+\.amazonaws\.com\/archive\.pcjs\.org\/)([^/]*)\/(.*?)\/([^/]*)$/,"/$2-demo/$3/archive/$4"),h=h.replace(/^https:\/\/([a-z0-9]+)-disks\.pcjs\.org\/(.*)$/, +"/disks-$1/$2")):h=a.replace(/^\/disks-([a-z0-9]+)\//,"https://$1-disks.pcjs.org/");var l=window.XMLHttpRequest?new window.XMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP"),k=!1,m="string"===typeof l.responseType,n=function(){if(4!==l.readyState)return null;try{g=k?l.response:l.responseText}catch(q){}if(null==g||200!=l.status&&(l.status||!g.length||"file:"!=(window?window.location.protocol:"file:")))if(e=l.status||-1,!l.status&&!za){var r=h.match(/(^https?:\/\/[^/]+)(.*)/);r&&(za=!0,C("PCjs was unable to perform a cross-origin resource request to '"+ +r[1]+"'.\n\nIf you're running an ad blocker, try adding '"+Aa()+"' to your whitelist (or find a smarter ad blocker)."))}b&&b(a,g,e);return[g,e]};d&&(l.onreadystatechange=n);if(c&&"object"==typeof c){m="";for(var p in c)c.hasOwnProperty(p)&&(m&&(m+="&"),m+=p+"="+encodeURIComponent(c[p]));m=m.replace(/%20/g,"+");l.open("POST",h,d);l.setRequestHeader("Content-type","application/x-www-form-urlencoded");l.send(m)}else l.open("GET",h,d),"arraybuffer"==c&&(m?(k=!0,l.responseType=c):l.overrideMimeType("text/plain; charset=x-user-defined")), +l.send();d||(l.readyState=4,n())}}function Aa(){return window?window.location.protocol+"//"+window.location.host:"https://www.pcjs.org"}function D(a){if(window){var b=window?window.navigator.userAgent:"";return"iOS"==a&&!!b.match(/(iPod|iPhone|iPad)/)&&!!b.match(/AppleWebKit/)||"MSIE"==a&&!!b.match(/(MSIE|Trident)/)||0<=b.indexOf(a)}return!1}function Ba(){var a,b=Ca("mobile");if(b)return"true"==b;if(D("Mobi")){if(!a)return!0;(b="!"==a[0])&&(a=a.substr(1));return D(a)!=b}return!1} +function Ca(a){if(!Da){var b,c={};if(window){b||(b=window.location.search.substr(1));for(var d,e=/\+/g,g=/([^&=]+)=?([^&]*)/g;d=g.exec(b);)c[decodeURIComponent(d[1].replace(e," "))]=decodeURIComponent(d[2].replace(e," "))}Da=c}return Da[a]||Da[a.toLowerCase()]}function Ea(a,b,c){function d(){--a;0<=a&&(b()||(a=0));0a?this.eb="PCjs":this.eb=this.id.substr(0,a);this.D={ready:!1,Ka:!1,ab:!1,Ue:!1,N:!1,Ne:!1,error:!1};this.cb=null;this.D.error=!1;this.ma=c||0;this.v=this.u=this.U=null;H.push(this)}function C(a){window&&window.alert(a)} +function Na(a,b){a.value+=b;b=a.value;8192l?h+(g+"\n"):h.substr(0,l)+(g+".")+ +h.substr(l+g.length);8192hb(a.O,b,c,d,e)&&(a.qa>b&&(a.qa=b),a.ra=a.O[d][0]&&b<=a.O[d][1]&&a.O[d][3].call(a.O[d][2],b,c)}function P(a,b,c,d,e){0>hb(a.I,b,c,d,e)&&(a.fa>b&&(a.fa=b),a.ga=a.I[d][0]&&b<=a.I[d][1]&&a.I[d][3].call(a.I[d][2],b,c)}function hb(a,b,c,d,e){for(var g=0;ga.Qa&&a.M&&(d=a.M);d>a.Ia&&2>a.speed&&(d=a.Ia);a.jb=Math.round(1E3/30);a.ka=Math.floor(1E6/c*d);a.ta=Math.floor(1E6/30*d);a.Ya=Math.floor(1E6/a.Ea*d);a.Xa=Math.floor(1E6/a.Da*d);b||(a.R=a.ta,a.Y=a.Ya,a.W=a.Xa);a.Ca=0} -function nb(a){var b=Ba(),c=a.jb;a.Z&&(c=Math.round(c*a.Z/a.ta));c-=b-a.kb;if(b-=a.Wa)a.M=Math.round(a.V/(100*b))/10,864E5<=b&&O(a);0>c?c=0:1==a.speed?a.M<=a.Ia&&(c=0):2==a.speed&&(c=0);a.Ca+=a.Z;return c} -f.va=function(){if(L(this,!0)){this.D.oa||(O(this),this.U&&this.U.start(),this.D.oa=!0,this.H.run&&(this.H.run.innerHTML="Halt"),this.da());1E6<=this.Ca&&kb(this,!0);this.Z=0;this.kb=Ba();try{do{this.step(this.ka);var a=this.L-this.C;this.V+=a;this.Z+=a;this.L=this.C=0;this.Y-=this.ka;0>=this.Y&&(this.Y+=this.Ya,this.bb());this.W-=this.ka;0>=this.W&&(this.W+=this.Xa,lb(this));this.R-=this.ka;if(0>=this.R){this.R+=this.ta;break}}while(this.D.oa)}catch(b){this.ba();this.update();L(this,!1);Za(this, -b.stack||b.message);return}setTimeout(function(a){return function(){a.va()}}(this),nb(this))}else this.update(),this.U&&this.U.stop(this.Wa,this.V)}; -f.step=function(a){var b=!0;this.b=this.g=-1;var c;if(c=a&&this.v)c=this.v,c=0=d.xa.length&&(d.La=0));d=!!g}if(d){b=void 0;this.ba();break}this.f++;this.m[a].call(this);if(0<=this.b){this.b>=this.qa&&this.b<=this.ra&&ib(this,this.b,this.f);if(d=c)d=this.v,e=!1,ob(d,this.b,d.wa,"read")&&(e=!0),d=!!e;if(d){b=!1;this.ba(); -break}this.b=-1}else if(0<=this.g){this.g>=this.fa&&this.g<=this.ga&&jb(this,this.g,this.f);if(d=c){d=this.v;e=this.g;g=this.a[this.g];var l=!1;(g&255)!=g&&(d.l("invalid value at "+x(e)+": "+g),l=!0);ob(d,e,d.ya,"write")&&(l=!0);d=!!l}if(d){b=!1;this.ba();break}this.g=-1}this.C-=this.hb[a]}while(0>1)&128?64:0;b|=a.i&128?128:0;return a.B&60|b}function rb(a){a.B|=8;a.m[97]=a.Xb;a.m[101]=a.Zb;a.m[105]=a.Wb;a.m[109]=a.Tb;a.m[113]=a.Yb;a.m[117]=a.$b;a.m[121]=a.Vb;a.m[125]=a.Ub;a.m[225]=a.me;a.m[229]=a.oe;a.m[233]=a.le;a.m[237]=a.ie;a.m[241]=a.ne;a.m[245]=a.pe;a.m[249]=a.ke;a.m[253]=a.je} -function sb(a){a.B&=-9;a.m[97]=a.sb;a.m[101]=a.ub;a.m[105]=a.rb;a.m[109]=a.ob;a.m[113]=a.tb;a.m[117]=a.vb;a.m[121]=a.qb;a.m[125]=a.pb;a.m[225]=a.Ab;a.m[229]=a.Cb;a.m[233]=a.zb;a.m[237]=a.wb;a.m[241]=a.Bb;a.m[245]=a.Db;a.m[249]=a.yb;a.m[253]=a.xb}function R(a,b,c){var d=a.c&256?1:0,e=(b&15)+(c&15)+d;10<=e&&(e=e+6&15|16);e+=(b&240)+(c&240);a.w=b^c;a.s=e;a.i=e&255;160<=e&&(e+=96);512<=e&&(e-=256);a.c=e;a.j=b+c+d&255;a.C--;return e&255} -function S(a,b,c){var d=a.c&256?0:1,e=(b&15)-(c&15)-d;0>e&&(e=(e-6&15)-16);e+=(b&240)-(c&240);0>e&&(e-=96);a.i=a.j=(a.c=b-c-d)&255;a.w=b^c;a.s=a.c;a.c^=256;a.C--;return e&255}function eb(a){a.h=0;a.A=0;a.F=0;a.G=256;a.B=0;a.i=0;a.j=0;a.w=0;a.s=0;a.c=0;a.f=0;a.b=-1;a.g=-1;a.M=0;a.V=a.L=a.C=0} -f.vc=function(){this.f++;this.a[this.G--]=this.f>>8;this.G|=256;this.a[this.G--]=this.f&255;this.G|=256;this.B|=16;this.B=mb(this);this.a[this.G--]=this.B;this.G|=256;this.B&=239;this.b=65534;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.Pd=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h|=this.a[this.b]};f.Rd=function(){this.b=this.a[this.f++];this.i=this.j=this.h|=this.a[this.b]}; -f.lc=function(){this.g=this.a[this.f++];this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.Ud=function(){this.B=mb(this);this.a[this.G--]=this.B;this.G|=256};f.Od=function(){this.b=this.f++;this.i=this.j=this.h|=this.a[this.b]};f.kc=function(){this.c=this.h<<1;this.i=this.j=this.h=this.c&255};f.Ld=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h|=this.a[this.b]}; -f.ic=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.uc=function(){this.f+=(this.i&128?0:(this.C--,this.a[this.f]<<24>>24))+1};f.Qd=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h|=this.a[this.b]};f.Sd=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h|=this.a[this.b]}; -f.mc=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.yc=function(){this.c=0};f.Nd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h|=this.a[this.b]};f.Md=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h|=this.a[this.b]};f.jc=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255}; -f.md=function(){this.b=this.f++;this.a[this.G--]=this.f>>8;this.G|=256;this.a[this.G--]=this.f&255;this.G|=256;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.ec=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h&=this.a[this.b]};f.rc=function(){this.b=this.a[this.f++];this.j=this.h&this.a[this.b];this.i=this.i&127|this.a[this.b]&128;this.s=0;this.w=this.a[this.b]&64?128:0};f.gc=function(){this.b=this.a[this.f++];this.i=this.j=this.h&=this.a[this.b]}; -f.$d=function(){this.g=this.a[this.f++];this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.Wd=function(){this.G=this.G+1&255|256;this.B=this.a[this.G];this.c=this.B&1?256:0;this.j=this.B&2?0:1;this.i=this.B&128;this.s=0;this.w=this.B&64?128:0};f.dc=function(){this.b=this.f++;this.i=this.j=this.h&=this.a[this.b]}; -f.Zd=function(){this.c=this.c&65280|this.h;this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.h=this.c&255};f.qc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.j=this.h&this.a[this.b];this.i=this.i&127|this.a[this.b]&128;this.s=0;this.w=this.a[this.b]&64?128:0};f.ac=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h&=this.a[this.b]}; -f.Xd=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.sc=function(){this.f+=(this.i&128?(this.C--,this.a[this.f]<<24>>24):0)+1};f.fc=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h&=this.a[this.b]};f.hc=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h&=this.a[this.b]}; -f.ae=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.qe=function(){this.c=256};f.cc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h&=this.a[this.b]};f.bc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h&=this.a[this.b]}; -f.Yd=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.ge=function(){this.G=this.G+1&255|256;this.B=this.a[this.G];this.c=this.B&1?256:0;this.j=this.B&2?0:1;this.i=this.B&128;this.s=0;this.w=this.B&64?128:0;this.G=this.G+2&255|256;this.f=this.a[this.G-1|256]|this.a[this.G]<<8}; -f.$c=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h^=this.a[this.b]};f.bd=function(){this.b=this.a[this.f++];this.i=this.j=this.h^=this.a[this.b]};f.Id=function(){this.g=this.a[this.f++];this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255};f.Td=function(){this.a[this.G--]=this.h;this.G|=256};f.Zc=function(){this.b=this.f++;this.i=this.j=this.h^=this.a[this.b]}; -f.Hd=function(){this.c=this.c&65279|(this.h&1?256:0);this.h=(this.c=this.c&65280|this.h>>1)&255;this.i=this.j=this.c&255};f.ld=function(){this.b=this.f;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.Wc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h^=this.a[this.b]};f.Fd=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; -f.wc=function(){this.f+=((this.s&255^this.w^this.s>>1)&128?0:(this.C--,this.a[this.f]<<24>>24))+1};f.ad=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h^=this.a[this.b]};f.cd=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h^=this.a[this.b]};f.Jd=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; -f.Ac=function(){this.B&=251};f.Yc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h^=this.a[this.b]};f.Xc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h^=this.a[this.b]};f.Gd=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; -f.he=function(){this.G=this.G+2&255|256;this.f=(this.a[this.G-1|256]|this.a[this.G]<<8)+1};f.sb=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Xb=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.h=R(this,this.h,this.a[this.b])}; -f.ub=function(){this.b=this.a[this.f++];this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Zb=function(){this.b=this.a[this.f++];this.h=R(this,this.h,this.a[this.b])};f.ee=function(){this.g=this.a[this.f++];this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.Vd=function(){this.G=this.G+1&255|256;this.i=this.j=this.h=this.a[this.G]}; -f.rb=function(){this.b=this.f++;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Wb=function(){this.b=this.f++;this.h=R(this,this.h,this.a[this.b])};f.de=function(){this.c=this.c&65280|this.h;this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.h=this.c&255};f.kd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.f=this.a[this.b]|this.a[this.b+1]<<8}; -f.ob=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Tb=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.h=R(this,this.h,this.a[this.b])};f.be=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255}; -f.xc=function(){this.f+=((this.s&255^this.w^this.s>>1)&128?(this.C--,this.a[this.f]<<24>>24):0)+1};f.tb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Yb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.h=R(this,this.h,this.a[this.b])}; -f.vb=function(){this.b=this.a[this.f++]+this.A&255;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.$b=function(){this.b=this.a[this.f++]+this.A&255;this.h=R(this,this.h,this.a[this.b])};f.fe=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.se=function(){this.B|=4}; -f.qb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Vb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.h=R(this,this.h,this.a[this.b])};f.pb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255}; -f.Ub=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.h=R(this,this.h,this.a[this.b])};f.ce=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.we=function(){this.g=this.a[this.f++]+this.A&255;this.g=this.a[this.g]|this.a[this.g+1]<<8;this.a[this.g]=this.h};f.Ee=function(){this.g=this.a[this.f++];this.a[this.g]=this.F}; -f.ye=function(){this.g=this.a[this.f++];this.a[this.g]=this.h};f.Be=function(){this.g=this.a[this.f++];this.a[this.g]=this.A};f.Vc=function(){this.i=this.j=this.F=this.F-1&255};f.Ke=function(){this.i=this.j=this.h=this.A};f.De=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.F};f.te=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.h};f.Ae=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.A}; -f.nc=function(){this.f+=(this.c&256?0:(this.C--,this.a[this.f]<<24>>24))+1};f.xe=function(){this.g=this.a[this.f++];this.g=(this.a[this.g]|this.a[this.g+1]<<8)+this.F;this.a[this.g]=this.h};f.Fe=function(){this.g=this.a[this.f++]+this.A&255;this.a[this.g]=this.F};f.ze=function(){this.g=this.a[this.f++]+this.A&255;this.a[this.g]=this.h};f.Ce=function(){this.g=this.a[this.f++]+this.F&255;this.a[this.g]=this.A};f.Me=function(){this.i=this.j=this.h=this.F}; -f.ve=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.a[this.g]=this.h};f.Le=function(){this.G=this.A|256};f.ue=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.a[this.g]=this.h};f.Cd=function(){this.b=this.f++;this.i=this.j=this.F=this.a[this.b]};f.rd=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h=this.a[this.b]};f.xd=function(){this.b=this.f++;this.i=this.j=this.A=this.a[this.b]}; -f.Dd=function(){this.b=this.a[this.f++];this.i=this.j=this.F=this.a[this.b]};f.td=function(){this.b=this.a[this.f++];this.i=this.j=this.h=this.a[this.b]};f.yd=function(){this.b=this.a[this.f++];this.i=this.j=this.A=this.a[this.b]};f.Ie=function(){this.i=this.j=this.F=this.h};f.qd=function(){this.b=this.f++;this.i=this.j=this.h=this.a[this.b]};f.He=function(){this.i=this.j=this.A=this.h};f.Ad=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.F=this.a[this.b]}; -f.nd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h=this.a[this.b]};f.vd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.A=this.a[this.b]};f.oc=function(){this.f+=(this.c&256?(this.C--,this.a[this.f]<<24>>24):0)+1};f.sd=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h=this.a[this.b]};f.Ed=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.F=this.a[this.b]}; -f.ud=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h=this.a[this.b]};f.zd=function(){this.b=this.a[this.f++]+this.F&255;this.i=this.j=this.A=this.a[this.b]};f.Bc=function(){this.w=this.s=0};f.pd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h=this.a[this.b]};f.Je=function(){this.i=this.j=this.A=this.G&255};f.Bd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.F=this.a[this.b]}; -f.od=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h=this.a[this.b]};f.wd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.A=this.a[this.b]};f.Oc=function(){this.b=this.f++;this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Gc=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256}; -f.Pc=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Ic=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Sc=function(){this.g=this.a[this.f++];this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.jd=function(){this.i=this.j=this.F=this.F+1&255};f.Fc=function(){this.b=this.f++;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Uc=function(){this.i=this.j=this.A=this.A-1&255}; -f.Nc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Cc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Qc=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.tc=function(){this.f+=(this.j&255?(this.C--,this.a[this.f]<<24>>24):0)+1}; -f.Hc=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Jc=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Tc=function(){this.g=this.a[this.f++]+this.A&255;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.zc=function(){sb(this)}; -f.Ec=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Dc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Rc=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.Lc=function(){this.b=this.f++;this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; -f.Ab=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.me=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.h=S(this,this.h,this.a[this.b])};f.Mc=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; -f.Cb=function(){this.b=this.a[this.f++];this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.oe=function(){this.b=this.a[this.f++];this.h=S(this,this.h,this.a[this.b])};f.fd=function(){this.g=this.a[this.f++];this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.hd=function(){this.i=this.j=this.A=this.A+1&255}; -f.zb=function(){this.b=this.f++;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.le=function(){this.b=this.f++;this.h=S(this,this.h,this.a[this.b])};f.Kd=function(){};f.Kc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; -f.wb=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ie=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.h=S(this,this.h,this.a[this.b])};f.dd=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.pc=function(){this.f+=(this.j&255?0:(this.C--,this.a[this.f]<<24>>24))+1}; -f.Bb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ne=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.h=S(this,this.h,this.a[this.b])}; -f.Db=function(){this.b=this.a[this.f++]+this.A&255;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.pe=function(){this.b=this.a[this.f++]+this.A&255;this.h=S(this,this.h,this.a[this.b])};f.gd=function(){this.g=this.a[this.f++]+this.A&255;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.re=function(){rb(this)}; -f.yb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ke=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.h=S(this,this.h,this.a[this.b])}; -f.xb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.je=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.h=S(this,this.h,this.a[this.b])};f.ed=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255}; -f.Ge=function(){var a=this.a[this.f++];switch(a){case 0:this.l("HALT");this.ba();break;case 1:a=this.f;for(var b="";aeb(a.O,b,c,d,e)&&(a.qa>b&&(a.qa=b),a.ra=a.O[d][0]&&b<=a.O[d][1]&&a.O[d][3].call(a.O[d][2],b,c)}function Q(a,b,c,d,e){0>eb(a.I,b,c,d,e)&&(a.fa>b&&(a.fa=b),a.ga=a.I[d][0]&&b<=a.I[d][1]&&a.I[d][3].call(a.I[d][2],b,c)} +function eb(a,b,c,d,e){for(var g=0;ga.Qa&&a.M&&(d=a.M);d>a.Ia&&2>a.speed&&(d=a.Ia);a.jb=Math.round(1E3/30);a.ka=Math.floor(1E6/c*d);a.ta=Math.floor(1E6/30*d);a.Ya=Math.floor(1E6/a.Ea*d);a.Xa=Math.floor(1E6/a.Da*d);b||(a.R=a.ta,a.Y=a.Ya,a.W=a.Xa);a.Ca=0} +function kb(a){var b=ya(),c=a.jb;a.Z&&(c=Math.round(c*a.Z/a.ta));c-=b-a.kb;if(b-=a.Wa)a.M=Math.round(a.V/(100*b))/10,864E5<=b&&P(a);0>c?c=0:1==a.speed?a.M<=a.Ia&&(c=0):2==a.speed&&(c=0);a.Ca+=a.Z;return c} +f.va=function(){if(M(this,!0)){this.D.oa||(P(this),this.U&&this.U.start(),this.D.oa=!0,this.H.run&&(this.H.run.innerHTML="Halt"),this.da());1E6<=this.Ca&&hb(this,!0);this.Z=0;this.kb=ya();try{do{this.step(this.ka);var a=this.L-this.C;this.V+=a;this.Z+=a;this.L=this.C=0;this.Y-=this.ka;0>=this.Y&&(this.Y+=this.Ya,this.bb());this.W-=this.ka;0>=this.W&&(this.W+=this.Xa,ib(this));this.R-=this.ka;if(0>=this.R){this.R+=this.ta;break}}while(this.D.oa)}catch(b){this.ba();this.update();M(this,!1);Wa(this, +b.stack||b.message);return}setTimeout(function(b){return function(){b.va()}}(this),kb(this))}else this.update(),this.U&&this.U.stop(this.Wa,this.V)}; +f.step=function(a){var b=!0;this.b=this.g=-1;var c;if(c=a&&this.v)c=this.v,c=0=d.xa.length&&(d.La=0));d=!!g}if(d){b=void 0;this.ba();break}this.f++;this.m[a].call(this);if(0<=this.b){this.b>=this.qa&&this.b<=this.ra&&fb(this,this.b,this.f);if(d=c)d=this.v,e=!1,lb(d,this.b,d.wa,"read")&&(e=!0),d=!!e;if(d){b=!1;this.ba(); +break}this.b=-1}else if(0<=this.g){this.g>=this.fa&&this.g<=this.ga&&gb(this,this.g,this.f);if(d=c){d=this.v;e=this.g;g=this.a[this.g];var h=!1;(g&255)!=g&&(d.l("invalid value at "+z(e)+": "+g),h=!0);lb(d,e,d.ya,"write")&&(h=!0);d=!!h}if(d){b=!1;this.ba();break}this.g=-1}this.C-=this.hb[a]}while(0>1)&128?64:0;b|=a.i&128?128:0;return a.B&60|b}function ob(a){a.B|=8;a.m[97]=a.Wb;a.m[101]=a.Yb;a.m[105]=a.Vb;a.m[109]=a.Sb;a.m[113]=a.Xb;a.m[117]=a.Zb;a.m[121]=a.Ub;a.m[125]=a.Tb;a.m[225]=a.le;a.m[229]=a.ne;a.m[233]=a.ke;a.m[237]=a.he;a.m[241]=a.me;a.m[245]=a.oe;a.m[249]=a.je;a.m[253]=a.ie} +function pb(a){a.B&=-9;a.m[97]=a.sb;a.m[101]=a.ub;a.m[105]=a.rb;a.m[109]=a.ob;a.m[113]=a.tb;a.m[117]=a.vb;a.m[121]=a.qb;a.m[125]=a.pb;a.m[225]=a.Ab;a.m[229]=a.Cb;a.m[233]=a.zb;a.m[237]=a.wb;a.m[241]=a.Bb;a.m[245]=a.Db;a.m[249]=a.yb;a.m[253]=a.xb}function S(a,b,c){var d=a.c&256?1:0,e=(b&15)+(c&15)+d;10<=e&&(e=e+6&15|16);e+=(b&240)+(c&240);a.w=b^c;a.s=e;a.i=e&255;160<=e&&(e+=96);512<=e&&(e-=256);a.c=e;a.j=b+c+d&255;a.C--;return e&255} +function T(a,b,c){var d=a.c&256?0:1,e=(b&15)-(c&15)-d;0>e&&(e=(e-6&15)-16);e+=(b&240)-(c&240);0>e&&(e-=96);a.i=a.j=(a.c=b-c-d)&255;a.w=b^c;a.s=a.c;a.c^=256;a.C--;return e&255}function bb(a){a.h=0;a.A=0;a.F=0;a.G=256;a.B=0;a.i=0;a.j=0;a.w=0;a.s=0;a.c=0;a.f=0;a.b=-1;a.g=-1;a.M=0;a.V=a.L=a.C=0} +f.uc=function(){this.f++;this.a[this.G--]=this.f>>8;this.G|=256;this.a[this.G--]=this.f&255;this.G|=256;this.B|=16;this.B=jb(this);this.a[this.G--]=this.B;this.G|=256;this.B&=239;this.b=65534;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.Od=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h|=this.a[this.b]};f.Qd=function(){this.b=this.a[this.f++];this.i=this.j=this.h|=this.a[this.b]}; +f.kc=function(){this.g=this.a[this.f++];this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.Td=function(){this.B=jb(this);this.a[this.G--]=this.B;this.G|=256};f.Nd=function(){this.b=this.f++;this.i=this.j=this.h|=this.a[this.b]};f.jc=function(){this.c=this.h<<1;this.i=this.j=this.h=this.c&255};f.Kd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h|=this.a[this.b]}; +f.hc=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.tc=function(){this.f+=(this.i&128?0:(this.C--,this.a[this.f]<<24>>24))+1};f.Pd=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h|=this.a[this.b]};f.Rd=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h|=this.a[this.b]}; +f.lc=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255};f.xc=function(){this.c=0};f.Md=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h|=this.a[this.b]};f.Ld=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h|=this.a[this.b]};f.ic=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.a[this.g]<<1;this.i=this.j=this.a[this.g]=this.c&255}; +f.ld=function(){this.b=this.f++;this.a[this.G--]=this.f>>8;this.G|=256;this.a[this.G--]=this.f&255;this.G|=256;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.dc=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h&=this.a[this.b]};f.qc=function(){this.b=this.a[this.f++];this.j=this.h&this.a[this.b];this.i=this.i&127|this.a[this.b]&128;this.s=0;this.w=this.a[this.b]&64?128:0};f.fc=function(){this.b=this.a[this.f++];this.i=this.j=this.h&=this.a[this.b]}; +f.Zd=function(){this.g=this.a[this.f++];this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.Vd=function(){this.G=this.G+1&255|256;this.B=this.a[this.G];this.c=this.B&1?256:0;this.j=this.B&2?0:1;this.i=this.B&128;this.s=0;this.w=this.B&64?128:0};f.cc=function(){this.b=this.f++;this.i=this.j=this.h&=this.a[this.b]}; +f.Yd=function(){this.c=this.c&65280|this.h;this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.h=this.c&255};f.pc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.j=this.h&this.a[this.b];this.i=this.i&127|this.a[this.b]&128;this.s=0;this.w=this.a[this.b]&64?128:0};f.$b=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h&=this.a[this.b]}; +f.Wd=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.rc=function(){this.f+=(this.i&128?(this.C--,this.a[this.f]<<24>>24):0)+1};f.ec=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h&=this.a[this.b]};f.gc=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h&=this.a[this.b]}; +f.$d=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.pe=function(){this.c=256};f.bc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h&=this.a[this.b]};f.ac=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h&=this.a[this.b]}; +f.Xd=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65280|this.a[this.g];this.c<<=1;this.c=this.c&65534|(this.c&512?1:0);this.i=this.j=this.a[this.g]=this.c&255};f.fe=function(){this.G=this.G+1&255|256;this.B=this.a[this.G];this.c=this.B&1?256:0;this.j=this.B&2?0:1;this.i=this.B&128;this.s=0;this.w=this.B&64?128:0;this.G=this.G+2&255|256;this.f=this.a[this.G-1|256]|this.a[this.G]<<8}; +f.Zc=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h^=this.a[this.b]};f.ad=function(){this.b=this.a[this.f++];this.i=this.j=this.h^=this.a[this.b]};f.Hd=function(){this.g=this.a[this.f++];this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255};f.Sd=function(){this.a[this.G--]=this.h;this.G|=256};f.Yc=function(){this.b=this.f++;this.i=this.j=this.h^=this.a[this.b]}; +f.Gd=function(){this.c=this.c&65279|(this.h&1?256:0);this.h=(this.c=this.c&65280|this.h>>1)&255;this.i=this.j=this.c&255};f.kd=function(){this.b=this.f;this.f=this.a[this.b]|this.a[this.b+1]<<8};f.Vc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h^=this.a[this.b]};f.Ed=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; +f.vc=function(){this.f+=((this.s&255^this.w^this.s>>1)&128?0:(this.C--,this.a[this.f]<<24>>24))+1};f.$c=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h^=this.a[this.b]};f.bd=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h^=this.a[this.b]};f.Id=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; +f.zc=function(){this.B&=251};f.Xc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h^=this.a[this.b]};f.Wc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h^=this.a[this.b]};f.Fd=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65279|(this.a[this.g]&1?256:0);this.a[this.g]=(this.c=this.c&65280|this.a[this.g]>>1)&255;this.i=this.j=this.c&255}; +f.ge=function(){this.G=this.G+2&255|256;this.f=(this.a[this.G-1|256]|this.a[this.G]<<8)+1};f.sb=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Wb=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.h=S(this,this.h,this.a[this.b])}; +f.ub=function(){this.b=this.a[this.f++];this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Yb=function(){this.b=this.a[this.f++];this.h=S(this,this.h,this.a[this.b])};f.de=function(){this.g=this.a[this.f++];this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.Ud=function(){this.G=this.G+1&255|256;this.i=this.j=this.h=this.a[this.G]}; +f.rb=function(){this.b=this.f++;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Vb=function(){this.b=this.f++;this.h=S(this,this.h,this.a[this.b])};f.ce=function(){this.c=this.c&65280|this.h;this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.h=this.c&255};f.jd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.f=this.a[this.b]|this.a[this.b+1]<<8}; +f.ob=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Sb=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.h=S(this,this.h,this.a[this.b])};f.ae=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255}; +f.wc=function(){this.f+=((this.s&255^this.w^this.s>>1)&128?(this.C--,this.a[this.f]<<24>>24):0)+1};f.tb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Xb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.h=S(this,this.h,this.a[this.b])}; +f.vb=function(){this.b=this.a[this.f++]+this.A&255;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Zb=function(){this.b=this.a[this.f++]+this.A&255;this.h=S(this,this.h,this.a[this.b])};f.ee=function(){this.g=this.a[this.f++]+this.A&255;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.re=function(){this.B|=4}; +f.qb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255};f.Ub=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.h=S(this,this.h,this.a[this.b])};f.pb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.h+this.a[this.b]+(this.c&256?1:0);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255}; +f.Tb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.h=S(this,this.h,this.a[this.b])};f.be=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.c&65280|this.a[this.g];this.c=this.c&65023|(this.c&1?512:0);this.c>>=1;this.i=this.j=this.a[this.g]=this.c&255};f.ve=function(){this.g=this.a[this.f++]+this.A&255;this.g=this.a[this.g]|this.a[this.g+1]<<8;this.a[this.g]=this.h};f.De=function(){this.g=this.a[this.f++];this.a[this.g]=this.F}; +f.xe=function(){this.g=this.a[this.f++];this.a[this.g]=this.h};f.Ae=function(){this.g=this.a[this.f++];this.a[this.g]=this.A};f.Uc=function(){this.i=this.j=this.F=this.F-1&255};f.Je=function(){this.i=this.j=this.h=this.A};f.Ce=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.F};f.se=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.h};f.ze=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.a[this.g]=this.A}; +f.mc=function(){this.f+=(this.c&256?0:(this.C--,this.a[this.f]<<24>>24))+1};f.we=function(){this.g=this.a[this.f++];this.g=(this.a[this.g]|this.a[this.g+1]<<8)+this.F;this.a[this.g]=this.h};f.Ee=function(){this.g=this.a[this.f++]+this.A&255;this.a[this.g]=this.F};f.ye=function(){this.g=this.a[this.f++]+this.A&255;this.a[this.g]=this.h};f.Be=function(){this.g=this.a[this.f++]+this.F&255;this.a[this.g]=this.A};f.Le=function(){this.i=this.j=this.h=this.F}; +f.ue=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.a[this.g]=this.h};f.Ke=function(){this.G=this.A|256};f.te=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.a[this.g]=this.h};f.Bd=function(){this.b=this.f++;this.i=this.j=this.F=this.a[this.b]};f.qd=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.h=this.a[this.b]};f.wd=function(){this.b=this.f++;this.i=this.j=this.A=this.a[this.b]}; +f.Cd=function(){this.b=this.a[this.f++];this.i=this.j=this.F=this.a[this.b]};f.sd=function(){this.b=this.a[this.f++];this.i=this.j=this.h=this.a[this.b]};f.xd=function(){this.b=this.a[this.f++];this.i=this.j=this.A=this.a[this.b]};f.He=function(){this.i=this.j=this.F=this.h};f.pd=function(){this.b=this.f++;this.i=this.j=this.h=this.a[this.b]};f.Ge=function(){this.i=this.j=this.A=this.h};f.zd=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.F=this.a[this.b]}; +f.md=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.h=this.a[this.b]};f.ud=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.A=this.a[this.b]};f.nc=function(){this.f+=(this.c&256?(this.C--,this.a[this.f]<<24>>24):0)+1};f.rd=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.h=this.a[this.b]};f.Dd=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.F=this.a[this.b]}; +f.td=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.h=this.a[this.b]};f.yd=function(){this.b=this.a[this.f++]+this.F&255;this.i=this.j=this.A=this.a[this.b]};f.Ac=function(){this.w=this.s=0};f.od=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.h=this.a[this.b]};f.Ie=function(){this.i=this.j=this.A=this.G&255};f.Ad=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.F=this.a[this.b]}; +f.nd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.h=this.a[this.b]};f.vd=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.A=this.a[this.b]};f.Nc=function(){this.b=this.f++;this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Fc=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256}; +f.Oc=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Hc=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Rc=function(){this.g=this.a[this.f++];this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.hd=function(){this.i=this.j=this.F=this.F+1&255};f.Ec=function(){this.b=this.f++;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Tc=function(){this.i=this.j=this.A=this.A-1&255}; +f.Mc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.F-this.a[this.b];this.c^=256};f.Bc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Pc=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.sc=function(){this.f+=(this.j&255?(this.C--,this.a[this.f]<<24>>24):0)+1}; +f.Gc=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Ic=function(){this.b=this.a[this.f++]+this.A&255;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Sc=function(){this.g=this.a[this.f++]+this.A&255;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.yc=function(){pb(this)}; +f.Dc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Cc=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.c=this.h-this.a[this.b];this.c^=256};f.Qc=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.a[this.g]=this.a[this.g]-1&255};f.Kc=function(){this.b=this.f++;this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; +f.Ab=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.le=function(){this.b=this.a[this.f++]+this.A&255;this.b=this.a[this.b]|this.a[this.b+1]<<8;this.h=T(this,this.h,this.a[this.b])};f.Lc=function(){this.b=this.a[this.f++];this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; +f.Cb=function(){this.b=this.a[this.f++];this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ne=function(){this.b=this.a[this.f++];this.h=T(this,this.h,this.a[this.b])};f.ed=function(){this.g=this.a[this.f++];this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.gd=function(){this.i=this.j=this.A=this.A+1&255}; +f.zb=function(){this.b=this.f++;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ke=function(){this.b=this.f++;this.h=T(this,this.h,this.a[this.b])};f.Jd=function(){};f.Jc=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.c=this.A-this.a[this.b];this.c^=256}; +f.wb=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.he=function(){this.b=this.a[this.f++]|this.a[this.f++]<<8;this.h=T(this,this.h,this.a[this.b])};f.cd=function(){this.g=this.a[this.f++]|this.a[this.f++]<<8;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.oc=function(){this.f+=(this.j&255?0:(this.C--,this.a[this.f]<<24>>24))+1}; +f.Bb=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.me=function(){this.b=this.a[this.f++];this.b=(this.a[this.b]|this.a[this.b+1]<<8)+this.F;this.h=T(this,this.h,this.a[this.b])}; +f.Db=function(){this.b=this.a[this.f++]+this.A&255;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.oe=function(){this.b=this.a[this.f++]+this.A&255;this.h=T(this,this.h,this.a[this.b])};f.fd=function(){this.g=this.a[this.f++]+this.A&255;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255};f.qe=function(){ob(this)}; +f.yb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.je=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.F;this.h=T(this,this.h,this.a[this.b])}; +f.xb=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.c=this.h-this.a[this.b]-(this.c&256?0:1);this.w=this.h^this.a[this.b];this.s=this.c;this.i=this.j=this.h=this.c&255;this.c^=256};f.ie=function(){this.b=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.h=T(this,this.h,this.a[this.b])};f.dd=function(){this.g=(this.a[this.f++]|this.a[this.f++]<<8)+this.A;this.i=this.j=this.a[this.g]=this.a[this.g]+1&255}; +f.Fe=function(){var a=this.a[this.f++];switch(a){case 0:this.l("HALT");this.ba();break;case 1:a=this.f;for(var b="";a=c&&(c+=32);a.K=a.K.substr(1);zb(a,c)}0=b&&(b+=32),Bb(a,b),Cb(a,b,!0,0)&&(2==a.u.speed?Cb(a,b,!1,1):(c=!1,a.B[b]&&(clearTimeout(a.B[b]),c=!0),c=Ab(a,c),a.B[a.C=b]=setTimeout(function(a){return function(){Cb(a,b,!1,3)}}(a),c),a.v&&M(a.v,a.v.za)&&a.v.message("keyPressSimulate("+w(b)+"): setTimeout()")),c=!0));a.v&&M(a.v,a.v.za)&&a.v.message("keyPressSimulate("+w(b)+"): "+(c?"true":"false"));return c} -function Cb(a,b,c,d){var e=!1;c||(a.B[b]=null,a.C==b&&(a.C=0));var g=0,l=a.b[b];void 0===l&&(1<=b&&26>=b&&(b+=64,g=a.O),l=a.b[b]);void 0!==l&&(b=l>>12,e=l>>8&15,g||(g=l&255),c?(a.s[b]|=1<b||8192<=b));b&&(b=a.V.shift(),void 0!==b&&(a.sa=b),a.Z=0,a.Da=d);for(b=d=0;8>b;b++)a.ta&1<b[d][0]&&(e=b[d][0]),g=a.Y&&(d-=a.Y,d=--c.Fa&&(0=c.nb&&(c.na=c.nb),0>c.na&&(c.na=0),c.Fa=20, -a.m.update(a.m.J|128),Ub(a))}this.J=b;a.C.J&4&&U(a,2,this)}}(a)};a.C={J:0,read:function(){},update:function(a){return function(b){void 0!==b&&(this.J=b&-193);U(a,3,this);a.w.update();a.L.update()}}(a)};a.O={J:0,read:function(){},update:function(a){return function(b){void 0!==b&&(3==(b&3)&&(a.s.J=14),this.J=b);a.s.update()}}(a)};a.s={J:14,read:function(){},update:function(a){return function(b){void 0===b&&(b=a.s.J);b&=-2;0<=a.b&&0<=a.g[a.b].Ba&&(b|=1);this.J=b;U(a,16,this)}}(a)};a.I={J:0,read:function(a){return function(){Vb(a)}}(a), -update:function(a){return function(b){void 0!==b&&(this.J=b);U(a,17,this)}}(a)};a.R={J:0,read:function(){},update:function(){return function(){}}(a)}} -f.T=function(a,b,c){switch(b){case "listDisk":return this.H[b]=c,!0;case "loadDisk":return this.H[b]=c,c.onclick=function(a){return function(){if(a.H.listDisk){var b=a.H.listDisk.value,c=b;".json"!=b.substr(b.length-5)&&(c="http://"+window.location.host+"/api/v1/dump?disk\x3d"+b);a.l("loading "+sa(b)+"...");z(c,function(b,c,d){Wb(a,b,c,d)})}}}(this),!0}return!1};f.ca=function(a,b,c,d){this.a=a;this.K=b;if(this.u=d)gb(d,b,c,this,this.S),P(d,b,c,this,this.Jb);this.X()}; -f.ja=function(a,b){a&&!this.D.N&&(this.D.N=!0,this.v=N(b,"debugger"))}; -function Wb(a,b,c,d){if(d)a.l("disk load error ("+d+")");else{d=[];a.l("mounting "+b+"...");try{if(d=eval("("+c+")"),d.length)if(d[0].length){var e=d[0];if(void 0===e[0].trackNum)a.l("data error: "+e[0]);else if(a.g[0]){for(c=0;c>8&255);a.push(b&255)}function Xb(a,b,c){b=b[c];if(void 0===b)throw Error("missing signature: "+c);for(c=0;cb?b&=3:32>b&&(b&=17);switch(b){case 0:a=a.B.J&4?a.m:a.M;break;case 1:a=a.B;break;case 2:a=a.C.J&4?a.w:a.L;break;case 3:a=a.C;break;case 16:a=c?a.O:a.s;break;case 17:a=a.I;break;default:a=a.R}return a}f.S=function(a,b){if(void 0!==b){var c=Zb(this,a-this.K,!1);this.v&&T(this.v,this,a,b,this.v.Ha,!1,c.Eb);c.read()}}; -f.Jb=function(a,b){if(void 0!==b){var c=this.u.S(a),d=Zb(this,a-this.K,!0);if(this.v&&M(this.v,this.v.Ha|this.v.mb)&&(T(this.v,this,a,b,this.v.Ha,!0,d.Eb),d.Ob))for(a=128,b=d.J^c;b&&a;)b&a&&this.v.message(" changed "+d.Eb+"."+d.Ob[a]+" to "+(c&a?"1":"0")),a>>=1;d.update(c)}};function Tb(a,b,c){var d=-1;void 0!==b&&void 0!==c&&(d=0,c&32||(d|=2),a.m.J&64||(d|=1));a.b!=d&&(a.b=d,a.s.update())}function Ub(a){0<=a.b&&(a.g[a.b].Ba=-1,a.I.update(255),a.s.update())} -function Vb(a){if(0<=a.b){var b=a.g[a.b];var c=b.Sa[b.na];void 0!==c&&(0<=b.Ba&&b.Ba=c&&(c+=32);a.K=a.K.substr(1);wb(a,c)}0=b&&(b+=32),yb(a,b),zb(a,b,!0,0)&&(2==a.u.speed?zb(a,b,!1,1):(c=!1,a.B[b]&&(clearTimeout(a.B[b]),c=!0),c=xb(a,c),a.B[a.C=b]=setTimeout(function(d){return function(){zb(d,b,!1,3)}}(a),c),a.v&&N(a.v,a.v.za)&&a.v.message("keyPressSimulate("+v(b)+"): setTimeout()")),c=!0));a.v&&N(a.v,a.v.za)&&a.v.message("keyPressSimulate("+v(b)+"): "+(c?"true":"false"));return c} +function zb(a,b,c,d){var e=!1;c||(a.B[b]=null,a.C==b&&(a.C=0));var g=0,h=a.b[b];void 0===h&&(1<=b&&26>=b&&(b+=64,g=a.O),h=a.b[b]);void 0!==h&&(b=h>>12,e=h>>8&15,g||(g=h&255),c?(a.s[b]|=1<b||8192<=b));b&&(b=a.V.shift(),void 0!==b&&(a.sa=b),a.Z=0,a.Da=d);for(b=d=0;8>b;b++)a.ta&1<b[d][0]&&(e=b[d][0]),g=a.Y&&(d-=a.Y,dMissing <canvas> support. Please try a newer web browser.";break}e.setAttribute("class","c1pjs-canvas");e.setAttribute("width",d.screenWidth);e.setAttribute("height",d.screenHeight);e.setAttribute("contenteditable","true");e.setAttribute("autocapitalize","off");e.setAttribute("autocorrect","off");e.style.backgroundColor=d.screenColor; +e.style.height="auto";0<=(window?window.navigator.userAgent:"").indexOf("MSIE")&&(e.style.height=(c.clientWidth*d.screenHeight/d.screenWidth|0)+"px",c.onresize=function(l,k,m,n){return function(){k.style.height=(l.clientWidth*n/m|0)+"px"}}(c,e,d.screenWidth,d.screenHeight));c.appendChild(e);var g=new Image,h=e.getContext("2d");e=new Db(d,e,h,g);g.onload=function(l){return function(){l.X()}}(e,d.charSet);g.src=d.charSet;I(e,c)}}); +function Gb(a){G.call(this,"C1PSerialPort",a);this.D.N=!1;this.C=a.demo;this.reset(!0)}t(Gb,G);f=Gb.prototype;f.reset=function(a){if(a||this.m!=Hb){this.s=-1;this.w=0;this.g="";if(this.C){a=1;if(this.eb){var b=this.eb.match(/\d+/);null!==b&&(a=parseInt(b[0],10))}this.g='10 PRINT "HELLO OSI #'+a+'"\n'}this.B=!0;this.m=Ib}};f.start=function(){this.b&&this.C&&(Ab(this.b," C\n\n",3E3),setTimeout(function(a){return function(){a.m=Jb;Ab(a.b,"LOAD\n")}}(this),12E3));this.C=!1}; +f.T=function(a,b,c){var d=this;switch(b){case "listSerial":return this.H[b]=c,!0;case "loadSerial":return this.H[b]=c,c.onclick=function(){d.H.listSerial&&B(d.H.listSerial.value,function(e,g,h){Kb(d,e,g,h)})},!0;case "mountSerial":return!Ba()&&window&&"FileReader"in window?(this.H[b]=c,c.onchange=function(){var e=c.children[0];e.children[1].disabled=!e.children[0].files.length},c.onsubmit=function(e){var g=e.currentTarget[1].files[0],h=new FileReader;h.onload=function(){Kb(d,g.name,h.result.toString(), +0)};h.readAsText(g);return!1}):c.parentNode.removeChild(c),!0}return!1};f.ca=function(a,b,c,d){this.a=a;this.K=b;this.M=c-b+1;this.I=this.K+this.M;if(this.u=d)db(d,b,c,this,this.S),Q(d,b,c,this,this.Lb);this.X()};f.ja=function(a,b){a&&!this.D.N&&(this.D.N=!0,this.U=b,this.b=O(b,"keyboard"),this.v=O(b,"debugger"))}; +function Kb(a,b,c,d){if(c){a.w=0;a.g=c;a.B=!0;a.m=Ib;if(-1!==b.indexOf(".json",b.length-5))try{d="";var e=eval("("+c+")").bytes;for(c=0;c=--d.Fa&&(0=d.nb&&(d.na=d.nb),0>d.na&&(d.na=0),d.Fa=20, +b.m.update(b.m.J|128),Sb(b))}this.J=c;b.C.J&4&&V(b,2,this)}}(a)};a.C={J:0,read:function(){},update:function(b){return function(c){void 0!==c&&(this.J=c&-193);V(b,3,this);b.w.update();b.L.update()}}(a)};a.O={J:0,read:function(){},update:function(b){return function(c){void 0!==c&&(3==(c&3)&&(b.s.J=14),this.J=c);b.s.update()}}(a)};a.s={J:14,read:function(){},update:function(b){return function(c){void 0===c&&(c=b.s.J);c&=-2;0<=b.b&&0<=b.g[b.b].Ba&&(c|=1);this.J=c;V(b,16,this)}}(a)};a.I={J:0,read:function(b){return function(){Tb(b)}}(a), +update:function(b){return function(c){void 0!==c&&(this.J=c);V(b,17,this)}}(a)};a.R={J:0,read:function(){},update:function(){return function(){}}(a)}}f.T=function(a,b,c){switch(b){case "listDisk":return this.H[b]=c,!0;case "loadDisk":return this.H[b]=c,c.onclick=function(d){return function(){if(d.H.listDisk){var e=d.H.listDisk.value,g=e;".json"!=e.substr(e.length-5)&&(g="http://"+window.location.host+"/api/v1/dump?disk="+e);d.l("loading "+oa(e)+"...");B(g,function(h,l,k){Ub(d,h,l,k)})}}}(this),!0}return!1}; +f.ca=function(a,b,c,d){this.a=a;this.K=b;if(this.u=d)db(d,b,c,this,this.S),Q(d,b,c,this,this.Jb);this.X()};f.ja=function(a,b){a&&!this.D.N&&(this.D.N=!0,this.v=O(b,"debugger"))}; +function Ub(a,b,c,d){if(d)a.l("disk load error ("+d+")");else{d=[];a.l("mounting "+b+"...");try{if(d=eval("("+c+")"),d.length)if(d[0].length){var e=d[0];if(void 0===e[0].trackNum)a.l("data error: "+e[0]);else if(a.g[0]){for(c=0;c>8&255);a.push(b&255)}function Vb(a,b,c){b=b[c];if(void 0===b)throw Error("missing signature: "+c);for(c=0;cb?b&=3:32>b&&(b&=17);switch(b){case 0:a=a.B.J&4?a.m:a.M;break;case 1:a=a.B;break;case 2:a=a.C.J&4?a.w:a.L;break;case 3:a=a.C;break;case 16:a=c?a.O:a.s;break;case 17:a=a.I;break;default:a=a.R}return a}f.S=function(a,b){if(void 0!==b){var c=Xb(this,a-this.K,!1);this.v&&U(this.v,this,a,b,this.v.Ha,!1,c.Eb);c.read()}}; +f.Jb=function(a,b){if(void 0!==b){var c=this.u.S(a),d=Xb(this,a-this.K,!0);if(this.v&&N(this.v,this.v.Ha|this.v.mb)&&(U(this.v,this,a,b,this.v.Ha,!0,d.Eb),d.Ob))for(a=128,b=d.J^c;b&&a;)b&a&&this.v.message(" changed "+d.Eb+"."+d.Ob[a]+" to "+(c&a?"1":"0")),a>>=1;d.update(c)}};function Rb(a,b,c){var d=-1;void 0!==b&&void 0!==c&&(d=0,c&32||(d|=2),a.m.J&64||(d|=1));a.b!=d&&(a.b=d,a.s.update())}function Sb(a){0<=a.b&&(a.g[a.b].Ba=-1,a.I.update(255),a.s.update())} +function Tb(a){if(0<=a.b){var b=a.g[a.b];var c=b.Sa[b.na];void 0!==c&&(0<=b.Ba&&b.Ba>24)} -f.S=function(a){if(a>=this.K&&a=a.Ga?a.l("invalid address: "+x(b)):(a.a[a.K+b]=c&255,jb(a.u,b),a.u.update())}function ic(a,b){W(a.pa,b,void 0)||a.pa.push(b);return!0}function W(a,b,c){for(var d=!1,e=0;eg&&(m+=" ;'"+String.fromCharCode(g)+"'")}if(e==a.u.$a&& -(gh?m+=String.fromCharCode(g):16==h&&(m+="\u2026"),h++;m+='"'}m&&(d+=" "+m);c&&(d=(d+" ").substr(0,30),d+=";"+c.toString());a.Z=b;return d} -function X(a,b){var c=a.ua;if(void 0!==b){var d=16;"$"==b.charAt(0)?b=b.substr(1):"0x"==b.substr(0,2)?b=b.substr(2):"."==b.charAt(b.length-1)&&(d=10,b=b.substr(0,b.length-1));c=parseInt(b,d);isNaN(c)&&(a.l("invalid base-"+d+" address: "+b),c=void 0)}void 0!==c&&(c=a.Ga)&&(a.l("address out of range: "+v(c)),c=void 0);return c} -function lc(a,b){if("?"==b)a.l("\nfrequency commands:"),a.l("clear\tclear all frequency counts");else{var c=0;if(a.B)if("clear"==b){for(b=0;ba.Pb.indexOf(g)&&(h=a.P);h==a.lb&&27!=g&&(h=a.P)}else a.l("unknown operand: "+l),g=-1;if(0<=g){k=-1;for(e=0;ek)k=e;else{a.l("too many instruction matches (both "+w(k)+" and "+w(e)+")");k=-2;break}if(0<=k){if(d.push(k),void 0!==h)if(b=a.ha[k][1],l=l.match(/[0-9A-F]+/),null!==l)for(l=parseInt(l[0],16),1==b&&h==a.ea&&(l-=c+2,-128>l||127>>=8;else b&&a.l("instruction missing "+b+" bytes")}else a.l("unknown instruction: "+b+" "+l)}}h=d;if(h.length){for(c=0;cg&&hk?String.fromCharCode(k):".",h++;a.l(v(e,4)+" "+b+l)}a.ua=h}break;case "e":h=c[1];if(void 0===h)a.l("missing address");else if(h=X(a,h),void 0!==h)for(d=2;dd.length&&(a.l("note: only "+ -d.length+" available"),b=d.length);void 0!==l&&(a.fb=0,a.l(b+" instructions earlier:"));l=a.fb?a.fb:1;c-=b;for(0>c&&(c=d.length-1);h&&c!=a.La;){e=d[c];if(0>e)break;a.l(kc(a,e,l++));++c==d.length&&(c=0);h--;b--}a.Sb=b;a.fb=l}10==h&&a.l("no history available");break;case "r":ec(a,c);break;case "s":a.S(a.u.f)==a.u.Pa?(jc(a,a.u.f+3),a.Aa=!0,a.va()||a.u.da()):mc(a);break;case "t":mc(a,c[1]);break;case "u":dc(a,c[1],c[2],8);break;case "?":case "help":a.l("\ncommands:\n?\thelp\na [#]\tassemble\nb [#]\tbreakpoint\nd [#]\tdump memory\ne [#]\tedit memory\nf\tdump frequencies\ng [#]\trun to [#]\nh\thalt\no\toptions\np [#]\tdump history\nr\tdump/edit registers\ns\tstep over instruction\nt [#]\tstep instruction(s)\nu [#]\tunassemble"); -a.l("note: frequency and history commands operate only when breakpoints are set");break;default:a.l("unknown command: "+b)}}}C(function(){for(var a=I(document,"c1pjs","debugger"),b=0;bg.indexOf("/")&&"/"==window.location.pathname.slice(-1)&&(g=window.location.pathname+g);h?"}"==h.slice(-1)?(h=h.slice(0,-1),1]*\sclass=)(['"])(.*?)(\2.*?>)/);k&&(a=a.replace(k[0],k[1]+k[2]+d+k[4]),d="")}a=a.replace(/(]*\sid=)(['"]).*?\2/, -"$1$2"+c+"$2"+(d?' class\x3d"'+d+'"':"")+(h?" parms\x3d'"+h+"'":"")+(g?' url\x3d"'+g+'"':""))}e||(a=a.replace(/().*?(<\/xsl:variable>)/,"$1C1Pjs$2"),a=a.replace(/().*?(<\/xsl:variable>)/,"$1c1pjs$2"));g=null;if("\x3c"==a.charAt(0))try{e||(a=a.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(g=new window.ActiveXObject("Microsoft.XMLDOM"),g.async=!1,g.loadXML(a)):g=(new window.DOMParser).parseFromString(a, -"text/xml")}catch(r){g=null,a=r.message}else a="unrecognized XML: "+(255/g.exec(a)){var e=d[2];b("Loading "+e+"...");z(e,function(g,l,k){if(k||!l)c(a,"unable to resolve XML reference: "+d[0]+" ("+k+")");else{if(g=d[3])if(k=l.match(new RegExp("\x3c"+d[1]+"[^\x3e]*\x3e"))){for(var h=k[0],m,n=/( [a-z]+=)(['"])(.*?)\2/gi;m=n.exec(g);)h=0>h.toLowerCase().indexOf(m[1].toLowerCase())?h.replace("\x3e",m[0]+"\x3e"):h.replace(new RegExp(m[1]+"(['\"])(.*?)\\1"),m[0]);k[0]!=h&&(l=l.replace(k[0],h))}else{c(a,"missing \x3c"+ -d[1]+"\x3e in "+e);return}l=l.replace(/<\?xml[^>]*>[\r\n]*/,"");a=a.replace(d[0],l);rc(a,b,c)}})}else c(a,"")} -function sc(a,b,c,d){function e(a){if(void 0===k){var b=l&&I(l,"machine-warning");k=b&&b[0]||l}k&&(k.innerHTML=ua(a))}function g(a){e("Error: "+a);h&&(--oc||Ma(!0));h=!1}var l,k,h=!0;b||(b="machine.xml",c||(c="components.xsl"));oc++;ab[a]={};try{if(l=document.getElementById(a)){var m;if("object"==typeof resources&&(m=resources.css)){var n=document.head||document.getElementsByTagName("head")[0],p=document.createElement("style");p.type="text/css";p.styleSheet?p.styleSheet.cssText=m:p.appendChild(document.createTextNode(m)); -n.appendChild(p)}c||(c="/versions/c1pjs/1.75.2/components.xsl");m=function(d,h){h?pc(c||"","","",!1,e,function(d,k){if(k){var m=c||"";ab[a]&&m&&(ab[a][m]=d);e("Processing "+b+"...");if(window.ActiveXObject||"ActiveXObject"in window)(k=h.transformNode(k))?(l.outerHTML=k,--oc||Ma(!0)):g("transformNodeToObject failed");else if(document.implementation&&document.implementation.createDocument){d=new XSLTProcessor;d.importStylesheet(k);var n=d.transformToFragment(h,document);if(n){var p=l.parentNode;p?(d= -k=0,m=l.getBoundingClientRect(),0>m.bottom&&(k=window.scrollX,d=window.scrollY),p.replaceChild(n,l),(l=document.getElementById(a))&&0>m.bottom&&(n=l.getBoundingClientRect(),d=window.performance&&window.performance.navigation.type==window.performance.navigation.TYPE_RELOAD?0:d+Math.ceil(n.height-m.height),window.scrollTo(k,d)),--oc||Ma(!0)):g("invalid machine element: "+a)}else g("transformToFragment failed")}else g("unable to transform XML: unsupported browser")}else g(d)}):g(d)};"\x3c"!=b.charAt(0)? -pc(b,a,d||"",!0,e,m):qc(b,"",a,d||"",!1,e,m)}else g("missing machine element: "+a)}catch(r){g(r.message)}return h}window.embedC1P=function(a,b,c,d,e){Ma(!1);return sc(a,b,c,e)}; -window.commandMachine=function(a,b,c,d,e,g){if("script"==e){d=!1;c+=".machine";if(!g)delete Ua[c],d=!0;else if("string"==typeof g&&!Ua[c]){d=!0;e=Ua;for(var l=c,k=g.length,h=[],m=[],n="",p=null,r=0;r>24)} +f.S=function(a){if(a>=this.K&&a=a.Ga?a.l("invalid address: "+z(b)):(a.a[a.K+b]=c&255,gb(a.u,b),a.u.update())}function gc(a,b){X(a.pa,b,void 0)||a.pa.push(b);return!0}function X(a,b,c){for(var d=!1,e=0;eg&&(m+=" ;'"+String.fromCharCode(g)+"'")}if(e==a.u.$a&& +(gk?m+=String.fromCharCode(g):16==k&&(m+="\u2026"),k++;m+='"'}m&&(d+=" "+m);c&&(d=(d+" ").substr(0,30),d+=";"+c.toString());a.Z=b;return d} +function Y(a,b){var c=a.ua;if(void 0!==b){var d=16;"$"==b.charAt(0)?b=b.substr(1):"0x"==b.substr(0,2)?b=b.substr(2):"."==b.charAt(b.length-1)&&(d=10,b=b.substr(0,b.length-1));c=parseInt(b,d);isNaN(c)&&(a.l("invalid base-"+d+" address: "+b),c=void 0)}void 0!==c&&(c=a.Ga)&&(a.l("address out of range: "+u(c)),c=void 0);return c} +function jc(a,b){if("?"==b)a.l("\nfrequency commands:"),a.l("clear\tclear all frequency counts");else{var c=0;if(a.B)if("clear"==b){for(b=0;ba.Pb.indexOf(g)&&(k=a.P);k==a.lb&&27!=g&&(k=a.P)}else a.l("unknown operand: "+h),g=-1;if(0<=g){l=-1;for(e=0;el)l=e;else{a.l("too many instruction matches (both "+v(l)+" and "+v(e)+")");l=-2;break}if(0<=l){if(d.push(l),void 0!==k)if(b=a.ha[l][1],h=h.match(/[0-9A-F]+/),null!==h)for(h=parseInt(h[0],16),1==b&&k==a.ea&&(h-=c+2,-128>h||127>>=8;else b&&a.l("instruction missing "+b+" bytes")}else a.l("unknown instruction: "+b+" "+h)}}k=d;if(k.length){for(c=0;cg&&kl?String.fromCharCode(l):".",k++;a.l(u(e,4)+" "+b+h)}a.ua=k}break;case "e":k=c[1];if(void 0===k)a.l("missing address");else if(k=Y(a,k),void 0!==k)for(d=2;dd.length&&(a.l("note: only "+ +d.length+" available"),b=d.length);void 0!==h&&(a.fb=0,a.l(b+" instructions earlier:"));h=a.fb?a.fb:1;c-=b;for(0>c&&(c=d.length-1);k&&c!=a.La;){e=d[c];if(0>e)break;a.l(ic(a,e,h++));++c==d.length&&(c=0);k--;b--}a.Rb=b;a.fb=h}10==k&&a.l("no history available");break;case "r":cc(a,c);break;case "s":a.S(a.u.f)==a.u.Pa?(hc(a,a.u.f+3),a.Aa=!0,a.va()||a.u.da()):kc(a);break;case "t":kc(a,c[1]);break;case "u":bc(a,c[1],c[2],8);break;case "?":case "help":a.l("\ncommands:\n?\thelp\na [#]\tassemble\nb [#]\tbreakpoint\nd [#]\tdump memory\ne [#]\tedit memory\nf\tdump frequencies\ng [#]\trun to [#]\nh\thalt\no\toptions\np [#]\tdump history\nr\tdump/edit registers\ns\tstep over instruction\nt [#]\tstep instruction(s)\nu [#]\tunassemble"); +a.l("note: frequency and history commands operate only when breakpoints are set");break;default:a.l("unknown command: "+b)}}}E(function(){for(var a=J(document,"c1pjs","debugger"),b=0;b");b&&b.ja(!0,a)} +E(function(){for(var a=J(document,"c1pjs","computer"),b=0;b');return}}if(void 0===h){C(' definition must appear first in the specification'); +break}if(e=Oa("debugger",d.id))g["debugger"]=[e],e.ca&&e.ca(h,l,k,g.cpu[0]);l=new Z(d,g);if(k=Oa("panel",d.id))if(g.panel=[k],k.H.print){e=void 0;d=d.id;g=[];d&&(d=0<(e=d.indexOf("."))?d.substr(0,e+1):"");for(e=0;en.indexOf("/")&&"/"==window.location.pathname.slice(-1)&&(n=window.location.pathname+n);k?"}"==k.slice(-1)?(k=k.slice(0,-1),1]*\sclass=)(['"])(.*?)(\2.*?>)/);p&&(m=m.replace(p[0],p[1]+p[2]+d+p[4]),d="")}m=m.replace(/(]*\sid=)(['"]).*?\2/, +"$1$2"+c+"$2"+(d?' class="'+d+'"':"")+(k?" parms='"+k+"'":"")+(n?' url="'+n+'"':""))}e||(m=m.replace(/().*?(<\/xsl:variable>)/,"$1C1Pjs$2"),m=m.replace(/().*?(<\/xsl:variable>)/,"$1c1pjs$2"));n=null;if("<"==m.charAt(0))try{e||(m=m.replace(/\s*/g,"")),window.ActiveXObject||"ActiveXObject"in window?(n=new window.ActiveXObject("Microsoft.XMLDOM"),n.async=!1,n.loadXML(m)):n=(new window.DOMParser).parseFromString(m,"text/xml")}catch(r){n= +null,m=r.message}else m="unrecognized XML: "+(255/g.exec(a)){var e=d[2];b("Loading "+e+"...");B(e,function(g,h,l){if(l||!h)c(a,"unable to resolve XML reference: "+d[0]+" ("+l+")");else{if(g=d[3])if(l=h.match(new RegExp("<"+d[1]+"[^>]*>"))){for(var k=l[0],m,n=/( [a-z]+=)(['"])(.*?)\2/gi;m=n.exec(g);)k=0>k.toLowerCase().indexOf(m[1].toLowerCase())?k.replace(">",m[0]+">"):k.replace(new RegExp(m[1]+"(['\"])(.*?)\\1"),m[0]);l[0]!=k&&(h=h.replace(l[0],k))}else{c(a,"missing <"+d[1]+"> in "+ +e);return}h=h.replace(/<\?xml[^>]*>[\r\n]*/,"");a=a.replace(d[0],h);pc(a,b,c)}})}else c(a,"")} +function qc(a,b,c,d){function e(r){if(void 0===l){var q=h&&J(h,"machine-warning");l=q&&q[0]||h}l&&(l.innerHTML=qa(r))}function g(r){e("Error: "+r);k&&(--mc||Ja(!0));k=!1}var h,l,k=!0;b||(b="machine.xml",c||(c="components.xsl"));mc++;Ya[a]={};try{if(h=document.getElementById(a)){var m;if("object"==typeof resources&&(m=resources.css)){var n=document.head||document.getElementsByTagName("head")[0],p=document.createElement("style");p.type="text/css";p.styleSheet?p.styleSheet.cssText=m:p.appendChild(document.createTextNode(m)); +n.appendChild(p)}c||(c="/versions/c1pjs/1.75.2/components.xsl");m=function(r,q){q?nc(c||"","","",!1,e,function(x,y){if(y){var w=c||"";Ya[a]&&w&&(Ya[a][w]=x);e("Processing "+b+"...");if(window.ActiveXObject||"ActiveXObject"in window)(y=q.transformNode(y))?(h.outerHTML=y,--mc||Ja(!0)):g("transformNodeToObject failed");else if(document.implementation&&document.implementation.createDocument){x=new XSLTProcessor;x.importStylesheet(y);var sa=x.transformToFragment(q,document);if(sa){var Lb=h.parentNode; +Lb?(x=y=0,w=h.getBoundingClientRect(),0>w.bottom&&(y=window.scrollX,x=window.scrollY),Lb.replaceChild(sa,h),(h=document.getElementById(a))&&0>w.bottom&&(sa=h.getBoundingClientRect(),x=window.performance&&window.performance.navigation.type==window.performance.navigation.TYPE_RELOAD?0:x+Math.ceil(sa.height-w.height),window.scrollTo(y,x)),--mc||Ja(!0)):g("invalid machine element: "+a)}else g("transformToFragment failed")}else g("unable to transform XML: unsupported browser")}else g(x)}):g(r)};"<"!=b.charAt(0)? +nc(b,a,d||"",!0,e,m):oc(b,"",a,d||"",!1,e,m)}else g("missing machine element: "+a)}catch(r){g(r.message)}return k}window.embedC1P=function(a,b,c,d,e){Ja(!1);return qc(a,b,c,e)}; +window.commandMachine=function(a,b,c,d,e,g){if("script"==e){d=!1;c+=".machine";if(!g)delete Ra[c],d=!0;else if("string"==typeof g&&!Ra[c]){d=!0;e=Ra;for(var h=c,l=g.length,k=[],m=[],n="",p=null,r=0;r\";\n\nvar LICENSE = \"License: GPL version 3 or later \";\n\nvar CSSCLASS = \"pcjs\";\n\n/**\n * @define {string}\n */\nvar SITEURL = \"http://localhost:8088\"; // this @define is overridden by the Closure Compiler with \"https://www.pcjs.org\"\n\n/**\n * @define {boolean}\n */\nvar COMPILED = false; // this @define is overridden by the Closure Compiler (to true)\n\n/**\n * @define {boolean}\n */\nvar DEBUG = true; // this @define is overridden by the Closure Compiler (to false) to remove DEBUG-only code\n\n/**\n * @define {boolean}\n */\nvar MAXDEBUG = false; // this @define is overridden by the Closure Compiler (to false) to remove MAXDEBUG-only code\n\n/**\n * @define {boolean}\n */\nvar PRIVATE = false; // this @define is overridden by the Closure Compiler (to false) to enable PRIVATE code\n\n/*\n * RS-232 DB-25 Pin Definitions, mapped to bits 1-25 in a 32-bit status value.\n *\n * SerialPorts in PCjs machines are considered DTE (Data Terminal Equipment), which means they should be \"virtually\"\n * connected to each other via a null-modem cable, which assumes the following cross-wiring:\n *\n * G 1 <-> 1 G (Ground)\n * TD 2 <-> 3 RD (Received Data)\n * RD 3 <-> 2 TD (Transmitted Data)\n * RTS 4 <-> 5 CTS (Clear To Send)\n * CTS 5 <-> 4 RTS (Request To Send)\n * DSR 6+8 <-> 20 DTR (Data Terminal Ready)\n * SG 7 <-> 7 SG (Signal Ground)\n * DTR 20 <-> 6+8 DSR (Data Set Ready + Carrier Detect)\n * RI 22 <-> 22 RI (Ring Indicator)\n *\n * TODO: Move these definitions to a more appropriate shared file at some point.\n */\nvar RS232 = {\n RTS: {\n PIN: 4,\n MASK: 0x00000010\n },\n CTS: {\n PIN: 5,\n MASK: 0x00000020\n },\n DSR: {\n PIN: 6,\n MASK: 0x00000040\n },\n CD: {\n PIN: 8,\n MASK: 0x00000100\n },\n DTR: {\n PIN: 20,\n MASK: 0x00100000\n },\n RI: {\n PIN: 22,\n MASK: 0x00400000\n }\n};\n\n/*\n * NODE should be true if we're running under NodeJS (eg, command-line), false if not (eg, web browser)\n */\nvar NODE = false;\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/dumpapi.js (C) Jeff Parsons 2012-2019\n */\n\n/*\n * Our \"DiskDump API\", such as it was, used to look like:\n *\n * http://pcjs.org/bin/convdisk.php?disk=/disks/pc/dos/ibm/2.00/PCDOS200-DISK1.json&format=img\n *\n * To make it (a bit) more \"REST-like\", the above request now looks like:\n *\n * https://www.pcjs.org/api/v1/dump?disk=/disks/pc/dos/ibm/2.00/PCDOS200-DISK1.json&format=img\n *\n * Similarly, our \"FileDump API\" used to look like:\n *\n * http://pcjs.org/bin/convrom.php?rom=/devices/pc/rom/5150/1981-04-24/PCBIOS-REV1.rom&format=json\n *\n * and that request now looks like:\n *\n * https://www.pcjs.org/api/v1/dump?file=/devices/pc/rom/5150/1981-04-24/PCBIOS-REV1.rom&format=json\n *\n * I don't think it makes sense to avoid \"query\" parameters, because blending the path of a disk image with the\n * the rest of the URL would be (a) confusing, and (b) more work to parse.\n */\nvar DumpAPI = {\n ENDPOINT: \"/api/v1/dump\",\n QUERY: {\n DIR: \"dir\", // value is path of a directory (DiskDump only)\n DISK: \"disk\", // value is path of a disk image (DiskDump only)\n FILE: \"file\", // value is path of a ROM image file (FileDump only)\n IMG: \"img\", // alias for DISK\n PATH: \"path\", // value is path of a one or more files (DiskDump only)\n FORMAT: \"format\", // value is one of FORMAT values below\n COMMENTS: \"comments\", // value is either \"true\" or \"false\"\n DECIMAL: \"decimal\", // value is either \"true\" to force all numbers to decimal, \"false\" or undefined otherwise\n MBHD: \"mbhd\", // value is hard drive size in Mb (formerly \"mbsize\") (DiskDump only) (DEPRECATED)\n SIZE: \"size\" // value is target disk size in Kb (supersedes \"mbhd\") (DiskDump only)\n },\n FORMAT: {\n JSON: \"json\", // default\n JSON_GZ: \"gz\", // gzip is currently used ONLY for compressed JSON\n DATA: \"data\", // same as \"json\", but built without JSON.stringify() (DiskDump only)\n HEX: \"hex\", // deprecated\n OCTAL: \"octal\", // displays data as octal words\n BYTES: \"bytes\", // displays data as hex bytes; normally used only when comments are enabled\n WORDS: \"words\", // displays data as hex words; normally used only when comments are enabled\n LONGS: \"longs\", // displays data as dwords\n IMG: \"img\", // returns the raw disk data (ie, using a Buffer object) (DiskDump only)\n ROM: \"rom\" // returns the raw file data (ie, using a Buffer object) (FileDump only)\n }\n};\n\n/*\n * Because we use an overloaded API endpoint (ie, one that's shared with the FileDump module), we must\n * also provide a list of commands which, when combined with the endpoint, define a unique request.\n */\nDumpAPI.asDiskCommands = [DumpAPI.QUERY.DIR, DumpAPI.QUERY.DISK, DumpAPI.QUERY.PATH];\nDumpAPI.asFileCommands = [DumpAPI.QUERY.FILE];\n\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/reportapi.js (C) Jeff Parsons 2012-2019\n */\n\nvar ReportAPI = {\n ENDPOINT: \"/api/v1/report\",\n QUERY: {\n APP: \"app\",\n VER: \"ver\",\n URL: \"url\",\n USER: \"user\",\n TYPE: \"type\",\n DATA: \"data\"\n },\n TYPE: {\n BUG: \"bug\"\n },\n RES: {\n OK: \"Thank you\"\n }\n};\n\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/strlib.js (C) Jeff Parsons 2012-2019\n */\n\nclass Str {\n /**\n * isValidInt(s, base)\n *\n * The built-in parseInt() function has the annoying feature of returning a partial value (ie,\n * up to the point where it encounters an invalid character); eg, parseInt(\"foo\", 16) returns 0xf.\n *\n * So it's best to use our own Str.parseInt() function, which will in turn use this function to\n * validate the entire string.\n *\n * @param {string} s is the string representation of some number\n * @param {number} [base] is the radix to use (default is 10); only 2, 8, 10 and 16 are supported\n * @return {boolean} true if valid, false if invalid (or the specified base isn't supported)\n */\n static isValidInt(s, base)\n {\n if (!base || base == 10) return s.match(/^-?[0-9]+$/) !== null;\n if (base == 16) return s.match(/^-?[0-9a-f]+$/i) !== null;\n if (base == 8) return s.match(/^-?[0-7]+$/) !== null;\n if (base == 2) return s.match(/^-?[01]+$/) !== null;\n return false;\n }\n\n /**\n * parseInt(s, base)\n *\n * This is a wrapper around the built-in parseInt() function. Our wrapper recognizes certain prefixes\n * ('$' or \"0x\" for hex, '#' or \"0o\" for octal) and suffixes ('.' for decimal, 'h' for hex, 'y' for\n * binary), and then calls isValidInt() to ensure we don't convert strings that contain partial values;\n * see isValidInt() for details.\n *\n * The use of multiple prefix/suffix combinations is undefined (although for the record, we process\n * prefixes first). We do NOT support the \"0b\" prefix to indicate binary UNLESS one or more commas are\n * also present (because \"0b\" is also a valid hex sequence), and we do NOT support a single leading zero\n * to indicate octal (because such a number could also be decimal or hex). Any number of commas are\n * allowed; we remove them all before calling the built-in parseInt().\n *\n * More recently, we've added support for \"^D\", \"^O\", and \"^B\" prefixes to accommodate the base overrides\n * that the PDP-10's MACRO-10 assembly language supports (decimal, octal, and binary, respectively).\n * If this support turns out to adversely affect other debuggers, then it will have to be \"conditionalized\".\n * Similarly, we've added support for \"K\", \"M\", and \"G\" MACRO-10-style suffixes that add 3, 6, or 9 zeros\n * to the value to be parsed, respectively.\n *\n * @param {string} s is the string representation of some number\n * @param {number} [base] is the radix to use (default is 10); can be overridden by prefixes/suffixes\n * @return {number|undefined} corresponding value, or undefined if invalid\n */\n static parseInt(s, base)\n {\n let value;\n\n if (s) {\n if (!base) base = 10;\n\n let ch, chPrefix, chSuffix;\n let fCommas = (s.indexOf(',') > 0);\n if (fCommas) s = s.replace(/,/g, '');\n\n ch = chPrefix = s.charAt(0);\n if (chPrefix == '#') {\n base = 8;\n chPrefix = '';\n }\n else if (chPrefix == '$') {\n base = 16;\n chPrefix = '';\n }\n if (ch != chPrefix) {\n s = s.substr(1);\n }\n else {\n ch = chPrefix = s.substr(0, 2);\n if (chPrefix == '0b' && fCommas || chPrefix == '^B') {\n base = 2;\n chPrefix = '';\n }\n else if (chPrefix == '0o' || chPrefix == '^O') {\n base = 8;\n chPrefix = '';\n }\n else if (chPrefix == '^D') {\n base = 10;\n chPrefix = '';\n }\n else if (chPrefix == '0x') {\n base = 16;\n chPrefix = '';\n }\n if (ch != chPrefix) s = s.substr(2);\n }\n ch = chSuffix = s.slice(-1);\n if (chSuffix == 'Y' || chSuffix == 'y') {\n base = 2;\n chSuffix = '';\n }\n else if (chSuffix == '.') {\n base = 10;\n chSuffix = '';\n }\n else if (chSuffix == 'H' || chSuffix == 'h') {\n base = 16;\n chSuffix = '';\n }\n else if (chSuffix == 'K') {\n chSuffix = '000';\n }\n else if (chSuffix == 'M') {\n chSuffix = '000000';\n }\n else if (chSuffix == 'G') {\n chSuffix = '000000000';\n }\n if (ch != chSuffix) s = s.slice(0, -1) + chSuffix;\n /*\n * This adds support for the MACRO-10 binary shifting (Bn) suffix, which must be stripped from the\n * number before parsing, and then applied to the value after parsing. If n is omitted, 35 is assumed,\n * which is a net shift of zero. If n < 35, then a left shift of (35 - n) is required; if n > 35, then\n * a right shift of -(35 - n) is required.\n */\n let v, shift = 0;\n if (base <= 10) {\n let match = s.match(/(-?[0-9]+)B([0-9]*)/);\n if (match) {\n s = match[1];\n shift = 35 - ((match[2] || 35) & 0xff);\n }\n }\n if (Str.isValidInt(s, base) && !isNaN(v = parseInt(s, base))) {\n /*\n * With the need to support larger (eg, 36-bit) integers, truncating to 32 bits is no longer helpful.\n *\n * value = v|0;\n */\n if (shift) {\n /*\n * Since binary shifting is a logical operation, and since shifting by division only works properly\n * with positive numbers, we must convert a negative value to a positive value, by computing the two's\n * complement.\n */\n if (v < 0) v += Math.pow(2, 36);\n if (shift > 0) {\n v *= Math.pow(2, shift);\n } else {\n v = Math.trunc(v / Math.pow(2, -shift));\n }\n }\n value = v;\n }\n }\n return value;\n }\n\n /**\n * toBase(n, radix, cch, sPrefix, nGrouping)\n *\n * Displays the given number as an unsigned integer using the specified radix and number of digits.\n *\n * @param {number|*} n\n * @param {number} radix (ie, the base)\n * @param {number} cch (the desired number of digits)\n * @param {string} [sPrefix] (default is none)\n * @param {number} [nGrouping]\n * @return {string}\n */\n static toBase(n, radix, cch, sPrefix = \"\", nGrouping = 0)\n {\n /*\n * We can't rely entirely on isNaN(), because isNaN(null) returns false, and we can't rely\n * entirely on typeof either, because typeof Nan returns \"number\". Sigh.\n *\n * Alternatively, we could mask and shift n regardless of whether it's null/undefined/NaN,\n * since JavaScript coerces such operands to zero, but I think there's \"value\" in seeing those\n * values displayed differently.\n */\n let s = \"\";\n if (isNaN(n) || typeof n != \"number\") {\n n = null;\n } else {\n /*\n * Callers that produced an input by dividing by a power of two rather than shifting (in order\n * to access more than 32 bits) may produce a fractional result, which ordinarily we would simply\n * ignore, but if the integer portion is zero and the sign is negative, we should probably treat\n * this value as a sign-extension.\n */\n if (n < 0 && n > -1) n = -1;\n /*\n * Negative values should be two's complemented according to the number of digits; for example,\n * 12 octal digits implies an upper limit 8^12.\n */\n if (n < 0) {\n n += Math.pow(radix, cch);\n }\n if (n >= Math.pow(radix, cch)) {\n cch = Math.ceil(Math.log(n) / Math.log(radix));\n }\n }\n let g = nGrouping || -1;\n while (cch-- > 0) {\n if (!g) {\n s = ',' + s;\n g = nGrouping;\n }\n if (n == null) {\n s = '?' + s;\n } else {\n let d = n % radix;\n d += (d >= 0 && d <= 9? 0x30 : 0x41 - 10);\n s = String.fromCharCode(d) + s;\n n = Math.trunc(n / radix);\n }\n g--;\n }\n return sPrefix + s;\n }\n\n /**\n * toBin(n, cch, nGrouping)\n *\n * Converts an integer to binary, with the specified number of digits (up to a maximum of 36).\n *\n * @param {number|*} n (supports integers up to 36 bits now)\n * @param {number} [cch] is the desired number of binary digits (0 or undefined for default of either 8, 18, or 36)\n * @param {number} [nGrouping]\n * @return {string} the binary representation of n\n */\n static toBin(n, cch, nGrouping)\n {\n if (!cch) {\n // cch = Math.ceil(Math.log(Math.abs(n) + 1) / Math.LN2) || 1;\n let v = Math.abs(n);\n if (v <= 0b11111111) {\n cch = 8;\n } else if (v <= 0b111111111111111111) {\n cch = 18;\n } else {\n cch = 36;\n }\n } else if (cch > 36) cch = 36;\n return Str.toBase(n, 2, cch, \"\", nGrouping);\n }\n\n /**\n * toBinBytes(n, cb, fPrefix)\n *\n * Converts an integer to binary, with the specified number of bytes (up to the default of 4).\n *\n * @param {number|null|undefined} n (interpreted as a 32-bit value)\n * @param {number} [cb] is the desired number of binary bytes (4 is both the default and the maximum)\n * @param {boolean} [fPrefix]\n * @return {string} the binary representation of n\n */\n static toBinBytes(n, cb, fPrefix)\n {\n let s = \"\";\n if (!cb || cb > 4) cb = 4;\n for (let i = 0; i < cb; i++) {\n if (s) s = ',' + s;\n s = Str.toBin(n & 0xff, 8) + s;\n n >>= 8;\n }\n return (fPrefix? \"0b\" : \"\") + s;\n }\n\n /**\n * toOct(n, cch, fPrefix)\n *\n * Converts an integer to octal, with the specified number of digits (default of 6; max of 12)\n *\n * You might be tempted to use the built-in n.toString(8) instead, but it doesn't zero-pad and it\n * doesn't properly convert negative values. Moreover, if n is undefined, n.toString() will throw\n * an exception, whereas this function will return '?' characters.\n *\n * @param {number|*} n (supports integers up to 36 bits now)\n * @param {number} [cch] is the desired number of octal digits (0 or undefined for default of either 6, 8, or 12)\n * @param {boolean} [fPrefix]\n * @return {string} the octal representation of n\n */\n static toOct(n, cch, fPrefix)\n {\n if (!cch) {\n // cch = Math.ceil(Math.log(Math.abs(n) + 1) / Math.log(8)) || 1;\n let v = Math.abs(n);\n if (v <= 0o777777) {\n cch = 6;\n } else if (v <= 0o77777777) {\n cch = 8;\n } else {\n cch = 12;\n }\n } else if (cch > 12) cch = 12;\n return Str.toBase(n, 8, cch, fPrefix? \"0o\" : \"\");\n }\n\n /**\n * toDec(n, cch)\n *\n * Converts an integer to decimal, with the specified number of digits (default of 5; max of 11)\n *\n * You might be tempted to use the built-in n.toString(10) instead, but it doesn't zero-pad and it\n * doesn't properly convert negative values. Moreover, if n is undefined, n.toString() will throw\n * an exception, whereas this function will return '?' characters.\n *\n * @param {number|*} n (supports integers up to 36 bits now)\n * @param {number} [cch] is the desired number of decimal digits (0 or undefined for default of either 5 or 11)\n * @return {string} the decimal representation of n\n */\n static toDec(n, cch)\n {\n if (!cch) {\n // cch = Math.ceil(Math.log(Math.abs(n) + 1) / Math.LN10) || 1;\n let v = Math.abs(n);\n if (v <= 99999) {\n cch = 5;\n } else {\n cch = 11;\n }\n } else if (cch > 11) cch = 11;\n return Str.toBase(n, 10, cch);\n }\n\n /**\n * toHex(n, cch, fPrefix)\n *\n * Converts an integer to hex, with the specified number of digits (default of 4 or 8, max of 9).\n *\n * You might be tempted to use the built-in n.toString(16) instead, but it doesn't zero-pad and it\n * doesn't properly convert negative values; for example, if n is -2147483647, then n.toString(16)\n * will return \"-7fffffff\" instead of \"80000001\". Moreover, if n is undefined, n.toString() will\n * throw an exception, whereas this function will return '?' characters.\n *\n * NOTE: The following work-around (adapted from code found on StackOverflow) would be another solution,\n * taking care of negative values, zero-padding, and upper-casing, but not null/undefined/NaN values:\n *\n * s = (n < 0? n + 0x100000000 : n).toString(16);\n * s = \"00000000\".substr(0, 8 - s.length) + s;\n * s = s.substr(0, cch).toUpperCase();\n *\n * @param {number|*} n (supports integers up to 36 bits now)\n * @param {number} [cch] is the desired number of hex digits (0 or undefined for default of either 4, 8, or 9)\n * @param {boolean} [fPrefix]\n * @return {string} the hex representation of n\n */\n static toHex(n, cch, fPrefix)\n {\n if (!cch) {\n // cch = Math.ceil(Math.log(Math.abs(n) + 1) / Math.log(16)) || 1;\n let v = Math.abs(n);\n if (v <= 0xffff) {\n cch = 4;\n } else if (v <= 0xffffffff) {\n cch = 8;\n } else {\n cch = 9;\n }\n } else if (cch > 9) cch = 9;\n return Str.toBase(n, 16, cch, fPrefix? \"0x\" : \"\");\n }\n\n /**\n * toHexByte(b)\n *\n * Alias for Str.toHex(b, 2, true)\n *\n * @param {number|null|undefined} b is a byte value\n * @return {string} the hex representation of b\n */\n static toHexByte(b)\n {\n return Str.toHex(b, 2, true);\n }\n\n /**\n * toHexWord(w)\n *\n * Alias for Str.toHex(w, 4, true)\n *\n * @param {number|null|undefined} w is a word (16-bit) value\n * @return {string} the hex representation of w\n */\n static toHexWord(w)\n {\n return Str.toHex(w, 4, true);\n }\n\n /**\n * toHexLong(l)\n *\n * Alias for Str.toHex(l, 8, true)\n *\n * @param {number|null|undefined} l is a dword (32-bit) value\n * @return {string} the hex representation of w\n */\n static toHexLong(l)\n {\n return Str.toHex(l, 8, true);\n }\n\n /**\n * getBaseName(sFileName, fStripExt)\n *\n * This is a poor-man's version of Node's path.basename(), which Node-only components should use instead.\n *\n * Note that if fStripExt is true, this strips ANY extension, whereas path.basename() strips the extension only\n * if it matches the second parameter (eg, path.basename(\"/foo/bar/baz/asdf/quux.html\", \".html\") returns \"quux\").\n *\n * @param {string} sFileName\n * @param {boolean} [fStripExt]\n * @return {string}\n */\n static getBaseName(sFileName, fStripExt)\n {\n let sBaseName = sFileName;\n\n let i = sFileName.lastIndexOf('/');\n if (i >= 0) sBaseName = sFileName.substr(i + 1);\n\n /*\n * This next bit is a kludge to clean up names that are part of a URL that includes unsightly query parameters.\n */\n i = sBaseName.indexOf('&');\n if (i > 0) sBaseName = sBaseName.substr(0, i);\n\n if (fStripExt) {\n i = sBaseName.lastIndexOf(\".\");\n if (i > 0) {\n sBaseName = sBaseName.substring(0, i);\n }\n }\n return sBaseName;\n }\n\n /**\n * getExtension(sFileName)\n *\n * This is a poor-man's version of Node's path.extname(), which Node-only components should use instead.\n *\n * Note that we EXCLUDE the period from the returned extension, whereas path.extname() includes it.\n *\n * @param {string} sFileName\n * @return {string} the filename's extension (in lower-case and EXCLUDING the \".\"), or an empty string\n */\n static getExtension(sFileName)\n {\n let sExtension = \"\";\n let i = sFileName.lastIndexOf(\".\");\n if (i >= 0) {\n sExtension = sFileName.substr(i + 1).toLowerCase();\n }\n return sExtension;\n }\n\n /**\n * endsWith(s, sSuffix)\n *\n * @param {string} s\n * @param {string} sSuffix\n * @return {boolean} true if s ends with sSuffix, false if not\n */\n static endsWith(s, sSuffix)\n {\n return s.indexOf(sSuffix, s.length - sSuffix.length) !== -1;\n }\n\n /**\n * escapeHTML(sHTML)\n *\n * @param {string} sHTML\n * @return {string} with special characters \"escaped\" as HTML entities, similar to PHP's htmlspecialchars()\n */\n static escapeHTML(sHTML)\n {\n /*\n * Most recently, '$' was added to the list to help avoid problems when callers use the resulting string\n * as a replacement string for JavaScript's string replace() function, which treats '$' specially. Technically,\n * that's on the callers of replace(), not us, but this doesn't seem harmful, and it's definitely helpful.\n */\n return sHTML.replace(/[&<>\"'$]/g, function(m)\n {\n return Str.HTMLEscapeMap[m];\n });\n }\n\n /**\n * replace(sSearch, sReplace, s)\n *\n * The JavaScript replace() function ALWAYS interprets \"$\" specially in replacement strings, even when\n * the search string is NOT a RegExp; specifically:\n *\n * $$ Inserts a \"$\"\n * $& Inserts the matched substring\n * $` Inserts the portion of the string that precedes the matched substring\n * $' Inserts the portion of the string that follows the matched substring\n * $n Where n is a positive integer less than 100, inserts the nth parenthesized sub-match string,\n * provided the first argument was a RegExp object\n *\n * So, if a replacement string containing dollar signs passes through a series of replace() calls, untold\n * problems could result. Hence, this function, which simply uses the replacement string as-is.\n *\n * Similar to the JavaScript replace() method (when sSearch is a string), this replaces only ONE occurrence\n * (ie, the FIRST occurrence); it might be nice to add options to replace the LAST occurrence and/or ALL\n * occurrences, but we'll revisit that later.\n *\n * @param {string} sSearch\n * @param {string} sReplace\n * @param {string} s\n * @return {string}\n */\n static replace(sSearch, sReplace, s)\n {\n let i = s.indexOf(sSearch);\n if (i >= 0) {\n s = s.substr(0, i) + sReplace + s.substr(i + sSearch.length);\n }\n return s;\n }\n\n /**\n * replaceAll(sSearch, sReplace, s)\n *\n * @param {string} sSearch\n * @param {string} sReplace\n * @param {string} s\n * @return {string}\n */\n static replaceAll(sSearch, sReplace, s)\n {\n let a = {};\n a[sSearch] = sReplace;\n return Str.replaceArray(a, s);\n }\n\n /**\n * replaceArray(a, s)\n *\n * @param {Object} a\n * @param {string} s\n * @return {string}\n */\n static replaceArray(a, s)\n {\n let sMatch = \"\";\n for (let k in a) {\n /*\n * As noted in:\n *\n * http://www.regexguru.com/2008/04/escape-characters-only-when-necessary/\n *\n * inside character classes, only backslash, caret, hyphen and the closing bracket need to be\n * escaped. And in fact, if you ensure that the closing bracket is first, the caret is not first,\n * and the hyphen is last, you can avoid escaping those as well.\n */\n k = k.replace(/([\\\\[\\]*{}().+?|$])/g, \"\\\\$1\");\n sMatch += (sMatch? '|' : '') + k;\n }\n return s.replace(new RegExp('(' + sMatch + ')', \"g\"), function(m)\n {\n return a[m];\n });\n }\n\n /**\n * pad(s, cch, fPadLeft)\n *\n * NOTE: the maximum amount of padding currently supported is 40 spaces.\n *\n * @param {string} s is a string\n * @param {number} cch is desired length\n * @param {boolean} [fPadLeft] (default is padding on the right)\n * @return {string} the original string (s) with spaces padding it to the specified length\n */\n static pad(s, cch, fPadLeft)\n {\n let sPadding = \" \";\n return fPadLeft? (sPadding + s).slice(-cch) : (s + sPadding).slice(0, cch);\n }\n\n /**\n * parseDate(date)\n * parseDate(date, time)\n * parseDate(year, month, day, hour, minute, second)\n *\n * Produces a UTC date when ONLY a date (no time) is provided; otherwise, it combines the date and\n * and time, producing a date that is either UTC or local, depending on the presence (or lack) of time\n * zone information. Finally, if numeric inputs are provided, then Date.UTC() is called to generate\n * a UTC time.\n *\n * In general, you should use this instead of new Date(s), because the Date constructor implicitly calls\n * Date.parse(s), which behaves inconsistently. For example, ISO date-only strings (e.g. \"1970-01-01\")\n * generate a UTC time, but non-ISO date-only strings (eg, \"10/1/1945\" or \"October 1, 1945\") generate a\n * local time.\n *\n * @param {...} args\n * @return {Date} (UTC unless a time string with a non-GMT timezone is explicitly provided)\n */\n static parseDate(...args)\n {\n let date;\n if (args[0] === undefined) {\n date = new Date(Date.now());\n }\n else if (typeof args[0] === \"string\") {\n date = new Date(args[0] + ' ' + (args[1] || \"00:00:00 GMT\"));\n }\n else if (args[1] === undefined) {\n date = new Date(args[0]);\n } else {\n date = new Date(Date.UTC(...args));\n }\n return date;\n }\n\n /**\n * isValidDate(date)\n *\n * @param {Date} date\n * @return {boolean}\n */\n static isValidDate(date)\n {\n return !isNaN(date.getTime());\n }\n\n /**\n * sprintf(format, ...args)\n *\n * Copied from the CCjs project (https://github.com/jeffpar/ccjs/blob/master/lib/stdio.js) and extended.\n *\n * Far from complete, let alone sprintf-compatible, but it's adequate for the handful of sprintf-style format\n * specifiers that I use.\n *\n * TODO: The %c and %s specifiers support a negative width (for left-justified output), but the numeric specifiers\n * (eg, %d and %x) do not; they support only positive widths and right-justified output. That's one of the more\n * glaring omissions at the moment.\n *\n * @param {string} format\n * @param {...} args\n * @return {string}\n */\n static sprintf(format, ...args)\n {\n let text = \"\";\n let aParts = format.split(/%([-+ 0#]*)([0-9]*|\\*)(\\.[0-9]+|)([hlL]?)([A-Za-z%])/);\n\n let iArg = 0, iPart;\n for (iPart = 0; iPart < aParts.length - 6; iPart += 6) {\n\n text += aParts[iPart];\n let arg, type = aParts[iPart+5];\n\n /*\n * Check for unrecognized types immediately, so we don't inadvertently pop any arguments;\n * the first 12 (\"ACDFHIMNSTWY\") are for our non-standard Date extensions (see below).\n *\n * For reference purposes, the standard ANSI C set of format types is: \"dioxXucsfeEgGpn%\".\n */\n let iType = \"ACDFHIMNSTWYdfjcsoXx%\".indexOf(type);\n if (iType < 0) {\n text += '%' + aParts[iPart+1] + aParts[iPart+2] + aParts[iPart+3] + aParts[iPart+4] + type;\n continue;\n }\n\n if (iArg < args.length) {\n arg = args[iArg];\n if (type != '%') iArg++;\n } else {\n arg = args[args.length-1];\n }\n let flags = aParts[iPart+1];\n let width = aParts[iPart+2];\n if (width == '*') {\n width = arg;\n if (iArg < args.length) {\n arg = args[iArg++];\n } else {\n arg = args[args.length-1];\n }\n } else {\n width = +width || 0;\n }\n let precision = aParts[iPart+3];\n precision = precision? +precision.substr(1) : -1;\n // let length = aParts[iPart+4]; // eg, 'h', 'l' or 'L' (all currently ignored)\n let hash = flags.indexOf('#') >= 0;\n let ach = null, s, radix = 0, p, prefix = \"\";\n\n /*\n * The following non-standard sprintf() format codes provide handy alternatives to the\n * PHP date() format codes that we used to use with the old datelib.formatDate() function:\n *\n * a: lowercase ante meridiem and post meridiem (am or pm) %A\n * d: day of the month, 2 digits with leading zeros (01, 02, ..., 31) %02D\n * D: 3-letter day of the week (\"Sun\", \"Mon\", ..., \"Sat\") %.3W\n * F: month (\"January\", \"February\", ..., \"December\") %F\n * g: hour in 12-hour format, without leading zeros (1, 2, ..., 12) %I\n * h: hour in 24-hour format, without leading zeros (0, 1, ..., 23) %H\n * H: hour in 24-hour format, with leading zeros (00, 01, ..., 23) %02H\n * i: minutes, with leading zeros (00, 01, ..., 59) %02N\n * j: day of the month, without leading zeros (1, 2, ..., 31) %D\n * l: day of the week (\"Sunday\", \"Monday\", ..., \"Saturday\") %W\n * m: month, with leading zeros (01, 02, ..., 12) %02M\n * M: 3-letter month (\"Jan\", \"Feb\", ..., \"Dec\") %.3F\n * n: month, without leading zeros (1, 2, ..., 12) %M\n * s: seconds, with leading zeros (00, 01, ..., 59) %02S\n * y: 2-digit year (eg, 14) %0.2Y\n * Y: 4-digit year (eg, 2014) %Y\n *\n * We also support a few custom format codes:\n *\n * %C: calendar output (equivalent to: %W, %F %D, %Y)\n * %T: timestamp output (equivalent to: %Y-%02M-%02D %02H:%02N:%02S)\n *\n * Use the optional '#' flag with any of the above '%' format codes to produce UTC results\n * (eg, '%#I' instead of '%I').\n *\n * The %A, %F, and %W types act as strings (which support the '-' left justification flag, as well as\n * the width and precision options), and the rest act as integers (which support the '0' padding flag\n * and the width option). Also, while %Y does act as an integer, it also supports truncation using the\n * precision option (normally, integers do not); this enables a variable number of digits for the year.\n *\n * So old code like this:\n *\n * printf(\"%s\\n\", formatDate(\"l, F j, Y\", date));\n *\n * can now be written like this:\n *\n * printf(\"%W, %F %D, %Y\\n\", date, date, date, date);\n *\n * or even more succinctly, as:\n *\n * printf(\"%C\\n\", date);\n */\n let ch, date = /** @type {Date} */ (iType < 12 && typeof arg != \"object\"? Str.parseDate(arg) : arg), dateUndefined;\n\n switch(type) {\n case 'C':\n ch = hash? '#' : '';\n text += (Str.isValidDate(date)? Str.sprintf(Str.sprintf(\"%%%sW, %%%sF %%%sD, %%%sY\", ch), date) : dateUndefined);\n continue;\n\n case 'D':\n arg = hash? date.getUTCDate() : date.getDate();\n type = 'd';\n break;\n\n case 'A':\n case 'H':\n case 'I':\n arg = hash? date.getUTCHours() : date.getHours();\n if (type == 'A') {\n arg = (arg < 12 ? \"am\" : \"pm\");\n type = 's';\n }\n else {\n if (type == 'I') {\n arg = (!arg? 12 : (arg > 12 ? arg - 12 : arg));\n }\n type = 'd';\n }\n break;\n\n case 'F':\n case 'M':\n arg = hash? date.getUTCMonth() : date.getMonth();\n if (type == 'F') {\n arg = Str.NamesOfMonths[arg];\n type = 's';\n } else {\n arg++;\n type = 'd';\n }\n break;\n\n case 'N':\n arg = hash? date.getUTCMinutes() : date.getMinutes();\n type = 'd';\n break;\n\n case 'S':\n arg = hash? date.getUTCSeconds() : date.getSeconds();\n type = 'd'\n break;\n\n case 'T':\n ch = hash? '#' : '';\n text += (Str.isValidDate(date)? Str.sprintf(Str.sprintf(\"%%%sY-%%%s02M-%%%s02D %%%s02H:%%%s02N:%%%s02S\", ch), date) : dateUndefined);\n continue;\n\n case 'W':\n arg = Str.NamesOfDays[hash? date.getUTCDay() : date.getDay()];\n type = 's';\n break;\n\n case 'Y':\n arg = hash? date.getUTCFullYear() : date.getFullYear();\n if (precision > 0) {\n arg = arg % (Math.pow(10, precision));\n precision = -1;\n }\n type = 'd';\n break;\n }\n\n switch(type) {\n case 'd':\n /*\n * We could use \"arg |= 0\", but there may be some value to supporting integers > 32 bits.\n *\n * Also, unlike the 'X' and 'x' hexadecimal cases, there's no need to explicitly check for string\n * arguments, because Math.trunc() automatically coerces any string value to a (decimal) number.\n */\n arg = Math.trunc(arg);\n /* falls through */\n\n case 'f':\n s = arg + \"\";\n if (precision > 0) {\n width -= (precision + 1);\n }\n if (s.length < width) {\n if (flags.indexOf('0') >= 0) {\n if (arg < 0) width--;\n s = (\"0000000000\" + Math.abs(arg)).slice(-width);\n if (arg < 0) s = '-' + s;\n } else {\n s = (\" \" + s).slice(-width);\n }\n }\n if (precision > 0) {\n arg = Math.round((arg - Math.trunc(arg)) * Math.pow(10, precision));\n s += '.' + (\"0000000000\" + Math.abs(arg)).slice(-precision);\n }\n text += s;\n break;\n\n case 'j':\n /*\n * 'j' is one of our non-standard extensions to the sprintf() interface; it signals that\n * the caller is providing an Object that should be rendered as JSON. If a width is included\n * (eg, \"%2j\"), it's used as an indentation value; otherwise, no whitespace is added.\n */\n text += JSON.stringify(arg, null, width || null);\n break;\n\n case 'c':\n arg = typeof arg == \"string\"? arg[0] : String.fromCharCode(arg);\n /* falls through */\n\n case 's':\n /*\n * 's' includes some non-standard behavior, such as coercing non-strings to strings first.\n */\n if (arg !== undefined) {\n if (typeof arg != \"string\") {\n arg = arg.toString();\n }\n if (precision >= 0) {\n arg = arg.substr(0, precision);\n }\n while (arg.length < width) {\n if (flags.indexOf('-') >= 0) {\n arg += ' ';\n } else {\n arg = ' ' + arg;\n }\n }\n }\n text += arg;\n break;\n\n case 'o':\n radix = 8;\n if (hash) prefix = \"0\";\n /* falls through */\n\n case 'X':\n ach = Str.HexUpperCase;\n if (hash) prefix = \"0X\";\n /* falls through */\n\n case 'x':\n s = \"\";\n if (!radix) radix = 16;\n if (!prefix && hash) prefix = \"0x\";\n if (!ach) ach = Str.HexLowerCase;\n if (typeof arg == \"string\") {\n /*\n * Since we're advised to ALWAYS pass a radix to parseInt(), we must detect explicitly\n * hex values ourselves, because using a radix of 10 with any \"0x...\" value always returns 0.\n *\n * And if the value CAN be interpreted as decimal, then we MUST interpret it as decimal, because\n * we have sprintf() calls in /modules/pcx86/lib/testmon.js that depend on this code to perform\n * decimal to hex conversion. We're going to make our own rules here, since passing numbers in\n * string form isn't part of the sprintf \"spec\".\n */\n arg = Number.parseInt(arg, arg.match(/(^0x|[a-f])/i)? 16 : 10);\n }\n p = width? \"\" : prefix;\n do {\n let d = arg & (radix - 1);\n arg >>>= (radix == 16? 4 : 3);\n if (flags.indexOf('0') >= 0 || s == \"\" || d || arg) {\n s = ach[d] + s;\n } else if (width) {\n if (!prefix) {\n s = ' ' + s;\n } else {\n s = prefix.slice(-1) + s;\n prefix = prefix.slice(0, -1);\n }\n }\n } while (--width > 0 || arg);\n text += p + s;\n break;\n\n case '%':\n text += '%';\n break;\n\n default:\n text += \"(unimplemented printf type %\" + type + \")\";\n break;\n }\n }\n\n text += aParts[iPart];\n return text;\n }\n\n /**\n * stripLeadingZeros(s, fPad)\n *\n * @param {string} s\n * @param {boolean} [fPad]\n * @return {string}\n */\n static stripLeadingZeros(s, fPad)\n {\n let cch = s.length;\n s = s.replace(/^0+([0-9A-F]+)$/i, \"$1\");\n if (fPad) s = Str.pad(s, cch, true);\n return s;\n }\n\n /**\n * trim(s)\n *\n * @param {string} s\n * @return {string}\n */\n static trim(s)\n {\n if (String.prototype.trim) {\n return s.trim();\n }\n return s.replace(/^\\s+|\\s+$/g, \"\");\n }\n\n /**\n * toASCIICode(b)\n *\n * @param {number} b\n * @return {string}\n */\n static toASCIICode(b)\n {\n let s;\n if (b != Str.ASCII.CR && b != Str.ASCII.LF) {\n s = Str.ASCIICodeMap[b];\n }\n if (s) {\n s = '<' + s + '>';\n } else {\n s = String.fromCharCode(b);\n }\n return s;\n }\n}\n\n/*\n * Map special characters to their HTML escape sequences.\n */\nStr.HTMLEscapeMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '$': '$'\n};\n\n/*\n * Map \"unprintable\" ASCII codes to mnemonics, to more clearly see what's being printed.\n */\nStr.ASCIICodeMap = {\n 0x00: \"NUL\",\n 0x01: \"SOH\", // (CTRL_A) Start of Heading\n 0x02: \"STX\", // (CTRL_B) Start of Text\n 0x03: \"ETX\", // (CTRL_C) End of Text\n 0x04: \"EOT\", // (CTRL_D) End of Transmission\n 0x05: \"ENQ\", // (CTRL_E) Enquiry\n 0x06: \"ACK\", // (CTRL_F) Acknowledge\n 0x07: \"BEL\", // (CTRL_G) Bell\n 0x08: \"BS\", // (CTRL_H) Backspace\n 0x09: \"TAB\", // (CTRL_I) Horizontal Tab (aka HT)\n 0x0A: \"LF\", // (CTRL_J) Line Feed (New Line)\n 0x0B: \"VT\", // (CTRL_K) Vertical Tab\n 0x0C: \"FF\", // (CTRL_L) Form Feed (New Page)\n 0x0D: \"CR\", // (CTRL_M) Carriage Return\n 0x0E: \"SO\", // (CTRL_N) Shift Out\n 0x0F: \"SI\", // (CTRL_O) Shift In\n 0x10: \"DLE\", // (CTRL_P) Data Link Escape\n 0x11: \"XON\", // (CTRL_Q) Device Control 1 (aka DC1)\n 0x12: \"DC2\", // (CTRL_R) Device Control 2\n 0x13: \"XOFF\", // (CTRL_S) Device Control 3 (aka DC3)\n 0x14: \"DC4\", // (CTRL_T) Device Control 4\n 0x15: \"NAK\", // (CTRL_U) Negative Acknowledge\n 0x16: \"SYN\", // (CTRL_V) Synchronous Idle\n 0x17: \"ETB\", // (CTRL_W) End of Transmission Block\n 0x18: \"CAN\", // (CTRL_X) Cancel\n 0x19: \"EM\", // (CTRL_Y) End of Medium\n 0x1A: \"SUB\", // (CTRL_Z) Substitute\n 0x1B: \"ESC\", // Escape\n 0x1C: \"FS\", // File Separator\n 0x1D: \"GS\", // Group Separator\n 0x1E: \"RS\", // Record Separator\n 0x1F: \"US\", // Unit Separator\n 0x7F: \"DEL\"\n};\n\n/*\n * Refer to: https://en.wikipedia.org/wiki/Code_page_437\n */\nStr.CP437ToUnicode = [\n '\\u0000', '\\u263A', '\\u263B', '\\u2665', '\\u2666', '\\u2663', '\\u2660', '\\u2022',\n '\\u25D8', '\\u25CB', '\\u25D9', '\\u2642', '\\u2640', '\\u266A', '\\u266B', '\\u263C',\n '\\u25BA', '\\u25C4', '\\u2195', '\\u203C', '\\u00B6', '\\u00A7', '\\u25AC', '\\u21A8',\n '\\u2191', '\\u2193', '\\u2192', '\\u2190', '\\u221F', '\\u2194', '\\u25B2', '\\u25BC',\n '\\u0020', '\\u0021', '\\u0022', '\\u0023', '\\u0024', '\\u0025', '\\u0026', '\\u0027',\n '\\u0028', '\\u0029', '\\u002A', '\\u002B', '\\u002C', '\\u002D', '\\u002E', '\\u002F',\n '\\u0030', '\\u0031', '\\u0032', '\\u0033', '\\u0034', '\\u0035', '\\u0036', '\\u0037',\n '\\u0038', '\\u0039', '\\u003A', '\\u003B', '\\u003C', '\\u003D', '\\u003E', '\\u003F',\n '\\u0040', '\\u0041', '\\u0042', '\\u0043', '\\u0044', '\\u0045', '\\u0046', '\\u0047',\n '\\u0048', '\\u0049', '\\u004A', '\\u004B', '\\u004C', '\\u004D', '\\u004E', '\\u004F',\n '\\u0050', '\\u0051', '\\u0052', '\\u0053', '\\u0054', '\\u0055', '\\u0056', '\\u0057',\n '\\u0058', '\\u0059', '\\u005A', '\\u005B', '\\u005C', '\\u005D', '\\u005E', '\\u005F',\n '\\u0060', '\\u0061', '\\u0062', '\\u0063', '\\u0064', '\\u0065', '\\u0066', '\\u0067',\n '\\u0068', '\\u0069', '\\u006A', '\\u006B', '\\u006C', '\\u006D', '\\u006E', '\\u006F',\n '\\u0070', '\\u0071', '\\u0072', '\\u0073', '\\u0074', '\\u0075', '\\u0076', '\\u0077',\n '\\u0078', '\\u0079', '\\u007A', '\\u007B', '\\u007C', '\\u007D', '\\u007E', '\\u2302',\n '\\u00C7', '\\u00FC', '\\u00E9', '\\u00E2', '\\u00E4', '\\u00E0', '\\u00E5', '\\u00E7',\n '\\u00EA', '\\u00EB', '\\u00E8', '\\u00EF', '\\u00EE', '\\u00EC', '\\u00C4', '\\u00C5',\n '\\u00C9', '\\u00E6', '\\u00C6', '\\u00F4', '\\u00F6', '\\u00F2', '\\u00FB', '\\u00F9',\n '\\u00FF', '\\u00D6', '\\u00DC', '\\u00A2', '\\u00A3', '\\u00A5', '\\u20A7', '\\u0192',\n '\\u00E1', '\\u00ED', '\\u00F3', '\\u00FA', '\\u00F1', '\\u00D1', '\\u00AA', '\\u00BA',\n '\\u00BF', '\\u2310', '\\u00AC', '\\u00BD', '\\u00BC', '\\u00A1', '\\u00AB', '\\u00BB',\n '\\u2591', '\\u2592', '\\u2593', '\\u2502', '\\u2524', '\\u2561', '\\u2562', '\\u2556',\n '\\u2555', '\\u2563', '\\u2551', '\\u2557', '\\u255D', '\\u255C', '\\u255B', '\\u2510',\n '\\u2514', '\\u2534', '\\u252C', '\\u251C', '\\u2500', '\\u253C', '\\u255E', '\\u255F',\n '\\u255A', '\\u2554', '\\u2569', '\\u2566', '\\u2560', '\\u2550', '\\u256C', '\\u2567',\n '\\u2568', '\\u2564', '\\u2565', '\\u2559', '\\u2558', '\\u2552', '\\u2553', '\\u256B',\n '\\u256A', '\\u2518', '\\u250C', '\\u2588', '\\u2584', '\\u258C', '\\u2590', '\\u2580',\n '\\u03B1', '\\u00DF', '\\u0393', '\\u03C0', '\\u03A3', '\\u03C3', '\\u00B5', '\\u03C4',\n '\\u03A6', '\\u0398', '\\u03A9', '\\u03B4', '\\u221E', '\\u03C6', '\\u03B5', '\\u2229',\n '\\u2261', '\\u00B1', '\\u2265', '\\u2264', '\\u2320', '\\u2321', '\\u00F7', '\\u2248',\n '\\u00B0', '\\u2219', '\\u00B7', '\\u221A', '\\u207F', '\\u00B2', '\\u25A0', '\\u00A0'\n];\n\n/*\n * TODO: Future home of a complete ASCII table.\n */\nStr.ASCII = {\n LF: 0x0A,\n CR: 0x0D\n};\n\nStr.TYPES = {\n NULL: 0,\n BYTE: 1,\n WORD: 2,\n DWORD: 3,\n NUMBER: 4,\n STRING: 5,\n BOOLEAN: 6,\n OBJECT: 7,\n ARRAY: 8\n};\n\nStr.HexLowerCase = \"0123456789abcdef\";\nStr.HexUpperCase = \"0123456789ABCDEF\";\nStr.NamesOfDays = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"];\nStr.NamesOfMonths = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\n\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/usrlib.js (C) Jeff Parsons 2012-2019\n */\n\n\n/** @typedef {{ mask: number, shift: number }} */\nvar BitField;\n\n/** @typedef {Object.} */\nvar BitFields;\n\nclass Usr {\n /**\n * binarySearch(a, v, fnCompare)\n *\n * @param {Array} a is an array\n * @param {number|string|Array|Object} v\n * @param {function((number|string|Array|Object), (number|string|Array|Object))} [fnCompare]\n * @return {number} the index of matching entry if non-negative, otherwise the index of the insertion point\n */\n static binarySearch(a, v, fnCompare)\n {\n let left = 0;\n let right = a.length;\n let found = 0;\n if (fnCompare === undefined) {\n fnCompare = function(a, b)\n {\n return a > b ? 1 : a < b ? -1 : 0;\n };\n }\n while (left < right) {\n let middle = (left + right) >> 1;\n let compareResult;\n compareResult = fnCompare(v, a[middle]);\n if (compareResult > 0) {\n left = middle + 1;\n } else {\n right = middle;\n found = !compareResult;\n }\n }\n return found ? left : ~left;\n }\n\n /**\n * binaryInsert(a, v, fnCompare)\n *\n * If element v already exists in array a, the array is unchanged (we don't allow duplicates); otherwise, the\n * element is inserted into the array at the appropriate index.\n *\n * @param {Array} a is an array\n * @param {number|string|Array|Object} v is the value to insert\n * @param {function((number|string|Array|Object), (number|string|Array|Object))} [fnCompare]\n */\n static binaryInsert(a, v, fnCompare)\n {\n let index = Usr.binarySearch(a, v, fnCompare);\n if (index < 0) {\n a.splice(-(index + 1), 0, v);\n }\n }\n\n /**\n * getTimestamp()\n *\n * @return {string} timestamp containing the current date and time (\"yyyy-mm-dd hh:mm:ss\")\n */\n static getTimestamp()\n {\n let date = new Date();\n return Str.sprintf(\"%T\", date);\n }\n\n /**\n * getMonthDays(nMonth, nYear)\n *\n * NOTE: If we're being called on behalf of the PCx86 RTC, its year is always truncated to two digits (mod 100),\n * so we have no idea what century the year 0 might refer to. When using the normal leap-year formula, 0 fails\n * the mod 100 test but passes the mod 400 test, so as far as the RTC is concerned, every century year is a leap\n * year. Since we're most likely dealing with the year 2000, that's fine, since 2000 was also a leap year.\n *\n * TODO: There IS a separate RTC CMOS byte that's supposed to be set to CMOS_ADDR.CENTURY_DATE; it's always BCD,\n * so theoretically it will contain values like 0x19 or 0x20 (for the 20th and 21st centuries, respectively), and\n * we could add that as another parameter to this function, to improve the accuracy, but that would go beyond what\n * a real RTC actually does.\n *\n * @param {number} nMonth (1-12)\n * @param {number} nYear (normally a 4-digit year, but it may also be mod 100)\n * @return {number} the maximum (1-based) day allowed for the specified month and year\n */\n static getMonthDays(nMonth, nYear)\n {\n let nDays = Usr.aMonthDays[nMonth - 1];\n if (nDays == 28) {\n if ((nYear % 4) === 0 && ((nYear % 100) || (nYear % 400) === 0)) {\n nDays++;\n }\n }\n return nDays;\n }\n\n /**\n * adjustDays(date, days)\n *\n * Although the setDate() method compensates for day-of-month values outside the current month:\n *\n * > let d = new Date('11/4/2012');d\n * 2012-11-04T07:00:00.000Z\n * > new Date(d.setDate(d.getDate() + 365))\n * 2014-11-04T08:00:00.000Z\n *\n * notice the discrepancy in the time-of-day. Even if there is some technical reason (eg, a DayLight\n * Savings Time side-effect) why that answer is correct, it doesn't satisfy my goal of adjusting ONLY the\n * day, not the time-of-day.\n *\n * By comparison, the method below (multiplying the number of milliseconds in a day by the number of days)\n * works just fine, without any unexpected side-effects:\n *\n * > let d = new Date('11/4/2012');d\n * 2012-11-04T07:00:00.000Z\n * > new Date(d.getTime() + 365 * 86400000)\n * 2013-11-04T07:00:00.000Z\n *\n * @param {Date} date\n * @param {number} days (+/-)\n * @return {Date}\n */\n static adjustDays(date, days)\n {\n return new Date(date.getTime() + days * 86400000);\n }\n\n /**\n * subtractDays(date1, date2)\n *\n * @param {Date|string} date1\n * @param {Date|string} date2\n * @return {number} (date1 - date2, returned as a signed integer number of days)\n */\n static subtractDays(date1, date2)\n {\n if (typeof date1 == \"string\") date1 = new Date(date1);\n if (typeof date2 == \"string\") date2 = new Date(date2);\n return Math.round((date1.getTime() - date2.getTime()) / 86400000);\n }\n\n /**\n * defineBitFields(bfs)\n *\n * Prepares a bit field definition for use with getBitField() and setBitField(); eg:\n *\n * let bfs = Usr.defineBitFields({num:20, count:8, btmod:1, type:3});\n *\n * The above defines a set of bit fields containing four fields: num (bits 0-19), count (bits 20-27), btmod (bit 28), and type (bits 29-31).\n *\n * Usr.setBitField(bfs.num, n, 1);\n *\n * The above set bit field \"bfs.num\" in numeric variable \"n\" to the value 1.\n *\n * @param {Object} bfs\n * @return {BitFields}\n */\n static defineBitFields(bfs)\n {\n let bit = 0;\n for (let f in bfs) {\n let width = bfs[f];\n let mask = ((1 << width) - 1) << bit;\n bfs[f] = {mask: mask, shift: bit};\n bit += width;\n }\n return bfs;\n }\n\n /**\n * initBitFields(bfs, ...)\n *\n * @param {BitFields} bfs\n * @param {...number} var_args\n * @return {number} a value containing all supplied bit fields\n */\n static initBitFields(bfs, var_args)\n {\n let v = 0, i = 1;\n for (let f in bfs) {\n if (i >= arguments.length) break;\n v = Usr.setBitField(bfs[f], v, arguments[i++]);\n }\n return v;\n }\n\n /**\n * getBitField(bf, v)\n *\n * @param {BitField} bf\n * @param {number} v is a value containing bit fields\n * @return {number} the value of the bit field in v defined by bf\n */\n static getBitField(bf, v)\n {\n return (v & bf.mask) >> bf.shift;\n }\n\n /**\n * setBitField(bf, v, n)\n *\n * @param {BitField} bf\n * @param {number} v is a value containing bit fields\n * @param {number} n is a value to store in v in the bit field defined by bf\n * @return {number} updated v\n */\n static setBitField(bf, v, n)\n {\n return (v & ~bf.mask) | ((n << bf.shift) & bf.mask);\n }\n\n /**\n * indexOf(a, t, i)\n *\n * Use this instead of Array.prototype.indexOf() if you can't be sure the browser supports it.\n *\n * @param {Array} a\n * @param {*} t\n * @param {number} [i]\n * @returns {number}\n */\n static indexOf(a, t, i)\n {\n if (Array.prototype.indexOf) {\n return a.indexOf(t, i);\n }\n i = i || 0;\n if (i < 0) i += a.length;\n if (i < 0) i = 0;\n for (let n = a.length; i < n; i++) {\n if (i in a && a[i] === t) return i;\n }\n return -1;\n }\n}\n\nUsr.aMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n\n/**\n * getTime()\n *\n * @return {number} the current time, in milliseconds\n */\nUsr.getTime = Date.now || function() { return +new Date(); };\n\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/weblib.js (C) Jeff Parsons 2012-2019\n */\n\n\n/*\n * According to http://www.w3schools.com/jsref/jsref_obj_global.asp, these are the *global* properties\n * and functions of JavaScript-in-the-Browser:\n *\n * Property Description\n * ---\n * Infinity A numeric value that represents positive/negative infinity\n * NaN \"Not-a-Number\" value\n * undefined Indicates that a variable has not been assigned a value\n *\n * Function Description\n * ---\n * decodeURI() Decodes a URI\n * decodeURIComponent() Decodes a URI component\n * encodeURI() Encodes a URI\n * encodeURIComponent() Encodes a URI component\n * escape() Deprecated in version 1.5. Use encodeURI() or encodeURIComponent() instead\n * eval() Evaluates a string and executes it as if it was script code\n * isFinite() Determines whether a value is a finite, legal number\n * isNaN() Determines whether a value is an illegal number\n * Number() Converts an object's value to a number\n * parseFloat() Parses a string and returns a floating point number\n * parseInt() Parses a string and returns an integer\n * String() Converts an object's value to a string\n * unescape() Deprecated in version 1.5. Use decodeURI() or decodeURIComponent() instead\n *\n * And according to http://www.w3schools.com/jsref/obj_window.asp, these are the properties and functions\n * of the *window* object.\n *\n * Property Description\n * ---\n * closed Returns a Boolean value indicating whether a window has been closed or not\n * defaultStatus Sets or returns the default text in the statusbar of a window\n * document Returns the Document object for the window (See Document object)\n * frames Returns an array of all the frames (including iframes) in the current window\n * history Returns the History object for the window (See History object)\n * innerHeight Returns the inner height of a window's content area\n * innerWidth Returns the inner width of a window's content area\n * length Returns the number of frames (including iframes) in a window\n * location Returns the Location object for the window (See Location object)\n * name Sets or returns the name of a window\n * navigator Returns the Navigator object for the window (See Navigator object)\n * opener Returns a reference to the window that created the window\n * outerHeight Returns the outer height of a window, including toolbars/scrollbars\n * outerWidth Returns the outer width of a window, including toolbars/scrollbars\n * pageXOffset Returns the pixels the current document has been scrolled (horizontally) from the upper left corner of the window\n * pageYOffset Returns the pixels the current document has been scrolled (vertically) from the upper left corner of the window\n * parent Returns the parent window of the current window\n * screen Returns the Screen object for the window (See Screen object)\n * screenLeft Returns the x coordinate of the window relative to the screen\n * screenTop Returns the y coordinate of the window relative to the screen\n * screenX Returns the x coordinate of the window relative to the screen\n * screenY Returns the y coordinate of the window relative to the screen\n * self Returns the current window\n * status Sets or returns the text in the statusbar of a window\n * top Returns the topmost browser window\n *\n * Method Description\n * ---\n * alert() Displays an alert box with a message and an OK button\n * atob() Decodes a base-64 encoded string\n * blur() Removes focus from the current window\n * btoa() Encodes a string in base-64\n * clearInterval() Clears a timer set with setInterval()\n * clearTimeout() Clears a timer set with setTimeout()\n * close() Closes the current window\n * confirm() Displays a dialog box with a message and an OK and a Cancel button\n * createPopup() Creates a pop-up window\n * focus() Sets focus to the current window\n * moveBy() Moves a window relative to its current position\n * moveTo() Moves a window to the specified position\n * open() Opens a new browser window\n * print() Prints the content of the current window\n * prompt() Displays a dialog box that prompts the visitor for input\n * resizeBy() Resizes the window by the specified pixels\n * resizeTo() Resizes the window to the specified width and height\n * scroll() This method has been replaced by the scrollTo() method.\n * scrollBy() Scrolls the content by the specified number of pixels\n * scrollTo() Scrolls the content to the specified coordinates\n * setInterval() Calls a function or evaluates an expression at specified intervals (in milliseconds)\n * setTimeout() Calls a function or evaluates an expression after a specified number of milliseconds\n * stop() Stops the window from loading\n */\n\nclass Web {\n /**\n * log(s, type)\n *\n * For diagnostic output only. DEBUG must be true (or \"--debug\" specified via the command-line)\n * for Component.log() to display anything.\n *\n * @param {string} [s] is the message text\n * @param {string} [type] is the message type\n */\n static log(s, type)\n {\n Component.log(s, type);\n }\n\n /**\n * notice(s, fPrintOnly, id)\n *\n * @param {string} s is the message text\n * @param {boolean} [fPrintOnly]\n * @param {string} [id] is the caller's ID, if any\n */\n static notice(s, fPrintOnly, id)\n {\n Component.notice(s, fPrintOnly, id);\n }\n\n /**\n * alertUser(sMessage)\n *\n * NOTE: Legacy function for older modules (eg, DiskDump); see Component.alertUser().\n *\n * @param {string} sMessage\n */\n static alertUser(sMessage)\n {\n if (window) {\n window.alert(sMessage);\n } else {\n Web.log(sMessage);\n }\n }\n\n /**\n * getResource(sURL, type, fAsync, done, progress)\n *\n * Request the specified resource (sURL), and once the request is complete, notify done().\n *\n * If fAsync is true, a done() callback should ALWAYS be supplied; otherwise, you'll have no\n * idea when the request is complete or what the response was. done() is passed three parameters:\n *\n * done(sURL, resource, nErrorCode)\n *\n * If nErrorCode is zero, resource should contain the requested data; otherwise, an error occurred.\n *\n * If type is set to a string, that string can be used to control the response format;\n * by default, the response format is plain text, but you can specify \"arraybuffer\" to request arbitrary\n * binary data, in which case the returned resource will be a ArrayBuffer rather than a string.\n *\n * @param {string} sURL\n * @param {string|Object|null} [type] (object for POST request, otherwise type of GET request)\n * @param {boolean} [fAsync] is true for an asynchronous request; false otherwise (MUST be set for IE)\n * @param {function(string,string,number)} [done]\n * @param {function(number)} [progress]\n * @return {Array|null} Array containing [resource, nErrorCode], or null if no response available (yet)\n */\n static getResource(sURL, type = \"text\", fAsync = false, done, progress)\n {\n let nErrorCode = 0, resource = null, response = null;\n\n if (typeof resources == 'object' && (resource = resources[sURL])) {\n if (done) done(sURL, resource, nErrorCode);\n return [resource, nErrorCode];\n }\n else if (fAsync && typeof resources == 'function') {\n resources(sURL, function(resource, nErrorCode) {\n if (done) done(sURL, resource, nErrorCode);\n });\n return response;\n }\n\n let sURLRedirect = sURL;\n if (Web.getHost() == \"pcjs:8088\" || NODE) {\n /*\n * The larger resources that I've put on archive.pcjs.org are assumed to also be available locally\n * whenever the hostname is \"pcjs\" (or NODE is true); otherwise, use \"localhost\" when debugging locally.\n *\n * NOTE: http://archive.pcjs.org is currently redirected to https://s3-us-west-2.amazonaws.com/archive.pcjs.org\n */\n sURLRedirect = sURL.replace(/^(http:\\/\\/archive\\.pcjs\\.org\\/|https:\\/\\/[a-z0-9-]+\\.amazonaws\\.com\\/archive\\.pcjs\\.org\\/)([^/]*)\\/(.*?)\\/([^/]*)$/, \"/$2-demo/$3/archive/$4\");\n sURLRedirect = sURLRedirect.replace(/^https:\\/\\/([a-z0-9]+)-disks\\.pcjs\\.org\\/(.*)$/, \"/disks-$1/$2\");\n }\n else {\n /*\n * TODO: Perhaps it's time for our code in netlib.js to finally add support for HTTPS; for now\n * though, it's just as well that the NODE environment assumes all resources are available locally.\n */\n sURLRedirect = sURL.replace(/^\\/disks-([a-z0-9]+)\\//, \"https://$1-disks.pcjs.org/\");\n }\n\n\n let request = (window.XMLHttpRequest? new window.XMLHttpRequest() : new window.ActiveXObject(\"Microsoft.XMLHTTP\"));\n let fArrayBuffer = false, fXHR2 = (typeof request.responseType === 'string');\n\n let callback = function() {\n if (request.readyState !== 4) {\n if (progress) progress(1);\n return null;\n }\n /*\n * The following line was recommended for WebKit, as a work-around to prevent the handler firing multiple\n * times when debugging. Unfortunately, that's not the only XMLHttpRequest problem that occurs when\n * debugging, so I think the WebKit problem is deeper than that. When we have multiple XMLHttpRequests\n * pending, any debugging activity means most of them simply get dropped on floor, so what may actually be\n * happening are mis-notifications rather than redundant notifications.\n *\n * request.onreadystatechange = undefined;\n */\n /*\n * If the request failed due to, say, a CORS policy denial; eg:\n *\n * Failed to load http://www.allbootdisks.com/downloads/Disks/Windows_95_Boot_Disk_Download48/Diskette%20Images/Windows95a.img:\n * Redirect from 'http://www.allbootdisks.com/downloads/Disks/Windows_95_Boot_Disk_Download48/Diskette%20Images/Windows95a.img' to\n * 'http://www.allbootdisks.com/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.\n * Origin 'http://pcjs:8088' is therefore not allowed access.\n *\n * and our request type was \"arraybuffer\", attempting to access responseText may trigger an exception; eg:\n *\n * Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's\n * 'responseType' is '' or 'text' (was 'arraybuffer').\n *\n * We could tiptoe around these potential landmines, but the safest thing to do is wrap this code with try/catch.\n */\n try {\n resource = fArrayBuffer? request.response : request.responseText;\n } catch(err) {\n if (MAXDEBUG) Web.log(\"xmlHTTPRequest(\" + sURLRedirect + \") exception: \" + err.message);\n }\n /*\n * The normal \"success\" case is a non-null resource and an HTTP status code of 200, but when loading files from the\n * local file system (ie, when using the \"file:\" protocol), we have to be a bit more flexible.\n */\n if (resource != null && (request.status == 200 || !request.status && resource.length && Web.getHostProtocol() == \"file:\")) {\n if (MAXDEBUG) Web.log(\"xmlHTTPRequest(\" + sURLRedirect + \"): returned \" + resource.length + \" bytes\");\n }\n else {\n nErrorCode = request.status || -1;\n Web.log(\"xmlHTTPRequest(\" + sURLRedirect + \"): error code \" + nErrorCode);\n if (!request.status && !Web.fAdBlockerWarning) {\n let match = sURLRedirect.match(/(^https?:\\/\\/[^/]+)(.*)/);\n if (match) {\n Web.fAdBlockerWarning = true;\n Component.alertUser(\"PCjs was unable to perform a cross-origin resource request to '\" + match[1] + \"'.\\n\\nIf you're running an ad blocker, try adding '\" + Web.getHostOrigin() + \"' to your whitelist (or find a smarter ad blocker).\");\n }\n }\n }\n if (progress) progress(2);\n if (done) done(sURL, resource, nErrorCode);\n return [resource, nErrorCode];\n };\n\n if (fAsync) {\n request.onreadystatechange = callback;\n }\n\n if (progress) progress(0);\n\n if (type && typeof type == \"object\") {\n let sPost = \"\";\n for (let p in type) {\n if (!type.hasOwnProperty(p)) continue;\n if (sPost) sPost += \"&\";\n sPost += p + '=' + encodeURIComponent(type[p]);\n }\n sPost = sPost.replace(/%20/g, '+');\n if (MAXDEBUG) Web.log(\"Web.getResource(POST \" + sURLRedirect + \"): \" + sPost.length + \" bytes\");\n request.open(\"POST\", sURLRedirect, fAsync);\n request.setRequestHeader(\"Content-type\", \"application/x-www-form-urlencoded\");\n request.send(sPost);\n } else {\n if (MAXDEBUG) Web.log(\"Web.getResource(GET \" + sURLRedirect + \")\");\n request.open(\"GET\", sURLRedirect, fAsync);\n if (type == \"arraybuffer\") {\n if (fXHR2) {\n fArrayBuffer = true;\n request.responseType = type;\n } else {\n request.overrideMimeType(\"text/plain; charset=x-user-defined\");\n }\n }\n request.send();\n }\n\n if (!fAsync) {\n request.readyState = 4; // this may already be set for synchronous requests, but I don't want to take any chances\n response = callback();\n }\n return response;\n }\n\n /**\n * parseMemoryResource(sURL, sData)\n *\n * This converts a variety of JSON-style data streams into an Object with the following properties:\n *\n * aBytes\n * aSymbols\n * addrLoad\n * addrExec\n *\n * If the source data contains a 'bytes' array, it's passed through to 'aBytes'; alternatively, if\n * it contains a 'words' array, the values are converted from 16-bit to 8-bit and stored in 'aBytes',\n * and if it contains a 'longs' array, the values are converted from 32-bit longs into bytes and\n * stored in 'aBytes'.\n *\n * Alternatively, if the source data contains a 'data' array, we simply pass that through to the output\n * object as:\n *\n * aData\n *\n * @param {string} sURL\n * @param {string} sData\n * @return {Object|null} (resource)\n */\n static parseMemoryResource(sURL, sData)\n {\n let i;\n let resource = {\n aBytes: null,\n aSymbols: null,\n addrLoad: null,\n addrExec: null\n };\n\n if (sData.charAt(0) == \"[\" || sData.charAt(0) == \"{\") {\n try {\n let a, ib, data;\n\n if (sData.substr(0, 1) == \"<\") { // if the \"data\" begins with a \"<\"...\n /*\n * Early server configs reported an error (via the nErrorCode parameter) if a tape URL was invalid,\n * but more recent server configs now display a somewhat friendlier HTML error page. The downside,\n * however, is that the original error has been buried, and we've received \"data\" that isn't actually\n * tape data. So if the data we've received appears to be \"HTML-like\", we treat it as an error message.\n */\n throw new Error(sData);\n }\n\n /*\n * TODO: IE9 is rather unfriendly and restrictive with regard to how much data it's willing to\n * eval(). In particular, the 10Mb disk image we use for the Windows 1.01 demo config fails in\n * IE9 with an \"Out of memory\" exception. One work-around would be to chop the data into chunks\n * (perhaps one track per chunk, using regular expressions) and then manually re-assemble it.\n *\n * However, it turns out that using JSON.parse(sDiskData) instead of eval(\"(\" + sDiskData + \")\")\n * is a much easier fix. The only drawback is that we must first quote any unquoted property names\n * and remove any comments, because while eval() was cool with them, JSON.parse() is more particular;\n * the following RegExp replacements take care of those requirements.\n *\n * The use of hex values is something else that eval() was OK with, but JSON.parse() is not, and\n * while I've stopped using hex values in DumpAPI responses (at least when \"format=json\" is specified),\n * I can't guarantee they won't show up in \"legacy\" images, and there's no simple RegExp replacement\n * for transforming hex values into decimal values, so I cop out and fall back to eval() if I detect\n * any hex prefixes (\"0x\") in the sequence. Ditto for error messages, which appear like so:\n *\n * [\"unrecognized disk path: test.img\"]\n */\n if (sData.indexOf(\"0x\") < 0 && sData.indexOf(\"0o\") < 0 && sData.substr(0, 2) != '[\"') {\n data = JSON.parse(sData.replace(/([a-z]+):/gm, '\"$1\":').replace(/\\/\\/[^\\n]*/gm, \"\"));\n } else {\n data = eval(\"(\" + sData + \")\");\n }\n\n resource.addrLoad = data['load'];\n resource.addrExec = data['exec'];\n\n if ((a = data['bytes'])) {\n resource.aBytes = a;\n }\n else if ((a = data['words'])) {\n /*\n * Convert all words into bytes\n */\n resource.aBytes = new Array(a.length * 2);\n for (i = 0, ib = 0; i < a.length; i++) {\n resource.aBytes[ib++] = a[i] & 0xff;\n resource.aBytes[ib++] = (a[i] >> 8) & 0xff;\n\n }\n }\n else if ((a = data['longs'])) {\n /*\n * Convert all dwords (longs) into bytes\n */\n resource.aBytes = new Array(a.length * 4);\n for (i = 0, ib = 0; i < a.length; i++) {\n resource.aBytes[ib++] = a[i] & 0xff;\n resource.aBytes[ib++] = (a[i] >> 8) & 0xff;\n resource.aBytes[ib++] = (a[i] >> 16) & 0xff;\n resource.aBytes[ib++] = (a[i] >> 24) & 0xff;\n }\n }\n else if ((a = data['data'])) {\n resource.aData = a;\n }\n else {\n resource.aBytes = data;\n }\n\n if (resource.aBytes) {\n if (!resource.aBytes.length) {\n Component.error(\"Empty resource: \" + sURL);\n resource = null;\n }\n else if (resource.aBytes.length == 1) {\n Component.error(resource.aBytes[0]);\n resource = null;\n }\n }\n resource.aSymbols = data['symbols'];\n\n } catch (e) {\n Component.error(\"Resource data error (\" + sURL + \"): \" + e.message);\n resource = null;\n }\n }\n else {\n /*\n * Parse the data manually; we assume it's a series of hex byte-values separated by whitespace.\n */\n let ab = [];\n let sHexData = sData.replace(/\\n/gm, \" \").replace(/ +$/, \"\");\n let asHexData = sHexData.split(\" \");\n for (i = 0; i < asHexData.length; i++) {\n let n = parseInt(asHexData[i], 16);\n if (isNaN(n)) {\n Component.error(\"Resource data error (\" + sURL + \"): invalid hex byte (\" + asHexData[i] + \")\");\n break;\n }\n ab.push(n & 0xff);\n }\n if (i == asHexData.length) resource.aBytes = ab;\n }\n return resource;\n }\n\n /**\n * redirectResource(sPath)\n *\n * The following replacements should only be necessary for (old) saved states, since all our disk manifests\n * should no longer be using any of these old paths.\n *\n * @param {string} sPath\n * @return {string}\n */\n static redirectResource(sPath)\n {\n sPath = sPath.replace(\"/disks/pc/\", \"/disks/pcx86/\");\n sPath = sPath.replace(\"/disks/pcx86/private/\", \"/disks-private/pcx86/\");\n if (sPath.indexOf(\"archive.pcjs.org\") < 0) {\n sPath = sPath.replace(\"/disks/pcx86/\", \"/disks-demo/pcx86/\");\n }\n sPath = sPath.replace(\"/pcjs-disks/\", \"/disks-demo/\");\n sPath = sPath.replace(\"/pcjs-games/\", \"/disks-game/\");\n sPath = sPath.replace(\"/disks-demo/pcx86/games/\", \"/disks-game/pcx86/\");\n sPath = sPath.replace(\"/private-disks/\", \"/disks-private/\");\n sPath = sPath.replace(\"/fixed/\", \"/drives/\");\n return sPath;\n }\n\n /**\n * sendReport(sApp, sVer, sURL, sUser, sType, sReport, sHostName)\n *\n * Send a report (eg, bug report) to the server.\n *\n * @param {string} sApp (eg, \"PCjs\")\n * @param {string} sVer (eg, \"1.02\")\n * @param {string} sURL (eg, \"/devices/pc/machine/5150/mda/64kb/machine.xml\")\n * @param {string} sUser (ie, the user key, if any)\n * @param {string} sType (eg, \"bug\"); one of ReportAPI.TYPE.*\n * @param {string} sReport (eg, unparsed state data)\n * @param {string} [sHostName] (default is SITEURL)\n */\n static sendReport(sApp, sVer, sURL, sUser, sType, sReport, sHostName)\n {\n let dataPost = {};\n dataPost[ReportAPI.QUERY.APP] = sApp;\n dataPost[ReportAPI.QUERY.VER] = sVer;\n dataPost[ReportAPI.QUERY.URL] = sURL;\n dataPost[ReportAPI.QUERY.USER] = sUser;\n dataPost[ReportAPI.QUERY.TYPE] = sType;\n dataPost[ReportAPI.QUERY.DATA] = sReport;\n let sReportURL = (sHostName? sHostName : SITEURL) + ReportAPI.ENDPOINT;\n Web.getResource(sReportURL, dataPost, true);\n }\n\n /**\n * getHost()\n *\n * This is like getHostName() but with the port number, if any.\n *\n * @return {string}\n */\n static getHost()\n {\n return (window? window.location.host : \"localhost\");\n }\n\n /**\n * getHostName()\n *\n * @return {string}\n */\n static getHostName()\n {\n return (window? window.location.hostname : \"localhost\");\n }\n\n /**\n * getHostOrigin()\n *\n * This could also be implemented with window.location.origin, but that wasn't originally available in all browsers.\n *\n * @return {string}\n */\n static getHostOrigin()\n {\n return (window? window.location.protocol + \"//\" + window.location.host : SITEURL);\n }\n\n /**\n * getHostProtocol()\n *\n * @return {string}\n */\n static getHostProtocol()\n {\n return (window? window.location.protocol : \"file:\");\n }\n\n /**\n * getHostURL()\n *\n * @return {string|null}\n */\n static getHostURL()\n {\n return (window? window.location.href : null);\n }\n\n /**\n * getUserAgent()\n *\n * @return {string}\n */\n static getUserAgent()\n {\n return (window? window.navigator.userAgent : \"\");\n }\n\n /**\n * hasLocalStorage\n *\n * true if localStorage support exists, is enabled, and works; false otherwise\n *\n * @return {boolean}\n */\n static hasLocalStorage()\n {\n if (Web.fLocalStorage == null) {\n let f = false;\n if (window) {\n try {\n window.localStorage.setItem(Web.sLocalStorageTest, Web.sLocalStorageTest);\n f = (window.localStorage.getItem(Web.sLocalStorageTest) == Web.sLocalStorageTest);\n window.localStorage.removeItem(Web.sLocalStorageTest);\n } catch (e) {\n Web.logLocalStorageError(e);\n f = false;\n }\n }\n Web.fLocalStorage = f;\n }\n return Web.fLocalStorage;\n }\n\n /**\n * logLocalStorageError(e)\n *\n * @param {Error} e is an exception\n */\n static logLocalStorageError(e)\n {\n Web.log(e.message, \"localStorage error\");\n }\n\n /**\n * getLocalStorageItem(sKey)\n *\n * Returns the requested key value, or null if the key does not exist, or undefined if localStorage is not available\n *\n * @param {string} sKey\n * @return {string|null|undefined} sValue\n */\n static getLocalStorageItem(sKey)\n {\n let sValue;\n if (window) {\n try {\n sValue = window.localStorage.getItem(sKey);\n } catch (e) {\n Web.logLocalStorageError(e);\n }\n }\n return sValue;\n }\n\n /**\n * setLocalStorageItem(sKey, sValue)\n *\n * @param {string} sKey\n * @param {string} sValue\n * @return {boolean} true if localStorage is available, false if not\n */\n static setLocalStorageItem(sKey, sValue)\n {\n try {\n window.localStorage.setItem(sKey, sValue);\n return true;\n } catch (e) {\n Web.logLocalStorageError(e);\n }\n return false;\n }\n\n /**\n * removeLocalStorageItem(sKey)\n *\n * @param {string} sKey\n */\n static removeLocalStorageItem(sKey)\n {\n try {\n window.localStorage.removeItem(sKey);\n } catch (e) {\n Web.logLocalStorageError(e);\n }\n }\n\n /**\n * getLocalStorageKeys()\n *\n * @return {Array}\n */\n static getLocalStorageKeys()\n {\n let a = [];\n try {\n for (let i = 0, c = window.localStorage.length; i < c; i++) {\n a.push(window.localStorage.key(i));\n }\n } catch (e) {\n Web.logLocalStorageError(e);\n }\n return a;\n }\n\n /**\n * reloadPage()\n */\n static reloadPage()\n {\n if (window) window.location.reload();\n }\n\n /**\n * isUserAgent(s)\n *\n * Check the browser's user-agent string for the given substring; \"iOS\" and \"MSIE\" are special values you can\n * use that will match any iOS or MSIE browser, respectively (even IE11, in the case of \"MSIE\").\n *\n * 2013-11-06: In a questionable move, MSFT changed the user-agent reported by IE11 on Windows 8.1, eliminating\n * the \"MSIE\" string (which MSDN calls a \"version token\"; see http://msdn.microsoft.com/library/ms537503.aspx);\n * they say \"public websites should rely on feature detection, rather than browser detection, in order to design\n * their sites for browsers that don't support the features used by the website.\" So, in IE11, we get a user-agent\n * that tries to fool apps into thinking the browser is more like WebKit or Gecko:\n *\n * Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko\n *\n * That's a nice idea, but in the meantime, they hosed the XSL transform code in embed.js, which contained\n * some very critical browser-specific code; turning on IE's \"Compatibility Mode\" didn't help either, because\n * that's a sledgehammer solution which restores the old user-agent string but also disables other features like\n * HTML5 canvas support. As an interim solution, I'm treating any \"MSIE\" check as a check for either \"MSIE\" or\n * \"Trident\".\n *\n * UPDATE: I've since found ways to make the code in embed.js more browser-agnostic, so for now, there's isn't\n * any code that cares about \"MSIE\", but I've left the change in place, because I wouldn't be surprised if I'll\n * need more IE-specific code in the future, perhaps for things like copy/paste functionality, or mouse capture.\n *\n * @param {string} s is a substring to search for in the user-agent; as noted above, \"iOS\" and \"MSIE\" are special values\n * @return {boolean} is true if the string was found, false if not\n */\n static isUserAgent(s)\n {\n if (window) {\n let userAgent = Web.getUserAgent();\n /*\n * Here's one case where we have to be careful with Component, because when isUserAgent() is called by\n * the init code below, component.js hasn't been loaded yet. The simple solution for now is to remove the call.\n *\n * Web.log(\"agent: \" + userAgent);\n *\n * And yes, it would be pointless to use the conditional (?) operator below, if not for the Google Closure\n * Compiler (v20130823) failing to detect the entire expression as a boolean.\n */\n return s == \"iOS\" && !!userAgent.match(/(iPod|iPhone|iPad)/) && !!userAgent.match(/AppleWebKit/) || s == \"MSIE\" && !!userAgent.match(/(MSIE|Trident)/) || (userAgent.indexOf(s) >= 0);\n }\n return false;\n }\n\n /**\n * isMobile(sDevice)\n *\n * Checks the URL for a \"mobile\" parameter, and failing that, checks the browser's user-agent string for the\n * substring \"Mobi\", as per Mozilla recommendation:\n *\n * https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent\n *\n * @param {string} [sDevice] (eg, \"iPad\" to check for iPad, or \"!iPad\" to specifically exclude it)\n * @return {boolean} is true if the browser appears to be a mobile (ie, non-desktop) web browser, false if not\n */\n static isMobile(sDevice)\n {\n let sMobile = Web.getURLParm(\"mobile\");\n if (sMobile) return sMobile == \"true\";\n if (Web.isUserAgent(\"Mobi\")) {\n if (!sDevice) return true;\n let fInvert = sDevice[0] == '!';\n if (fInvert) sDevice = sDevice.substr(1);\n return Web.isUserAgent(sDevice) != fInvert;\n }\n return false;\n }\n\n /**\n * findProperty(obj, sProp, sSuffix)\n *\n * If both sProp and sSuffix are set, then any browser-specific prefixes are inserted between sProp and sSuffix,\n * and if a match is found, it is returned without sProp.\n *\n * For example, if findProperty(document, 'on', 'fullscreenchange') discovers that 'onwebkitfullscreenchange' exists,\n * it will return 'webkitfullscreenchange', in preparation for an addEventListener() call.\n *\n * More commonly, sSuffix is not used, so whatever property is found is returned as-is.\n *\n * @param {Object|null|undefined} obj\n * @param {string} sProp\n * @param {string} [sSuffix]\n * @return {string|null}\n */\n static findProperty(obj, sProp, sSuffix)\n {\n if (obj) {\n for (let i = 0; i < Web.asBrowserPrefixes.length; i++) {\n let sName = Web.asBrowserPrefixes[i];\n if (sSuffix) {\n sName += sSuffix;\n let sEvent = sProp + sName;\n if (sEvent in obj) return sName;\n } else {\n if (!sName) {\n sName = sProp[0];\n } else {\n sName += sProp[0].toUpperCase();\n }\n sName += sProp.substr(1);\n if (sName in obj) return sName;\n }\n }\n }\n return null;\n }\n\n /**\n * getURLParm(sParm)\n *\n * First looks for sParm exactly as specified, then looks for the lower-case version.\n *\n * @param {string} sParm\n * @return {string|undefined}\n */\n static getURLParm(sParm)\n {\n if (!Web.parmsURL) {\n Web.parmsURL = Web.parseURLParms();\n }\n return Web.parmsURL[sParm] || Web.parmsURL[sParm.toLowerCase()];\n }\n\n /**\n * parseURLParms(sParms)\n *\n * @param {string} [sParms] containing the parameter portion of a URL (ie, after the '?')\n * @return {Object} containing properties for each parameter found\n */\n static parseURLParms(sParms)\n {\n let aParms = {};\n if (window) { // an alternative to \"if (typeof module === 'undefined')\" if require(\"defines\") was used\n if (!sParms) {\n /*\n * Note that window.location.href returns the entire URL, whereas window.location.search\n * returns only the parameters, if any (starting with the '?', which we skip over with a substr() call).\n */\n sParms = window.location.search.substr(1);\n }\n let match;\n let pl = /\\+/g; // RegExp for replacing addition symbol with a space\n let search = /([^&=]+)=?([^&]*)/g;\n let decode = function(s)\n {\n return decodeURIComponent(s.replace(pl, \" \"));\n };\n\n while ((match = search.exec(sParms))) {\n aParms[decode(match[1])] = decode(match[2]);\n }\n }\n return aParms;\n }\n\n /**\n * downloadFile(sData, sType, fBase64, sFileName)\n *\n * @param {string|Uint8Array} sData\n * @param {string} sType\n * @param {boolean} [fBase64]\n * @param {string} [sFileName]\n */\n static downloadFile(sData, sType, fBase64, sFileName)\n {\n let link = null, sAlert, sURI;\n\n if (typeof sData != 'string') {\n if (typeof Blob == 'function' && typeof URL != 'undefined' && URL && typeof URL.createObjectURL == 'function') {\n let blob = new Blob([sData], {type: 'application/octet-stream'});\n sURI = URL.createObjectURL(blob);\n }\n }\n else {\n sURI = \"data:application/\" + sType + (fBase64? \";base64\" : \"\") + \",\";\n if (!Web.isUserAgent(\"Firefox\")) {\n sURI += (fBase64? sData : encodeURI(sData));\n } else {\n sURI += (fBase64? sData : encodeURIComponent(sData));\n }\n }\n if (!sURI) {\n sAlert = 'Operation unsupported by your browser.';\n }\n else {\n if (sFileName) {\n link = document.createElement('a');\n if (typeof link.download != 'string') link = null;\n }\n if (link) {\n link.href = sURI;\n link.download = sFileName;\n document.body.appendChild(link); // Firefox allegedly requires the link to be in the body\n link.click();\n document.body.removeChild(link);\n sAlert = 'Check your Downloads folder for ' + sFileName + '.';\n // if (Web.isUserAgent(\"Chrome\")) {\n // sAlert += '\\n\\nIn Chrome, after clicking OK, you may ALSO have to select the \"Window\" menu, choose \"Downloads\", and then locate this download and select \"Keep\".';\n // sAlert += '\\n\\nThis is part of Chrome\\'s \"Security By Jumping Through Extra Hoops\" technology, which is much easier for Google to implement than actually checking for something malicious.';\n // sAlert += '\\n\\nAnd for the record, there is nothing malicious on the PCjs website.';\n // }\n }\n else {\n window.open(sURI);\n sAlert = 'Check your browser for a new window/tab containing the requested data' + (sFileName? (' (' + sFileName + ')') : '') + '.';\n }\n }\n return sAlert;\n }\n\n /**\n * onCountRepeat(n, fnRepeat, fnComplete, msDelay)\n *\n * Call fnRepeat() n times with an msDelay millisecond delay between calls,\n * then call fnComplete() when n has been exhausted OR fnRepeat() returns false.\n *\n * @param {number} n\n * @param {function()} fnRepeat\n * @param {function()} fnComplete\n * @param {number} [msDelay]\n */\n static onCountRepeat(n, fnRepeat, fnComplete, msDelay)\n {\n let fnTimeout = function doCountRepeat()\n {\n n -= 1;\n if (n >= 0) {\n if (!fnRepeat()) n = 0;\n }\n if (n > 0) {\n setTimeout(fnTimeout, msDelay || 0);\n return;\n }\n fnComplete();\n };\n fnTimeout();\n }\n\n /**\n * onClickRepeat(e, msDelay, msRepeat, fn)\n *\n * Repeatedly call fn() with an initial msDelay, and an msRepeat delay thereafter,\n * as long as HTML control Object e has an active \"down\" event and fn() returns true.\n *\n * @param {Object} e\n * @param {number} msDelay\n * @param {number} msRepeat\n * @param {function(boolean)} fn is passed false on the first call, true on all repeated calls\n */\n static onClickRepeat(e, msDelay, msRepeat, fn)\n {\n let ms = 0, timer = null, fIgnoreMouseEvents = false;\n\n let fnRepeat = function doClickRepeat()\n {\n if (fn(ms === msRepeat)) {\n timer = setTimeout(fnRepeat, ms);\n ms = msRepeat;\n }\n };\n e.onmousedown = function()\n {\n // Web.log(\"onMouseDown()\");\n if (!fIgnoreMouseEvents) {\n if (!timer) {\n ms = msDelay;\n fnRepeat();\n }\n }\n };\n e.ontouchstart = function()\n {\n // Web.log(\"onTouchStart()\");\n if (!timer) {\n ms = msDelay;\n fnRepeat();\n }\n };\n e.onmouseup = e.onmouseout = function()\n {\n // Web.log(\"onMouseUp()/onMouseOut()\");\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n e.ontouchend = e.ontouchcancel = function()\n {\n // Web.log(\"onTouchEnd()/onTouchCancel()\");\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n /*\n * Devices that generate ontouch* events ALSO generate onmouse* events,\n * and generally do so immediately after all the touch events are complete,\n * so unless we want double the action, we need to ignore mouse events.\n */\n fIgnoreMouseEvents = true;\n };\n }\n\n /**\n * onPageEvent(sName, fn)\n *\n * For 'onload', 'onunload', and 'onpageshow' events, most callers should NOT use this function, but\n * instead use Web.onInit(), Web.onShow(), and Web.onExit(), respectively.\n *\n * The only components that should still use onPageEvent() are THIS component (see the bottom of this file)\n * and components that need to capture other events (eg, the 'onresize' event in the Video component).\n *\n * This function creates a chain of callbacks, allowing multiple JavaScript modules to define handlers\n * for the same event, which wouldn't be possible if everyone modified window['onload'], window['onunload'],\n * etc, themselves. However, that's less of a concern now, because assuming everyone else is now using\n * onInit(), onExit(), etc, then there really IS only one component setting the window callback: this one.\n *\n * NOTE: It's risky to refer to obscure event handlers with \"dot\" names, because the Closure Compiler may\n * erroneously replace them (eg, window.onpageshow is a good example).\n *\n * @param {string} sFunc\n * @param {function()} fn\n */\n static onPageEvent(sFunc, fn)\n {\n if (window) {\n let fnPrev = window[sFunc];\n if (typeof fnPrev !== 'function') {\n window[sFunc] = fn;\n } else {\n /*\n * TODO: Determine whether there's any value in receiving/sending the Event object that the\n * browser provides when it generates the original event.\n */\n window[sFunc] = function onWindowEvent()\n {\n if (fnPrev) fnPrev();\n fn();\n };\n }\n }\n }\n\n /**\n * onInit(fn)\n *\n * Use this instead of setting window.onload. Allows multiple JavaScript modules to define their own 'onload' event handler.\n *\n * @param {function()} fn\n */\n static onInit(fn)\n {\n Web.aPageEventHandlers['init'].push(fn);\n }\n\n /**\n * onShow(fn)\n *\n * @param {function()} fn\n *\n * Use this instead of setting window.onpageshow. Allows multiple JavaScript modules to define their own 'onpageshow' event handler.\n */\n static onShow(fn)\n {\n Web.aPageEventHandlers['show'].push(fn);\n }\n\n /**\n * onError(sMessage)\n *\n * @param {string} sMessage\n */\n static onError(sMessage)\n {\n Web.notice(sMessage + \"\\n\\nIf it happens again, please send the URL to support@pcjs.org. Thanks.\");\n }\n\n /**\n * onExit(fn)\n *\n * @param {function()} fn\n *\n * Use this instead of setting window.onunload. Allows multiple JavaScript modules to define their own 'onunload' event handler.\n */\n static onExit(fn)\n {\n Web.aPageEventHandlers['exit'].push(fn);\n }\n\n /**\n * doPageEvent(afn)\n *\n * @param {Array.} afn\n */\n static doPageEvent(afn)\n {\n if (Web.fPageEventsEnabled) {\n try {\n for (let i = 0; i < afn.length; i++) {\n afn[i]();\n }\n } catch (e) {\n Web.onError(\"An unexpected error occurred: \" + e.message);\n }\n }\n }\n\n /**\n * enablePageEvents(fEnable)\n *\n * @param {boolean} fEnable is true to enable page events, false to disable (they're enabled by default)\n */\n static enablePageEvents(fEnable)\n {\n if (!Web.fPageEventsEnabled && fEnable) {\n Web.fPageEventsEnabled = true;\n if (Web.fPageLoaded) Web.sendPageEvent('init');\n if (Web.fPageShowed) Web.sendPageEvent('show');\n return;\n }\n Web.fPageEventsEnabled = fEnable;\n }\n\n /**\n * sendPageEvent(sEvent)\n *\n * This allows us to manually trigger page events.\n *\n * @param {string} sEvent (one of 'init', 'show' or 'exit')\n */\n static sendPageEvent(sEvent)\n {\n if (Web.aPageEventHandlers[sEvent]) {\n Web.doPageEvent(Web.aPageEventHandlers[sEvent]);\n }\n }\n}\n\nWeb.parmsURL = null; // initialized on first call to parseURLParms()\n\nWeb.aPageEventHandlers = {\n 'init': [], // list of window 'onload' handlers\n 'show': [], // list of window 'onpageshow' handlers\n 'exit': [] // list of window 'onunload' handlers (although we prefer to use 'onbeforeunload' if possible)\n};\n\nWeb.asBrowserPrefixes = ['', 'moz', 'ms', 'webkit'];\n\nWeb.fPageLoaded = false; // set once the page's first 'onload' event has occurred\nWeb.fPageShowed = false; // set once the page's first 'onpageshow' event has occurred\nWeb.fPageEventsEnabled = true; // default is true, set to false (or true) by enablePageEvents()\nWeb.fAdBlockerWarning = false;\n\n/**\n * fLocalStorage\n *\n * true if localStorage support exists, is enabled, and works; \"falsey\" otherwise\n *\n * @type {boolean|null}\n */\nWeb.fLocalStorage = null;\n\n/**\n * TODO: Is there any way to get the Closure Compiler to stop inlining this string? This isn't cutting it.\n *\n * @const {string}\n */\nWeb.sLocalStorageTest = \"PCjs.localStorage\";\n\nWeb.onPageEvent('onload', function onPageLoad() {\n Web.fPageLoaded = true;\n Web.doPageEvent(Web.aPageEventHandlers['init']);\n});\n\nWeb.onPageEvent('onpageshow', function onPageShow() {\n Web.fPageShowed = true;\n Web.doPageEvent(Web.aPageEventHandlers['show']);\n});\n\nWeb.onPageEvent(Web.isUserAgent(\"iOS\")? 'onpagehide' : (Web.isUserAgent(\"Opera\")? 'onunload' : 'onbeforeunload'), function onPageUnload() {\n Web.doPageEvent(Web.aPageEventHandlers['exit']);\n});\n\n/*\n * If this is DEBUG (eg, un-COMPILED) code, then allow the user to override DEBUG with a \"debug=false\" embedded in\n * the URL; note that the Closure Compiler won't let us alter the DEBUG variable, because it's defined as a @define, which\n * implies @const as well, so we must resort to modifying it indirectly, using the global window object.\n *\n * TODO: Consider yet another embedXXX() parameter that would also allow DEBUG to be turned off on a page-by-page basis;\n * it's low priority, because it would only affect machines that explicitly request un-COMPILED code, and there are very\n * few such machines (eg, /_posts/2015-01-17-pcjs-uncompiled.md).\n *\n * Deal with Web.getURLParm(\"backtrack\") in /modules/pcx86/lib/defines.js at the same time.\n */\nif (DEBUG && window) {\n let sDebug = Web.getURLParm(\"debug\");\n if (sDebug == \"false\") {\n window['DEBUG'] = false;\n }\n}\n\n\n\n/**\n * @copyright https://www.pcjs.org/modules/shared/lib/component.js (C) Jeff Parsons 2012-2019\n */\n\n/*\n * All PCjs components now use JSDoc types, primarily so that Google's Closure Compiler will compile\n * everything with zero warnings when ADVANCED_OPTIMIZATIONS are enabled. For more information about\n * the JSDoc types supported by the Closure Compiler:\n *\n * https://developers.google.com/closure/compiler/docs/js-for-compiler#types\n *\n * I also attempted to validate this code with JSLint, but it complained too much; eg, it didn't like\n * \"while (true)\", a tried and \"true\" programming convention for decades, and it wanted me to replace\n * all \"++\" and \"--\" operators with \"+= 1\" and \"-= 1\", use \"(s || '')\" instead of \"(s? s : '')\", etc.\n *\n * I prefer sticking with traditional C-style idioms, in part because they are more portable. That\n * does NOT mean I'm trying to write \"portable JavaScript,\" but some of this code was ported from C code\n * I'd written long ago, so portability is good, and I'm not going to throw that away if there's no need.\n *\n * UPDATE: I've since switched from JSLint to JSHint, which seems to have more reasonable defaults.\n * And for new code, I have adopted some popular JavaScript idioms, like \"(s || '')\", although the need\n * for those kinds of expressions will be reduced as I also start adopting some ES6 features, like\n * default parameters.\n */\n\n\n\n/**\n * Since the Closure Compiler treats ES6 classes as @struct rather than @dict by default,\n * it deters us from defining named properties on our components; eg:\n *\n * this['exports'] = {...}\n *\n * results in an error:\n *\n * Cannot do '[]' access on a struct\n *\n * So, in order to define 'exports', we must override the @struct assumption by annotating\n * the class as @unrestricted (or @dict). Note that this must be done both here and in the\n * subclass (eg, SerialPort), because otherwise the Compiler won't allow us to *reference*\n * the named property either.\n *\n * TODO: Consider marking ALL our classes unrestricted, because otherwise it forces us to\n * define every single property the class uses in its constructor, which results in a fair\n * bit of redundant initialization, since many properties aren't (and don't need to be) fully\n * initialized until the appropriate init(), reset(), restore(), etc. function is called.\n *\n * The upside, however, may be that since the structure of the class is completely defined by\n * the constructor, JavaScript engines may be able to optimize and run more efficiently.\n *\n * @unrestricted\n */\nclass Component {\n /**\n * Component(type, parms, bitsMessage)\n *\n * A Component object requires:\n *\n * type: a user-defined type name (eg, \"CPU\")\n *\n * and accepts any or all of the following (parms) properties:\n *\n * id: component ID (default is \"\")\n * name: component name (default is \"\"; if blank, toString() will use the type name only)\n * comment: component comment string (default is undefined)\n *\n * Component subclasses will usually have additional (parms) properties.\n *\n * @param {string} type\n * @param {Object} [parms]\n * @param {number} [bitsMessage] selects message(s) that the component wants to enable (default is 0)\n */\n constructor(type, parms, bitsMessage)\n {\n this.type = type;\n\n if (!parms) parms = {'id': \"\", 'name': \"\"};\n\n this.id = parms['id'] || \"\";\n this.name = parms['name'];\n this.comment = parms['comment'];\n this.parms = parms;\n\n /*\n * The following Component properties need to be accessible by other machines and/or command scripts;\n * well, OK, or we could have exported some new functions to walk the contents of these properties, as we\n * did with findMachineComponent(), but this works just as well.\n *\n * Also, while the double-assignment looks silly (ie, using both dot and bracket property notation), it\n * resolves a complaint from the Closure Compiler, because if we use ONLY bracket notation here, then the\n * Compiler wants us to change all the other references to bracket notation as well.\n */\n this.exports = this['exports'] = {};\n this.bindings = this['bindings'] = {};\n\n let i = this.id.indexOf('.');\n if (i < 0) {\n this.idMachine = \"PCjs\";\n this.idComponent = this.id;\n } else {\n this.idMachine = this.id.substr(0, i);\n this.idComponent = this.id.substr(i + 1);\n }\n\n /*\n * Gather all the various component flags (booleans) into a single \"flags\" object, and encourage\n * subclasses to do the same, to reduce the property clutter we have to wade through while debugging.\n */\n this.flags = {\n ready: false,\n busy: false,\n busyCancel: false,\n initDone: false,\n powered: false,\n unloading: false,\n error: false\n };\n\n this.fnReady = null;\n this.clearError();\n this.bitsMessage = bitsMessage || 0;\n\n this.cmp = null;\n this.bus = null;\n this.cpu = null;\n this.dbg = null;\n\n /*\n * TODO: Consider adding another parameter to the Component() constructor that allows components to tell\n * us if they support single or multiple instances per machine. For example, there can be multiple SerialPort\n * components per machine, but only one CPU component (some machines also support an FPU, but that component\n * is considered separate from the CPU).\n *\n * It's not critical, but it would help catch machine configuration errors; for example, a machine that mistakenly\n * includes two CPU components may, aside from wasting memory, end up with odd side-effects, like unresponsive\n * CPU controls.\n */\n Component.add(this);\n }\n\n /**\n * Component.add(component)\n *\n * @param {Component} component\n */\n static add(component)\n {\n /*\n * This just generates a lot of useless noise, handy in the early days, not so much these days....\n *\n * if (DEBUG) Component.log(\"Component.add(\" + component.type + \",\" + component.id + \")\");\n */\n Component.components.push(component);\n }\n\n /**\n * Component.addMachine(idMachine)\n *\n * @param {string} idMachine\n */\n static addMachine(idMachine)\n {\n Component.machines[idMachine] = {};\n }\n\n /**\n * Component.getMachines()\n *\n * @return {Array.}\n */\n static getMachines()\n {\n return Object.keys(Component.machines);\n }\n\n /**\n * Component.addMachineResource(idMachine, sName, data)\n *\n * @param {string} idMachine\n * @param {string|null} sName (name of the resource)\n * @param {*} data\n */\n static addMachineResource(idMachine, sName, data)\n {\n /*\n * I used to assert(Component.machines[idMachine]), but when we're running as a Node app, embed.js is not used,\n * so addMachine() is never called, so resources do not need to be recorded.\n */\n if (Component.machines[idMachine] && sName) {\n Component.machines[idMachine][sName] = data;\n }\n }\n\n /**\n * Component.getMachineResources(idMachine)\n *\n * @param {string} idMachine\n * @return {Object|undefined}\n */\n static getMachineResources(idMachine)\n {\n return Component.machines[idMachine];\n }\n\n /**\n * Component.getTime()\n *\n * @return {number} the current time, in milliseconds\n */\n static getTime()\n {\n return Date.now() || +new Date();\n }\n\n /**\n * Component.log(s, type)\n *\n * For diagnostic output only.\n *\n * @param {string} [s] is the message text\n * @param {string} [type] is the message type\n */\n static log(s, type)\n {\n if (!COMPILED) {\n if (s) {\n let sElapsed = \"\", sMsg = (type? (type + \": \") : \"\") + s;\n if (typeof Usr != \"undefined\") {\n if (Component.msStart === undefined) {\n Component.msStart = Component.getTime();\n }\n sElapsed = (Component.getTime() - Component.msStart) + \"ms: \";\n }\n sMsg = sMsg.replace(/\\r/g, '\\\\r').replace(/\\n/g, ' ');\n if (window && window.console) console.log(sElapsed + sMsg);\n }\n }\n }\n\n /**\n * Component.assert(f, s)\n *\n * Verifies conditions that must be true (for DEBUG builds only).\n *\n * The Closure Compiler should automatically remove all references to Component.assert() in non-DEBUG builds.\n * TODO: Add a task to the build process that \"asserts\" there are no instances of \"assertion failure\" in RELEASE builds.\n *\n * @param {boolean} f is the expression we are asserting to be true\n * @param {string} [s] is description of the assertion on failure\n */\n static assert(f, s)\n {\n if (DEBUG) {\n if (!f) {\n if (!s) s = \"assertion failure\";\n Component.log(s);\n throw new Error(s);\n }\n }\n }\n\n /**\n * Component.print(s)\n *\n * Components that inherit from this class should use this.print(), rather than Component.print(), because\n * if a Control Panel is loaded, it will override only the instance method, not the class method (overriding the\n * class method would improperly affect any other machines loaded on the same page).\n *\n * @this {Component}\n * @param {string} s\n */\n static print(s)\n {\n if (!COMPILED) {\n let i = s.lastIndexOf('\\n');\n if (i >= 0) {\n Component.println(s.substr(0, i));\n s = s.substr(i + 1);\n }\n Component.printBuffer += s;\n }\n }\n\n /**\n * Component.println(s, type, id)\n *\n * Components that inherit from this class should use this.println(), rather than Component.println(), because\n * if a Control Panel is loaded, it will override only the instance method, not the class method (overriding the\n * class method would improperly affect any other machines loaded on the same page).\n *\n * @param {string} [s] is the message text\n * @param {string} [type] is the message type\n * @param {string} [id] is the caller's ID, if any\n */\n static println(s, type, id)\n {\n if (!COMPILED) {\n s = Component.printBuffer + (s || \"\");\n Component.log((id? (id + \": \") : \"\") + (s? (\"\\\"\" + s + \"\\\"\") : \"\"), type);\n Component.printBuffer = \"\";\n }\n }\n\n /**\n * Component.notice(s, fPrintOnly, id)\n *\n * notice() is like println() but implies a need for user notification, so we alert() as well.\n *\n * @param {string} s is the message text\n * @param {boolean} [fPrintOnly]\n * @param {string} [id] is the caller's ID, if any\n * @return {boolean}\n */\n static notice(s, fPrintOnly, id)\n {\n if (!COMPILED) {\n Component.println(s, Component.PRINT.NOTICE, id);\n }\n if (!fPrintOnly) Component.alertUser((id? (id + \": \") : \"\") + s);\n return true;\n }\n\n /**\n * Component.warning(s)\n *\n * @param {string} s describes the warning\n */\n static warning(s)\n {\n if (!COMPILED) {\n Component.println(s, Component.PRINT.WARNING);\n }\n Component.alertUser(s);\n }\n\n /**\n * Component.error(s)\n *\n * @param {string} s describes the error; an alert() is displayed as well\n */\n static error(s)\n {\n if (!COMPILED) {\n Component.println(s, Component.PRINT.ERROR);\n }\n Component.alertUser(s);\n }\n\n /**\n * Component.alertUser(sMessage)\n *\n * @param {string} sMessage\n */\n static alertUser(sMessage)\n {\n if (window) {\n window.alert(sMessage);\n } else {\n Component.log(sMessage);\n }\n }\n\n /**\n * Component.confirmUser(sPrompt)\n *\n * @param {string} sPrompt\n * @returns {boolean} true if the user clicked OK, false if Cancel/Close\n */\n static confirmUser(sPrompt)\n {\n let fResponse = false;\n if (window) {\n fResponse = window.confirm(sPrompt);\n }\n return fResponse;\n }\n\n /**\n * Component.promptUser()\n *\n * @param {string} sPrompt\n * @param {string} [sDefault]\n * @returns {string|null}\n */\n static promptUser(sPrompt, sDefault)\n {\n let sResponse = null;\n if (window) {\n sResponse = window.prompt(sPrompt, sDefault === undefined? \"\" : sDefault);\n }\n return sResponse;\n }\n\n /**\n * Component.appendControl(control, sText)\n *\n * @param {Object} control\n * @param {string} sText\n */\n static appendControl(control, sText)\n {\n control.value += sText;\n /*\n * Prevent the