Volume 2 Number 3 February/March 1989

Contents

Editorial
Dave Menconi

Applause Instead Of Victory?
Chris Crawford

What is a Computer?
Chris Crawford

Bringing Characters To Life
David Graves

A Mickey Mouse Approach to Game Design
Jeff Johannigman

Real Life in a Box or, How to Design and Implement a Computer Vehicle Simulator
Gordon Walton, John Polasek, and Karen Hunter — Digital Illusions, Inc.

Editor Chris Crawford

Subscriptions The Journal of Computer Game Design is published six times a  year.  To subscribe to The Journal, send a check or money order for $30 to:

The Journal of Computer Game Design
5251 Sierra Road
San Jose, CA 95132

Submissions Material for this Journal is solicited from the readership.  Articles should address artistic or technical aspects of computer game design at a level suitable for professionals in the industry.  Reviews of games are not published by this Journal.  All articles must be submitted electronically, either on Macintosh disk , through MCI Mail (my username is CCRAWFORD), through the JCGD BBS, or via direct modem.  No payments are made for articles.  Authors are hereby notified that their submissions may be reprinted in Computer Gaming World.

Back Issues Back issues of the Journal are available.  Volume 1 may be purchased only in its entirety; the price is $30.  Individual numbers from Volume 2 cost $5 apiece.

Copyright The contents of this Journal are copyright © Chris Crawford 1988.

_________________________________________________________________________________________________________

Dear JCGD,

As a boondocks-dweller I felt honor-bound to boot up my brand new Altair and toggle in a scathing rejoinder to the "Florence during the Renaissance" bit of Bay area cheekiness in JCGD 2,2.

What Renaissance?  Where are the masterpieces?  Artists pushing a mature artform to transcendant heights?  Cross-fertilization between media?

See my article in JCGD 1,1 for my depressing ETA for computer gaming’s Renaissance. At this point in the history of computer game design there are advantages to isolation.  Our medium is in such a primitive state that it may be vital to an artist to avoid influences.  Aesthetic prophylaxis.

Most importantly, if you live well to the east of New Florence you can rest assured that your publisher will seldom phone before noon.

Gamely,
Doug Sharp

_________________________________________________________________________________________________________

Applause instead of victory?
Chris Crawford

The notion of victory is standard in all our games.  The player expects to either win the game or lose it.  We designers have always accepted this as a given in our craft.  Unfortunately, the emphasis on victory creates a design trap that robs our games of dramatic power.

Exactly how does a player win a game?  By doing everything correctly.  There is a set of behaviors we impose on the player.  If he masters that set of behaviors, he wins.  Otherwise, he loses.

Unfortunately, this imposes a conservative playing strategy on the player.  He moves through the dungeon, taking everything portable and slaughtering everything mortal.  He launches attacks only at 3-to-1 odds.  He saves the game before attempting anything risky.

What is especially sad about this is that we have no way of encouraging the player to attempt truly bold play.  Imagine, for example, the classic movie scene in which the heroine’s car sputters to a stop just in front of the darkened castle.  Blood-red eyes peer out through blackened windows as she chirps, “I’ll just ask to use their telephone.”  Nobody in their right mind would go near that spooky house, but our heroine does so.  Here’s the problem:  how do we induce our players to go into the house?  What induces them to take dangerous and dramatic chances that will forward the play of the game?

ICOM Simulations came up with one solution in Uninvited.  If you don’t get out of the car soon, it blows up and you die.  That’s one way, but we can’t sprinkle too many burning cars through our games.  A more common solution is to wait out the player, not allowing him any forward progress until he bites the bullet and takes the courageous course of action we choose to cram down his throat.  The problem is, what satisfaction can a player take in enforced courage?

I propose another solution.  Suppose that we were to dispense with the conventional notion of victory and replace it with a virtual audience.  The player strives not for some absolute notion of victory but instead sees himself as a performer for this audience.  The game is a play, a stage for him to strut his stuff.  He seeks not to win or lose but to play gloriously.  At the outset of play, he cannot know whether this particular performance will be a tragedy or a heart-warming affirmation of human triumph in the face of adversity.  All he knows is that he will face the trials soon to come his way with verve and panache.  In so doing, he will win the approbation of the audience, and that is what he seeks.

To implement this scheme we will require the creation of algorithms that imbue our artificial audience with taste and discernment.  The audience must somehow be able to generate expectations and compare the player’s behavior with those expectations.  When the player surprises the audience, he wins their admiration (unless, of course, his behavior is surprisingly bad!)  

Such algorithms will not be easy to create.  Perhaps we will need to apply some of those Aristotelian notions of dramatic theory that Brenda Laurel has been telling us about all these years.  Perhaps we should model the audience as a group of individuals and have each one render judgement individually.  Perhaps each audience member could reflect a given point of view or school of thought.  Even then the problem is not solved.  We must also create a “Situation-Generator” capable of developing a dramatic situation in response to the player’s actions.  This in itself will be a major work.  

So what I am proposing is not an easy solution to a difficult problem but rather a difficult strategy for solving what may be an otherwise impossible problem.

_________________________________________________________________________________________________________

The BBS is Moving!
Our hardware sysop, Sean Barger, is moving to Sausalito, and he is taking the JCGD BBS with him.  So we have a new telephone number for the BBS.  It is (415) 332-4535.  It should be operational by the time you receive this issue of the Journal.

_________________________________________________________________________________________________________

A Techno-wimp Revisits “Scribes Versus Authors”
Chet Day

[Chet is GEnie’s Apple II bulletin board editor.  His all-text game, Germ  Lab,  will be published by UpTime as a serialized adventure.  He’s also the author of Halo, a paperback thriller published by Pocket Books, Inc.  His second novel, Surgery, will hit the bookstores in November of 1989.  Day teaches English and a computer course on how to write interactive fiction at a New Orleans prep school when he isn’t doing all or some of the above.]

As a middle-aged author and techno-wimp with a couple of paperback novels under my belt... and as a diligent but admittedly mediocre programmer who’s designed and sold several programs for Apple II computers, “Scribes versus Authors”  hit home with enough punch to provoke a reply.

In August of 1984, when I decided to stop typing words and start processing them, I purchased an Apple IIc to complete a novel I’d been struggling with for years.  I also bought a copy of Zork I--this as a result of reading Tracy Kidder’s The Soul of a New Machine and being fascinated by the scenes where the engineers test their prototype by playing the original Adventure.

The idea and potential of interactive fiction chomped into me with the force of strong back molars, and, soon, I found myself spending more time exploring the underground empire than I did spelunking the world of the book I had supposedly purchased the computer to finish.

So I dropped out as a novelist and dropped in as a player of interactive games.  I buried myself in programming and operating system textbooks.  As an English teacher and writer, I spent hours thinking about what I was convinced was an entirely new genre of literature:  interactive fiction.  The potential of this new genre engendered goose bumps in odd places on me in the wee hours of the night as I drew maps, outlined scenes, developed characters and plot, figured out multiple endings, and created a computerized world in my first attempt at becoming a disk-based story teller.

It took me close to twenty-four months of midnight oil, weekends, and vacations, but I finally completed my first interactive novella, a tyro’s program that executed without errors but was ultimately a failure.  At this point, frustration needled through my veins.  My programming skills were so limited I had failed to even come close to doing justice to this new genre.  Yes, an engaging plot provided a beefy skeleton; yes, believable characters populated my mini-world; yes, vivid writing sizzled across the monitor; and, yes, the story fascinated and drew nice praise from the teenagers who beta tested the game for me.

But the completed game didn’t meet my idealized vision of what this genre could and should be.  As is the case with all the interactive fiction that I’ve played, my first effort failed because the bottomline execution of the program fell on the sword of the old Guess what the programmer was thinking when he coded the game  conundrum.  The wholly inadequate parser overshadowed and, ultimately, defeated the engaging story and characters.

Stubborn to the core, I decided to try a different language.  I turned to working with ACOS, the proprietary language of GBBS Pro  bulletin board systems for the Apple II series.  It was a dialect I felt comfortable with, a language I could understand without quitting my job and taking serious time off to really learn 6502 assembly.  And I was intrigued with the concept of online game playing.  But...

... my interactive fiction efforts in ACOS stubbed their toes against the aforementioned parsing problem.  My talents as a writer aside, my adventures were still little more than engaging stories transferred to a monitor with a conundrum as a user interface.  Because I did not have at my disposal the tools to write my ideal adventure and because, with a family to support, I was unable to quit my job and learn what Chris Crawford calls “high-performance C code,” frustration continued to taint the blood of my creative efforts in our field.

“Be patient,” I kept telling myself.  “Someday a programmer will produce a package for professional writers like yourself that’ll provide you with the tools you need to create the sort of interactive fiction you feel could be written.”

So I waited impatiently and worked diligently... finished and sold a couple of paperback novels... completed and sold several adventures in ACOS, as well as a simple but interesting Lisa-like online artificial intelligence simulator called Ask Dr. Shem  that has proven to be my most popular computer work to date... but all the time I waited for a tool that would give me the freedom to actualize a conception, the freedom to do what I think of as the real work.

Hypercard burst on the scene.  Reading beyond Hyperhype, I decided Hypercard was a potential answer to my long dilemma, so I approached my wife with this newest scheme for bringing to life my often-voiced goal.

“You have to buy ANOTHER computer to do it?” she probed.  (My wife is a lovely woman and I love her dearly, but she does not often sympathize with the problems that we techno-wimps have to overcome.)  I retreated.  Marshalled my forces.  Advanced gingerly.  Peppered dinner conversation and pillow talk with thoughts about what interactive fiction really could be if I only had another computer.  I waited... a Patient Griselda that would have made a technoid Chaucer proud.

“You really think this’ll work, eh?” my wife inquired, worn down from the onslaught of my unrelenting explanations.  “A Macintosh will lift you out of the pocket change sales figures?”

“I don’t know,” I answered honestly, “but hope springs eternal, doesn’t it?”

Who could resist such honest optimism?  Who could stand firm in the face of such stubborn devotion to the art of computer game design?  

My life’s companion gave me a green light.

Anyway, to break out of the anecdotal flow that this article has suddenly fallen into, a few weeks ago I trashed the family budget for the rest of the year and purchased a Macintosh SE and Hypercard.

I’m only now beginning to explore HyperTalk, but, already, I can see that it may be the tool I’ve been waiting for.  This enigmatic and fascinating program may finally allow me to give life to an idealized conception.  At long last, my limitations as a programmer may no longer be relevant to my abilities as a writer and story teller who wants to explore and help advance what I see as having the potential of being the first new genre of literature in many years.

Time will tell, of course.

Finally, I sensed in Chris’s original article what may be a sliver of paranoia.  Then again, however, it might be Crawford’s sometimes enigmatic sense of humor.  Or it could be a rare inexactness of phrasing on the part of our editor.  Probably, though, it was an intentional prod to elicit a response such as mine.  (After all, show me a game designer who doesn’t play games in real life and I’ll show you someone who isn’t a real game designer.)

Whatever the case, one quick comment in regards to the clause “... my untrained, techno-wimp young friend grows more powerful.”  

Given the proper tools, we techno-wimps just might have more than a few surprises for the hoary-haired scribes of yore.

If those of us who are deadly serious about designing games indeed compose a professional association, techno-elitism must give way to creative fellowship.

The time has come to open the circle.

_________________________________________________________________________________________________________

Real Life in a Box
Or, How to Design and Implement a Computer Vehicle Simulator

Gordon Walton, John Polasek, and Karen Hunter of Digital Illusions, Inc.

Part 3 - Enemy & Friendly Unit Intelligence and Testing the Program.

Introduction
In this segment we will cover how to give enemy and friendly units within your simulated world some “intelligence” and how to adequately test your product prior to publication.  To give you the context of our article, we are designing a Nuclear Submarine Simulator in which the player controls the submarine.  He will have contact with both friendly and enemy ships, submarines and planes.

Enemy and Friendly Unit “Intelligence”
Though we have used the term “intelligence” in the section heading, it is a misleading term.  What we will construct to give the appearance of “intelligence” is in fact a system of conditioned responses.

The items we will need for each unit, in addition to what type of vehicle/unit it is and its capabilities, are as follows:

KnowYou  whether the unit knows that you exist.
Solution     how well this unit is identified, (0-100%)
Possible_Location    where the unit thinks you are.
Possible_Distance   how far away the unit thinks you are.
Heading_Uncertainty    uncertainty in the direction from the unit to your possible location.
Uncertainty_Area    the radius from the Possible Location in which the unit believes you are if it does not know your present exact location.

The unit, using its sensors (which may include visual, sonar, electronic emission sensors or radar assets) may get a fix on your actual location or just a heading to your location.  If the contact is repeated and strong, the uncertainties are reduced, eventually to zero.  Once the contact with your submarine is lost by the unit, the Uncertainty will grow over time, until they have no idea where you may be.  In addition, each new contact that they make may be a different unit than your submarine, and the solution they have on the contact must rise above a certain percentage prior to classifying the contact as your submarine or some other unit.  This gives you an idea of the process involved in updating the variables that we will need to have the unit properly respond to contacting your submarine.

The “C” pseudo code that demonstrates this variable update process is as follows:

Additional Variables Utilized:

depth:   depth of unit (0=surface, negative in air)
PassiveSonarFlag:  does this object have passive sonar available?
ActiveSonarOn: is active sonar on on this unit?
RadarOn: does this unit have active radar on?
RadioTransmitterOn: is this unit using an active radio transmitter?
ESMCapable: does this unit have ESM sensing capability?
PassiveSonarFlag: does this object have passive sonar available?

Routines Utilized:

These first four routines modify the our_unit variables for the particular unit_to_check:

CheckVisual(our_unit,unit_to_check ) CheckSonar(our_unit,unit_to_check )       CheckRadar(our_unit,unit_to_check )   CheckESM(our_unit,unit_to_check )
UpdateObject(our_unit,unit_to_check )
short int our_unit;
{
   /* first we would decrement the current   solution and increase the error by the amount of time that has passed */
   /* if both objects above or on surface of the water */
   if ((theObjects[our_unit].depth>=0) && (theObjects[unit_to_check].depth>=0))
       CheckVisual(our_unit,unit_to_check );
  

   /* does our unit have passive sonar or is active sonar on? */
   if ((theObjects[our_unit].PassiveSonarFlag) && (theObjects[unit_to_check].ActiveSonarOn))
      CheckSonar(our_unit,unit_to_check );

   /* does our unit have radar on? */
   if (theObjects[our_unit].RadarOn)
      CheckRadar(our_unit,unit_to_check );

   /* does our unit have ESM capability and does the unit being checked have active ESM emissions? */
   if (( theObjects[our_unit].ESMCapable) && ((theObjects[unit_to_check].RadarOn) ||
       (theObjects[unit_to_check].ActiveSonarOn)|| (theObjects[unit_to_check].RadioTransmitterOn )))
      CheckESM(our_unit,unit_to_check );

  /* at this point, the our_unit has the most up-to-date location info on unit_to_check */
}

Once we have our current solution variables updated on an object, we can go through the conditioned responses to the contact, based on what type of unit we are operating on and the reliability of the contact.  Unarmed merchant ships will act much differently than a screen destroyer or an ASW helicopter.  For illustration purposes, we will show conditioned responses for each of the these examples.  Our full system would need routines for each major ship class and perhaps different routines for different nationalities to match their differing tactical doctrines.

Additional Variables Utilized:

TimeRate:  seconds since last execution of this routine
Base_Course: each object has its own base course
ZigZag: each object has a potential zigzag value (in plus or minus degrees)
Endurance: number of seconds of remaining endurance (for aircraft) set when launched.
DipTime: Time in seconds for this sonar dip for helos or sonar listen periods for screening ships.
UnitType: The numeric index value of this unit type.

Additional (not shown) Routines Utilized:

ChangeHeading(our_unit,desired_heading) : steers our_unit  to the desired_heading based on unit’s turn rate and the time compression ratio.

DropASWTorp(our_unit): causes helo to drop an ASW Torpedo.

DropASWDC(our_unit): causes helo to drop an ASW depth charge.

ChooseNewLocation(our_unit): causes our_unit to move to another spot within our assigned sector.  Called until you get to the spot then sonar is dipped, or other sensors activated.

NewContactLocation(our_unit):  causes our_unit to move to get a better reading on currently prosecuted contact.  Takes all info on a contact, chooses a new position that will   (hopefully) improve the solution on the   contact and allow prosecution of the contact.   Called until you get to the spot then sonar is dipped, or other sensors activated.

------------------------------------------------------

UnitIntelligence(our_unit)
short int our_unit;
{
   switch (theObjects[out_unit].UnitType)
      {
         case MERCHANTSHIP:
            {
               MerchantResponses(our_unit);
               break;
            }

         case DESTROYER:
            {
               DestroyerResponses(our_unit);
               break;
            }
        case ASWHELECOPTER:
           {
              ASWHeloResponses(our_unit);
              break;
           }
       break;
    }
}

----------------------------------------------

MerchantResponses(our_unit)
short int our_unit;
{
   /* since a merchant ship has no offensive capability, we can only run away! */
   /* first see if our ship is aware of enemy presence */
    if (theObjects[our_unit].KnowYou==TRUE)
       {
          /* yes we are, lets get out of here! */
          /* if contact is a torpedo, trail a decoy if available, else maneuver to avoid it */
          /* else if contact is a missile, make yourself a smaller target */
          /* else if contact is a sub then get away from there*/
          /* if escorts near by, try to get behind them, else put as much distance between you and the contact as you can */
      }
  else
     {
        /* no enemy detected, stay on base course, zigzag if set for it */
        ChangeHeading(our_unit,theObjects[our_unit].
        Base_Course+theObjects[our_unit].ZigZag);
     }
}

----------------------------------------------

DestroyerResponses(our_unit)
short int our_unit;
{
   /* since a destroyer is capable of fighting a variety of threats and is responsible for screening the force from subs, we
will go in harms way! */
   /* first see if our ship is aware of enemy presence */
   if (theObjects[our_unit].KnowYou==TRUE)
      {
         /* yes we are, lets get them! */
         if (theObjects[our_unit].DipTime>0)
            {
              /* finish our dip first */
              theObjects[our_unit].DipTime=
theObjects[our_unit].DipTime-TimeRate;
              /* see how good our solution is, and what weapons we can use */
              if (theObjects[our_unit].Solution>75)
                 {
                    /* we could also use surface weapons if contact is on or above the surface, but this is not shown here */
                    if (theObjects[our_unit].Possible_Distance<6000
                       {
                          /* fire a depth charge or RBU, if any left */
                          DropASWDC(our_unit);
                        }
                    else if(theObjects[our_unit].Possible_Distance>=6000)
                        {
                           /* fire a standoff homing torpedo, if any left */
                           DropASWTorp(our_unit);
                         }
                      }
                  }
              else NewContactLocation(our_unit);
            }
        else
            {
               /* no enemy detected, move from place to place within our sector slowing to
                    listen for subs, the slow times use the DipTime variable, shift sectors when directed */
                if (theObjects[our_unit].DipTime>0)
                   {
                     /* finish our dip first */
                     theObjects[our_unit].DipTime =  theObjects[our_unit].DipTime-TimeRate;
                    }
                else ChooseNewLocation(our_unit);
            }
        }

----------------------------------------------

ASWHeloResponses(our_unit)
short int our_unit;
{
   /* since an ASW helicopter is designed to search for submarine contacts, we must patrol our sector, switching sectors
        as directed, and prosecute any solidcontacts*/
   /* first see if our ship is aware of enemy presence */
    if (theObjects[our_unit].KnowYou==TRUE)
    {
      /* yes we are, lets get them! */
      if (theObjects[our_unit].DipTime>0)
        {
          /* finish our dip first */
          theObjects[our_unit].DipTime=theObjects[our_unit].DipTime-TimeRate;
          if (theObjects[our_unit].Solution>75)
            {
              if (theObjects[our_unit].Possible_Distance<100)
                {
                  /* drop a depth charge, if any left */
                  DropASWDC(our_unit);
                }
             else if   (theObjects[our_unit].Possible_Distance<800)
                {
                  /* drop a torp, if any left */
                  DropASWTorp(our_unit);
                 }
             }
         }
        else
          {
            /* move to a new dip spot to improve contact! */
            NewContactLocation(our_unit);
          }
      }
      else
      {
        /* no enemy detected, move from place to place within our sector dipping
            and dropping sonobuoys, shift sectors when directed */
         if (theObjects[our_unit].DipTime>0)
         {
           /* finish our dip first */
           theObjects[our_unit].DipTime-TimeRate;
         }
     else ChooseNewLocation(our_unit);
  {
}

Note that while the code to do these conditioned responses is quite large, in fact only a very small portion of this code is actually executed, and variable compares utilized to get to the proper response are quite computationally cheap.  Also note that friendly units utilize the same conditioned responses until they determine that the contact is on their side, making accidental sinkings/damage possible.

Now that you have seen how to construct a limited conditioned response system for enemy units, remember that this will be complicated by multiple enemy units communicating with each other their solution on your location!  In addition, occasionally the screening elements are assigned to new sectors.  The synergy of such shifts and communication (and the possible ESM emissions caused by such communication) may make our conditioned response system appear much smarter than it actually is!  Only extensive playtesting will  tell how well you have modeled these responses.

Play Testing and Shipping the Product
Our experience in testing is that you cannot ever do enough prior to shipping a product.  Once you have the majority of the programming done for the product you must test it extensively!  We divide our testing into 3 distinct phases, which we call alpha, beta, and final.

Your alpha test group (6-12 persons) must include people who are intimately familiar with the topic of the product and the target machine it is being created for.  They should get the earliest playable product, and you must listen carefully to their feedback.  Be somewhat careful of the disease of “featuritus” which is brought on by highly technical customers who your alpha testers represent.  Add new features which were not included in your original design only after making sure they conform to the design thrust of our game.

To offset the danger of “featuritus”, start introducing your beta testers  (12-24 persons) into the process as you send out revisions to your alpha testers.  On each revision, bring in 1-2 of your beta testers.  Beta testers should represent a broader spectrum of users, including those who are not fanatical about the topic of your product, and some who are not well versed on the target machine.  If you listened carefully to your alpha testers, listen even closer to the beta testers as they represent the more average customer you will be selling your product to.  Be prepared as they will find some really dumb things that you have already trained your alpha testers to ignore.

Once all your beta testers have been added to the process and you feel the game has no faults, it’s time to get serious.  Contact your local user group for the target machine and set up a time and place where you can get 8-12 users for 2-4 hours to look over your product.  Watch carefully without helping (have an assistant do the help).  If the program can be crashed, the preliminary documentation is inadequate, or features are unclear or awkward to use, you will spot it.  This is the first part of the final test.  Now pull out 8-12 possible alpha testers (people who are experts on the topic of your product and well versed in their machine’s operation) who you did not include in either the alpha or beta test groups.  Send them the near final program and get them to play it extensively, and if possible complete it.  They are looking for the problems that occur in intensive, long term play by experts on your topic.  Your alpha test group will also do this, but they will not have the fresh impression of the program that these final testers will bring to their work.

If you utilize this process, you will be about 99% sure that the program is ready for market.  The major problems that this procedure creates relate to time and logistics.  It takes a lot of time to prepare revisions and mail them to the 8-32 people involved.  In addition, the turnaround time tends to be 3 weeks from when you mail the revision until you receive the feed back from the tester.  Using people who have access to national on-line services such as CompuServe, GEnie, bix or AppleLink can cut down turnaround time to a 7-10 days.  You can reduce the logistics somewhat by preparing the disk labels, address labels and mailing envelopes early in the process.  Also, get to know the leadership of your local computer user group early on!  Given the typical development times in the industry, this type of testing tends to be more of an ideal than a practice.  We strongly urge you to include plenty of time for testing, a bare minimum of two months for simulations, after all design and programming work is done.  If you don’t test adequately, you will be doing revisions and creating dissatisfied customers.  Do not count on the publisher to do your play testing!  By the time your publishers’ Quality Assurance people see your product for the 3rd or 4th time they have a pattern of play that may not be exercising some key options or circumstances.

Finally, how do you find people who will test your products?  This is really easy, as we have found that there are so many people who will test your product for free that we are able to pick and choose.  By subscribing to a national on-line service and putting a message (in an appropriate area) that you are looking for people who will test games, you will get literally dozens, sometimes hundreds, of applicants.  Create a series of questions that these prospective users can answer that will let you know their qualifications to help you test.  Once you are satisfied that they are the right kind of person to help you, create and send them a Non-Disclosure form which is their promise that they will hold your product in confidence and not distribute it to anyone.  After utilizing over 300 outside testers over the last 3-1/2 years, we only had one (unverified) report of a tester giving away a copy of one of our programs.  Make sure your testers understand what they will get out of helping you test.  We give ours a copy of the final product, and when possible, credit in the program and/or manual (people love to see their name in print!).

Summary
We hope our article has given those of you interested in vehicle simulations information useful in putting one together.  A lot of the detail was left out in the interest of fitting within the Journal, but all the key points were covered.  If you have questions or comments feel free to contact us on the Journal’s BBS (User #13).