Back To Home - HTML Course Exports - Archive.org upload
The Story
This is a set of UNIX Computer-Based Training courses, for software I do not have a name for, by CourseWare Technologies, Inc. They were a small company based out of California, like so many others. There's about a dozen companies with functionally identical names since. I can find nothing about them prior to 1988, but CourseWare did go on to release additional training. There's an ad for courses for AIX in 1991, which interestingly are stated to have ran on AIX or on MS-DOS, and cost $1200-2200. A 1995 ad in SunExpert lists courses in "Introduction to Object-Oriented Technology" and associated OOP/C++ material, costing around $1200-$1500 each. I'm sure there were many more. Also in 1995, CTI was bought by "The Cerplex Group", and the trail largely stops there. I don't know if the acquisition was them running out of money, or Cerplex being optimistic. Cerplex was a moderate-sized company specializing in electronics and computer repair, even servicing DEC, but seemingly also did vehicle repair as their name shows up on some DOT-related websites. Possibly they bought CTI to try to diversify further.
The only other thing I can find on CourseWare's history is that CTI went on to get sued several times in 2000 (while under Cerplex), but all of the cases were dismissed with prejudice. Cerplex themselves filed for chapter 7 liquidation in 2001.
Background
At some point in BSD's early history, it gained the "learn" utility. Finding any information on this is difficult given its name. Based on a random thread on the FreeBSD forums, it goes at least as far back as 2.8 BSD (~1982). This provided a fixed set of lessons you could run that would quiz you on how to use UNIX. It's a fairly simple concept, with a basic interpreter that can ask you questions and react to right and wrong answers. It could provide lessons on:
- files
- editor
- vi
- morefiles
- macros
- eqn
- C
It is not clear if all of these were there since 2.8 BSD, but it seems like at least vi was not.
There is at least a github repo of somebody who made a docker container to run it. Check it out if you want: https://github.com/goblimey/learn-unix.
This being the 80s, of course, AT&T saw this and decided to make their own version of learn that they could charge for, costing $2500 per CPU (though I can't tell if this is for the runtime or the authoring software), and thus was born "UNIX® SYSTEM V INSTRUCTIONAL WORKBENCH®". As far as I can tell, effectively no documentation on this has survived. Nor have I been able to locate the software itself. As this was no doubt marketed and sold only to massive companies, this is not a particular surprise. I'm also not entirely certain that IWB came after learn since I can't get exact dates for either, but that seems to be the right way around.
The Files
These courses came from a set of six floppies with one tar archive each, cryptically named things like "STARTTAR" and just labeled "Environment: UNIX". Extracting the tar archives was easy, but it took a bit to figure out what these files actually were. The files are encrypted (poorly, but still); I'd like to take credit for figuring out that part but I had to ask for help on that one. Then after some additional trial and error to figure out exactly how the decryption worked I discovered these were UNIX training courses, as above.
As to what software this is, it was relatively obvious it wasn't learn. That's got a pretty specific format and it's also a pretty small-time utility overall, not really meant to load arbitrary courses from disk. Instructional WorkBench should be more capable, but the only thing I can find on it at all is a single whitepaper telling the world that AT&T had launched this cool new thing that you should totally buy. It has examples of the syntax, and they're also different from what I have. Instead, it looks like CourseWare wrote their own runtime/interpreter for this language. As above I don't have that, though, I only have the courses. There is a comment in there about using the software not on the CPU it was licensed for will terminate your license, so maybe this was just done to try to get the money AT&T was getting.
On the other hand, the software was seemingly very capable. Its language was reminiscent of BASIC, including subroutines, input handling, inline text formatting, conditional text execution, navigate between files, and even came with a built-in way to write text that would display on the Nth correct or incorrect answer so you could provide gradually stronger hints. Not bad for the mid 80s. I don't have a date on the software itself without any kind of binary, but these courses have a copyright date of 1985-1988, with file dates of 1988-09-13. Though that may be when the person who made the disks I got these from archived them as it seems unlikely they'd all have the same date from CourseWare.
The files being text executed by a single interpreter program makes porting it to MS-DOS as the one ad described something that makes a lot of sense. I wonder if they ever ported it to anything else.
I have six course archives:
- start, "GETTING STARTED IN UNIX", Course 845
- 861, "THE UNIX USER", Course 861
- 862, "ADVANCED UNIX USER", Course 862
- 863, "ADVANCED UNIX SYSTEM ADMINISTRATOR", Course 863
- admin, "THE UNIX SYSTEM ADMINISTRATOR", Course 851
- C, "PROGRAMMING IN C", Course 842
I don't know if they made 863 training courses or if the numbers are some kind of category thing, or just inflated to sound more impressive to customers. One of the latter would make more sense than having authored practically one of these every two or three workdays since 1980.
I'll let CTI's sales spiel from one of the included files cover it (some formatting manually adjusted in this and any following excerpts for readability):
Welcome to computer based training, presented to you by CourseWare Technologies, Inc..
The CTI UNIX Tutorials are designed for fast, cost effective, captivating, and flexible interactive training of users like yourself, using your own facilities and at your own convenience.
Because training provided by this program is designed to be run on your computer, it is referred to as computer based training!
The following demonstration session will provide you with information about:
- the various CTI UNIX Tutorial Modules available NOW from CourseWare Technologies Inc.,
- the contents of the CTI UNIX Tutorials,
- the format of the presentations, and
- how easily you can obtain a CTI UNIX Tutorial module to provide effective, captivating, and low cost training for all levels in the UNIX operating system and the C programming language.
You can do no harm by making incorrect keystrokes. If you make any mistakes, you will be gently corrected. Do not be afraid! You can do nothing that can cause your CTI UNIX Tutorial or your computer any harm! CTI UNIX Tutorials include:
- The UNIX User
- The Advanced UNIX User
- Programming in C
- The UNIX System Administrator
- The Advanced UNIX System Administrator
STRUCTURED LEARNING METHOD
Designed by experts in instructional design, every lesson of the CTI UNIX Tutorials contains the following:
- Instructional Objectives
- Concept Presentations
- Concept Examples with Explanations
- Graphic Illustrations
- Practice
- Review
I'd also like to point out that despite the "gently corrected" claim a couple of files have messages that say "You will be helped this time, but please be more careful in the future!". Not very gentle, that. And if you're about to tell me that it's gentle compared to the error messages of the time, consider this set of messages that you get after subsequent failurs on one of the review questions (formatting semi-original):
Please type date
Please type date
I guess I must type this for you:
Each archive consists of a set of files describing the overall course, and then several study writeups that each come with some associated figures, reviews/quizzes, and so on. The actual writeups are honestly pretty good in my opinion. For example, this bit about manuals:
When you need information about a command and there is no one around to ask, you can turn to the books that come with your system. They are called the Reference Manuals.
The User's Reference manual provides information on most of the commands, files, and functions that have been delivered with your system.
The manual is divided into 2 sections:
1 - Commands (C) and
2 - Hardware Dependent (HW) commandsThe programmer's manual provides information on most of the commands, files, and functions that have been delivered with your system.
The manual is divided into 8 sections:
1 - commands available to users,
2 - system calls,
3 - C library routines, including the standard I/O package, standard input and output, and the math function library,
4 - special files,
5 - file formats and conventions,
6 - games,
7 - word processing packages, and
8 - system maintenance commands and procedures.
The review sections came out somewhat mixed because of how the files are structured. Here's one of the C reviews:
REVIEW
Which of the following identifiers is illegal?
a _chapter_1
b 1_chapter_
c _1chapter_1
Select one:The correct answer is b , a legal
identifier never starts with a digit!
Which of the following statements is TRUE?
a Braces may delimit any statement.
b Braces delimit functions or argument lists.
c Standard C library functions are explicitly linked during the
compile stage using the "-lstandard" option.
d The standard C library is included in a C function
with the statement #include <stdio.h>
Select one:
The correct answer is a . The standard C library
functions are included automatically during the linking phase.
Braces do not delimit argument lists
A variable declared as char[27] can hold at least
13 variables of type: ___________.
Answer here:
The correct answer is char .
None of this is mindblowing, of course, but for the mid-80s it's pretty capable.
File Format
The files are encrypted with a rotating XOR, with a key of
0x03, 0x08, 0x0D, 0x12, 0x17, 0x1C, 0x21, 0x26, 0x2B, 0x30, 0x35, 0x3A, 0x3F
To decrypt them you XOR the 0th byte with 0x03, the 1st with 0x08, ..., the 13th with 0x03 again, and so on.
All remaining analysis of the format has been derived from just reading the files and having a vague understanding of how this should work. Without the authoring tools (if any) or the runtime, there's a lot left unknown.
Line Format
The file format appears simple but has some advanced features. Each line has the format:
[command][(condition)]: [data]
The : is mandatory except for subroutine declarations, and all other parts are optional. If command is omitted, it will print text, but has some knowledge about whether it should do this always or based on the global yes/no (see below). If condition is present, it is a boolean expression that determines if the command should run. data is whatever the command needs, and may be text, a variable name, a comma-delimited pair of integers, or so on.
Spaces between elements of the line are optional, though it appears spaces to the right of the : are preserved.
Also, technically bare lines consisting solely of the trailing linebreak without even a : are acceptable, they just don't do anything.
Every command that outputs text will after the text is completed move the cursor to the left edge of the next line. There are commands to reposition the cursor to draw to specific parts of the screen. It's possible that one of the many text command variants is different by not doing that, but it doesn't seem that way.
Successive text prints may write more lines than the screen is tall. I do not know how the interpreter would handle this. Presumably it would wait for a down arrow keypress or something similar.
Commands and Command Suffixes
As a most basic example, the following will print text:
T:Hello world!
It appears that every command can take a parenthetical condition that controls whether or not it executes. For example:
T(#FOO>1):Hello world!
Some commands can have suffixes that control their execution as well. I have observed Y and N for certain. These execute only if the result of a preceding M command (match user input) was success or failure, respectively. I am calling this the "global yes/no" for lack of a better term. For example:
T:Enter 1 to proceed
M:1
TY:Correct!
TN:Incorrect!
You can also suffix some(?) commands like TN and TY with numbers to indicate on which attempt that line should show:
T:Enter 1 to proceed
M:1
TN1: One wrong answer
TN2: Two wrong answers
TN3: Three wrong answers
Each line's M must track its count independently, or perhaps one of the commands I can't identify resets the counter.
You can even combine this with the above Y/N suffixes:
T:Enter 1 to proceed
M:1
TN1: One wrong answer
TN2: Two wrong answers
TN3: Three wrong answers
TY1: Right first try
TY2: Right second try
TY3: Right third try
There are other letters that I suspect may be suffixes like these two, but I can't determine that for sure.
As above, "empty" commands (lines starting with a : character) print text, but seem to inherit the Y/N suffix of the last Tx command. For example:
TY: A
: B
TN: C
: D
T: E
: F
Will print either "ABEF" or "CDEF" (plus linebreaks) depending on the last M result.
The commands I'm at least relatively certain of are as follows:
| Command | Name | Data | Effect | Notes |
|---|---|---|---|---|
| * | Subroutine declaration | - | Special command, *FOO declares a subroutine named FOO | |
| A | Anchor | [String variable] | Sets an anchor | Used by J as a kind of GOTO, but only one A can be active at a time. Unclear what providing a variable name does |
| C | Calculate or Compute | Statement | Generally used to set variables | Supports only = + and -, plus some prebuilt functions. Can set string variables as well |
| CA | Cursor Address | #[,#] | Moves terminal cursor to specified line or coordinates | |
| CS | Clear Screen | - | Clears the screen | |
| D | Declare | Variable declaration | Declares a variable, used to set string lengths | |
| E | ? | [Subroutine name] | If used without data, appears to be a return statement; unclear what it means to have it name a subroutine | Often used to end subroutines, but not always |
| J | Jump | Subroutine name | Jumps to a specified subroutine | JN/JY are common, as are numbered suffixes like JN3 |
| L | Link | Filename[,subroutine name] | Loads a specified file and optionally jumps to a subroutine within it | If no subroutine is provided, I assume it starts at the top of the file |
| M | Match | Pattern | Tests user input against a specified pattern | I believe this waits until the user presses enter to proceed |
| PA | Pause | # | Pauses for the specified number of seconds | |
| R | Remark | - | Line comment | |
| T | Text | Text | Writes text to the screen | There are many variants of T, such as TA, TC, and TH |
| TP | Text Position | #[,#] | Sets the next text position. | Unclear what the difference is vs CA |
| TS | Text Size | #,# | Sets the dimensions of the following text. | Unsure why this is necessary or what uses this data |
| TW | ? | Text | Seems to declare a section header | Always has a four-part body delimited by |s of title, subtitle, a #-# range, and text size (same as TS). |
| U | ? | Subroutine name | Another that seems to be a different kind of jump | Unsure how this is different from J or E |
There's many more, though. As a handful of examples, there's a bunch of As up through AHSXR and ASHXR; CA has CAH, CAL, CANL, and CAS; there's a PR that only ever is used with data of "H", "+H", and "-H", and XI which is mostly used to somehow control a following E, like such:
XI(#FOO>1): E: BAR
I have no idea what any of those do. It would not surprise me if "L", "R", "S", "X" were also suffixes on at least some commands (the commands like CANL that have an N as not the last character feel like anything after the N is also a modifier), but I have nothing to go on for what these would do either. Some of these may also just be typos in the original material as I have seen other errors.
Also, it's not just that there are base commands and suffixes. For example, there's the base T, with TY and TN variants, but also TS and TP which are completely different so they aren't all just "T, but". Likely internally these were all unique and the suffixes are just a convention.
User Input
The vast majority of input is performed with the M command, or occasionally MR. I do not know what the difference is. This matches the input against a specified pattern. For example, answering "YES" to:
M:YES
Will set the global yes/no bit to "yes" so further xY/xN commands can react to it. Note that M is case-sensitive.
I am pretty sure I've seen other methods occasionally, but I forgot to take notes when I did and now I can't find it. Your choice if I'm imagining that or not.
Boolean Logic
The language does support Boolean ANDs using &, and ORs using ! (which has to be the first time I've ever seen that syntax). M uses the ! to delimit options, so you will often seen things like
M:q!Q
But they also get used in conditionals, along with some built-in commands that I have not exhaustively enumerated:
T(LEN($FOO$) > 3 & #BAR > 1): BAZ
Variables can be tested for equality with =. I have not observed an inequality operator:
T(#FOO=1): BAR
The language does not seem to support parentheticals for operator precedence.
Math
The C command can set variable values and perform basic math, which for this language is + and -. It does not even seem to support multiplication or division. Example:
C:FOO = FOO + 2
That's about it, really. As above it does not seem to support parentheticals, but if all you have is addition and subtraction I guess it doesn't matter.
Control Flow
Like BASIC the language is built around subroutines, but unlike BASIC it does not use line numbers. Subroutines are a name prefixed with a * character on a line by themselves:
*FOO
Subroutines are generally ended with an empty E:, except when they aren't. Sometimes they end on an an XI, or sometimes they just end with the next subroutine.
There are several commands for navigating around a file. J jumps to a subroutine, and comes in optional JY or JN suffixed versions, along with numbered suffixes ala JN3:
J: FOO
J(#BAR > 1): FOO
JY: FOO
E is usually found bare, where it looks like it's meant as an analog of the "return" statement in other languages. It is not clear to me what E does if it names a subroutine, or how this would be different from J. It also is observed with conditionals and suffixed EY variant:
*FOO
...
E:
*BAR:
...
E(#BAZ>1): FOO
EY: FOO
U seems to just do what J does. I don't know what the difference is. My original thought was that one preserves state for a return and one doesn't, but both seem to be used both ways. Same syntax as J, also seen with UN and UY suffixed variants.
L navigates to a different file, and optionally to a subroutine within that file. Subroutines and variables appear to be preserved across navigation. I believe that files can redefine subroutines, but I don't know what happens when the "child" file ends to know if the child's redefinition is preserved or it was attached to that file's context and discarded. I suspect the former given the relative simplicity of the language. Examples:
L:filename
L:filename,FOO
Some J and U commands refer to a special @A target. This appears to refer back to a preceding A or AR (and possibly other variants) and is used to construct loops, such as those used with numbered TY/TN commands:
A: M:1 TN1: No TN2: No 2 TN3: No 3 JN3: FOO JN: @A
Execution starts at the top of the file and most have a J in the first few lines to move to the start of the lesson. There does not appear to be any kind of "exit" command. Execution appears to end when the interpreter hits the end of the file and has nothing further to do. The majority of files end with an L that takes them back to their parent.
Variables
Integer variables are prefixed with #, except when they aren't. C seems to not need the prefixes:
C: FOO = FOO + 1
But virtually all other uses do:
CAL: #FOO
TP: 5,#FOO
This is because the variables seem to get string-replaced before processing. They get used in regular text printing:
T: YOUR SELECTION IS NOT IN THE 0 - #SELIMIT RANGE Please try again
Rarely, C is used with the # prefix:
C: #FOO = #FOO - 1
I do not know if this is equivalent, or an error that would resolve into literals before evaluation of the statement and thus probably not do what the author intended.
You can even use the variable replacement to perform a hacky version of indirection by naming a subroutine with a number, without leading 0s. For example:
*FOO1
...
*FOO2
...
C: BAR = 2
J FOO#BAR
This will jump to FOO2. Confusingly, CourseWare seemed to like to use P0, P1, etc for "page" subroutines, and then use "#P" to store current page, so you'll see a lot of things like
J P#P
But to make it extra confusing it's often as part of an XI:
XI: E: P#P
Which will jump to P0, P1, etc., based on whatever the XI does.
String variables are suffixed with $, like BASIC. When used in C and D commands the suffix is sufficient:
C: FOO$ = BAR
D: FOO$(3)
String literals are usually bare. There are occasionally ones that are quoted, ala:
ANSWER$ = "cd /usr2"
It is not clear if the interpreter removes the quotes during processing, or if the string actually includes the quotes.
String variables used in other commands require a $ prefix as well, like how integers work:
T: You answered $FOO$
There's also inline formatting, using $s1$ and $s0$ pairs and $u1$ and $u0$ pairs, with 1 activating the format and 0 deactivating it. The latter is almost certainly underline. The former I am fairly certain is reverse-color (dark-on-light rather than the at the time default of light-on-dark). I suspect these are just predefined variables that are set to ANSI control codes, likely because there is no way to enter an escape character into a string variable other than the CHR() built-in command, and the ANSI control codes are not terribly memorable in the first place. CourseWare also liked to use $V1$ specifically to define a regular variable, just to confuse you.
The built-in formatting variables are not case sensitive (i.e. both $s0$ and $S0$ will turn off reverse color), which implies that variables as a whole are not case sensitive.
Some commands refer to a special %B variable. From context, this appears to be text the user entered (perhaps "B" for "Buffer"?). It seems to always follow an AR, ASH, or ASHX:
AR:
MR:^passwd$
JY:COR1
C:A$ = %B
Some commands refer to a special %P variable. It seems to always follow an XSP (which seems to be some kind of prompt, expecting that input):
XSP: date
C: %B = %P
C: B$ = %B
I have no idea what this is.
For reference, BASIC generally used a % suffix for integers, but these two appear to be strings (and this is a prefix anyway).
Conclusion
To generate a more human-readable summary I wrote a parser with a tiny state engine that just tracks whether it thinks it should be outputting text based on which command it just saw. Combined with some basic formatting I have rendered the files to HTML and made them available via a link above. These are not ideal, but they try to at least be complete. Each subroutine has its own heading, and then within it are its texts, colored gray for comments, green for "yes" text, and red for "no" text. It's not ideal, but it means you don't need to read the raw source text to see what's going on. It even preserved the ASCII art reasonably well. Note that some files genuinely had issues from the source, with things like unclosed format tags. I did my best to correct for these, but you may occasionally see individual lines with weird formatting.
I have uploaded the full set of original tar archives along with the extracted files, their un-copy-protected contents, and the aforementioned HTML conversions of those to Archive.org if you want to flip through them and be amused at this unbelievably obscure corner of computing history. Sadly though we'll probably never be able to "run" these to experience them in their original form. It is theoretically possible for someone to brute force a replacement interpreter, but that person will not be me.
Citations
CTI:
- https://www.techmonitor.ai/technology/aix_expo_91
- https://www.plainsite.org/dockets/1389eig1a/superior-court-of-california-county-of-riverside/applegate-v-mccall-center-bowl/
- https://vtda.org/pubs/SunExpert/SunExpert-v06n01-1995-01.pdf
- https://www.latimes.com/archives/la-xpm-1995-08-24-fi-38594-story.html
Cerplex Group:
- https://www.storagenewsletter.com/2021/04/02/history-1995-the-cerplex-group-completed-acquisition-of-peripheral-computer-support-fo-20-million/
- https://www.techmonitor.ai/technology/cerplex_group_wins_contract_with_digital_worth_16m
- https://safer.fmcsa.dot.gov/query.asp?searchtype=ANY&query_type=queryCarrierSnapshot&query_param=USDOT&query_string=2622066
- https://www.latimes.com/archives/la-xpm-2001-feb-01-fi-19659-story.html