XML

kent logo

CO538 Anonymous Questions and Answers Keyword Index

This page provides a keyword index to questions and answers. Clicking on a keyword will take you to a page containing all questions and answers for that keyword, grouped by year.

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.

Keyword reference for q2

2012

Question 7 (2012):

Submission reference: IN2159

In Question 5 (2012), we have to write the process differentiate. I've read the anonymous Q&A and you said that if we have to call differentiate only with an input channel = 0, 1, 2, 3 ,4.. etc, the output should be 0, 1, 1, 1, 1.. etc. But my output channel turn out to have 0, 1, 1, 2, 2, 3, 3, 4.. etc. I can't seem to find the problem and fix it.

Is this caused by my minus process (where I simply changed PLUS to MINUS within the code body), or my differentiate process (where I have called delta, prefix and minus)?

Answer 7:

Let's first get the language correct. If the stream of integers supplied to a differentiate process is 0, 1, 2, 3 ,4, etc., then its output stream should be 0, 1, 1, 1, 1, etc. For the reason why, see the last paragraph of the answer given in Question 5 (2012).

The reason why your differentiate is producing a different stream of integers is that your circuit for it is incorrect. Your minus process, modified as you describe, is certainly one of the components needed for a correct circuit – as stated in the question. But I suspect that you have just reused the integrate circuit, substituting your minus for its plus. Why should that work?

You need to work out, first, what is the transformation differentiate has to make on its input stream. Its definition implies that if the input stream is:

    a, a+b, a+b+c, a+b+c+d, a+b+c+d+e, ...

then its output stream should be:

    a, b, c, d, e, ...

In which case, if the input stream is:

    p, q, r, s, t, ...

What should its output stream be? Once you have written that list of formulae, you will know what has to be done and the circuit should become reasonably obvious, :).

Keywords: q2


Question 5 (2012):

Submission reference: IN2156

In q2, we have to write the process differentiate. Does this process have to be dependent on the integrate process?

Basically, if we have to call differentiate only, with an input channel "in" = 0, 1, 2, 3, 4....., is the output channel "out" = 0, -1, -3, -6, 10, ... ?

Answer 5:

The question says that pipelining a differentiate process following an integrate process results in no change to the stream of numbers flowing through them – i.e. the output stream is the same as the input stream. Now, integrate emits running sums of the numbers from its input stream. Therefore, differentiate must do something with such running sums to retrieve the original stream. Working this out, implementing it in the required style (i.e. one similar to the parallel implementation of integrate, "Basics" slide 9) and, then, demonstrating its correct working in the test network given in the diagram for process q2 is what you are asked to do.

Of course, differentiate can be used in any network – it does not have to be pipelined with an integrate, nor need any integrate be present! However, if the input stream of numbers to differentiate were:

    0, 1, 2, 3, 4, ...

the output stream from differentiate would need to be:

    0, 1, 1, 1, 1, ...

To understand why, imagine this second stream as the input to an integrate process: the output (running sums) would be an increasing sequence of numbers starting from 0 (the first stream). So, pushing that second stream though integrate and then differentiate gets it back again – differentiate has done its job correctly!

Keywords: q2

Referrers: Question 7 (2012) , Question 7 (2012)

2011

Question 10 (2011):

Submission reference: IN2040

The following will compile:

    PROC test (CHAN INT out!)
      WHILE TRUE
	INT x:
	out ! x
    :

and will output "-1431655766". What's significant about that number?

Answer 10:

Your code declares a variable, x, and outputs its value down a channel. That value has not been set and, therefore, may be anything, :(.

In occam-pi, there is no automatic initialisation of variables to some default value. From the point of view of engineering, that's a good thing ... because what that default value should be depends on the application.

In Java, object fields are always initialised to something (number types to zero, object types to null) ... unless, of course, you assign it yourself to some initial value in the declaration (which I always do, even when that value is zero or null). But do you know to what value Java char fields are auto-initialised?

Java has a different rule for local variables (declared within methods or constructors). For these, there is no automatic initialisation of values (same as occam-pi) and, if your code tries to use those values, the compiler declares an error and refuses to compile. That is a good thing ... and, IMHO, Java should have this rule for object fields as well.

The occam-pi compiler only issues warnings about uninitialised variables, but lets them compile anyway. This is a temporary state ... because something has broken in the uninitialised tracking logic of the compiler and, when things get more complex, it gets this wrong, :(. When this gets fixed, these compiler warnings will be replaced with errors and the compilation refused. Meanwhile, take seriously all compiler warnings and ask yourself if you need to respond!

So, what happens if you use the value of an uninitialised occam-pi variable and have ignored the warning from the compiler? Well, the variable gets the bit-pattern left in whatever piece of memory it's been allocated ... which could be anything (especially for pieces of memory re-allocated during runtime).

However, for security reasons, many runtimes clear all memory to zero before running a program.

The Transterpreter takes the same care, but (I need to check this!) clears all memory to the bit-pattern "10101010101010101010101010101010" (which is -1431655766 in decimal ... I think!), just because that is a value that is most unlikely to be the default value you want ... and you will notice this ... and do something about it!

For the same reason, the KRoC runtime also clears its memory, but less excitingly to the smallest integer (-2147483648).

Clearing memory to zero is not safe, for the same engineering reason that auto-initialising number variables to zero is not safe: for many cases, initialising to zero is what's wanted ... but not for all cases. If we are lazy when coding and rely on auto-initialisation when we shouldn't, the bug from an incorrect variable initialisation to zero (which manifests itself some time later) may be difficult to find. If we are lazy when coding and rely on auto-initialisation at any time, getting an initial value of -1431655766 (or -2147483648) will probably be more noticeable!

Keywords: initial , q2


Question 9 (2011):

Submission reference: IN2039

Regarding the integrate process, I was confused on how the network was initiated. Is the following explanation correct?

Thinking sequentially, from the network diagram, it appears to begin with a number read in by the plus component. plus requires two inputs, so my thought was that the network would deadlock since only a single number could possibly be read in.

However, since all components are ran in parallel, the network is in-fact initiated by the *prefix* component. prefix outputs a 0, which is read in by plus (as well as the input number), passed to delta, with prefix copying the stream from delta from then on.

Answer 9:

Thank you for this question. Apologies for this lengthy reply ...

Thinking sequentially about a parallel network is not a good idea. The network does not begin with, nor is it initiated by, any of its parallel components. All its components start independently and in whatever order they happen to get going.

The platform on which the components run does not matter. They could be physically separate pieces of silicon real-estate, part of a larger chip, in which case the order in which they power up is indeterminate (though separated by nanoseconds). They could be on different computers in the cloud (in separate parts of the planet), in which case the order in which they start is also indeterminate (and may be hours apart). They could be software scheduled on a single core (as is the case with the Transterpreter) – in which case the order they are scheduled is still indeterminate! On some magic platform of the future, they might even start up simultaneously (though the Special Theory of Relativity pours scorn on the idea of simultaneity).

The point is that PAR components start in any order and that order does not matter! So, stop worrying about which component physically starts first.

In the case of the integrate process, its components' first actions are to communicate either between each other or with devices external to integrate. Indeed, apart from the addition in the plus component, there is nothing else that they do!

Other components (of other PARs) may get on with lots of computation (e.g. calculate pi to a billion decimal places, invert some very large matrices) before any communication. If those components are placed on separate computational engines (e.g. separate cores on a microprocessor or separate computers in the cloud), then their computations can proceed in parallel (i.e. at the same time). Clearly, the order in which they actually start is not relevant.

Back with integrate, because they communicate with each other, we do need to consider the patterns (i.e. sequences) of communication that are possible. In general (and in this case), there can be several.

The last paragraph in your question pretty much says it right.

The above bullets, however, do not describe all the possible initial patterns of communication!

For example, in the fourth bullet above, the second input value could be taken (it it is being offered by some external device) by plus (actually, by one if its freshly spawned sub-processes). So, that second external input could happen inteleaved anywhere between the two outputs from delta described in this bullet.

Do not be alarmed by all these different possible sequences in which the communications may happen. Apart from getting a feel for the rules of synchronised communication (fundemental to the occam-pi/CSP concurrency model), we don't need to think at this low-level about what is actually happening! A crucial property of the occam-pi/CSP concurrency algebra is that the function performed by a network is deterministic (i.e. independent of the order in which events actually happen). For integrate, its outputs are the running sums of its inputs, regardless of the order of its internal actions.

At least, that's the story so far ...

In lecture 6, we will introduce Choice mechanisms that are provided so that we can design processes whose functions are determined by the order in which events happen. However, the nice thing about occam-pi is that we only get non-determinism by explicitly programming it. For almost all other concurrency models, non-determinacy is the default mode of operation (which means that the understanding we had about serial coding no longer applies) and we have to become skillful in eliminating it ... and that turns out to be very hard ...

With occam-pi/CSP concurrency, our intuition about serial programming remains trustworthy. For example, a variable only changes its value if the code working on it changes its value. There's no guarantee of that with, for example, threads-and-locks concurrency – i.e. what you see is not what you get.

[Aside: in most Object Oriented languages (including Java), the position is even worse ... that guarantee does not even apply to purely serial programming ... but that's another story ...]

Keywords: q2 , non-determinism , choice , alt


Question 8 (2011):

Submission reference: IN2038

Why can you not use id() in a SEQ? For example:

    SEQ
      id (in0?, out!) 
      id (in1?, out!) --This line is ignored or never outputted

but you can use another solution which involves copying between chan and int and that works fine? (Essentially rewriting id.)

Answer 8:

The id() process has a never-ending loop, so never terminates. Asking for something to be done after an id() process has finished is, therefore, pointless – the asked-for something will never be reached.

Generally, we use an id() process in PAR with other processes, connected to them via channels on which it receives and sends data – its function in such circuits being a one-place buffer.

I don't understand what you mean by: "involves copying between chan and int"? What chan (channel?) and what int (integer?)?

Keywords: q2

2008

Question 11 (2008):

Submission reference: IN1526

Is the differentiate process the only part of Assignment 2? It just seems too easy.

Answer 11:

Yes!

It's not meant to be hard. Working out a correct circuit means you understand how to design and reason about concurrent process networks. You have achieved one of the primary learning goals of this module, :).

Keywords: q2


Question 10 (2008):

Submission reference: IN1512

For Q2, is there a way I can identify the cause of deadlocks in windows?

I've swapped out a component (to test that most of the proc works), got parameters right and everything for what I swapped out, and yet I keep getting a deadlock.

Answer 10:

I'm afraid there is currently no debugging support for deadlocks in occam-pi (under either the Transterpreter or the kroc compiler).

Your system should be designed free from deadlocks, so that you don't have to debug for it! However, encountering deadlock at this early stage will be a very good learning experience. Deadlock happens in occam-pi for two reasons only:

Keywords: q2


Question 8 (2008):

Submission reference: IN1513

If there are several processes and they are all waiting for input from another in a parallel set of processes, such as:

  PAR
    procA (a?, b!)
    procB (b?, c!)
    procC (c?, a!)

Is there a way of instantiating c, for example, for the first run to kick it all off because I think that's what's causing deadlocks.

This question relates to a problem I am facing in Q2. Thank you.

Answer 8:

First: you are right in that if you connect n processes in a ring network and each process then waits for input from the one upstream, the result is deadlock. Everyone is waiting for someone to do something!

We could eliminate that immediate deadlock by injecting something into the ring (e.g. with a prefix process). With your example, the same thing can be done directly by doing that prefix explicitly - e.g. kicking something off on the 'c' channel:

  PAR
    procA (a?, b!)         -- one process
    SEQ                    -- second process
      c ! something        -- still second process
      procB (b?, c!)       -- still second process
    procC (c?, a!)         -- third process

However, Q2 is best answered without tricks like this!

Keywords: q2

Referrers: Question 10 (2008)


Question 7 (2008):

Submission reference: IN1511

Question 2 of the first assignment states that we will need a minus process and 2 others, but lists 3 (delta, tail and another I forget the name of). Should we use 3?

If so, should we choose from the list of 3 (since we already have minus)?

Or have I got it totally wrong? If I have got it totally wrong, could you please clarify? Thanks.

Answer 7:

You are asking about Exercise 2, which is the second assignment (not the first).

The question says you need two others from a set of three (delta, tail and prefix). So, don't choose three! Choose two ... you have to work out the right two, of course, and design the circuit that uses them (with the minus process that you still have to write).

You did have things wrong! Are you OK now?

Keywords: q2


Question 6 (2008):

Submission reference: IN1505

Assignment 2 (q2) says not to re-type existing procs: "(e.g. the `Legoland' components 'numbers', 'integrate' ...)".

But I get "Error-occ21-q2.occ(144)- integrate is not a procedure" when I try to use integrate.

However, numbers works fine though, having printed its output to be sure.

Do we actually have to define a new PROC, in contradiction of our instructions, or am I really not getting something?

Thanks.

Answer 6:

Like numbers, integrate is in the course library (imported by the "#INCLUDE "course.module" line at the start of your q2.occ starter file). You must invoke it correctly, of course, with the correct number and type of arguments. Documentation for the libraries packaged with the standard occam-pi release are linked from the Co631 web page. The relevant library here is the one on demonstration networks. Others are demonstration cycles and a whole bunch of stuff for terminal i/o.

Keywords: q2


Question 4 (2008):

Submission reference: IN1502

Hi, I am having trouble outputting the initial zero, in exercise 2 of the first assessment. I currently have the following for the body of my differentiate process:

  ...  omitted
At present, this is just outputting zeros every time. When I remove the <deleted> line however, it outputs correctly just without that initial zero. I'd be grateful if you could point me in the right direction as to where I may be going wrong. Many Thanks.

Answer 4:

Sorry – there was too much detail in the code in your question to pass on. See the note at the top of each Q&A page: "please do not simply paste in your code and ask what is wrong with it ...".

The only feedback I can give is that the code you sent does indeed produce nothing but zeroes. That is reasonably clear from looking at (and not running) the code ... I'm afraid it's just wrong. It can, however, be quickly corrected ... the basic approach is sound ... you just have the wrong circuit.

Keywords: q2

2006

Question 34 (2006):

Submission reference: IN987

In the older answers, you mention model answers. Are these still available to look at?

Answer 34:

OK - I've put model answers to completing q1.occ, q2.occ, q3.occ and q4.occ in the raptor folder:

    \courses\co631\answers\

Keywords: q1 , q2 , q3 , q4

2003

Question 7 (2003):

In the method `tabulate.int' from q2.occ, how does the sequence:

    SEQ
      in ? n
      out.int (n, 15, out)
      out.string ("*c*n", 0, out)

work ?

I'm curious because I'd like to make a:

    PROC testing (CHAN OF BYTE in, CHAN OF INT out)

procedure/method for testing purposes. In other words, how does the conversion work and is it basically the same to convert the other way around?

Answer 7:

The conversion from an `INT' value to the sequence of decimal digits that represents it is performed inside `out.int'. Essentially it involves a sequence of `modulo 10' then `divide-by 10', until the value is zero. It's mildly more complicated since the digits are generated in the reverse order.

The code for `out.int' can be found on raptor in:

    /usr/local/courses/co516/libsrc/utils.occ

Converting the other way is, as you suspect, largely the reverse. However, it's already been programmed for you (also in `utils.occ'):

    PROC ask.int (VAL []BYTE prompt, INT n, VAL INT max, CHAN OF BYTE in, out)

As an example, your `testing' PROC can be implemented with:

    PROC testing (CHAN OF BYTE in, out, CHAN OF INT vals.out)
      WHILE TRUE
        INT n:
        SEQ
          ask.int ("Enter a number: ", n, 11, in, out)
          vals.out ! n
    :

The `in' and `out' channels should be wired to the keyboard and screen respectively. The screen channel is needed so that characters can be echo'd as typed, in addition to displaying the prompt. `ask.int' handles all the unpleasantness of keyboard input, such as rejecting invalid characters and handling backspace properly.

The `max' parameter specifies the maximum number of digits that may be entered, inclusive of any leading `+' or `-'.

Keywords: q2 , output , conversion


Question 5 (2003):

How do we submit the occam coursework due in next week ?

Answer 5:

You should print out your code and submit it with a cover-sheet to CAS reception. Remember also to include a network diagram of your `differentiate' process. You can do the diagram in ASCII-art, print it separately, or hand-draw it (neatly, please!).

Keywords: q2 , submission


Question 4 (2003):

In question 2 we display the numbers on the screen. Trouble is that the numbers go too fast and end up giving a fatal error. Is their a way, or a command, to show a window's worth and than wait for you to push a button. Also, what output should we be getting from numbers anyway.

Answer 4:

You can pipe the output through "more", e.g.

    ./q2 | more

Hitting the space bar will give you another screenful of output. Pressing `control-c' will interrupt it, but that leaves the terminal in a funny state, with echoing turned off. Type (blind)

    stty sane

to restore sanity.

The fatal error that occurs is usually integer overflow. Don't worry too much about this yet, but in general, it is an important consideration for software systems. Integer overflow in question 2 ought not to happen until a significant number of values have been input. If it overflows early, there's probably a problem with your code/network.

The `numbers' process generates the sequence `0, 1, 2, 3, 4, ...', forever. After being sent through `integrate' and your `differentiate', you should get the same sequence (0, 1, 2, 3, ...).

There are executable answers in `/usr/local/courses/co516/answers' on raptor, for all 7 questions.

Keywords: fast-output , q2

Referrers: Question 6 (2003)


Question 3 (2003):

I seem to have some problems when I run q1.occ and q2.occ. They both compile but when i run them I get:

    Program deadlock: no process to run.

What am I doing wrong ?

Answer 3:

This generally means that your program deadlocked before anything useful happened. A common error is mis-construction of the top-level process, using `SEQ' instead of `PAR'.

If you have access to KRoC on a Linux system, compile the program with the `-d' flag (debugging). When the system deadlocks, it will report the location (in the source file(s)) of deadlocked processes, e.g.:

linux$ kroc -d q1.occ -lcourse
kroc: Selecting post-mortem debugging
Warning-oc-q1.occ(40)- Parameter error is not used
Warning-oc-q1.occ(40)- Parameter keyboard is not used

linux$ ./q1
KRoC: Deadlock:

  Instruction "OUTWORD"
    in PROC "A"
    in file "q1.occ"
    near line 29

In this case, the system deadlocked with the `A' PROC trying to perform an output (line 29 in this particular q1.occ). Note that this will not work with the version of KRoC on raptor. It will, however, work on gonzo.

Keywords: q2 , deadlock

2001

Question 4 (2001):

When is our first assignment (q2.occ) due?

Answer 4:

A hard-copy listing of your source code should be handed in to the CAS office by close of service (around 4pm) on Thursday, 8th. November, 2001. Cover sheets will be made available next week.

Note: remember that your differentiate process should be implemented in the same style as the implementation of integrate -- i.e. as a network of simple components of the level of those in the demo_cycles.occ library (see slides 5-3 and 5-8). This requirement is made in the comments in your q2.occ starter file. A solution for differentiate in the form of a single serial process will get a maximum of 6 out of 10. [See also the Hint: given in those comments.]

Note: you must include network diagrams of your differentiate and q2 processes (the latter contains your test rig). These can be hand-drawn neatly on your hard-copy listing or machine-drawn on other paper and stapled to your listing. The diagrams should be annotated with process/channel names that correspond to those used in your code. Channels should be arrowed to show the direction of data-flow. Also, think carefully about the icon you choose to represent the minus component. Unlike plus, minus is not symmetric over its input channels and your icon must reflect this. When looking at its use in a network diagram, we must be able to tell which channel numbers are being subtracted from which.

Note: your source code must be adequately (but not over-) commented, should use meaningful variable names and be well laid out. Of course, you have no choice in indentation layout (;-), but spacing within lines and between them (e.g. between PROC declarations) helps readability (and marking!).

Note: comments in occam source code are introduced by two dashes, --, and include everything following this symbol to the end of the line. [This works like // in Java.]

Keywords: q2 , diagrams , comments

Referrers: Question 6 (2001) , Question 6 (2001) , Question 12 (2001)


Question 2 (2001):

Hi, I have completed the first assesed exercies question 2. However, the minus I made to do it is a little weird. It has two input channels and two output channels - is this a problem? Does it matter what it looks like or is it fine as long as it works?

Answer 2:

Your minus sounds weird indeed! "As long as it works ..." is never good enough though. Solutions must work and it must be easy to see how they work. So, as long as you document clearly what your two-output minus does and how this helps solve the question, that will be fine.

Keywords: q2

2000

Question 15 (2000):

Please could you tell me who, and where, do we submit this assignment (q2) to?

Answer 15:

As explained in the seminars, you must submit hard copy listing plus diagrams (see answer to Question 14 (2000)), attached to a cover sheet, to the CAS office by their close of business this Thursday (9th. November). Cover sheets were given out during seminars or may be obtained from the Co516 pigeon hole near CAS reception.

Keywords: q2 , submission


Question 14 (2000):

I have completed q2.occ and as far as I can make out, it works!!!

My class supervisor said we had to produce 2 chip diagrams to hand in as part of our assignment. Am I right in thinking they are:

Is there any particular program I should use to create the diagrams? I done them in Word, using the flowchart symbols, but it don't look that great.

Also, how do I print my source code from Origami on a public PC????

Answer 14:

Yes to your first question - you do have to submit these two diagrams as well as your code listing.

No to your second question - the quickest thing is simply to draw them neatly by hand on your listing (next to the occam code that implements each diagram).

Origami doesn't have a print command. The files it produces are, of course, plain text. So you could pick up q2.occ (say) in a Windows editor (e.g. PFE) and print from there. Or you can print the file directly from Unix.

To help with the latter, there are two commands (pt and pq) in the etc directory in the course area:

  /usr/local/work/co516/etc/pt
  /usr/local/work/co516/etc/pq

If you haven't already done so, make a bin directory in your home directory and copy the above files over to it:

  mkdir ~/bin
  cp /usr/local/work/co516/etc/p* ~/bin

Then, set this ~/bin directory to be the first item in your path environment variable. This can be done by editing the definition of that variable in the .cshrc file in your home directory (if you are using the C-shell) or the .bash_profile file in your home directory (if you are using bash). If your unix command prompt ends with %, then you are using C-shell - if it ends in $, you are using bash. The syntax of how to set these environment variables is different for the different shells - but you can work it out from how they are already defined.

Once the above has been done, to print a file (say q2.occ) to a printer (say myprinter), the command is:

  pt q2.occ myprinter

To inspect the print-queue on a printer (say myprinter), the command is:

  pq myprinter

Keywords: diagrams , q2 , printing

Referrers: Question 15 (2000)


Question 13 (2000):

I am doing q2. When I run it I can't tell if it is working properly because once I break, I can't scroll up and see whether the 0 appears in the output. Is there any way of dumping my ouput to a file so I can see it all?

Answer 13:

The simplest answer is to get a scroll bar - see the answer to Question 9 (2000) to find out how to get one.

It is possible to redirect your output to a file - but, in this case, that's not a good idea since the output is infinite and you will flood the disc!

Simpler is to pipe your output through the Unix more utility:

  q2 | more

Now, you only get a screenful at a time. Press carriage-return to see one more line or space for a further screenful. To end your program, type ctl-C. Warning: do not type q to quit the more program. That sends a broken pipe signal to the occam process which doesn't handle it properly. Your occam program will exit but not reset keyboard input to echo mode. That means that you get back to the Unix prompt and type in commands ... but you won't see those commands. To restore things to normal, type in (blindly!):

  stty sane

and you will now be able to see what you type again.

An alternative to all this is to slow down the output so that you can read it! For example, put in a tenth of a second delay after printing each output line. Then, only 10 lines per second will be displayed and you will have time to check if your output sequence starts with a zero. One way to do this is to modify the tabulate.int (see the latest version of q2.occ) as follows:

  PROC tabulate.int (CHAN OF INT in, CHAN OF BYTE out)
    WHILE TRUE
      INT n:
      SEQ
        in ? n
        out.int (n, 15, out)
        out.string ("*c*n", 0, out)
        --{{{  delay 100 milliseconds
        TIMER tim:
        VAL INT milliseconds IS 1000:    -- TIMERs measure microseconds
        INT t:
        SEQ
          tim ? t
          tim ? AFTER t PLUS 100*milliseconds
        --}}}
  :

Keywords: q2 , output

Referrers: Question 24 (2003) , Question 7 (2001)


Question 11 (2000):

We were told in our class that there is a process called minus that we can use in answering question 2. If this is the case, then where is the process as it's not in demo_nets or demo_cycles? If this is not true, then can we make up process called minus?

Answer 11:

You must have mis-heard. There is no process called minus in the course library. For question 2, you must make up your own - use the process called plus, which is in the library (in demo_cycles) and which was presented in today's lecture (slide 5-5), as a model.

Keywords: q2

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:30 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.