README updates (and some code inspection fixes)
This commit is contained in:
parent
efab8c7147
commit
383de1cd8a
12 changed files with 262 additions and 820 deletions
243
README.md
243
README.md
|
|
@ -50,70 +50,114 @@ and the original machine are available in the [C1Pjs Documentation](/docs/c1pjs/
|
||||||
|
|
||||||
<!--BEGIN:EXCLUDE-->
|
<!--BEGIN:EXCLUDE-->
|
||||||
|
|
||||||
Updating PCjs
|
Installing PCjs
|
||||||
===
|
|
||||||
|
|
||||||
Developing
|
|
||||||
---
|
---
|
||||||
Let's say you just finished developing, testing and deploying version 1.12.1, and you want to start developing some
|
The following instructions were written for OS X users. However, users of other operating systems should have
|
||||||
new features for version 1.13.0. Here are the recommended steps:
|
no problem following along.
|
||||||
|
|
||||||
1. Create and switch to a new Git development branch (eg, "node_dev")
|
|
||||||
2. Change the version number in [package.json](/package.json) (eg, to "1.13.0")
|
|
||||||
3. Run "grunt" (the default task will build fresh "1.13.0" copies of everything under "/versions")
|
|
||||||
4. Run "grunt promote" to bump the version in all the site's machine XML files to match (ie, to "1.13.0")
|
|
||||||
|
|
||||||
You may not want to do the last step until you're ready to start testing the new version. In fact, you may want to
|
|
||||||
manually edit the version in only a few machine configuration files for testing, leaving the rest set to the previous
|
|
||||||
version to make comparison runs easier, and then run "grunt promote" when the new version is much closer to being
|
|
||||||
released.
|
|
||||||
|
|
||||||
Commit the development branch to GitHub as often as desired. I probably tend to "over-commit", checking in lots of
|
Open Terminal and `cd` to a directory where you'd like to install *pcjs*, and run the following commands:
|
||||||
intermediate changes before I finally decide that the new version is "good enough". But having too much delta history is
|
|
||||||
probably better than too little. Note that the initial "node_dev" commit may not get pushed to GituHub without first
|
|
||||||
running:
|
|
||||||
|
|
||||||
git push --set-upstream origin node_dev
|
git clone git@github.com:jeffpar/pcjs.git pcjs
|
||||||
|
cd pcjs
|
||||||
|
npm install
|
||||||
|
node server.js
|
||||||
|
|
||||||
One downside to intermediate commits to GitHub is that compiled versions of the sources (such as those in
|
Now open a web browser and go to `http://localhost:8088/`. You're done!
|
||||||
[/docs/pcjs/demos/](/docs/pcjs/demos/)) may keep changing, and those particular commits are pretty useless.
|
|
||||||
To temporarily ignore changes to those files:
|
|
||||||
|
|
||||||
cd docs/pcjs/demos
|
It's assumed that the OS X Developer Tools (which include Git) have already been installed, as well as
|
||||||
git update-index --assume-unchanged components.xsl pc.js pc-dbg.js samples.zip
|
Node and NPM. Node (which now includes NPM) should be downloaded from [nodejs.org](http://nodejs.org/download/).
|
||||||
|
|
||||||
|
The current version of Node ([0.10.32](http://nodejs.org/dist/v0.10.32/node-v0.10.32.pkg) at the time of this
|
||||||
|
writing) should work fine, but version [0.10.26](http://nodejs.org/dist/v0.10.26/node-v0.10.26.pkg)
|
||||||
|
is what's been used to develop and test PCjs so far.
|
||||||
|
|
||||||
|
Also, [server.js](server.js) was originally written using [Express](http://expressjs.com/) v3.x. Since then,
|
||||||
|
Express v4.x has been released, but `npm install` will make sure that v3.x is installed locally.
|
||||||
|
|
||||||
|
The plan is to eventually move development to a newer version of Node, and migrate the PCjs server to a newer
|
||||||
|
version of Express; there's no desire to remain stuck in the past (well, ignoring the fact that PCjs is the
|
||||||
|
quintessential "stuck in the past" project), but there's also no urgency to update.
|
||||||
|
|
||||||
|
### Building PCjs
|
||||||
|
|
||||||
|
Unlike a typical project, where you have to *build* or *configure* or *make* something, PCjs is "ready to run".
|
||||||
|
That's because both the compiled and uncompiled versions of PCjs are checked into the project, making deployment
|
||||||
|
to a web server easy.
|
||||||
|
|
||||||
|
However, in order to build and test PCjs modifications, you'll want to use [Grunt](http://gruntjs.com/) and the
|
||||||
|
Grunt tasks defined by [Gruntfile.js](Gruntfile.js).
|
||||||
|
|
||||||
|
Although Grunt was installed locally when you ran `npm install`, you'll also want to install the command-line
|
||||||
|
interface to Grunt; you can install that locally as well, but it's recommended that you install it globally, with
|
||||||
|
the "-g" option:
|
||||||
|
|
||||||
|
sudo npm install grunt-cli -g
|
||||||
|
|
||||||
|
Now you can run `grunt` anywhere within the PCjs project to build an updated version. If no command-line arguments
|
||||||
|
are specified, `grunt` runs the "default" task defined by [Gruntfile.js](Gruntfile.js); that task runs Google's
|
||||||
|
[Closure Compiler](https://developers.google.com/closure/compiler/) if any of the target files (eg, pc.js, pc-dbg.js,
|
||||||
|
etc) are out-of date.
|
||||||
|
|
||||||
|
To ensure identical compilation results for everyone, a copy of the Closure Compiler has been checked into the
|
||||||
|
[bin](bin/) folder. This version of Closure Compiler, in turn, requires Java v7.x or later. Use the following
|
||||||
|
commands to confirm that everything is working properly:
|
||||||
|
|
||||||
|
java -version
|
||||||
|
|
||||||
To see a list of all files that are marked as "assume-unchanged", use this command:
|
which should report a version >= 1.7.x; eg:
|
||||||
|
|
||||||
git ls-files -v | grep '^[[:lower:]]'
|
|
||||||
|
|
||||||
The same issue would exist for all new files created under "/versions", but fortunately, those files are ignored until
|
java version "1.7.0_67"
|
||||||
you explicitly add them to Git, which you'll want to do just prior to deployment:
|
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
|
||||||
|
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
|
||||||
|
|
||||||
git add versions/pcjs/1.13.0/*
|
Then run:
|
||||||
git add versions/c1pjs/1.13.0/*
|
|
||||||
|
|
||||||
which is when you'll also want to do undo the "assume-unchanged" operation above:
|
|
||||||
|
|
||||||
cd docs/pcjs/demos
|
java -jar bin/compiler.jar --version
|
||||||
git update-index --no-assume-unchanged components.xsl pc.js pc-dbg.js samples.zip
|
|
||||||
|
|
||||||
Testing
|
which should report:
|
||||||
|
|
||||||
|
Closure Compiler (http://code.google.com/closure/compiler)
|
||||||
|
Version: v20140407
|
||||||
|
Built on: 2014/04/07 14:04
|
||||||
|
|
||||||
|
If you don't have Java installed, it's recommended that you install the JDK (*not* the JRE), because the JRE may not
|
||||||
|
update your command-line tools properly. Note that Java is used *only* by the Closure Compiler; none of the PCjs
|
||||||
|
client or server components use Java.
|
||||||
|
|
||||||
|
Newer versions of the Closure Compiler should work as well, and at some point, a newer version will be checked into the
|
||||||
|
project.
|
||||||
|
|
||||||
|
Using PCjs
|
||||||
---
|
---
|
||||||
PCjs can now be run from the command-line mode using Node, making it possible to script the application,
|
|
||||||
|
### From The Browser
|
||||||
|
|
||||||
|
The PCjs web server is little more than a file/directory browser for the PCjs project, plus a collection of APIs.
|
||||||
|
|
||||||
|
If a URL corresponds to a PCjs project folder and no "index.html" exists in that folder, the server loads an HTML
|
||||||
|
template ([common.html](my_modules/shared/templates/common.html)) and generates an "index.html" for that folder.
|
||||||
|
|
||||||
|
The contents of the "index.html" will vary depending on the contents of the folder; for example, if the folder
|
||||||
|
contains a README.md, then that file is converted to HTML and embedded in the "index.html". Similarly, if the folder
|
||||||
|
contains a machine XML file, that is embedded as well.
|
||||||
|
|
||||||
|
### From The Command-Line
|
||||||
|
|
||||||
|
The PCjs client app can also be run from the command-line mode using Node, making it possible to script the application,
|
||||||
run a series of automated tests, etc:
|
run a series of automated tests, etc:
|
||||||
|
|
||||||
cd ./my_modules/pcjs-client/bin
|
cd ./my_modules/pcjs-client/bin
|
||||||
node pcjs
|
node pcjs
|
||||||
|
|
||||||
The [pcjs](/my_modules/pcjs-client/bin/pcjs) script in the *bin* directory loads all the PCjs browser scripts listed
|
The [pcjs](my_modules/pcjs-client/bin/pcjs) script in [/my_modules/pcjs-client/bin](my_modules/pcjs-client/bin) loads
|
||||||
in [package.json](/package.json), and then it starts a Node REPL ("read-eval-print loop"). The REPL handles a few
|
all the PCjs browser scripts listed in [package.json](/package.json), and then it starts a Node REPL ("read-eval-print loop").
|
||||||
special commands (eg, "load", "quit") and passes anything else to the PCjs Debugger component. If no Debugger component
|
The REPL handles a few special commands (eg, "load", "quit") and passes anything else to the PCjs Debugger component.
|
||||||
has been created yet, or if the Debugger didn't recognize the command, then it's passed on to *eval()*, like a good
|
If no Debugger component has been created yet, or if the Debugger didn't recognize the command, then it's passed on to *eval()*,
|
||||||
little REPL.
|
like a good little REPL.
|
||||||
|
|
||||||
Use the "load" command to load a JSON machine configuration file. A sample [machine.json](/my_modules/pcjs-client/bin/machine.json)
|
Use the "load" command to load a JSON machine configuration file. A sample [machine.json](my_modules/pcjs-client/bin/machine.json)
|
||||||
is provided in the *bin* directory, which is a "JSON-ified" version of the [machine.xml](/configs/pc/machines/5150/mda/64kb/machine.xml)
|
is provided in the *bin* directory, which is a "JSON-ified" version of the [machine.xml](configs/pc/machines/5150/mda/64kb/machine.xml)
|
||||||
displayed on the [pcjs.org](http://www.pcjs.org/) home page.
|
displayed on the [pcjs.org](/) home page.
|
||||||
|
|
||||||
The command-line loader creates all the JSON-defined machine components in the same order that the browser creates
|
The command-line loader creates all the JSON-defined machine components in the same order that the browser creates
|
||||||
XML-defined components. You can also issue the "load" command directly from the command-line:
|
XML-defined components. You can also issue the "load" command directly from the command-line:
|
||||||
|
|
@ -139,65 +183,72 @@ supports *only* JSON machine configuration files.
|
||||||
I haven't decided whether I'll add support for JSON configuration files to the client, or add some XML-to-JSON conversion
|
I haven't decided whether I'll add support for JSON configuration files to the client, or add some XML-to-JSON conversion
|
||||||
to the server, or both.
|
to the server, or both.
|
||||||
|
|
||||||
Deploying
|
Debugging PCjs
|
||||||
---
|
---
|
||||||
I like to use the AWS Elastic Beanstalk web interface to create a new "development" environment ("pcjs-dev") for testing:
|
|
||||||
|
### Server Components
|
||||||
|
|
||||||
|
To help test/debug changes to PCjs server components (eg, [DiskDump](my_modules/diskdump/), [HTMLOut](my_modules/htmlout/)),
|
||||||
|
you can start the server with some additional options; eg:
|
||||||
|
|
||||||
|
node server.js --logging --console --debug
|
||||||
|
|
||||||
|
The `--logging` option will create a [node.log](/logs/node.log) that records all the HTTP requests, `--debug`
|
||||||
|
will generate additional debug-only messages (which will also be logged if `--logging` is enabled), and `--console`
|
||||||
|
will replicate any messages to your console as well.
|
||||||
|
|
||||||
|
A complete list of command-line options can be found in [server.js](server.js).
|
||||||
|
|
||||||
|
### Client Components
|
||||||
|
|
||||||
|
A special parameter ("gort") can be appended to the URL to request uncompiled client source files, making problems
|
||||||
|
much easier to debug:
|
||||||
|
|
||||||
|
http://localhost:8088/?gort=debug
|
||||||
|
|
||||||
|
However, the "gort=debug" parameter is unnecessary if the server was started with `--debug`; the server always
|
||||||
|
serves uncompiled files when running in "debug" mode.
|
||||||
|
|
||||||
|
Conversely, if the server is running "debug" mode but you want to test a compiled version of PCjs, use:
|
||||||
|
|
||||||
|
http://localhost:8088/?gort=release
|
||||||
|
|
||||||
|
and the server will serve compiled JavaScript files, regardless whether the server is running in "debug" or "release"
|
||||||
|
mode.
|
||||||
|
|
||||||
|
Updating PCjs
|
||||||
|
---
|
||||||
|
|
||||||
|
### Developing
|
||||||
|
|
||||||
|
To start developing features for a new version of PCjs, here are the recommended steps:
|
||||||
|
|
||||||
1. Save the current production environment ("pcjs-env") as configuration "pcjs-config"
|
1. Change the version number in [package.json](/package.json)
|
||||||
2. Create a new environment ("pcjs-dev") using the "pcjs-config" configuration
|
2. Run the "grunt promote" task to bump the version in all machine XML files
|
||||||
3. Wait for the new environment ("pcjs-dev") to start (ie, for its health to become "Green")
|
3. Make changes
|
||||||
4. From Terminal, go to the `~/Sites/pcjs` folder and run `eb branch` followed by `git aws.push`
|
4. Run "grunt" to build new versions of the apps (eg, "/versions/pcjs/1.xx/pc.js")
|
||||||
|
|
||||||
The `eb branch` command will display:
|
However, you may want to skip step #2 until you're ready to start testing the new version. Depending on the nature
|
||||||
|
of your changes, it may be better to manually edit the version number in only a few machine XML files for testing,
|
||||||
|
leaving the rest of the XML files pointing to the previous version. Run "grunt promote" when the new version is much
|
||||||
|
closer to being released.
|
||||||
|
|
||||||
The current branch is "node_dev".
|
### Testing
|
||||||
Enter an AWS Elastic Beanstalk environment name (auto-generated value is "pcjs-nodedev-env"): pcjs-dev
|
|
||||||
Do you want to copy the settings from environment "pcjs-env" for the new branch? [y/n]: y
|
|
||||||
|
|
||||||
after which we're ready for `git aws.push` to the new "pcjs-dev" environment.
|
|
||||||
|
|
||||||
See the "[Develop, Test, and Deploy](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_nodejs.sdlc.html)"
|
In the course of testing PCjs, there may be stale "index.html" files that prevent you from seeing application
|
||||||
AWS documentation for more details.
|
updates, changes to README.md files, etc. So, before running Node, you may want to "touch" the default HTML template:
|
||||||
|
|
||||||
On a local machine, the process is similar. If this is a "virgin" machine, you must first install Node and NPM;
|
touch my_modules/shared/templates/common.html
|
||||||
see my notes on "[Installing Node (and NPM)](/my_modules/#installing-node-and-npm)" for more details.
|
|
||||||
|
|
||||||
Then install and run the PCjs web server files:
|
|
||||||
|
|
||||||
[iMac:~/Sites] git clone git@github.com:jeffpar/jsmachines.git pcjs
|
|
||||||
[iMac:~/Sites] cd pcjs
|
|
||||||
[iMac:~/Sites/pcjs] git checkout node_dev
|
|
||||||
[iMac:~/Sites/pcjs] npm install --production
|
|
||||||
[iMac:~/Sites/pcjs] export PORT=8086 (this is optional)
|
|
||||||
[iMac:~/Sites/pcjs] node server.js
|
|
||||||
|
|
||||||
For a machine that is simply out-of-date, you can do something like this:
|
|
||||||
|
|
||||||
[iMac:~/Sites/pcjs] git pull
|
|
||||||
[iMac:~/Sites/pcjs] npm update --production
|
|
||||||
[iMac:~/Sites/pcjs] export PORT=8086 (this is optional)
|
|
||||||
[iMac:~/Sites/pcjs] node server.js
|
|
||||||
|
|
||||||
In the second scenario, there may be stale "index.html" files that prevent you from seeing the latest versions
|
|
||||||
of everything, so before running Node, you may want to do this first:
|
|
||||||
|
|
||||||
[iMac:~/Sites/pcjs] touch my_modules/shared/templates/common.html
|
|
||||||
|
|
||||||
The [HTMLOut](/my_modules/htmlout/) module compares the timestamp of that template file to the timestamp of any
|
The [HTMLOut](/my_modules/htmlout/) module compares the timestamp of that template file to the timestamp of any
|
||||||
"index.html" and will regenerate the latter if it's out-of-date. There's a TODO to expand that check to include
|
"index.html" and will regenerate the latter if it's out-of-date.
|
||||||
the timestamp of any local README.md file, but there are many other factors that contribute to stale "index.html"
|
|
||||||
files, so the safest thing to do is touch the [common.html](/my_modules/shared/templates/common.html) template,
|
|
||||||
or delete all existing "index.html" files -- either by hand, or by using:
|
|
||||||
|
|
||||||
[iMac:~/Sites/pcjs] grunt clean
|
There's a TODO to expand that check to include the timestamp of any local README.md file, but there are many other
|
||||||
|
factors that can contribute to stale "index.html" files, so usually the safest thing to do is "touch" the
|
||||||
However, if you included "--production" in your NPM install/update commands, you won't have the necessary grunt
|
[common.html](/my_modules/shared/templates/common.html) template, or delete all existing "index.html" files, either
|
||||||
task files. You may not even have grunt itself installed, unless you've previously run:
|
manually or with the Grunt "clean" task:
|
||||||
|
|
||||||
[iMac:~/Sites/pcjs] sudo npm install grunt-cli -g
|
grunt clean
|
||||||
|
|
||||||
Stale "index.html" files may be a non-issue on AWS, because it appears to create a completely new directory
|
|
||||||
structure when it rebuilds the environment following a `git aws.push` -- but I'm not sure that's always true.
|
|
||||||
|
|
||||||
<!--END:EXCLUDE-->
|
<!--END:EXCLUDE-->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,649 +1,7 @@
|
||||||
Private Node Modules
|
Private Node Modules
|
||||||
===
|
===
|
||||||
|
|
||||||
**my_modules** contains all the *private* **JSMachines** Node modules. It is the counterpart to
|
**my_modules** contains all the *private* **PCjs** Node modules. It is the counterpart to
|
||||||
**node_modules**, where all the *public* Node modules are installed. Only private Node modules are checked
|
**node_modules**, where all the *public* Node modules are installed. Only private Node modules are checked
|
||||||
into GitHub; if we later decide to publish any or all of these on [npmjs.org](http://npmjs.org), then they will
|
into GitHub; if any of these are later published on [npmjs.org](http://npmjs.org), then they will
|
||||||
be moved to **node_modules** and removed from this folder.
|
be moved to **node_modules** and removed from this folder.
|
||||||
|
|
||||||
The rest of this file documents some of the early steps involved in porting the **JSMachines** project,
|
|
||||||
which required a web server running PHP, to the new **PCjs** web server running Node. That includes setting up
|
|
||||||
my first Node web server and then extending its functionality with these private Node modules.
|
|
||||||
|
|
||||||
For more details on the private Node modules stored here, refer to the README.md for each module (which, alas,
|
|
||||||
may be nothing more than placeholders at this point, but I have good intentions).
|
|
||||||
|
|
||||||
Creating My First Node Project
|
|
||||||
===
|
|
||||||
|
|
||||||
Plan A: Fork jsmachines.net -> pcjs.org
|
|
||||||
---
|
|
||||||
The original **JSMachines** project assumed a web server running PHP
|
|
||||||
(eg, [http://jsmachines.net](http://jsmachines.net)). However, to improve client-server integration, reduce
|
|
||||||
the number of languages/frameworks used, and implement some new features, such as socket-based disk I/O interfaces,
|
|
||||||
I decided to create a fork, **PCjs**, and port all the server-side PHP to JavaScript, running on a Node web server.
|
|
||||||
|
|
||||||
Unfortunately, when I tried to fork my private **JSMachines** project on GitHub, I discovered that you're
|
|
||||||
not allowed to [fork](https://help.github.com/articles/fork-a-repo) your own projects. Adding to the confusion: GitHub
|
|
||||||
displays the "Fork" button on my project's home page, and even lets me click it, but then quietly does nothing.
|
|
||||||
|
|
||||||
The recommended work-around (as per [this post](http://bitdrift.com/post/4534738938/fork-your-own-project-on-github))
|
|
||||||
seemed to be:
|
|
||||||
|
|
||||||
- Create new project on GitHub
|
|
||||||
- Clone old project with new name
|
|
||||||
- Replace new project's "origin URL" with URL for new GitHub project
|
|
||||||
- Add original project as an "upstream source"
|
|
||||||
- Push new project to GitHub
|
|
||||||
|
|
||||||
Plan B: Branch jsmachines -> node_dev
|
|
||||||
---
|
|
||||||
The above seemed a bit clunky, so I decided to branch instead of fork. This new development branch was called
|
|
||||||
**node_pcjs**, but I've since branched to **node_dev**. I should probably remove the original **node_pcjs** branch,
|
|
||||||
but for now, it's still there.
|
|
||||||
|
|
||||||
Then I pushed the **node_dev** branch to the remote, as per [GitHub](https://help.github.com/articles/pushing-to-a-remote):
|
|
||||||
|
|
||||||
[~/Sites/jsmachines] git push origin node_dev
|
|
||||||
Total 0 (delta 0), reused 0 (delta 0)
|
|
||||||
To git@github.com:jeffpar/jsmachines.git
|
|
||||||
* [new branch] node_dev -> node_dev
|
|
||||||
[~/Sites/jsmachines]
|
|
||||||
|
|
||||||
That seemed to work fine, so I then created a new folder and cloned the project, as per
|
|
||||||
[GitHub](https://help.github.com/articles/fetching-a-remote):
|
|
||||||
|
|
||||||
[~/Sites] git clone git@github.com:jeffpar/jsmachines.git pcjs
|
|
||||||
Cloning into 'pcjs'...
|
|
||||||
remote: Reusing existing pack: 2725, done.
|
|
||||||
remote: Total 2725 (delta 0), reused 0 (delta 0)
|
|
||||||
Receiving objects: 100% (2725/2725), 59.48 MiB | 2.67 MiB/s, done.
|
|
||||||
Resolving deltas: 100% (1543/1543), done.
|
|
||||||
Checking connectivity... done
|
|
||||||
|
|
||||||
Then I checked-out the new branch:
|
|
||||||
|
|
||||||
[~/Sites] cd pcjs
|
|
||||||
[~/Sites/pcjs] git checkout node_dev
|
|
||||||
Branch node_dev set up to track remote branch node_dev from origin.
|
|
||||||
Switched to a new branch 'node_dev'
|
|
||||||
|
|
||||||
If I have to make any changes to the "master" branch (ie, the original jsmachines project) in the interim,
|
|
||||||
then after I've pushed those changes to GitHub, I can pull them into the **node_dev** branch like so:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] git pull origin master
|
|
||||||
|
|
||||||
Installing Node (and NPM)
|
|
||||||
---
|
|
||||||
I downloaded the latest Node installation package for my MacBook from [nodejs.org](http://nodejs.org/),
|
|
||||||
which provided the usual `node` and `npm` commands. Here are the versions they reported:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] node -v
|
|
||||||
v0.10.26
|
|
||||||
[~/Sites/pcjs] npm -v
|
|
||||||
1.4.3
|
|
||||||
|
|
||||||
I also installed a Node helper on my MacBook called `n` that makes it easy to keep Node up-to-date, per this tip on
|
|
||||||
[stackoverflow](http://stackoverflow.com/questions/8191459/how-to-update-node-js-npm-and-all-other-dependencies):
|
|
||||||
|
|
||||||
1) Clear NPM's cache:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo npm cache clean -f
|
|
||||||
|
|
||||||
2) Install a little helper called 'n':
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo npm install -g n
|
|
||||||
|
|
||||||
3) Install latest stable NodeJS version:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo n stable
|
|
||||||
|
|
||||||
Alternatively pick a specific version and install like so:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo n 0.8.20
|
|
||||||
|
|
||||||
I'm not sure I like the generic name for this command ("n"); what would have been wrong with "node-update"
|
|
||||||
or "update-node"? Oh well.
|
|
||||||
|
|
||||||
Next, I wanted to make sure `npm` was up-to-date. According to
|
|
||||||
[FAQ on npmjs.org](https://npmjs.org/doc/faq.html#How-do-I-update-npm), that's as easy as:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo npm update npm -g
|
|
||||||
|
|
||||||
although occasionally `npm` won't be able to update itself, in which case the fallback is:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] curl https://npmjs.org/install.sh | sh
|
|
||||||
|
|
||||||
So, I made sure `npm` itself, along with `n` and all my other globally installed packages, were up-to-date,
|
|
||||||
and then I used `n` to make sure I was running the latest stable version of Node:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo npm update -g
|
|
||||||
[~/Sites/pcjs] sudo n stable
|
|
||||||
[~/Sites/pcjs] node -v
|
|
||||||
v0.10.26
|
|
||||||
|
|
||||||
I've also seen suggestions to run this command before the preceding commands, but I don't know how often this is
|
|
||||||
recommended:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] sudo npm cache clean -f
|
|
||||||
|
|
||||||
Next, I ran `npm init`:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] npm adduser
|
|
||||||
Username: jeffpar
|
|
||||||
Password:
|
|
||||||
Email: (this IS public) jeff@pcjs.org
|
|
||||||
npm http PUT http://registry.npmjs.org/-/user/org.couchdb.user:jeffpar
|
|
||||||
npm http 201 http://registry.npmjs.org/-/user/org.couchdb.user:jeffpar
|
|
||||||
|
|
||||||
[~/Sites/pcjs] npm init
|
|
||||||
This utility will walk you through creating a package.json file.
|
|
||||||
It only covers the most common items, and tries to guess sane defaults.
|
|
||||||
|
|
||||||
See `npm help json` for definitive documentation on these fields
|
|
||||||
and exactly what they do.
|
|
||||||
|
|
||||||
Use `npm install <pkg> --save` afterwards to install a package and
|
|
||||||
save it as a dependency in the package.json file.
|
|
||||||
|
|
||||||
Press ^C at any time to quit.
|
|
||||||
name: (pcjs)
|
|
||||||
version: (0.0.0) 0.1.0
|
|
||||||
description: Node-enabled version of PCjs
|
|
||||||
entry point: (server.js)
|
|
||||||
test command:
|
|
||||||
git repository: (git://github.com/jeffpar/jsmachines.git)
|
|
||||||
keywords: pcjs,ibm pc,emulator
|
|
||||||
author: Jeff Parsons <Jeff@pcjs.org>
|
|
||||||
license: (ISC)
|
|
||||||
About to write to /Users/Jeff/Sites/pcjs/package.json:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "pcjs",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Node-enabled version of PCjs",
|
|
||||||
"main": "server.js",
|
|
||||||
"directories": {
|
|
||||||
"doc": "docs",
|
|
||||||
"test": "tests"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/jeffpar/jsmachines.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"pcjs",
|
|
||||||
"ibm",
|
|
||||||
"pc",
|
|
||||||
"emulator"
|
|
||||||
],
|
|
||||||
"author": "Jeff Parsons <Jeff@pcjs.org>",
|
|
||||||
"license": "ISC",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/jeffpar/jsmachines/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/jeffpar/jsmachines"
|
|
||||||
}
|
|
||||||
|
|
||||||
Is this ok? (yes)
|
|
||||||
|
|
||||||
Next, I installed `express` using `npm install --save express`:
|
|
||||||
|
|
||||||
[~/Sites/pcjs] npm install --save express
|
|
||||||
npm http GET http://registry.npmjs.org/express
|
|
||||||
...
|
|
||||||
express@3.4.8 node_modules/express
|
|
||||||
├── methods@0.1.0
|
|
||||||
├── merge-descriptors@0.0.1
|
|
||||||
├── range-parser@0.0.4
|
|
||||||
├── cookie-signature@1.0.1
|
|
||||||
├── fresh@0.2.0
|
|
||||||
├── debug@0.7.4
|
|
||||||
├── buffer-crc32@0.2.1
|
|
||||||
├── cookie@0.1.0
|
|
||||||
├── mkdirp@0.3.5
|
|
||||||
├── commander@1.3.2 (keypress@0.1.0)
|
|
||||||
├── send@0.1.4 (mime@1.2.11)
|
|
||||||
└── connect@2.12.0 (uid2@0.0.3, pause@0.0.1, qs@0.6.6, bytes@0.2.1, raw-body@1.1.2, batch@0.5.0, negotiator@0.3.0, multiparty@2.2.0)
|
|
||||||
|
|
||||||
This added the following lines to my "package.json" file:
|
|
||||||
|
|
||||||
"dependencies": {
|
|
||||||
"express": "~3.4.8"
|
|
||||||
}
|
|
||||||
|
|
||||||
Then I created a test "server.js" in the root of the project:
|
|
||||||
|
|
||||||
var http = require("http");
|
|
||||||
var express = require("express");
|
|
||||||
var app = express();
|
|
||||||
app.get("/", function(req, res) {
|
|
||||||
res.end("Testing");
|
|
||||||
});
|
|
||||||
http.createServer(app).listen(3000);
|
|
||||||
|
|
||||||
and ran `node server.js` and verified that all was working as expected.
|
|
||||||
|
|
||||||
Creating My First Node Module
|
|
||||||
---
|
|
||||||
The first module I decided to write was a port of the diskconv.php script I'd written to convert disk images to/from
|
|
||||||
JSON. I decided to call this new module **DiskDump**, since it will output disk images in a variety of formats, although
|
|
||||||
initially only as JSON.
|
|
||||||
|
|
||||||
[~/Sites/pcjs/my_modules] mkdir diskdump
|
|
||||||
[~/Sites/pcjs/my_modules] cd diskdump
|
|
||||||
[~/Sites/pcjs/my_modules/diskdump] npm init
|
|
||||||
This utility will walk you through creating a package.json file.
|
|
||||||
It only covers the most common items, and tries to guess sane defaults.
|
|
||||||
|
|
||||||
See `npm help json` for definitive documentation on these fields
|
|
||||||
and exactly what they do.
|
|
||||||
|
|
||||||
Use `npm install <pkg> --save` afterwards to install a package and
|
|
||||||
save it as a dependency in the package.json file.
|
|
||||||
|
|
||||||
Press ^C at any time to quit.
|
|
||||||
name: (diskdump)
|
|
||||||
version: (0.0.0) 0.1.0
|
|
||||||
description: Convert disk images to/from JSON
|
|
||||||
entry point: (index.js)
|
|
||||||
test command:
|
|
||||||
git repository:
|
|
||||||
keywords:
|
|
||||||
author: Jeff Parsons <Jeff@pcjs.org>
|
|
||||||
license: (ISC)
|
|
||||||
About to write to /Users/Jeff/Sites/pcjs/my_modules/diskdump/package.json:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "diskdump",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Convert disk images to/from JSON",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "Jeff Parsons <Jeff@pcjs.org>",
|
|
||||||
"license": "ISC"
|
|
||||||
}
|
|
||||||
|
|
||||||
Is this ok? (yes)
|
|
||||||
|
|
||||||
Next, I followed the steps outlined [here](http://www.anupshinde.com/posts/how-to-create-nodejs-npm-package/) to
|
|
||||||
create a package skeleton with a CLI (command-line interface).
|
|
||||||
|
|
||||||
Filtering Web Server Requests
|
|
||||||
---
|
|
||||||
The next module I created was [HTMLOut](/my_modules/htmlout/), which provides a filter() function for the Express module,
|
|
||||||
taking an early crack at the server's HTTP requests.
|
|
||||||
|
|
||||||
If the request is for a directory, **HTMLOut** builds an "index.html" from a common HTML template file, and then saves
|
|
||||||
the file in that directory, so that future requests can be served by the Express static() function. The HTML template
|
|
||||||
file can specify a variety of replacement tokens, including a reference to a "README.md" file in the same directory,
|
|
||||||
which **HTMLOut** will load and pass to the private **MarkOut** Node module for conversion from Markdown to HTML.
|
|
||||||
|
|
||||||
Similarly, if the URL is an API request, **HTMLOut** will direct the request to the appropriate private Node module
|
|
||||||
(eg, **DiskDump** or **FileDump**).
|
|
||||||
|
|
||||||
What's The Right Way To Incorporate Node Module Fixes?
|
|
||||||
---
|
|
||||||
My current version of Express was 3.4.8, and looking at its dependencies in package.json, it wanted "fresh" v0.2.0.
|
|
||||||
|
|
||||||
Unfortunately, there seemed to be a problem with Safari and that version of "fresh", occasionally resulting in
|
|
||||||
blank pages, as discussed [here](http://stackoverflow.com/questions/18811286/nodejs-express-cache-and-304-status-code):
|
|
||||||
|
|
||||||
Safari sends Cache-Control: max-age=0 on reload. Express (or more specifically, Express's dependency, node-fresh)
|
|
||||||
considers the cache stale when Cache-Control: no-cache headers are received, but it doesn't do the same for
|
|
||||||
Cache-Control: max-age=0.
|
|
||||||
|
|
||||||
Further investigation revealed that [node-fresh](https://github.com/visionmedia/node-fresh) v0.2.1 added a fix for
|
|
||||||
that problem. But what was the right (or best) way to incorporate that fix into my local Express installation?
|
|
||||||
|
|
||||||
I decided to hand-edit the "fresh" dependency in Express' package.json and then run "npm update" in the Express folder.
|
|
||||||
That pulled in the newer "fresh" module. But I noticed that other modules that Express depends on include their OWN
|
|
||||||
version of "fresh", which were also locked at v0.2.0. Even after creating an "npm-shrinkwrap.json" and hand-editing
|
|
||||||
it, "npm update" refused to upgrade them from v0.2.0. I could edit the package.json files in each of the Express
|
|
||||||
"connect" and "send" folders, run "npm update" in those folders, and force v0.2.1 that way, but as soon as I ran another
|
|
||||||
"npm update" in the root, those folders reverted to v0.2.0 again.
|
|
||||||
|
|
||||||
However, this all turned out to be moot. The "Cache-Control: max-age=0" work-around added to "fresh" v0.2.1 was later
|
|
||||||
backed-out in v0.2.2. And I discovered that the "blank page" problem went away at the same time I added trailing-slash
|
|
||||||
redirects (see below), so there was likely a connection. The underlying issue with Safari is discussed in more detail
|
|
||||||
[here](https://github.com/visionmedia/node-fresh/issues/8); it seems likely the problem wasn't related to "fresh" after all.
|
|
||||||
|
|
||||||
Problems With Directory URLs and Slashes
|
|
||||||
---
|
|
||||||
I discovered that I needed to install "express-slash", enable Express "strict routing", and make HTMLOut.filter()
|
|
||||||
pass on directory requests that didn't include a trailing slash, so that the Node web server could call slash() and
|
|
||||||
trigger a trailing-slash redirect. This is apparently what apache's "mod_dir" module does automatically, and why
|
|
||||||
I never had a problem with apache. Without trailing slashes on directories, client-side requests for files relative to
|
|
||||||
those "slash-less" directories can fail. More details on this issue can be found in [htmlout.js](htmlout/lib/htmlout.js).
|
|
||||||
|
|
||||||
npm install express-slash --save
|
|
||||||
|
|
||||||
Moving from Make to Grunt
|
|
||||||
---
|
|
||||||
Step 1:
|
|
||||||
|
|
||||||
sudo npm install grunt-cli -g
|
|
||||||
|
|
||||||
Step 2:
|
|
||||||
|
|
||||||
npm install grunt --save-dev
|
|
||||||
|
|
||||||
which automatically adds the following to my package.json:
|
|
||||||
|
|
||||||
"devDependencies": {
|
|
||||||
"grunt": "^0.4.3"
|
|
||||||
}
|
|
||||||
|
|
||||||
Step 3: Create a basic Gruntfile.js:
|
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
|
||||||
grunt.initConfig({
|
|
||||||
});
|
|
||||||
grunt.registerTask("default", []);
|
|
||||||
};
|
|
||||||
|
|
||||||
Step 4: Install some grunt modules; eg:
|
|
||||||
|
|
||||||
npm install grunt-contrib-uglify --save-dev
|
|
||||||
|
|
||||||
Step 5: Add a task (eg, uglify):
|
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
|
||||||
grunt.initConfig({
|
|
||||||
uglify: {
|
|
||||||
dist: {
|
|
||||||
src: "dist/myfile.js",
|
|
||||||
dest: "dist/myfile.min.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
grunt.loadNpmTasks("grunt-contrib-uglify");
|
|
||||||
grunt.registerTask("default", ["uglify"]);
|
|
||||||
};
|
|
||||||
|
|
||||||
However, while all of the above is a very nice example, I'm not really interested in uglify.
|
|
||||||
|
|
||||||
I use Google's Closure Compiler, so I needed to do this instead:
|
|
||||||
|
|
||||||
npm install grunt-closure-tools --save-dev
|
|
||||||
|
|
||||||
There was also an NPM module called "grunt-closure-compiler", but it hadn't been updated as recently, and from
|
|
||||||
the examples it provided, it wasn't clear that it included support for all the Closure Compiler options, like
|
|
||||||
"output_wrapper", so I went with "grunt-closure-tools", even though it also contains support for other tools that
|
|
||||||
I'm not currently using.
|
|
||||||
|
|
||||||
So now my package.json includes:
|
|
||||||
|
|
||||||
"devDependencies": {
|
|
||||||
"grunt": "^0.4.3",
|
|
||||||
"grunt-closure-tools": "^0.9.4"
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional Node Modules
|
|
||||||
===
|
|
||||||
|
|
||||||
replace
|
|
||||||
---
|
|
||||||
I use the Node "replace" module to perform project-wide search-and-replace operations on files; eg:
|
|
||||||
|
|
||||||
node node_modules/replace/bin/replace.js '(<machine.*class)="c1pjs"' '$1="c1p"' . -r --include=*.xml --preview
|
|
||||||
node node_modules/replace/bin/replace.js '(<machine.*class)="pcjs"' '$1="pc"' . -r --include=*.xml --preview
|
|
||||||
node node_modules/replace/bin/replace.js '(href="/versions/c1pjs)/[^/]*/(.*)' '$1/1.12.1/$2' . -r --include=*.xml --preview
|
|
||||||
node node_modules/replace/bin/replace.js '(href="/versions/pcjs)/[^/]*/(.*)' '$1/1.12.1/$2' . -r --include=*.xml --preview
|
|
||||||
|
|
||||||
Most people probably install modules like this globally, but I'd rather just define a command-line alias
|
|
||||||
("replace" => "node node_modules/replace/bin/replace.js") instead of cluttering my system-level directories.
|
|
||||||
|
|
||||||
Testing with Azure
|
|
||||||
===
|
|
||||||
> NOTE: I've since abandoned Azure in favor of AWS Elastic Beanstalk, because Amazon's service has a simpler UI,
|
|
||||||
provides more control over the virtual machine environment (you can even log into the machine via SSH), and
|
|
||||||
the logging services for Node on AWS are more reliable. I also wrote a short [blog post](/blog/2014/03/30/)
|
|
||||||
on some of my frustrations with Azure.
|
|
||||||
|
|
||||||
I subscribed to Azure (formerly Windows Azure, now [Microsoft Azure](http://azure.microsoft.com/)), and started
|
|
||||||
watching this YouTube video "[Lightning nodejs dev in Windows Azure](http://www.youtube.com/watch?v=WbtV1bX_m2I)"
|
|
||||||
by Glenn Block ([@gblock](http://twitter.com/gblock)). I was glad to see that he used a Mac, because a number of
|
|
||||||
other Azure videos on Youtube were made using Windows.
|
|
||||||
|
|
||||||
The first recommendation was to install the "azure-cli" command-line tools:
|
|
||||||
|
|
||||||
sudo npm install azure-cli -g
|
|
||||||
|
|
||||||
To display available commands:
|
|
||||||
|
|
||||||
azure
|
|
||||||
|
|
||||||
To connect the command-line tools to my Azure account (after setting my default browser to Chrome, since I used
|
|
||||||
Chrome to set up my Azure account and browse the Azure portal):
|
|
||||||
|
|
||||||
azure account download
|
|
||||||
|
|
||||||
To import my acount info:
|
|
||||||
|
|
||||||
azure account import ~/Downloads/Pay-As-You-Go-3-30-2014-credentials.publishsettings
|
|
||||||
|
|
||||||
To create a site, the video recommends:
|
|
||||||
|
|
||||||
azure site create pcjs --git
|
|
||||||
|
|
||||||
However, I'm holding off until I understand how to link a new Azure site deployment with an existing GitHub repository,
|
|
||||||
as discussed [here](http://www.windowsazure.com/en-us/documentation/articles/web-sites-publish-source-control/),
|
|
||||||
because the above command appears intended for new project folders, which are then associated with a remote Azure-hosted
|
|
||||||
Git repository -- not what I need or want.
|
|
||||||
|
|
||||||
The following command would show the remote Azure repository:
|
|
||||||
|
|
||||||
git remote -v
|
|
||||||
|
|
||||||
In my case, that command shows:
|
|
||||||
|
|
||||||
origin git@github.com:jeffpar/jsmachines.git (fetch)
|
|
||||||
origin git@github.com:jeffpar/jsmachines.git (push)
|
|
||||||
|
|
||||||
The following command would then be used to push updates to Azure:
|
|
||||||
|
|
||||||
git push azure master
|
|
||||||
|
|
||||||
Although in my case, I'm guessing it would be:
|
|
||||||
|
|
||||||
git push origin master
|
|
||||||
|
|
||||||
Or, rather:
|
|
||||||
|
|
||||||
git push origin node_dev
|
|
||||||
|
|
||||||
Since my local "pcjs" project is based on the **node_dev** branch.
|
|
||||||
|
|
||||||
If I was using an Azure-hosted Git repository, I could then run:
|
|
||||||
|
|
||||||
azure site browse
|
|
||||||
|
|
||||||
because the `git push azure master` command would have triggered a website update.
|
|
||||||
|
|
||||||
The video goes on to show how I can specify the version Node I want Azure to use, by adding the
|
|
||||||
following to my "package.json":
|
|
||||||
|
|
||||||
"engines": {
|
|
||||||
"node": "0.8.x"
|
|
||||||
}
|
|
||||||
|
|
||||||
This command:
|
|
||||||
|
|
||||||
azure site deployment list
|
|
||||||
|
|
||||||
will list all the deployments so far, any one of which can be redeployed like so:
|
|
||||||
|
|
||||||
azure site deployment redeploy xxx
|
|
||||||
|
|
||||||
The video finally gets that what I *really* care about, which is deploying via GitHub. This command
|
|
||||||
lists some of the commands we care about:
|
|
||||||
|
|
||||||
azure site create --help
|
|
||||||
|
|
||||||
To create a site from a repository on GitHub:
|
|
||||||
|
|
||||||
azure site create pcjs --github
|
|
||||||
|
|
||||||
JavaScript Coding Conventions
|
|
||||||
===
|
|
||||||
|
|
||||||
This is not intended to be an exhaustive list. It just lists a few things that came to mind, and I'll
|
|
||||||
probably update it over time.
|
|
||||||
|
|
||||||
Tabs
|
|
||||||
---
|
|
||||||
I've configured my IDE (PhpStorm) to NEVER use tab characters in .js files (spaces only) and to
|
|
||||||
ALWAYS use tab characters in almost every other type of text file. This is largely because when a web
|
|
||||||
browser displays a JavaScript file (either in the main window or in the Developer Tools window), tabs
|
|
||||||
usually screw up the formatting, which I find annoying when I'm debugging. XML files, on the other hand,
|
|
||||||
are usually reformatted by the browser, so in those cases, I opt for smaller files and use real tabs.
|
|
||||||
|
|
||||||
Moreover, most of the JavaScript delivered by a production server will have been pre-compiled by Google's
|
|
||||||
Closure Compiler, which completely eliminates all non-essential whitespace, so this is really a development
|
|
||||||
preference, with little to no impact on production files.
|
|
||||||
|
|
||||||
Regardless of the choice of tab character however, I almost always use 4-column tab stops, except
|
|
||||||
in legacy .asm files, where 8-column tab stops were the norm. I know that 2-column tab stops have
|
|
||||||
recently become "all the rage," especially in Node projects; NPM, for example, will rewrite package.json
|
|
||||||
files, replacing all the 4-column tabs with 2-column tabs, and I don't fight that trend -- I just ignore it.
|
|
||||||
|
|
||||||
JSDoc
|
|
||||||
---
|
|
||||||
I've taken a great deal of care to "[JSDoc](http://usejsdoc.org/)-ify" nearly all my JavaScript code, not
|
|
||||||
because I want to be able to generate documentation (although that's something to think about), but because
|
|
||||||
it's the only way to tell both Google's Closure Compiler and my IDE (PhpStorm) exactly what data
|
|
||||||
types are passed into/out of every function. The goals are to minimize the number of "code inspection"
|
|
||||||
warnings in the IDE and produce warning-free compilations.
|
|
||||||
|
|
||||||
In order to use the Closure Compiler's ADVANCED_OPTIMIZATIONS option and get maximum performance
|
|
||||||
(and maximum "minification", sometimes called "uglification"), every function and its parameters needs to
|
|
||||||
be fully typed; otherwise, the Compiler will generate WAY too many warnings/errors -- at least, that was the
|
|
||||||
case when I first started using it a couple of years ago.
|
|
||||||
|
|
||||||
So, I've adopted a zero-tolerance policy for warnings: no check-ins allowed if the Closure Compiler generates
|
|
||||||
even a SINGLE warning.
|
|
||||||
|
|
||||||
I'm not sure the [JSDoc](http://usejsdoc.org/) folks and the
|
|
||||||
[Closure Compiler](https://developers.google.com/closure/compiler/docs/js-for-compiler) are totally in sync on
|
|
||||||
everything. And then there's [PhpStorm](http://www.jetbrains.com/phpstorm/webhelp/creating-jsdoc-comments.html),
|
|
||||||
whose code inspections occasionally fail; sometimes a bogus code inspection warning can be fixed with some
|
|
||||||
additional JSDoc @name or @class annotations, but not always.
|
|
||||||
|
|
||||||
In any case, the subset of variable and function type declarations I use works pretty well across the board;
|
|
||||||
code inspection warnings are allowed in the IDE, as long as they are clearly erroneous (or clearly innocuous).
|
|
||||||
|
|
||||||
Braces, Parentheses, etc.
|
|
||||||
---
|
|
||||||
Most of my opening braces appear at the end of the line containing the associated "if", "while", "for", "switch",
|
|
||||||
"function" etc, preceded by a single space. And most of my opening parentheses are also preceded by a single space,
|
|
||||||
except when following "function" or a function name, in which case there is NO space. This is just an historical
|
|
||||||
preference, dating back to my BASIC and C programming days; it's not that those preferences matter anymore, it's just
|
|
||||||
that I see no reason to change them.
|
|
||||||
|
|
||||||
I'm not obsessed with these conventions. Sometimes, for example, I'll write a bunch of code where the opening
|
|
||||||
brace of every function body begins underneath the "function" keyword, because the extra whitespace can make the
|
|
||||||
file a bit more readable. It may sometimes depend on my mood, but I do try to be consistent within a given file
|
|
||||||
at least.
|
|
||||||
|
|
||||||
Variable Names
|
|
||||||
---
|
|
||||||
I still tend to follow Charles Simonyi's "[Hungarian](http://en.wikipedia.org/wiki/Hungarian_notation)" naming
|
|
||||||
conventions -- or rather, a naming convention loosely inspired by Hungarian. I know lots of people sneer at
|
|
||||||
those conventions and think they're useless, and all I can say is, they're wrong: they are not useless to ME.
|
|
||||||
I admit they may be useless to anyone who has a phenomenal memory and can remember that an obscure variable named
|
|
||||||
"foo" was initialized with a string or a number, or who has an IDE that can answer that question with the press
|
|
||||||
of a key (or two), but for me, with my non-phenomenal memory and lazy fingers, I prefer being able to simply
|
|
||||||
look at a variable to immediately know what *type* of data it contains, if nothing else.
|
|
||||||
|
|
||||||
I rarely name a string or numeric variable something vague like "foo." At worst, I would name it "sFoo" if it
|
|
||||||
was a string or "iFoo" if it was a number (or possibly "nFoo" or "cFoo" if it represented a total of Foos or a
|
|
||||||
counter of Foos). And if a string or numeric variable has a very short-term use, I often just call it "s" or "i"
|
|
||||||
(or "n").
|
|
||||||
|
|
||||||
As I mention [below](./#quotation-marks), I still tend to distinguish single characters from strings too,
|
|
||||||
which means I may sometimes prefix character variables with "ch" and character counters with "cch".
|
|
||||||
|
|
||||||
Of course, these letter prefixes like "s" and "n" are irrelevant if you already give your variables meaningful
|
|
||||||
names like "nameOfPerson" or "numberOfPeople". And that's fine -- I do that sometimes, too. But in general,
|
|
||||||
I still prefer variable names like "sPerson" and "nPeople".
|
|
||||||
|
|
||||||
I don't try to come up with special prefixes for Objects. If there's a Person object, for example, I'll probably
|
|
||||||
use colloquial names like "personHere" or "personThere". I am stricter about Arrays though: I prefix array variables
|
|
||||||
with "a", arrays of strings and numbers with "as" and "ai" (or "an"), and arrays of arrays with "aa". As for Arrays
|
|
||||||
of anything else, I usually don't bother with anything more than an "a" prefix.
|
|
||||||
|
|
||||||
Quotation Marks
|
|
||||||
---
|
|
||||||
Coming from a long C background, I prefer to use double-quotes around multi-character strings and single quotes
|
|
||||||
around single-character strings. While the reasons for doing so are largely historical and currently irrelevant,
|
|
||||||
characters are STILL the building blocks of strings, and even the JavaScript String class contains methods that
|
|
||||||
deal with individual characters (eg, charCodeAt() and fromCharCode()). So for any code that knowingly deals with
|
|
||||||
single characters, I like to reinforce that distinction with single quotes.
|
|
||||||
|
|
||||||
Also, to emphasize that an object property name isn't really a string, I tend to use single quotes around property
|
|
||||||
names as well. I realize that the JSON standard insists on property names with double-quotes, but functions like
|
|
||||||
JSON.stringify() take care of that for us -- besides, I find that aspect of the JSON standard to be rather annoying
|
|
||||||
(not to mention JSON's disapproval of comments).
|
|
||||||
|
|
||||||
Obviously, it's possible to set and get object properties without any quotes at all, as in:
|
|
||||||
|
|
||||||
obj.prop = true;
|
|
||||||
|
|
||||||
instead of:
|
|
||||||
|
|
||||||
obj['prop'] = true;
|
|
||||||
|
|
||||||
but that works only if the property name conforms to the same syntax that variable names use. Also, the "dot"
|
|
||||||
syntax can create problems for code compiled with Google's Closure Compiler (using ADVANCED_OPTIMIZATIONS),
|
|
||||||
because it likes to rename "dot" property names to smaller "minified" property names. Which means if you
|
|
||||||
need to export your objects as JSON later, or if you ever need to access a property using an externally defined
|
|
||||||
string, you must avoid the "dot" syntax.
|
|
||||||
|
|
||||||
However, if an object and all its properties are purely internal, there's usually no reason not to use it:
|
|
||||||
|
|
||||||
obj = {foo: "old", modified: false};
|
|
||||||
obj.foo = "new";
|
|
||||||
obj.modified = true;
|
|
||||||
|
|
||||||
I break my own quoting rules slightly when dealing with strings that *contain* double-quotes, since it's more readable
|
|
||||||
to put double-quotes inside single-quoted strings than to "escape" every double-quote with a backslash.
|
|
||||||
|
|
||||||
For code that was originally written in PHP and later ported to JavaScript, there was a tendency in the original
|
|
||||||
code to always use double-quotes around strings and "escape" double-quotes regardless, and that tendency may linger
|
|
||||||
in code I didn't feel like rewriting much, but the tendency was due more to idiosyncrasies of PHP than any convention
|
|
||||||
of mine; for example:
|
|
||||||
|
|
||||||
- single-quoted PHP strings may not include any escaped characters (except for single-quote and backslash)
|
|
||||||
- single-quoted PHP strings cannot resolve references to string variables (eg, "the value of foo is {$foo}")
|
|
||||||
|
|
||||||
Because of PHP's restrictions on single-quoted strings, I tended to avoid them. However, in JavaScript, the
|
|
||||||
first restriction isn't true, and the second isn't even a feature of the language, so they have no bearing on the use
|
|
||||||
of single-quoted strings in JavaScript.
|
|
||||||
|
|
||||||
Arrays
|
|
||||||
---
|
|
||||||
In [this article](http://stackoverflow.com/questions/8668174/indexof-method-in-an-object-array), it's asserted,
|
|
||||||
without disagreement, that searching arrays of objects for a particular object is best performed with code that looks
|
|
||||||
like this:
|
|
||||||
|
|
||||||
pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
|
|
||||||
|
|
||||||
I disagree. Depending on how often that function is called, creating a new array by iterating over every element
|
|
||||||
of the original array, and doing that every time you want to search for an array object with a property (eg, `hello`)
|
|
||||||
equal to some value (eg, 'stevie'), is a bad idea; I don't care how fast your JavaScript engine is or how fantastic
|
|
||||||
your garbage collector is.
|
|
||||||
|
|
||||||
My preferred approach is to create parallel arrays: one array for each property that you might want to search on, and
|
|
||||||
another array of objects that contain all the other object properties. Then searching doesn't involve creating new
|
|
||||||
arrays:
|
|
||||||
|
|
||||||
pos = myArrayOfHello.indexOf('stevie');
|
|
||||||
|
|
||||||
Yes, it's not quite as *clean* as one, unified array of objects, and yes, it would be nicer if the JavaScript Array
|
|
||||||
class had better search methods, but I think this is the right trade-off given the current reality.
|
|
||||||
|
|
@ -72,8 +72,8 @@ var fCache = true;
|
||||||
var fConsole = false;
|
var fConsole = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fServerDebug controls debug console messages; it is false by default and can be enabled using the setOptions()
|
* fServerDebug controls server-related debug features; it is false by default and can be enabled using the
|
||||||
* 'debug' property (or from the command-line interface using "--debug").
|
* setOptions() 'debug' property (or from the command-line interface using "--debug").
|
||||||
*/
|
*/
|
||||||
var fServerDebug = false;
|
var fServerDebug = false;
|
||||||
|
|
||||||
|
|
@ -262,8 +262,11 @@ function HTMLOut(sDir, sFile, fRebuild, req, done)
|
||||||
* of fDebug to simply never cache, instead of always rebuilding the cache.
|
* of fDebug to simply never cache, instead of always rebuilding the cache.
|
||||||
*
|
*
|
||||||
* if (this.fDebug) this.fRebuild = true;
|
* if (this.fDebug) this.fRebuild = true;
|
||||||
|
*
|
||||||
|
* Note that a production server should not need the GORT_REBUILD command, so we accept
|
||||||
|
* it only if fServerDebug is true.
|
||||||
*/
|
*/
|
||||||
if (net.hasParm(net.GORT_COMMAND, net.GORT_REBUILD, req)) {
|
if (fServerDebug && net.hasParm(net.GORT_COMMAND, net.GORT_REBUILD, req)) {
|
||||||
req.query[net.GORT_COMMAND] = undefined;
|
req.query[net.GORT_COMMAND] = undefined;
|
||||||
this.fRebuild = true;
|
this.fRebuild = true;
|
||||||
}
|
}
|
||||||
|
|
@ -887,9 +890,15 @@ HTMLOut.prototype.getVersion = function(sToken, sIndent, aParms)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Use the same test that processMachines() uses for setting fCompiled: if we're not using compiled code,
|
* Use the same test that processMachines() uses for setting fCompiled: if we're not using compiled code,
|
||||||
* then we should be using "current" CSS and template files (as opposed to version-specific template files) as well.
|
* then we should be using "current" CSS and template files (as opposed to version-specific template files).
|
||||||
|
*
|
||||||
|
* NOTE: I used to create a symlink in each app's "versions" directory (eg, /versions/pcjs/current ->
|
||||||
|
* ../../my_modules/shared/templates), so that when fDebug was true, I could simply insert "current" in
|
||||||
|
* place of a version number. However, that symlink didn't get added to the repository, and I'm not sure
|
||||||
|
* all operating systems would deal with it properly even if was added, so now I'm treating the "version"
|
||||||
|
* token as the equivalent of a symlink here.
|
||||||
*/
|
*/
|
||||||
this.aTokens[sToken] = this.fDebug? "current" : pkg.version;
|
this.aTokens[sToken] = this.fDebug? "../../my_modules/shared/templates" : pkg.version;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1432,6 +1441,8 @@ HTMLOut.prototype.getManifestXML = function(sToken, sIndent, aParms)
|
||||||
case "default":
|
case "default":
|
||||||
sDefault = matchParams[2];
|
sDefault = matchParams[2];
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sLabel) {
|
if (sLabel) {
|
||||||
|
|
|
||||||
|
|
@ -386,6 +386,7 @@ MarkOut.prototype.convertMD = function(sIndent)
|
||||||
*/
|
*/
|
||||||
var aMatch;
|
var aMatch;
|
||||||
var re = /(^|\n)( ? ?)([\*+-]|[0-9]+\.)([^\n]*\n)([ \t]+[^\n]*\n|\n)+([ \t]+[^\n]+)/g;
|
var re = /(^|\n)( ? ?)([\*+-]|[0-9]+\.)([^\n]*\n)([ \t]+[^\n]*\n|\n)+([ \t]+[^\n]+)/g;
|
||||||
|
//noinspection UnnecessaryLocalVariableJS
|
||||||
var sMDOrig = sMD;
|
var sMDOrig = sMD;
|
||||||
while ((aMatch = re.exec(sMDOrig))) {
|
while ((aMatch = re.exec(sMDOrig))) {
|
||||||
var sReplace = aMatch[0].replace(/\n\n/g, "\n\t\n");
|
var sReplace = aMatch[0].replace(/\n\n/g, "\n\t\n");
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ Structure
|
||||||
All the code for PCjs is contained in the following JavaScript files, which roughly divide the
|
All the code for PCjs is contained in the following JavaScript files, which roughly divide the
|
||||||
functionality into major PC components, aka "devices". However, not every file implements a device,
|
functionality into major PC components, aka "devices". However, not every file implements a device,
|
||||||
and "component" is an overloaded term, since *[Component](/docs/pcjs/component/)* is also the name of
|
and "component" is an overloaded term, since *[Component](/docs/pcjs/component/)* is also the name of
|
||||||
the shared base class used for most PCjs objects (see [component.js](../../shared/lib/component.js)).
|
the shared base class used for most PCjs devices (see [component.js](../../shared/lib/component.js)).
|
||||||
So it's best to refer to these files generically as "modules", and more specifically as "device modules"
|
So it's best to refer to these files generically as "modules", and more specifically as "device modules"
|
||||||
whenever they implement a specific device (or set of devices, in the case of [*Chipset*](/docs/pcjs/chipset/)).
|
whenever they implement a specific device (or set of devices, in the case of [*Chipset*](/docs/pcjs/chipset/)).
|
||||||
|
|
||||||
Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js),
|
Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js),
|
||||||
and sub-modules like [x86code.js](x86code.js), [x86mode.js](x86mode.js) and [x86help.js](x86help.js)
|
and sub-modules like [x86opxx.js](x86opxx.js), [x86mods.js](x86mods.js) and [x86help.js](x86help.js)
|
||||||
that separate the CPU functionality of [x86.js](x86.js) into more manageable pieces.
|
that separate the CPU functionality of [x86.js](x86.js) into more manageable pieces.
|
||||||
|
|
||||||
These modules should always be loaded or compiled in the order listed by the *pcJSFiles* property in
|
These modules should always be loaded or compiled in the order listed by the *pcJSFiles* property in
|
||||||
|
|
@ -32,11 +32,14 @@ At the time of this writing, the order is:
|
||||||
* [pcjs-client/bus.js](bus.js)
|
* [pcjs-client/bus.js](bus.js)
|
||||||
* [pcjs-client/mem.js](mem.js)
|
* [pcjs-client/mem.js](mem.js)
|
||||||
* [pcjs-client/cpu.js](cpu.js)
|
* [pcjs-client/cpu.js](cpu.js)
|
||||||
* [pcjs-client/x86defs.js](x86defs.js)
|
|
||||||
* [pcjs-client/x86help.js](x86help.js)
|
|
||||||
* [pcjs-client/x86code.js](x86code.js)
|
|
||||||
* [pcjs-client/x86mode.js](x86mode.js)
|
|
||||||
* [pcjs-client/x86.js](x86.js)
|
* [pcjs-client/x86.js](x86.js)
|
||||||
|
* [pcjs-client/x86seg.js](x86seg.js)
|
||||||
|
* [pcjs-client/x86cpu.js](x86cpu.js)
|
||||||
|
* [pcjs-client/x86grps.js](x86grps.js)
|
||||||
|
* [pcjs-client/x86help.js](x86help.js)
|
||||||
|
* [pcjs-client/x86mods.js](x86mods.js)
|
||||||
|
* [pcjs-client/x86op0f.js](x86op0f.js)
|
||||||
|
* [pcjs-client/x86opxx.js](x86opxx.js)
|
||||||
* [pcjs-client/chipset.js](chipset.js)
|
* [pcjs-client/chipset.js](chipset.js)
|
||||||
* [pcjs-client/rom.js](rom.js)
|
* [pcjs-client/rom.js](rom.js)
|
||||||
* [pcjs-client/ram.js](ram.js)
|
* [pcjs-client/ram.js](ram.js)
|
||||||
|
|
@ -55,16 +58,10 @@ At the time of this writing, the order is:
|
||||||
Some of the modules *can* be reordered or even omitted (eg, [debugger.js](debugger.js) or
|
Some of the modules *can* be reordered or even omitted (eg, [debugger.js](debugger.js) or
|
||||||
[embed.js](../../shared/lib/embed.js)), but you should observe the following:
|
[embed.js](../../shared/lib/embed.js)), but you should observe the following:
|
||||||
|
|
||||||
* [component.js](../../shared/lib/component.js) should be listed before any module that extends [*Component*](/docs/pcjs/component/)
|
* [component.js](../../shared/lib/component.js) must be listed before any module that extends [*Component*](/docs/pcjs/component/)
|
||||||
* [panel.js](panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible
|
* [panel.js](panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible
|
||||||
* [computer.js](computer.js) should be the last device module, as it supervises and notifies all the other device modules
|
* [computer.js](computer.js) should be the last device module, as it supervises and notifies all the other device modules
|
||||||
|
|
||||||
To minimize ordering requirements, the init() handlers and constructors of all modules should avoid
|
To minimize ordering requirements, the init() handlers and constructors of all modules should avoid
|
||||||
referencing other modules. Device modules should define an initBus() notification handler, which the
|
referencing other modules. Device modules should define an initBus() notification handler, which the
|
||||||
[*Computer*](/docs/pcjs/computer/) will call after it has created/initialized the *Bus* object.
|
[*Computer*](/docs/pcjs/computer/) will call after it has created/initialized the *Bus* object.
|
||||||
|
|
||||||
What's Next
|
|
||||||
---
|
|
||||||
EGA support. I've added the infrastructure for EGA I/O operations, but there's no "meat" yet. All the EGA
|
|
||||||
code is in [video.js](video.js), alongside the CGA and MDA support, but EGA functionality is pretty isolated; you have
|
|
||||||
to set the "model" attribute of the video component to "ega" to enable it.
|
|
||||||
|
|
|
||||||
|
|
@ -1713,12 +1713,14 @@ ChipSet.prototype.toggleSwitch = function(control)
|
||||||
var asParts = sID.split("-");
|
var asParts = sID.split("-");
|
||||||
var b = (0x1 << (parseInt(asParts[1], 10) - 1));
|
var b = (0x1 << (parseInt(asParts[1], 10) - 1));
|
||||||
switch (asParts[0]) {
|
switch (asParts[0]) {
|
||||||
case "sw1":
|
case "sw1":
|
||||||
this.sw1Init = (this.sw1Init & ~b) | (f? 0 : b);
|
this.sw1Init = (this.sw1Init & ~b) | (f? 0 : b);
|
||||||
break;
|
break;
|
||||||
case "sw2":
|
case "sw2":
|
||||||
this.sw2Init = (this.sw2Init & ~b) | (f? 0 : b);
|
this.sw2Init = (this.sw2Init & ~b) | (f? 0 : b);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.updateSwitchDesc();
|
this.updateSwitchDesc();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -72,34 +72,37 @@ var PREFETCH = false;
|
||||||
/**
|
/**
|
||||||
* @define {boolean}
|
* @define {boolean}
|
||||||
*
|
*
|
||||||
* FASTDISABLE turns on memory-function switching to dynamically disable
|
* FASTDISABLE turns on memory-function switching to dynamically disable memory accesses whenever the CPU wants
|
||||||
* memory accesses whenever the CPU wants to disable spurious memory reads
|
* to disable spurious memory reads (which are mostly harmless) or stale memory writes (which tend to be destructive
|
||||||
* (or stale memory writes, which are worse). If FASTDISABLE is false, then
|
* and are NOT mostly harmless).
|
||||||
* the code falls back to setting/testing internal OP_NOREAD and OP_NOWRITE
|
|
||||||
* CPU opFlags as needed.
|
|
||||||
*
|
*
|
||||||
* At the moment, it seems that FASTDISABLE is a bit slower than relying on
|
* If FASTDISABLE is false, then the code falls back to setting/testing internal OP_NOREAD and OP_NOWRITE opFlags
|
||||||
* the OP_NOREAD/OP_NOWRITE flags, so it's turned off.
|
* as needed.
|
||||||
|
*
|
||||||
|
* At the moment, it seems that FASTDISABLE is a bit slower than relying on the OP_NOREAD/OP_NOWRITE flags, so it's
|
||||||
|
* turned off; apparently, I was a bit too optimistic calling it "FAST". But your mileage may vary, depending on the
|
||||||
|
* browser and its version.
|
||||||
*
|
*
|
||||||
* See the Bus component for details.
|
* See the X86CPU component for details, since it is the CPU, not the underlying Bus or Memory components, that needs
|
||||||
|
* to be able to do this.
|
||||||
*/
|
*/
|
||||||
var FASTDISABLE = false;
|
var FASTDISABLE = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @define {boolean}
|
* @define {boolean}
|
||||||
*
|
*
|
||||||
* FATARRAYS is a Closure Compiler compile-time option that allocates 1 number per byte
|
* FATARRAYS is a Closure Compiler compile-time option that allocates 1 number per byte for Memory blocks;
|
||||||
* for Memory blocks; wasteful, but slightly faster.
|
* wasteful, but potentially slightly faster.
|
||||||
*
|
*
|
||||||
* See the Memory component for details.
|
* See the Memory component for details.
|
||||||
*/
|
*/
|
||||||
var FATARRAYS = false;
|
var FATARRAYS = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time
|
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time * option, but since I've
|
||||||
* option, but since I've added memory access functions for typed arrays (see Memory.afnTArray),
|
* added memory access functions for typed arrays (see Memory.afnTArray), I can turn the support on dynamically now.
|
||||||
* I can turn the support on dynamically now. Originally, I didn't see much of a speed increase
|
* Originally, I didn't see much of a speed increase over the original (non-typed) implementation, but that will probably
|
||||||
* over the original (non-typed) implementation, but that will probably change over time.
|
* change over time.
|
||||||
*
|
*
|
||||||
* See the Memory component for details.
|
* See the Memory component for details.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -439,20 +439,22 @@ Mouse.prototype.clickMouse = function(iButton, fDown) {
|
||||||
if (this.isActive()) {
|
if (this.isActive()) {
|
||||||
var sDiag;
|
var sDiag;
|
||||||
switch (iButton) {
|
switch (iButton) {
|
||||||
case 0:
|
case 0:
|
||||||
if (this.fButton1 != fDown) {
|
if (this.fButton1 != fDown) {
|
||||||
this.fButton1 = fDown;
|
this.fButton1 = fDown;
|
||||||
sDiag = DEBUGGER ? ("mouse button1 " + (fDown ? "dn" : "up")) : null;
|
sDiag = DEBUGGER ? ("mouse button1 " + (fDown ? "dn" : "up")) : null;
|
||||||
this.sendPacket(sDiag);
|
this.sendPacket(sDiag);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (this.fButton2 != fDown) {
|
if (this.fButton2 != fDown) {
|
||||||
this.fButton2 = fDown;
|
this.fButton2 = fDown;
|
||||||
sDiag = DEBUGGER ? ("mouse button2 " + (fDown ? "dn" : "up")) : null;
|
sDiag = DEBUGGER ? ("mouse button2 " + (fDown ? "dn" : "up")) : null;
|
||||||
this.sendPacket(sDiag);
|
this.sendPacket(sDiag);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,9 @@ SerialPort.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, cont
|
||||||
serial.sendRBR([charCode]);
|
serial.sendRBR([charCode]);
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3158,6 +3158,8 @@ Video.prototype.getAccess = function()
|
||||||
case Card.GRC.DATAROT.XOR:
|
case Card.GRC.DATAROT.XOR:
|
||||||
nWriteAccess = Card.ACCESS.WRITE.MODE0XOR;
|
nWriteAccess = Card.ACCESS.WRITE.MODE0XOR;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
card.nDataRotate = regDataRotate & Card.GRC.DATAROT.COUNT;
|
card.nDataRotate = regDataRotate & Card.GRC.DATAROT.COUNT;
|
||||||
}
|
}
|
||||||
|
|
@ -3463,6 +3465,8 @@ Video.prototype.checkMode = function(fForce)
|
||||||
card.sizeBuffer = cbBufferText;
|
card.sizeBuffer = cbBufferText;
|
||||||
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.CGA_80X25_BW : Video.MODES.CGA_80X25);
|
nMode = (this.nMonitorType == ChipSet.MONITOR.MONO? Video.MODES.CGA_80X25_BW : Video.MODES.CGA_80X25);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fSEQDotClock = (card.aSEQRegs[Card.SEQ.CLK.INDX] & Card.SEQ.CLK.DOTCLOCK);
|
var fSEQDotClock = (card.aSEQRegs[Card.SEQ.CLK.INDX] & Card.SEQ.CLK.DOTCLOCK);
|
||||||
|
|
@ -4532,6 +4536,8 @@ Video.prototype.outGRCData = function(port, bOut, addrFrom)
|
||||||
case Card.GRC.BITMASK.INDX:
|
case Card.GRC.BITMASK.INDX:
|
||||||
this.cardEGA.nBitMapMask = bOut | (bOut << 8) | (bOut << 16) | (bOut << 24);
|
this.cardEGA.nBitMapMask = bOut | (bOut << 8) | (bOut << 16) | (bOut << 24);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,8 @@ var X86Help = {
|
||||||
case 0x7: // BH
|
case 0x7: // BH
|
||||||
this.regBX = (this.regBX & 0xff) | (dst << 8);
|
this.regBX = (this.regBX & 0xff) | (dst << 8);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break; // there IS no other case, but JavaScript inspections don't know that
|
||||||
}
|
}
|
||||||
this.nStepCycles -= this.nOpCyclesXchgRR;
|
this.nStepCycles -= this.nOpCyclesXchgRR;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -390,6 +392,8 @@ var X86Help = {
|
||||||
case 0x7: // DI
|
case 0x7: // DI
|
||||||
this.regDI = dst;
|
this.regDI = dst;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break; // there IS no other case, but JavaScript inspections don't know that
|
||||||
}
|
}
|
||||||
this.nStepCycles -= this.nOpCyclesXchgRR;
|
this.nStepCycles -= this.nOpCyclesXchgRR;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1807,43 +1807,47 @@ var X86OpXX = {
|
||||||
case 0x7: // this form of MOV to DS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
|
case 0x7: // this form of MOV to DS is undocumented on 8086/8088/80186/80188, invalid on 80286 and up
|
||||||
temp = this.regDI;
|
temp = this.regDI;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
X86Mods.aOpModsRegWord[bModRM].call(this, X86Help.opHelpMOV);
|
X86Mods.aOpModsRegWord[bModRM].call(this, X86Help.opHelpMOV);
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
this.setES(this.regAX);
|
this.setES(this.regAX);
|
||||||
this.regAX = temp;
|
this.regAX = temp;
|
||||||
break;
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
this.setCS(this.regCX);
|
this.setCS(this.regCX);
|
||||||
this.regCX = temp;
|
this.regCX = temp;
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
this.setSS(this.regDX);
|
this.setSS(this.regDX);
|
||||||
this.regDX = temp;
|
this.regDX = temp;
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
this.setDS(this.regBX);
|
this.setDS(this.regBX);
|
||||||
this.regBX = temp;
|
this.regBX = temp;
|
||||||
break;
|
break;
|
||||||
case 0x4:
|
case 0x4:
|
||||||
this.setES(this.regSP);
|
this.setES(this.regSP);
|
||||||
this.regSP = temp;
|
this.regSP = temp;
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
this.setCS(this.regBP);
|
this.setCS(this.regBP);
|
||||||
this.regBP = temp;
|
this.regBP = temp;
|
||||||
break;
|
break;
|
||||||
case 0x6:
|
case 0x6:
|
||||||
this.setSS(this.regSI);
|
this.setSS(this.regSI);
|
||||||
this.regSI = temp;
|
this.regSI = temp;
|
||||||
break;
|
break;
|
||||||
case 0x7:
|
case 0x7:
|
||||||
this.setDS(this.regDI);
|
this.setDS(this.regDI);
|
||||||
this.regDI = temp;
|
this.regDI = temp;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break; // there IS no other case, but JavaScript inspections don't know that
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue