kent logo

CO538 Anonymous Questions and Answers

This page lists the various questions and answers. To submit a question, use the anonymous questions page. You may find the keyword index and/or top-level index useful for locating past questions and answers.

We have taken the liberty of making some minor typographical corrections to some of the questions as originally put. Although most of the questions here will have been submitted anonymously, this page also serves to answer some questions of general interest to those on the course.

When asking questions, please do not simply paste in your code and ask what is wrong with it, as these types of question are hard to answer in a public forum (resulting in either no answer, or an answer which will only be of use to the person asking the question). In many cases, a question about code can be formulated in general terms. For example, if you have an `IF' block that results in an `incorrect indentation' error, you might ask, ``what is the correct syntax for an occam `if' statement ?''. Questions of this form are easier to answer, and are meaningful to all.

Questions that are not suitable for these public pages (i.e. those that contain assignment-specific code), should be mailed to your seminar-leader.

Question 41:

Submission reference: IN1006

I'm sure this information is somewhere else but I can't seem to find it. What are the submission dates for the two assessments?

Answer 41:

Follow the link, "Assessment & class details", which is in a box on the right side of the Co631 module page. Alternatively:

Having said that, we will be encouraging you to submit the rododeb report earlier than the deadline. This is because it's not much work and so that (a) we can get it marked and feedback to you before the end of term and (b) we can give you something more ambitious to do – voluntarily!

Question 42:

Submission reference: IN971

Hi, for the Robo assessment, do I need to use the player library?

Answer 42:

The "player library" is a set of processes and utilities developed by (postgrads) Christian, Matt, Jon, Carl, and others who have worked on the Pioneer. See:


Both of these documents detail all kinds of things you can use in your solutions. I don't think, to make a simple wall follower, you need any more than positive.slice, negative.slice, etc. – basically, the processes that you saw in your first experience with RoboDeb. The point of the robotics control portion of the assignment is not to challenge you to develop new, complex algorithms for robotics control.

That said, you may want to have a bit more control than that provided by the few processes we showed you. In which case, you are welcome to explore the above URLs and make use of them in your solutions. There is nothing in them that is "advanced", so we did not "hide" them from you for fear that they would be "too much". They are there for you to use if you want to.

Keywords: robodeb

Question 43:

Submission reference: IN1007

I'm having some trouble with my replicated ALT. My display process contains:

      ALT i = 0 FOR 5
        phils[i] ? n[i]
	    pause (50000) -- to be replaced by random delays in phil proc
	    out.string ("Philospher ", 0, out!)
	    out.int (i, 0, out!)
            ...  more stuff

The idea is that it'll pick an arbitrary channel from the phils array but when I run this it always seems to pick 0 for i. I tried replacing the ALT with an alternative block of code using a SEQ to ensure all the channels were producing output, which they are.

Answer 43:

I've no idea why you have a delay in response to a message from one of the philosophers?!! The delay is to model a thinking or eating period in the life of a philosopher – so that (i.e. the philosopher process) is where the delay should be invoked. The code we write in occam-pi really is process-oriented: code that relates to the behaviour of a process always is executed by that process.

[Aside: note that the same statement does not apply to object-orientation. Code that relates to the behaviour of an object might be executed by all sorts of threads of control. Unfortunately, this means that to understand/write the code for one method, we have to understand/write the code for all other methods that operate on the fields used by the orginal method and might be exectued by concurrent threads. Such logic is impossible to scale to the management of complex behaviour.]

Assuming you have no delays in your philosopher code, the behaviour you describe can be explained. At the start of each loop, every philosopher is trying to make a report - their think and eat times are zero. The ALT sees all channels with messages pending and it chooses one arbitrarily. Please note that this does not mean randomly or fairly! Always choosing channel index 0 is quite arbitrary and perfectly legal – you cannot complain.

You need to invoke delays, ideally for random amounts of time within some defined limits, in the philospher process to model its thinking and eating times. Then, there will not generally be messages pending on all report channels each time the display process starts its loop – and the ALT will cope just fine.

By the way, why does your code only receive reports from the philosophers? You may find it much easier to receive reports from all players (the philosophers, forks and security guard) in one replicated ALT (over an array of 11 report channels).

Note: sometimes we really do need to service an array of ALT guards (e.g. channel inputs) fairly – for example, when the server is under stress from the continued pushing of messages by very active clients. In this case, we cannot use a simple replicated ALT. We could try a replicated PRI ALT, but that guarantees unfairness – only channel 0 will be serviced.

However, from guaranteed unfairness, we can obtain fairness. A PRI ALT gives priority to its first guard that's ready – that's first in the listed order, not in time of readyness. Find a way to arrange that the guard serviced last time is the last in the PRI ALT order next time.

Please try to work this out – it's very simple once you see it! The technique is know as fair alting. It guarantees that no pending message has to wait more than (n - 1) cycles of a server process loop before it is taken. This gives us worst case response times in a stressed real-time system.

Keywords: q7 , fair-alt , process-orientation , object-orientation

Referrers: Question 44 (2006) , Question 51 (2006) , Question 51 (2006)

Question 44:

Submission reference: IN1008

Can I just check that something like:

      ALT i = 0 FOR 5
      ALT i = 0 FOR 5

gives a 1/15 chance of selection to each element, or whether its 1/3, then 1/5 for each of the bits of code in the 2nd, if that makes sense?

Answer 44:

The above code flattens into an ALT over 11 guarded processes. Assuming all were ready, this does not give each guarded process a 1/11 chance of selection! That selection is arbitrary. One way to do it would be to choose a ready guard at random. But computing random numbers is expensive! A simpler and legal way to make the selection is to choose the first – or maybe the last. With an ALT, we can say nothing about the likelyhood of selection when more than one guard is ready. See the answer to Question 43 (2006).

Keywords: q7 , fair-alt

Question 45:

Submission reference: IN1010

How do we get colour for the terminal?

Answer 45:

There's an easy way ... and then there's the better way.

The easy way is to copy the (just installed) raptor file:


over to your exercises folder – or wherever you have your occam source code that needs it. Then, at the start of your occam source file, add the line:

    #INCLUDE "colours.inc"

This introduces a COLOUR data type (just a new name for BYTE, as it happens), a bunch of COLOUR constants (red, yellow, bold.magenta etc.) and a procedure:

    PROC set.text.colour (VAL COLOUR c, CHAN BYTE out!)

Invoking this, with the colour of your choice and screen channel, outputs the (VT100) terminal control sequence that means that subsequent text will be displayed in that colour.

A slight awkwardness is that the Transterpreter, currently, does not reset the text colour to the default (white) when it starts a new run of a program. To fix this, invoke the following on the screen channel before doing any other output there:

    set.text.colour (default, screen!)

where default is one of the COLOUR constants defined in colours.inc.

The better way is to use a library process we have pre-defined for you. Unfortunately, this is not part of the course library. Also, we have mis-named a file in the Transterpreter release and in the documentation. We will correct this – watch this space. Meanwhile, apologies.

Keywords: q7

Question 46:

Submission reference: IN1011

Does the assessment require that forks are animated? Can we just have the philosphers and a security guard, because unless we make tiny weeny little hands for the philosophers and tiny weeny little forks, there doesn't seem to be any nice way to fit them into the animation :(

Answer 46:

Yes, the forks should be animated – along with reports from the security guard.

Currently, all we have talked you through (in the seminar groups) is producing a system where the college makes all its reports and a display process receives them all, outputting one (appropriate) line of text for each report. That's about enough for half marks in the assessment.

Full marks will be obtained for some minimal animation. We will be talking you through this in the seminar groups next week. Solaris executables have been placed on raptor in the directory:

    /courses/co631/answers/    (Unix path name)
    \courses\co631\answers\    (Windows path name)

The executables have the names:

    a7  a7-callanan-2002  a7-stott-2001  a7-barnes-1998  a7-griffin-2000
    a7-bodden-2003  a7-hollands-1997  a7-braun-2000  a7-sampson-2002

To execute any of these, you must open a Unix terminal window and login to raptor (e.g. by using eXceed or putty). These are solaris executables and will not run on PCs! Once opened, change to the above directory and execute, for example:

    cd /courses/co631/answers/

The minimal standard for animation is that demonstrated by the a7 executable (where you will notice the defined limits for random thinking and eating intervals have been reduced to make the show more lively). The other examples are to challenge you – you may have to work through a few nights! If you do take up this challenge, please be original, :).

Warning: executing some of the above codes may leave your terminal window in a funny state: invisible cursor, coloured text, backspace key not working, mess on screen! Most of this can be repaired by the commands:


If that doesn't work, just open another terminal window.

Here's another challenge. Java .class files can be easily de-compiled back to reasonable source code. Try de-compiling the above back into occam-pi! [This is not a sensible challenge.]

Keywords: q7

Referrers: Question 51 (2006) , Question 51 (2006) , Question 52 (2006)

Question 47:

Submission reference: IN1012

Why does typing this into the xterm not copy my file?

    scp test2.occ z:/

or this:

    scp z:/ test2.occ


    scp bodiam:test.occ ./test.occ


    scp bodiam:test.occ ./test.occ

or anything? Can you give me the exact code I have to type to use scp?

I downloaded subversion to windows and it's just a blank command prompt I can't make it copy anything!

Answer 47:

First, I'm afraid there's a small rant. Then, we'll give some answers ... bear with us!

It's hard to know exactly where to begin. You need to grab a friend, or do some Googling, or make an appointment for some help. You are confused about how scp works. To begin with, you could start by typing:

    man scp

on a UNIX command line, and carefully read that document. Take notes. Experiment. Use your notebook to record what you did, what worked, and what didn't. If you don't work methodically through problems like these, you'll never learn. And, in case you didn't know, you're going to be continuously learning new tools and technologies for your entire career in computing/informatics, so developing these strategies sooner rather than later is going to be good for you.

Regarding subversion, it's pre-installed both in your VMWare image and on raptor. So, all you have to do is learn to use it. Try typing "subversion tutorial" or "subversion book" into Google. There are loads of tutorials and a whole book! The basics are outlined pretty early, and there are only a few commands you really need:

    svn commit


    svn checkout

However, again, if you're going to learn about version control (another common tool in computing), you're going to have to do some reading. By "some reading", I mean it will probably take you an hour or two of careful reading and experimentation. You can make an office appointment to help get you started, but we can only *teach* you, not *learn* you. Learning is something you have to do yourself.

OK, rant over ... :)

To transfer your file test2.occ from your VMWare linux to raptor, first change directory to the one containing the file. Now, assuming your raptor login is xyz42:

    scp mycode.occ xyz42@raptor:mycode.occ

will copy the file to your home directory on raptor. You will be asked for your raptor login password.

To copy it directly to, say, a sub-directory co631/robodeb/ from your home directory, the command would be:

    scp mycode.occ xyz42@raptor:co631/robodeb/mycode.occ

To restore this file from raptor back to VMWare, operate still from VMWare:

    scp xyz42@raptor:co631/robodeb/mycode.occ mycode.occ

If you are doing this from a PC, not on the university network, but connected to the Internet:

    scp mycode.occ xyz42@raptor.kent.ac.uk:co631/robodeb/mycode.occ

Humm ... actually, our firewalls might stop you making that connection. Will check.

Keywords: robodeb

Question 48:

Submission reference: IN1014

How do I make a function that returns nothing? I want to make one that draws a queue of people waiting to enter the dining hall.

Answer 48:

We haven't done functions yet in occam-pi! Functions in occam-pi are like functions in mathematics (or functional programming). Their only purpose is to return something – they can perform no side-effects (like communicating over a channel). See the PPT/PDF shared-etc, slides 88-93, if you want to read ahead.

I can only think that you mean a procedure – i.e. a PROC. These don't return anything and their only purpose is to cause side-effects (like communicating over a channel).

An occam-pi PROC that runs for a long time and is invoked as a component in a PAR construct ... is usually called a process. An occam-pi PROC that runs for a bounded time and is invoked as a component in a SEQ construct (or just on its own in response to an IF condition or ALT guard) ... is usually called a procedure ... or, in OO terminology, a method.

However, this is just a convention. Technically, every syntactically complete fragment of code – even a primitive assignment or communication or timeout – is a process.

Keywords: q7

Question 49:

Submission reference: IN1016

Hi, I have a few questions! How can I use the random function? This doesn't work:

      ...  stuff
      rr := random (800, 666)
      pause (rr)
      ... more stuff

nor this:

      ...  stuff
      pause (random (800, 666))
      ... more stuff

How do I get the number random is giving out? And what's with the second number (the seed)? Seems a bit loopy to me, why not just have random (upTo)? Doesn't the seed just complicate things? I don't get it! Thanks very much!

Answer 49:

This is being explained in your seminar groups. However, all the information can be found in past answers to these anonymous questions. Before asking, always check through the keyword index page!

In this case, there's loads of information about random. You have to get your head round the very useful concept of a function returning more than one result. The answers also explain why we need a seed variable and how to initialise it and operate it when we use the random function. A random number generator without a seed is like a butterfly without wings ... it won't fly very far.

Note: Java protects the user from having to operate the seed when computing the next random number – but you still need to know about initialising it. We could do the same very elegantly in occam-pi with a random number process (not function) running concurrently with the processes that need it. Probably, we should include such a process in the course library. The reason we haven't, so far, is performance. Random numbers tend to be needed heavily in complex modelling systems. Indeed, most of the compute time can be spent just computing random numbers! Using a function, rather than channel communication with another process, has significant speedup for such models. But that's not relevant for initial learning exercises.

Keywords: q7

Question 50:

Submission reference: IN1018

Why is it some PROCs are commented and some aren't in q7? I want to put comments in so I don't get confused, but I'm not sure which style to use ... :(

Answer 50:

Only two styles of comment are in the q7.occ starter file: fold comments (around entire PROCs and special chunks of code) and line comments (annotating particular lines).

To appreciate the fold comments properly, you need to use a folding editor – such as vim or gvim. Look up "folding" in the keyword index for these anonymous questions.

As far as occam-pi is concerned, there is only one kind of comment: everything from "--" to the end of the line is a comment. Both fold and line comments obey this – the former being a line comment on an otherwise empty line.

Without a folding editor, the fold comments around entire PROCs are a nasty distraction. So, only add them in your script if you are using a folding editor! The fold comments around special chunks of code do supply useful information, even when not using a folding editor. So, please copy that style.

For the ambitious, find out how to use the occamdoc tool. See the link, "occam-doc documentation" from this module's web page. Of course, this is not necessary to obtain full marks in this assessment!

Keywords: q7

Question 51:

Submission reference: IN1019

I have a printing process which uses this:

    ...  code hidden

Which I presume would be fair ...? If so, I still get some inconsistencies, such as the security guard saying there are 4 seats taken, where as the dining table only has 2 people 'sat' at it? Is there a way to get rid of this problem, or is it just random that problems like this pop up and I have no way to stop it?

Answer 51:

First, please note the third paragraph at the top of these pages. You included far too much and too specific code for general discussion.

Having said that, you are trying to set up a fair alt over all your report channels - see the note at the end of the answer to Question 43 (2006) (and the whole set of questions on this found from the keywordindex under "fair-alt"). Your code is fair between the security guard and the general set of philosophers and forks, but there is strink priority between the philosophers themselves (the lowered number ones always being preferred) and bewteen the forks themselves. So, your code is clever ... but not fully fair.

It would be much easier to be fair if you have only one array of report channels (11 altogether – 5 from the phils, 5 from the forks and one from security). I note you are using PROTOCOLs for the report channels. Great! Naturally, your PROTOCOL for the phils is different from that for the forks and that for the security guard. To have all these channels in a single array, there are two ways. Either merge the three PROTOCOL definitions into a single PROTOCOL (which is not nice semantically). Or read on to learn about variant protocols (which we will do in the next lecture) and, to be really cool, shared channels and protocol inheritance (in shared-etc.ppt and which comes next).

However, for this exercise, there is no need to set up fair alting by the display process on its report channels – see the fourth paragraph in the answer to Question 43 (2006).

Regarding your inconsistency problem, I'm afraid that this is not an inevitable problem resulting from arbitrary scheduling of your processes – your code is in error. That problem doesn't arise in any of the example executables mentioned in the answer to Question 46 (2006). So long as your security guard, phils and forks are wired directly to your display process (i.e. not routed through some other processes) and so long as your display process outputs directly to screen channel, your inconsistency cannot arise. That's all you need for the minimum animation standard (Question 46 (2006)) that gets full marks. If you are doing something fancier, you must find a way to ensure that when a college process makes a report it waits for confirmation that the report has been fully animated before proceeding (e.g. by waiting for some acknowledgement).

Keywords: q7

Referrers: Question 52 (2006)

Question 52:

Submission reference: IN1021

My philosophers currently teleport between the table and the office. Will I lose marks for this if I stick with it, and say its a magic college?

Answer 52:

No – that's fine! That's all the minimum animation standard (Question 46 (2006)) requires for full marks. But letting them move smoothly in parallel is not hard and very satisfying – you will need an extra process between each mover (philosopher or fork) and the display process. Plus a way to let each phil/fork know when its movement animation is complete, as mentioned in the last sentence of the answer to Question 51 (2006). That requires a further small modification to your phil/fork processes. Actually, if you find out about the extended rendezvous (slides 52-61 of shared-etc), an explicit acknowledgement back to the mover is not needed, :).

Keywords: q7

Question 53:

Submission reference: IN1023

I keep getting a STOP error when I try to run my animation, it works for about a second or two and then gives me the error. Is this deadlock? I don't remember getting a STOP error when getting deadlock in the classes.

Answer 53:

No, it's not deadlock – that would give you a deadlock error.

Please browse through the questions and answers from "q7" in the keyword index. The best help for this is probably Question 70 (2000), which also tells how to get more information on the line causing the error – unfortunately, you need the Linux occam-pi compiler (kroc) for this (available within your VMWare linux environment).

Keywords: q7 , stop

Question 54:

Submission reference: IN1036

I was wondering how you would do a double variant protocol. I want to have a variant to express the types (philosopher, fork, security) as well as having a separate one to indicate the actions. Currently I have:

      philosopher; INT; BYTE
      fork; INT; FORKSTATUS
      security; INT

But when I say:

  report ! fork; id; left.pickup

it complains about left.pickup not being defined. Also to how would I make this readable in the CASE statements, because I would somehow need to say something like:

  report ? CASE
    INT id:
    BYTE status:
    philosopher; id; CASE

Answer 54:

You can't do this, as you say, handling the input sensibly is hard. The normal approach would be to define some constants and use these. What we really want is an enumerated type, but until then, something like:

  -- fork status values

      fork; INT; INT


Keywords: coursework , protocol

Question 55:

Submission reference: IN1029

Am I defining my random numbers seeds correctly?

    PROC philosopher (VAL INT id, CHAN BOOL left!, right!, down!, up!, CHAN INT state!)
      INT waiting.time, seed:
      TIMER tim:
        tim ? seed
        seed := (seed >> 2) + (id + 1)
        WHILE TRUE

The philsophers all seem to start off with the same thinking time? So I'm a bit confused as to what I've done wrong.

Answer 55:

All your philosophers will start in the same few microseconds – possibly all in the same microsecond! So, all get the same initial seed value from the timer. That is shifted right by 2 bits, which makes it positive but also makes it even more likely the result (so far) is the same. Finally, the philospher's id, plus 1, is added which makes it very likely they all go into their loops with different seeds. However, if philosophers with lower ids were scheduled after those with higher ones, they could still go into their loops with the same seeds.

To ensure they start with different seeds, compute an initial seed just once (using the timer, as in your code above) and before starting any philosophers (e.g. before starting the whole college). Pass this same initial seed into each philosopher and get them to add in their id number. Now, each philosopher is guaranteed to start its loop with a different seed.

However, random number generation is a black art. Starting from consecutive initial seeds, it takes some of them (like the cheap-but-fast one used by the course library's random function) a little while to diverge. So, I'm not surprised they all start off with the same thinking time.

To combat that, warm up your generator before first using it! Here is an example routine to do that:

    PROC warm.up.random (VAL INT warm.up.count, INT seed)
      SEQ i = 0 FOR warm.up.count
        INT dummy:
        dummy, seed := random (42, seed)

A warm.up.count of 1000 will suffice.

Keywords: q7 , random

Referrers: Question 29 (2008) , Question 33 (2007)

Question 56:

Submission reference: IN1031

Hi, I got a process:

    PROC display ([]CHAN MESSAGE in?, CHAN BYTE out!)
      ...  code just dealing with phil messages (edited out)

which reads an array of variant protocols named MESSAGE.

I am just wondering: do I need another process that reads the reports from the philosophers, forks and the security, multiplexes them and outputs an array of variant protocols named MESSAGE to the display process. Thanks.

Answer 56:

No. Connect all report channels (in a single array) to your display process. Your MESSAGE protocol should define all messages from all agents (i.e. phils, forks and security). Your display just needs expanding to deal with all varieties of MESSAGE.

Keywords: q7

Question 57:

Submission reference: IN1055

Hi, I am using a variant protocol MESSAGE for carrying messages and I have a display process that inputs from only one channel that carries MESSAGE. In the header of each process within the college, there is a SHARED CHAN MESSAGE report! parameter. In each college process, e.g. the philosopher, I report one of the states like this:

    CLAIM report!
      report ! thinking; id

But when I am running it, it does not print out anything! I really don't know what's wrong with it.

Answer 57:

Everything you have described looks right. Check your wiring. The college process itself must take a shared report! channel parameter, which it passes on to all its sub-processes. The actual report! channel, shared at the writing end, must be declared before the PAR setting up the college and display processes – and, of course, the right ends plugged into them. Finally, make sure your display process really is connected to the outermost screen channel.

Keywords: q7

Referrers: Question 58 (2006) , Question 69 (2006)

Question 58:

Submission reference: IN1032

Hello, currently I have:

    PROC reports (SHARED CHAN MESSAGE out!)

    PROC display (CHAN MESSAGE in?, CHAN BYTE out!)

But I dont know how to connect the reports from the colleges to the reports process.

Answer 58:

I don't know what your reports process does or is for? It's the college and its sub-processes that should be give this channel – and the sub-processes (claim and) use them. See Question 57 (2006) for more clues.

Keywords: q7

Question 59:

Submission reference: IN1038

I have the following report process, which is linked to the screen output channel. I want to be able to output the value of the INTs coming in on up and down, but I seem to have a casting issue.

    PROC report (CHAN INT up?, down?, CHAN BYTE output!)
          INT a:
	  up ? a
	    output ! BYTE a
          INT b:
	  down ? b
	    output ! BYTE b

As the screen output only accepts bytes, I have attempted to cast the integers. But when this process is run, the output is simply a bunch of smilies :-) ...

Is there is simple casting issue or do I have to attack this from a different angle?

Answer 59:

If the arriving INT were, say, 65 – then, casting it to a BYTE and outputting it to a channel connected to the main screen channel would print the symbol 'A'. Further, if the arriving INT were, say, 7 – then, casting it to a BYTE and outputting it to an channel connected to the main screen channel would cause the terminal to bleep (since 7 is ASCII code for BELL). Neither of these is probably what you wanted!

If the arriving INT were, say, 65 and you wanted to print the symbols "65" – then:

	    out.int (n, 0, out!)

would do the trick (assuming n is a variable holding the value 65 and out! is connected to the main screen channel).

But I don't recognise this report process in connection with the dining philosophers animation? What are you trying to do here??

Keywords: q7 , cast , out.int

Question 60:

Submission reference: IN1039

Hi! My code won't compile. The compiler says its outputting to variable "doing" in parallel, which it is ... is there a way to avoid this?

I could use 4 different variables, but that seems wasteful ... any suggestions? Here's the relevant bit of my code (which gives the error: 'doing can't be output in parallel')

      --{{{  pick up the forks
	left ! TRUE
	doing ! 2
	right ! TRUE
	doing ! 3


Answer 60:

For any specific channel, occam-pi only allows one process at a time to output to (or input from) it. For normal channels, this means that only one process in a PAR block is allowed to have the output end (respectively, input end). In the code fragment in your question, there are 4 processes running in parallel – and 2 of them are outputting to the same channel. The compiler is right to complain!

I suspect that you really meant your code to be:

      --{{{  pick up the forks
	  left ! TRUE
	  doing ! 2
	  right ! TRUE
	  doing ! 3

so that the doing reports are sent only after the relevant fork was obtained. However, that still leaves 2 processes running in parallel and outputting to the same channel – still illegal!! But picking up the forks must be done in parallel.

To do the above correctly, you would need a doing.a and a doing.b channel so that the reports could be made in parallel. Now, each philosopher has 2 report channels that must be connected to your display process. Alternatively, if all your philosophers, forks and security guard reported through a SHARED output channel, then the above code would be legal (provided, of course, the doing channel was CLAIMed first). [I've no idea what you might mean by using "4 different variables" to solve this?]

However, you were advised in your seminar groups not to bother reporting the picking up, or putting down, of forks by the philosphers. Much easier is for the forks to report their being picked up and put down. Hopefully, you are doing that ... in which case, there is no need to program the philosophers to duplicate that information. Problem deleted!

Keywords: q7

Valid CSS!

Valid XHTML 1.0!

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Last modified Mon May 20 13:50:23 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.