This commit is contained in:
Joshua Bell 2012-02-08 22:13:44 -05:00
commit 9aa91a4410
68 changed files with 12464 additions and 0 deletions

2411
basic.js Normal file

File diff suppressed because it is too large Load Diff

55
bell.js Normal file
View File

@ -0,0 +1,55 @@
//
// Applesoft BASIC in Javascript
// Bell - play an audio file for the CHR$(7) "BEL" beep
//
// Copyright (C) 2009-2011 Joshua Bell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
var Bell;
if (typeof Bell !== 'function') {
Bell = function(base) {
var tag;
// Prefer HTML5 audio
tag = document.createElement('audio');
if (typeof tag.canPlayType === 'function') {
tag.setAttribute('preload', 'true');
if (tag.canPlayType('audio/mp3')) {
tag.setAttribute('src', base + 'bell.mp3');
} else if (tag.canPlayType('audio/ogg')) {
tag.setAttribute('src', base + 'bell.ogg');
} else if (tag.canPlayType('audio/wav')) {
tag.setAttribute('src', base + 'bell.wav');
}
this.play = function() { tag.play(); };
this.stop = function() { tag.pause(); tag.currentTime = 0; };
return;
}
// Fallback for IE<9
tag = document.createElement('bgsound');
if ('loop' in tag) {
tag.src = base + 'bell.wav';
tag.loop = 1;
this.play = function() { document.body.appendChild(tag); };
this.stop = function() { document.body.removeChild(tag); };
return;
}
this.play = function() { };
this.stop = function() { };
};
}

BIN
bell.mp3 Normal file

Binary file not shown.

BIN
bell.ogg Normal file

Binary file not shown.

BIN
bell.wav Normal file

Binary file not shown.

46
cm2/mode/basic/basic.css Normal file
View File

@ -0,0 +1,46 @@
.cm-s-default span.cm-basic-statement {
color: #00007f;
}
.cm-s-default span.cm-basic-unsupported {
color: #00007f;
background-color: #ff7f7f
}
.cm-s-default span.cm-basic-function {
color: teal;
}
.cm-s-default span.cm-basic-identifier {
color: #7f7f00;
}
.cm-s-default span.cm-basic-string {
color: #007f00;
}
.cm-s-default span.cm-basic-number {
color: #0000ff;
}
.cm-s-default span.cm-basic-operator {
color: #7f007f;
}
.cm-s-default span.cm-basic-separator {
color: #7f7f7f;
}
.cm-s-default span.cm-basic-linenumber {
color: orange;
}
.cm-s-default span.cm-basic-comment {
color: #cc00ff;
font-style: italic;
}
.cm-s-default span.cm-basic-error {
color: black;
background-color: red;
}

222
cm2/mode/basic/basic.js Normal file
View File

@ -0,0 +1,222 @@
// Really just a lexer
CodeMirror.defineMode('basic', function(config, parserConfig) {
var STATEMENT = 'basic-statement',
OPERATOR = 'basic-operator',
FUNCTION = 'basic-function',
UNSUPPORTED = 'basic-unsupported';
var reserved = {
"ABS": FUNCTION,
"AND": OPERATOR,
"ASC": FUNCTION,
"ATN": FUNCTION,
"AT": STATEMENT,
"CALL": STATEMENT,
"CHR$": FUNCTION,
"CLEAR": STATEMENT,
"COLOR=": STATEMENT,
"CONT": UNSUPPORTED,
"COS": FUNCTION,
"DATA": STATEMENT,
"DEF": STATEMENT,
"DEL": UNSUPPORTED,
"DIM": STATEMENT,
"DRAW": UNSUPPORTED,
"END": STATEMENT,
"EXP": FUNCTION,
"FLASH": STATEMENT,
"FN": STATEMENT,
"FOR": STATEMENT,
"FRE": FUNCTION,
"GET": STATEMENT,
"GOSUB": STATEMENT,
"GOTO": STATEMENT,
"GR": STATEMENT,
"HCOLOR=": STATEMENT,
"HGR2": STATEMENT,
"HGR": STATEMENT,
"HIMEM:": UNSUPPORTED,
"HLIN": STATEMENT,
"HOME": STATEMENT,
"HPLOT": STATEMENT,
"HTAB": STATEMENT,
"IF": STATEMENT,
"IN#": UNSUPPORTED,
"INPUT": STATEMENT,
"INT": FUNCTION,
"INVERSE": STATEMENT,
"LEFT$": FUNCTION,
"LEN": FUNCTION,
"LET": STATEMENT,
"LIST": UNSUPPORTED,
"LOAD": UNSUPPORTED,
"LOG": FUNCTION,
"LOMEM:": UNSUPPORTED,
"MID$": FUNCTION,
"NEW": UNSUPPORTED,
"NEXT": STATEMENT,
"NORMAL": STATEMENT,
"NOTRACE": STATEMENT,
"NOT": OPERATOR,
"ONERR": STATEMENT,
"ON": STATEMENT,
"OR": OPERATOR,
"PDL": FUNCTION,
"PEEK": FUNCTION,
"PLOT": STATEMENT,
"POKE": STATEMENT,
"POP": STATEMENT,
"POS": FUNCTION,
"PRINT": STATEMENT,
"PR#": STATEMENT,
"READ": STATEMENT,
"RECALL": UNSUPPORTED,
"REM": STATEMENT,
"RESTORE": STATEMENT,
"RESUME": STATEMENT,
"RETURN": STATEMENT,
"RIGHT$": FUNCTION,
"RND": FUNCTION,
"ROT=": UNSUPPORTED,
"RUN": UNSUPPORTED,
"SAVE": UNSUPPORTED,
"SCALE=": UNSUPPORTED,
"SCRN": FUNCTION,
"SGN": FUNCTION,
"SHLOAD": UNSUPPORTED,
"SIN": FUNCTION,
"SPC": FUNCTION,
"SPEED=": STATEMENT,
"SQR": FUNCTION,
"STEP": STATEMENT,
"STOP": STATEMENT,
"STORE": UNSUPPORTED,
"STR$": FUNCTION,
"TAB": FUNCTION,
"TAN": FUNCTION,
"TEXT": STATEMENT,
"THEN": STATEMENT,
"TO": STATEMENT,
"TRACE": STATEMENT,
"USR": FUNCTION,
"VAL": FUNCTION,
"VLIN": STATEMENT,
"VTAB": STATEMENT,
"WAIT": UNSUPPORTED,
"XDRAW": UNSUPPORTED,
"&": UNSUPPORTED,
"?": STATEMENT
};
var reservedKeys = (function() {
// Need longer stems first: ATN/AT, ONERR/ON, NOTRACE/NOT
var keys = [], name;
for (name in reserved) {
if (Object.prototype.hasOwnProperty.call(reserved, name)) {
keys.push(name);
}
}
keys.sort();
keys.reverse();
return keys;
} ());
// states are 'normal' and 'comment'
return {
startState: function() {
return {
state: 'normal'
};
},
token: function(stream, state) {
var name, i;
if (state.state === 'normal') {
if (stream.eatSpace()) {
return null;
}
else if (/[0-9.]/.test(stream.peek())) {
stream.eatWhile(/[0-9]/);
if (stream.peek() === '.') {
stream.next();
stream.eatWhile(/[0-9]/);
}
if (/[eE]/.test(stream.peek())) {
stream.next();
stream.eatWhile(/[ \u00a0]/);
if (stream.peek() === '-' || stream.peek() === '+') {
stream.next();
}
stream.eatWhile(/[ \u00a0]/);
stream.eatWhile(/[0-9]/);
}
return 'basic-number';
}
else if (stream.peek() === '"') {
stream.next();
while (!stream.eol()) {
if (stream.next() === '"') {
break;
}
}
return 'basic-string';
}
else if (/[;=<>+\-*\/\^(),]/.test(stream.peek())) {
stream.next();
return 'basic-operator';
}
else if (stream.peek() === ':') {
stream.next();
return 'basic-separator';
}
else if (stream.match('REM', true, true)) {
stream.eatWhile(/[ \u00a0]/);
if (!stream.eol()) {
state.state = 'comment';
}
return 'basic-statement';
}
// TODO: Applesoft-style space ignoring within reserved words
for (i = 0; i < reservedKeys.length; i += 1) {
name = reservedKeys[i];
if (stream.match(name, true, true)) {
return reserved[name];
}
}
if (/[A-Za-z]/.test(stream.peek())) {
stream.next();
stream.eatWhile(/[A-Za-z0-9]/);
if (stream.peek() === '$' || stream.peek() === '%') {
stream.next();
}
return 'basic-identifier';
}
stream.next();
return 'basic-error';
}
else if (state.state === 'comment') {
while (!stream.eol()) {
stream.next();
}
state.state = 'normal';
return 'basic-comment';
}
else {
throw 'WTF!?';
}
}
};
});
CodeMirror.defineMIME("text/x-basic", "basic");
CodeMirror.defineMIME("text/x-applesoft", "basic");

509
dos.js Normal file
View File

@ -0,0 +1,509 @@
//
// Applesoft BASIC in Javascript
// DOS Emulation
// Copyright (C) 2009-2011 Joshua Bell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Usage:
// var dos = new DOS( tty ) // hooks tty's writeChar/readChar/readLine
// dos.reset() // Close all open buffers
/*global basic*/
function DOS(tty) {
/*jslint bitwise: false, browser: true*/
var DOSErrors = {
LANGUAGE_NOT_AVAILABLE: [1, "Language not available"],
RANGE_ERROR: [2, 'Range error'],
WRITE_PROTECTED: [4, 'Write protected'],
END_OF_DATA: [5, 'End of data'],
FILE_NOT_FOUND: [6, 'File not found'],
VOLUME_MISMATCH: [7, 'Volume mismatch'],
IO_ERROR: [8, 'I/O error'],
DISK_FULL: [9, 'Disk full'],
FILE_LOCKED: [10, 'File locked'],
INVALID_OPTION: [11, 'Invalid option'],
NO_BUFFERS_AVAILABLE: [12, 'No buffers available'],
FILE_TYPE_MISMATCH: [13, 'File type mismatch'],
PROGRAM_TOO_LARGE: [14, 'Program too large'],
NOT_DIRECT_COMMAND: [15, 'Not direct command']
},
STORAGE_PREFIX = 'vfs/',
// For MON/NOMON
MON_I = 1,
MON_C = 2,
MON_O = 4,
// Original versions of hooked I/O routines
tty_readLine,
tty_readChar,
tty_writeChar,
// character output state
commandBuffer = "",
commandMode = false,
// I/O buffers
buffers = {},
activebuffer = null,
mode = "",
// other state
monico = 0;
function doserror(msg) {
throw new basic.RuntimeError(msg[1], msg[0]);
}
// Internal - crack arguments e.g. ",S6,D1"
function parseArgs(str, opts) {
opts = opts || '';
// Set these to zero so they're always defined when passed into command handlers
var args = {
V: 0, // Volume
D: 0, // Drive
S: 0, // Slot
L: 0, // Length
R: 0, // Record/Relative
B: 0, // Byte
A: 0, // Address
C: undefined, // Echo Commands
I: undefined, // Echo Input
O: undefined // Echo Output
};
while (str.match(/^,?\s*([VDSLRBACIO])\s*([0-9]+|\$[0-9A-Fa-f]+)?\s*([\x20-\x7E]*)/)) {
if (opts.indexOf(RegExp.$1) === -1) {
doserror(DOSErrors.INVALID_OPTION);
}
args[RegExp.$1] = Number(RegExp.$2);
str = RegExp.$3;
}
if (str.length > 0) {
doserror(DOSErrors.INVALID_OPTION);
}
return args;
}
//----------------------------------------------------------------------
// Browser-side VFS
//----------------------------------------------------------------------
function vfs_set(key, value) {
return window.localStorage.setItem(STORAGE_PREFIX + key, encodeURIComponent(value));
}
function vfs_get(key) {
var item = window.localStorage.getItem(STORAGE_PREFIX + key);
return item !== null ? decodeURIComponent(item) : null;
}
function vfs_remove(key) {
return window.localStorage.removeItem(STORAGE_PREFIX + key);
}
//----------------------------------------------------------------------
// Implementation
//----------------------------------------------------------------------
this.reset = function _reset() {
buffers = {};
activebuffer = null;
mode = "";
};
function unlink(filename) {
var item = vfs_get(filename);
if (item === null) {
doserror(DOSErrors.FILE_NOT_FOUND);
}
vfs_remove(filename);
}
function rename(oldname, newname) {
var item = vfs_get(oldname);
if (item === null) {
doserror(DOSErrors.FILE_NOT_FOUND);
}
vfs_remove(oldname);
vfs_set(newname, item);
}
function open(filename, recordlength) {
if (recordlength === 0) {
// Sequential access
recordlength = 1;
}
// Peek in the VFS cache first
var file = vfs_get(filename),
req, url, async;
if (file === null) {
// Not cached - do a synchronous XmlHttpRequest for the file here
req = new XMLHttpRequest();
try {
url = "vfs/" + encodeURIComponent(filename.replace(/\./g, '_')) + ".txt";
async = false;
req.open("GET", url, async);
req.send(null);
if (req.status === 200 || req.status === 0) { // 0 for file:// protocol
file = req.responseText.replace(/\r\n/g, "\r");
vfs_set(filename, file);
}
} catch (e) {
// File doesn't exist - APPEND/READ will fail
throw e;
}
}
// Create a buffer for the file
buffers[filename] = {
file: file,
recordlength: recordlength,
recordnum: 0,
filepointer: 0
};
}
function append(filename, recordlength) {
// Normal open logic
open(filename, recordlength);
if (!buffers.hasOwnProperty(filename)) {
doserror(DOSErrors.FILE_NOT_FOUND);
}
var buf = buffers[filename];
// Then seek to the end of the file
buf.filepointer = buf.file.length;
buf.recordnum = Math.floor(buf.filepointer / buf.recordlength);
}
function close(filename) {
var buf, fn;
// If not specified, close all buffers
if (!filename) {
for (fn in buffers) {
if (buffers.hasOwnProperty(fn)) {
close(fn);
}
}
return;
}
buf = buffers[filename];
if (buf) {
// flush changes to "disk"
vfs_set(filename, buf.file);
delete buffers[filename];
if (buf === activebuffer) {
activebuffer = null;
mode = "";
}
}
}
function read(filename, recordnum, bytenum) {
var buf = buffers[filename];
if (!buf) {
// Open file if no such named buffer, but don't create it
open(filename, 0);
buf = buffers[filename];
}
if (buf.file === null) {
doserror(DOSErrors.FILE_NOT_FOUND);
}
// Set the file position
buf.recordnum = recordnum;
buf.filepointer = buf.recordlength * recordnum + bytenum;
// Set the active buffer into read mode
activebuffer = buf;
mode = "r";
}
function write(filename, recordnum, bytenum) {
var buf = buffers[filename];
if (!buf) {
// Must open the file before writing
doserror(DOSErrors.FILE_NOT_FOUND);
}
if (buf.file === null) {
// If we still don't have it, create in VFS if necessary
vfs_set(filename, '');
buf.file = '';
}
// Set up the file position
buf.recordnum = recordnum;
if (buf.recordlength > 1) {
buf.filepointer = buf.recordlength * recordnum;
}
buf.filepointer += bytenum;
// Set the active buffer into write mode
activebuffer = buf;
mode = "w";
}
function position(filename, records) {
var buf = buffers[filename];
if (!buf) {
// Open file if no such named buffer, but don't create it
open(filename, 0, false);
buf = buffers[filename];
}
// Set up the file position
buf.recordnum += records;
buf.filepointer += buf.recordlength * records;
}
//----------------------------------------------------------------------
// Command Dispatch
//----------------------------------------------------------------------
function executeCommand(command) {
// Delegate to various commands
// http://www.xs4all.nl/~fjkraan/comp/apple2faq/app2doscmdfaq.html
// http://www.textfiles.com/apple/ANATOMY/
var filename, filename2, args, slot;
if (monico & MON_C && tty) {
tty.writeString(command + "\r");
}
if (command.match(/^MON([\x20-\x7E]*)/)) {
// MON[,C][,I][,O] Traces DOS 3.3 commands ('Commands', 'Input' and 'Output')
args = parseArgs(RegExp.$1, 'ICO');
if (args.I !== undefined) {
monico |= MON_I;
}
if (args.C !== undefined) {
monico |= MON_C;
}
if (args.O !== undefined) {
monico |= MON_O;
}
} else if (command.match(/^NOMON([\x20-\x7E]*)/)) {
// NOMON[,C][,I][,O] Cancels tracing of DOS 3.3 commands ('Commands', 'Input' and 'Output')
args = parseArgs(RegExp.$1, 'ICO');
if (args.I !== undefined) {
monico &= ~MON_I;
}
if (args.C !== undefined) {
monico &= ~MON_C;
}
if (args.O !== undefined) {
monico &= ~MON_O;
}
} else if (command.match(/^OPEN\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// OPEN filename[,Llen] Opens a text file.
filename = RegExp.$1;
args = parseArgs(RegExp.$2, 'L');
open(filename, args.L);
} else if (command.match(/^APPEND\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// APPEND filename Appends to a text file.
filename = RegExp.$1;
args = parseArgs(RegExp.$2);
append(filename, args.L);
} else if (command.match(/^CLOSE\s*([\x20-\x2B\x2D-\x7E]+)?(,[\x20-\x7E]*)?/)) {
// CLOSE [filename] Closes specified (or all) open text files.
filename = RegExp.$1;
close(filename);
} else if (command.match(/^POSITION\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// POSITION filename[,Rnum] Advances position in text file.
filename = RegExp.$1;
args = parseArgs(RegExp.$2, 'R');
position(filename, args.R);
} else if (command.match(/^READ\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// READ filename[,Rnum][,Bbyte] Reads from a text file.
filename = RegExp.$1;
args = parseArgs(RegExp.$2, 'RB');
read(filename, args.R, args.B);
} else if (command.match(/^WRITE\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// WRITE filename[,Rnum][,Bbyte] Writes to a text file.
filename = RegExp.$1;
args = parseArgs(RegExp.$2, 'RB');
write(filename, args.R, args.B);
} else if (command.match(/^DELETE\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// DELETE filename Delete a file
filename = RegExp.$1;
args = parseArgs(RegExp.$2);
unlink(filename);
} else if (command.match(/^RENAME\s*([\x20-\x2B\x2D-\x7E]+),\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// RENAME filename,filename Rename a file
filename = RegExp.$1;
filename2 = RegExp.$2;
args = parseArgs(RegExp.$3);
rename(filename, filename2);
} else if (command.match(/^PR#\s*([\x20-\x2B\x2D-\x7E]+)(,[\x20-\x7E]*)?/)) {
// PR# slot Direct output to slot
slot = Number(RegExp.$1);
args = parseArgs(RegExp.$2);
if (slot === 0) {
if (tty.setFirmwareActive) { tty.setFirmwareActive(false); }
} else if (slot === 3) {
if (tty.setFirmwareActive) { tty.setFirmwareActive(true); }
} else {
doserror(DOSErrors.RANGE_ERROR);
}
} else if (command.match(/^$/)) {
// Null command - terminates a READ/WRITE, but doesn't CLOSE
// (leaves record length intact on open buffer)
activebuffer = null;
mode = "";
} else {
doserror(DOSErrors.INVALID_OPTION);
}
}
//----------------------------------------------------------------------
// Install TTY Hooks
//----------------------------------------------------------------------
tty_readLine = tty.readLine;
tty_readChar = tty.readChar;
tty_writeChar = tty.writeChar;
tty.readLine = function _dos_readLine(callback, prompt) {
var string = "", c, data, len, fp, buffer;
if (mode === "r") {
// Cache for performance
data = activebuffer.file;
len = data.length;
fp = activebuffer.filepointer;
if (fp >= len) {
doserror(DOSErrors.END_OF_DATA);
}
buffer = [];
while (fp < len) {
// Sequential Access
c = data[fp];
fp += 1;
if (c === "\r" || c === "\n" || c === "\x00") {
break;
} else {
buffer.push(c);
}
}
activebuffer.filepointer = fp;
string = buffer.join("");
if (monico & MON_I) {
tty.writeString(prompt + string + "\r");
}
// Non-blocking return
setTimeout(function() { callback(string); }, 0);
} else {
tty_readLine(callback, prompt);
}
};
tty.readChar = function _dos_readChar(callback) {
var character = "";
if (mode === "r") {
if (activebuffer.filepointer >= activebuffer.file.length) {
doserror(DOSErrors.END_OF_DATA);
}
character = activebuffer.file[activebuffer.filepointer];
activebuffer.filepointer += 1;
if (monico & MON_I && tty) {
tty_writeChar(character);
}
// Non-blocking return
setTimeout(function() { callback(character); }, 0);
} else {
tty_readChar(callback);
}
};
tty.writeChar = function _dos_writeChar(c) {
if (commandMode) {
if (c === "\r") {
commandMode = false;
executeCommand(commandBuffer);
commandBuffer = "";
} else {
commandBuffer += c;
}
return;
} else if (c === "\x04") {
commandBuffer = "";
commandMode = true;
return;
}
if (mode === "w") {
var buf, d;
if (monico & MON_O) {
tty_writeChar(c);
}
buf = activebuffer;
// Extend file to necessary length
while (buf.filepointer > buf.file.length) {
buf.file += "\x00";
}
// Append or insert character
if (buf.filepointer === buf.file.length) {
buf.file += c;
} else {
d = buf.file.substring(0, buf.filepointer);
d += c;
d += buf.file.substring(buf.filepointer + 1);
buf.file = d;
}
buf.filepointer += 1;
} else {
tty_writeChar(c);
}
}; // writeChar
}

66
feed.js Normal file
View File

@ -0,0 +1,66 @@
//
// Atom to HTML - fetch a feed, inject it as dl/dt/dd
//
// Copyright (C) 2009-2010 Joshua Bell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
function atomToHtml(uri, element) {
var READYSTATE_UNINITIALIZED = 0;
var READYSTATE_LOADING = 1;
var READYSTATE_LOADED = 2;
var READYSTATE_INTERACTIVE = 3;
var READYSTATE_COMPLETE = 4;
var xhr = new XMLHttpRequest();
var async = true;
xhr.open("GET", uri, async);
xhr.onreadystatechange = function() {
if (xhr.readyState === READYSTATE_COMPLETE) {
if ((xhr.status === 200 || xhr.status === 0) && xhr.responseXML) {
var doc = xhr.responseXML;
var entries = doc.getElementsByTagName('entry');
var html = [];
html.push('<dl>');
for (var i = 0; i < entries.length; i += 1) {
var entry = entries[i];
try {
var entryHTML = [];
entryHTML.push('<dt>', entry.getElementsByTagName('title')[0].childNodes[0].nodeValue);
entryHTML.push('<dd>', entry.getElementsByTagName('content')[0].childNodes[0].nodeValue);
html.push(entryHTML.join(''));
} catch (e) {
if (console && console.log) { console.log("Error:", e); }
}
}
html.push('</dl>');
element.innerHTML = html.join('');
} else {
element.innerHTML = '<em>Unable to load feed</em>';
}
}
};
try {
xhr.send(null);
} catch (e) {
element.innerHTML = '<em>Unable to load feed</em>';
}
}

789
feed.xml Normal file
View File

@ -0,0 +1,789 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://www.calormen.com/Applesoft/</id>
<title>Applesoft BASIC in Javascript - Change Log</title>
<updated>2011-12-06T23:00:00Z</updated>
<author>
<name>Joshua Bell</name>
<email>inexorabletash@hotmail.com</email>
<uri>http://www.calormen.com/</uri>
</author>
<link rel="self" href="http://www.calormen.com/Applesoft/feed.xml"/>
<entry>
<title>2011-12-06</title>
<id>http://www.calormen.com/Applesoft/20111206</id>
<updated>2011-12-06T23:00:00Z</updated>
<content type="html">
&lt;p&gt;
Added &lt;code&gt;PEEK&lt;/code&gt; and &lt;code&gt;POKE&lt;/code&gt; shim for 230 (Hi-Res plotting page), to
enable drawing on the back buffer for animations.
</content>
</entry>
<entry>
<title>2011-04-20</title>
<id>http://www.calormen.com/Applesoft/20110420</id>
<updated>2011-04-20T21:00:00Z</updated>
<content type="html">
&lt;p&gt;
Re-added support for running under
&lt;a href="http://en.wikipedia.org/wiki/Windows_Script_Host"&gt;Windows Scripting Host&lt;/a&gt; and added
&lt;a href="http://www.mozilla.org/rhino/"&gt;Mozilla Rhino&lt;/a&gt; support too.
</content>
</entry>
<entry>
<title>2011-04-16</title>
<id>http://www.calormen.com/Applesoft/20110416</id>
<updated>2011-04-16T23:00:00Z</updated>
<content type="html">
&lt;p&gt;
Total internal revamp: Now a compiler rather than interpreter. Source errors are reported
by BASIC line number as well as source line/column.
&lt;p&gt;
Display defaults to 40 columns, emulates 80-column firmware more accurately. Character output
(&lt;code&gt;CHR$()&lt;/code&gt;, &lt;code&gt;INVERSE&lt;/code&gt;, etc) tweaked to match Apple
behavior.
&lt;p&gt;
Files written via DOS now persist in your browser via &lt;a href="http://dev.w3.org/html5/webstorage/"&gt;Web Storage&lt;/a&gt;.
&lt;p&gt;
Floating point and integer overflows are caught rather than propagating infinities and NaNs.
&lt;p&gt;
&lt;code&gt;DATA&lt;/code&gt; statements and &lt;code&gt;INPUT&lt;/code&gt; entries parse
more accurately as comma delimited, optionally-quoted strings. &lt;code&gt;RE-ENTER?&lt;/code&gt;
is shown on invalid &lt;code&gt;INPUT&lt;/code&gt; (and can be trapped via &lt;code&gt;ONERR&lt;/code&gt;)
&lt;p&gt;
Added &lt;code&gt;HGR2&lt;/code&gt; and page-flipping &lt;code&gt;POKE&lt;/code&gt; shims, plus a few &lt;code&gt;CALL&lt;/code&gt; shims
for graphics. Hires graphics are now to a 280x192 bitmap, rather than trying to be sneaky with a 140x192 bitmap.
&lt;p&gt;
Error codes can be distinguished in &lt;code&gt;ONERR&lt;/code&gt; via &lt;code&gt;PEEK(222)&lt;/code&gt;.
Out-of-memory and stack-overflow conditions reported where possible (this is
&lt;a href="http://cautionsingularityahead.blogspot.com/2011/03/stack-overflow-and-out-of-memory-in.html"&gt;
non-standard across browsers&lt;/a&gt;).
&lt;p&gt;
Tweaked samples that were dependent on language/environment quirks.
&lt;p&gt;
Updated code editor to (the much improved) &lt;a href="http://codemirror.net/"&gt;CodeMirror 2.0&lt;/a&gt;. On parse errors,
the cursor is moved to the offending line/character.
</content>
</entry>
<entry>
<title>2011-01-29</title>
<id>http://www.calormen.com/Applesoft/20110129</id>
<updated>2011-01-29T23:30:00Z</updated>
<content type="html">
&lt;p&gt;
Fixed error handling issues, e.g. DOS errors w/ &lt;code&gt;ONERR&lt;/code&gt; and syntax
errors e.g. &lt;code&gt;10 INPUT PRINT&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Added &lt;code&gt;HSCRN(x,y)&lt;/code&gt; extension function.
&lt;/p&gt;
&lt;p&gt;
Fix mouse-as-joystick to hit full range of 0...255.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2011-01-26</title>
<id>http://www.calormen.com/Applesoft/20110126</id>
<updated>2011-01-26T23:00:00Z</updated>
<content type="html">
&lt;p&gt;
No longer show paddles/joysticks automatically; rely on mouse-as-joystick primarily.
&lt;/p&gt;
&lt;p&gt;
Use &lt;a href="http://flashcanvas.net/"&gt;FlashCanvas&lt;/a&gt; for older IE versions, instead of
&lt;a href="http://excanvas.sourceforge.net/"&gt;excanvas&lt;/a&gt;, and switch to plotting hires
pixels/lines directly rather than relying on canvas scaling and line drawing.
&lt;/p&gt;
&lt;p&gt;
Added Gaussian Distribution 2D plot sample, by John Russ
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2011-01-25</title>
<id>http://www.calormen.com/Applesoft/20110125</id>
<updated>2011-01-25T21:00:00Z</updated>
<content type="html">
&lt;p&gt;
Added compatibility shims for &lt;code&gt;PEEK(78)&lt;/code&gt; and &lt;code&gt;PEEK(79)&lt;/code&gt;
for seeding the random number generator. On a real Apple these are incremented during the input
polling loop and are a good source of entropy for seeding a random number generator. In this
interpreter, they are simply generated by the JavaScript &lt;code&gt;Math.random()&lt;/code&gt; function.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2010-11-21</title>
<id>http://www.calormen.com/Applesoft/20101121</id>
<updated>2010-11-21T19:00:00Z</updated>
<content type="html">
&lt;p&gt;
Added lexical highlighting in code editor via &lt;a href="http://codemirror.net"&gt;CodeMirror&lt;/a&gt;. Note that this only highlights tokens, it does not check statement or expression syntax. It will highlight invalid tokens and unsupported statements.
&lt;p&gt;
Mousing over the screen now updates paddle position - try the lo-res painting demo for an example.
&lt;/p&gt;
&lt;p&gt;
Lots of internal code cleanup with hopefully no behavior changes.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2010-11-18</title>
<id>http://www.calormen.com/Applesoft/20101118</id>
<updated>2010-11-18T19:00:00Z</updated>
<content type="html">
&lt;p&gt;
Fix &lt;code&gt;RETURN&lt;/code&gt; and &lt;code&gt;POP&lt;/code&gt;
from inside a &lt;code&gt;FOR ... NEXT&lt;/code&gt; loop.
&lt;/p&gt;
&lt;p&gt;
Fix &lt;code&gt;TRACE&lt;/code&gt; and &lt;code&gt;NOTRACE&lt;/code&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2010-11-13</title>
<id>http://www.calormen.com/Applesoft/20101113</id>
<updated>2010-11-13T19:00:00Z</updated>
<content type="html">
&lt;p&gt;
Added &lt;code&gt;SPEED=&lt;/code&gt; shim (does nothing)
&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;SPC()&lt;/code&gt; and &lt;code&gt;TAB()&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Work around
&lt;a href="http://code.google.com/p/chromium/issues/detail?id=58144"&gt;Chrome bug&lt;/a&gt;
to show full error alert text.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2010-08-29</title>
<id>http://www.calormen.com/Applesoft/20100829</id>
<updated>2010-08-29T11:22:00Z</updated>
<content type="html">
&lt;p&gt;
Added "Echo to Printer" option to allow copy/paste of output
&lt;/p&gt;
&lt;p&gt;
Big refactor of internals. Statement parsing and execution now separated. A library of statement functions are
used for execution. Hopefully nothing broke - all unit tests still pass.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2010-05-04</title>
<id>http://www.calormen.com/Applesoft/20100504</id>
<updated>2010-05-04T20:28:00-08:00</updated>
<content type="html">
&lt;p&gt;
When run under &lt;code&gt;cscript.exe&lt;/code&gt;, the program still blocks until the user
presses Enter when a &lt;code&gt;GET&lt;/code&gt; statement executes, but the entered
characters are returned by subsequent &lt;code&gt;GET&lt;/code&gt; statements.
&lt;/p&gt;
&lt;p&gt;
Added Hello World Sine Wave sample by Jamie Beu.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-11-01</title>
<id>http://www.calormen.com/Applesoft/20091101</id>
<updated>2009-11-01T14:22:00-08:00</updated>
<content type="html">
&lt;p&gt;
Changes are now recorded in an &lt;a href="feed.xml"&gt;Atom Feed&lt;/a&gt;.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-10-24</title>
<id>http://www.calormen.com/Applesoft/20091024</id>
<updated>2009-10-24T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Now licensed under the &lt;a href="http://www.apache.org/licenses/LICENSE-2.0"&gt;Apache 2.0 license&lt;/a&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-10-15</title>
<id>http://www.calormen.com/Applesoft/20091015</id>
<updated>2009-10-15T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Fixed bug with &lt;code&gt;POKE&lt;/code&gt; and negative addresses (introduced 2009-05-15, bleah)
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-06-10</title>
<id>http://www.calormen.com/Applesoft/20090610</id>
<updated>2009-06-10T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Added &lt;a href="http://en.wikipedia.org/wiki/Boy%27s_surface"&gt;Boy's Surface&lt;/a&gt; sample by Lukas Innig
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-05-08</title>
<id>http://www.calormen.com/Applesoft/20090508b</id>
<updated>2009-05-08T13:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Fixed running with &lt;code&gt;cscript&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;Slight performance tweaks for IE c/o explicit sizing&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-05-08</title>
<id>http://www.calormen.com/Applesoft/20090508</id>
<updated>2009-05-08T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Tracked down source of IE perf issues when drawing with paddles; when the thumb/stick moves,
IE does a relayout/repaint of any content above the paddle in the HTML flow. If I delete the
page header it's silky-smooth. Unfortunately, any text above the screen seems to make it fall
off the deep end - so no fix yet without gutting the page.
&lt;/p&gt;
&lt;p&gt;
Undid "Line breaks from &lt;code&gt;PRINT&lt;/code&gt; now clear to the right edge" - doesn't repro on Apple. &lt;em&gt;What was I thinking?&lt;/em&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-05-06</title>
<id>http://www.calormen.com/Applesoft/20090506</id>
<updated>2009-05-06T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
A bunch of performance tweaks based on IE8's JavaScript profiler. While they look good on paper,
they mean diddly-squat to perceived performance. Don't precalc default variable values, avoid DOM
changes that are no-ops, and (sigh) don't scan the whole screen looking for &lt;code&gt;FLASH&lt;/code&gt;-styled
cells - maintain a list instead so perf isn't impacted if there are none.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-05-01</title>
<id>http://www.calormen.com/Applesoft/20090501</id>
<updated>2009-05-01T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Expressions are now just-in-time compiled to JavaScript. Screen updates are the real bottleneck, though,
so this isn't a big performance boost. Performance comparison (on my 1.73GHz machine) of the lores Mandelbrot set demo:
&lt;ul&gt;
&lt;li&gt;Google Chrome (V8 JavaScript compiler): 25% faster (21s vs. 27s)&lt;/li&gt;
&lt;li&gt;Firefox 3: 14% faster (64s vs. 73s)&lt;/li&gt;
&lt;li&gt;Internet Explorer 8: &amp;lt;1% faster (249s vs. 251s)&lt;/li&gt;
&lt;/ul&gt;
So not a huge win except on faster execution engines. But this is just the first step...
&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;POKE 216,x&lt;/code&gt; shim to disable &lt;code&gt;ONERR&lt;/code&gt; handler
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-30</title>
<id>http://www.calormen.com/Applesoft/20090430</id>
<updated>2009-04-30T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Rejiggered internal value storage/passing system to use fundamental JavaScript types instead of &lt;code&gt;{number: value}&lt;/code&gt; or
&lt;code&gt;{string: value}&lt;/code&gt;. I didn't trust JavaScript's type system when I first wrote this code.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-26</title>
<id>http://www.calormen.com/Applesoft/20090426</id>
<updated>2009-04-26T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Performance - made &lt;code&gt;GOTO&lt;/code&gt;/&lt;code&gt;GOSUB&lt;/code&gt; not do a linear scan to find the line (d'oh). Significant perf boost for IE.
&lt;/p&gt;
&lt;p&gt;Added Unit Tests sample. Coverage is not complete but it's getting there.&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;RND()&lt;/code&gt; with negative now consistently reseeds (added custom pseudoranom number generator)
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;FOR I = 10 TO 1 : PRINT I : NEXT&lt;/code&gt; now correctly prints &lt;samp&gt;10&lt;/samp&gt; then finishes (was previously incorrectly inferring &lt;code&gt;STEP -1&lt;/code&gt;)
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-25</title>
<id>http://www.calormen.com/Applesoft/20090425</id>
<updated>2009-04-25T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Line breaks from &lt;code&gt;PRINT&lt;/code&gt; now clear to the right edge of the text window
&lt;/p&gt;
&lt;p&gt;
Automatically show input devices if &lt;code&gt;PDL()&lt;/code&gt; called
&lt;/p&gt;
&lt;p&gt;Added Zhodani Relay Station Placement example (run after generating a sector with Traveller Sector Generator)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-24</title>
<id>http://www.calormen.com/Applesoft/20090424</id>
<updated>2009-04-24T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Fixed a bug where changing text mode (e.g. &lt;code&gt;PR#3&lt;/code&gt;) after calling &lt;code&gt;HGR&lt;/code&gt; would break split-screen mode.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-14</title>
<id>http://www.calormen.com/Applesoft/20090414</id>
<updated>2009-04-14T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Updated to an &lt;a href="http://explorercanvas.blogspot.com/2009/03/new-explorer-canvas-release.html"&gt;IE8-compatible&lt;/a&gt; version of &lt;a href="http://code.google.com/p/explorercanvas/"&gt;excanvas&lt;/a&gt;.
Updated &lt;a href="excanvas.patch"&gt;my excanvas patch to support scaling&lt;/a&gt;.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-04-05</title>
<id>http://www.calormen.com/Applesoft/20090405</id>
<updated>2009-04-05T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Allow &lt;code&gt;DEF FN&lt;/code&gt; to be invalid (errors occur in &lt;code&gt;FN&lt;/code&gt;, per Applesoft)
&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;PR#0&lt;/code&gt; in Safari
&lt;/p&gt;
&lt;p&gt;
Added &lt;code&gt;
RENAME &lt;var&gt;old&lt;/var&gt;,&lt;var&gt;new&lt;/var&gt;
&lt;/code&gt;to DOS
&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;LIST&lt;/code&gt; for assignment statements with no &lt;code&gt;LET&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Fixed operator spacing for &lt;code&gt;LIST&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Fixed parsing of empty &lt;code&gt;REM&lt;/code&gt; statements
&lt;/p&gt;
&lt;p&gt;Program would execute after a tokenization error was encountered - fixed.&lt;/p&gt;
&lt;p&gt;Added Traveller Sector Generator sample&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-03-07</title>
<id>http://www.calormen.com/Applesoft/20090307</id>
<updated>2009-03-07T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Fixed cursor blinking&lt;/p&gt;
&lt;p&gt;Added Connections, Puzzler, and Squiggle by Gregg Buntin&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-03-06</title>
<id>http://www.calormen.com/Applesoft/20090306</id>
<updated>2009-03-06T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Addressed IE performance issues: sped up Text and LoRes screen initialization, don't use classes for characters (&lt;em&gt;sigh&lt;/em&gt;).
&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;PRINT SPC()&lt;/code&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-03-05</title>
<id>http://www.calormen.com/Applesoft/20090305</id>
<updated>2009-03-05T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
&lt;code&gt;PRINT CHR$(7)&lt;/code&gt; now rings a &lt;code&gt;BELL&lt;/code&gt; (if your browser has an audio/wav WAV handler configured)
&lt;/p&gt;
&lt;p&gt;Reimplemented the text display (TTY) using bitmap font, to mimic the look of 40/80 column text (no more copy/paste, alas)&lt;/p&gt;
&lt;p&gt;
Added MouseText support. &lt;code&gt;INVERSE:PRINT CHR$(27);"XY";CHR$(24):NORMAL&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
The ASCII Pac-Man sample was really &lt;em&gt;Unicode&lt;/em&gt; Pac-Man, which the bitmap font doesn't support, so it broke. So I cheated.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-03-01</title>
<id>http://www.calormen.com/Applesoft/20090301</id>
<updated>2009-03-01T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added Scribble sample, by William Simms&lt;/p&gt;
</content>
</entry>
<entry>
<title>2009-02-12</title>
<id>http://www.calormen.com/Applesoft/20090212</id>
<updated>2009-02-12T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added February Surprise sample by Antti Pirskanen&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-11-08</title>
<id>http://www.calormen.com/Applesoft/20081108</id>
<updated>2008-11-08T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Ignore whitespace-only lines, as a convenience&lt;/p&gt;
&lt;p&gt;Added ASCII PAC-MAN(ish) sample by Michael Kemp&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-10-19</title>
<id>http://www.calormen.com/Applesoft/20081019</id>
<updated>2008-10-19T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added TEXT ADVENTURE sample by Floyd McWilliams.&lt;/p&gt;
&lt;p&gt;Allow string literals to be terminated by end-of-line (suggested by Mike Kienenberger for compatibility)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-09-18</title>
<id>http://www.calormen.com/Applesoft/20080918</id>
<updated>2008-09-18T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Fixed a case where syntax errors were ignored&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-09-17</title>
<id>http://www.calormen.com/Applesoft/20080917</id>
<updated>2008-09-17T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Fixed input focus to work in Google Chrome&lt;/p&gt;
&lt;p&gt;
Fixed &lt;code&gt;READ&lt;/code&gt; to support multiple variables, e.g. &lt;code&gt;READ I,J,S$&lt;/code&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-08-23</title>
<id>http://www.calormen.com/Applesoft/20080823</id>
<updated>2008-08-23T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added Save/Load buttons that let you save your work to a cookie&lt;/p&gt;
&lt;p&gt;Added DRAWING PROGRAM sample by Brian Broker&lt;/p&gt;
&lt;p&gt;Fixed power operator (^) which wasn't being parsed correctly&lt;/p&gt;
&lt;p&gt;Fixed subtle bug with string comparisons (result was double-typed as number and string)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-05-01</title>
<id>http://www.calormen.com/Applesoft/20080501</id>
<updated>2008-05-01T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Fixed &lt;code&gt;NEXT I,J,...&lt;/code&gt; to terminate multiple loops - thanks to Scott Alfter for pointing this out
&lt;/p&gt;
&lt;p&gt;
Bowing to popular demand, it now supports &lt;code&gt;?&lt;/code&gt; as an alias for &lt;code&gt;PRINT&lt;/code&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-03-15</title>
<id>http://www.calormen.com/Applesoft/20080315</id>
<updated>2008-03-15T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Implemented &lt;code&gt;ONERR GOTO line&lt;/code&gt; and &lt;code&gt;RESUME&lt;/code&gt;, including &lt;code&gt;POKE 216,0&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;Added demo for ONERR, added ONERR support to sequential file access demo&lt;/p&gt;
&lt;p&gt;Fix hires graphics on Safari - not sure when it broke&lt;/p&gt;
</content>
</entry>
<entry>
<title>2008-03-14</title>
<id>http://www.calormen.com/Applesoft/20080314</id>
<updated>2008-03-14T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Code cleanup c/o &lt;a href="http://www.jslint.com"&gt;jslint.com&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Bug fix: &lt;code&gt;INPUT A,B,C&lt;/code&gt; no longer worked. Probably mis-re-factored at some point.
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-12-08</title>
<id>http://www.calormen.com/Applesoft/20071208</id>
<updated>2007-12-08T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Implement file writing (to client-side VFS only), including &lt;code&gt;APPEND&lt;/code&gt; operations
&lt;/p&gt;
&lt;p&gt;
Added DOS &lt;code&gt;DELETE&lt;/code&gt; command
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;GR&lt;/code&gt; does implicit &lt;code&gt;HTAB 1 : VTAB 24&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;PEEK(49168)&lt;/code&gt; has the same effect as &lt;code&gt;POKE 49168,N&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
As a convenience, &lt;code&gt;PEEK&lt;/code&gt; and &lt;code&gt;POKE&lt;/code&gt; at 49200/-16336 (speaker toggle) now accepted, but a no-op
&lt;/p&gt;
&lt;p&gt;
As a convenience, spaces now accepted before &lt;code&gt;=&lt;/code&gt; for&lt;code&gt;COLOR=&lt;/code&gt; and &lt;code&gt;HCOLOR=&lt;/code&gt;
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-11-22</title>
<id>http://www.calormen.com/Applesoft/20071122</id>
<updated>2007-11-22T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added button to submit your sample (via email) for inclusion&lt;/p&gt;
&lt;p&gt;Added SIMPLE.PONG sample c/o USENET post by mad.scientist.jr&lt;/p&gt;
&lt;p&gt;Improved comment handling (doesn't tokenize)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-10-22</title>
<id>http://www.calormen.com/Applesoft/20071022</id>
<updated>2007-10-22T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Make &lt;code&gt;GET&lt;/code&gt; support keyboard flag, so &lt;code&gt;IF PEEK(-16384) > 127 THEN GET A$&lt;/code&gt; works
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-10-20</title>
<id>http://www.calormen.com/Applesoft/20071020</id>
<updated>2007-10-20T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Bug fix: User could type after hitting Stop. Now TTY state is reset.&lt;/p&gt;
&lt;p&gt;
Added missing statement: &lt;code&gt;ON expr GOSUB ...&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;RND(0)&lt;/code&gt; returns last, negative reseeds
&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-10-14</title>
<id>http://www.calormen.com/Applesoft/20071014</id>
<updated>2007-10-14T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Fixed location of paddle button 3 (C060)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-09-22</title>
<id>http://www.calormen.com/Applesoft/20070922</id>
<updated>2007-09-22T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Implemented scaling in &lt;a target="_blank" href="http://excanvas.sourceforge.net/"&gt;
ExplorerCanvas&lt;/a&gt; (&lt;a target="_blank" href="excanvas.js"&gt;source&lt;/a&gt;); hires now scaled somewhat correctly in IE
&lt;/p&gt;
&lt;p&gt;Bug fixes: HOME would force full-screen text; HPLOT can now plot a single pixel&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-09-20</title>
<id>http://www.calormen.com/Applesoft/20070920</id>
<updated>2007-09-20T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Added hires support via &lt;a target="_blank" href="http://www.whatwg.org/specs/web-apps/current-work/#canvas"&gt;canvas&lt;/a&gt; tag
&lt;/p&gt;
&lt;p&gt;Display switches (POKE 49232...49239, not counting page 2) supported.&lt;/p&gt;
&lt;p&gt;Added text window support: POKE 32,left : POKE 33,width : POKE 34,top : POKE 35,bottom&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-09-16</title>
<id>http://www.calormen.com/Applesoft/20070916</id>
<updated>2007-09-16T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;
Added full screen lores support via &lt;a target="_blank" href="reference.htm#Poke"&gt;POKE&lt;/a&gt; 29234,0
&lt;/p&gt;
&lt;p&gt;Fixed keyboard input on Safari - hacky, but logical&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-09-15</title>
<id>http://www.calormen.com/Applesoft/20070915</id>
<updated>2007-09-15T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added Mandelbrot set demo to DEMOS&lt;/p&gt;
&lt;p&gt;
Added &lt;a target="_blank" href="reference.htm#Peek"&gt;PEEK&lt;/a&gt; and &lt;a target="_blank" href="reference.htm#Poke"&gt;POKE&lt;/a&gt; shims
&lt;/p&gt;
&lt;p&gt;Added paddle buttons: Home = 0 = Open Apple, End = 1 = Solid Apple, Page Up = 2, Page Down = 3&lt;/p&gt;
&lt;p&gt;Added Caps Lock (defaults to on; real Caps Lock key toggles it; this means it usually ends up in an inverted state)&lt;/p&gt;
&lt;p&gt;Round numerical results to 8 decimal places (hacky)&lt;/p&gt;
</content>
</entry>
<entry>
<title>2007-09-10</title>
<id>http://www.calormen.com/Applesoft/20070910</id>
<updated>2007-09-10T12:00:00-08:00</updated>
<content type="html">
&lt;p&gt;Added demo file links, cleaned up UI a bit.&lt;/p&gt;
&lt;p&gt;Added hacky PR#0/PR#3 support (to set 40 columns)&lt;/p&gt;
</content>
</entry>