0% found this document useful (0 votes)
31 views

Cvs

Uploaded by

Cassiano Avelar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views

Cvs

Uploaded by

Cassiano Avelar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

BRL-CAD Concurrent Versions System Policy and Guidelines

========================================================

**********************************************************************
NOTE: THESE INSTRUCTIONS ARE OUT-OF-DATE AS BRL-CAD NOW USES
SUBVERSION INSTEAD OF CVS. CONSULT WITH CAUTION AS SOME PORTIONS ARE
STILL RELEVANT BUT OTHERS THAT ARE CVS-SPECIFIC ARE NOT.
**********************************************************************

The document includes a set of requirements and recommended procedures


for how to effectively use CVS with this project. Included are
details on checking code in and out, effective use of commit messages,
tag naming conventions, branch management, making releases, and more.
Basic knowledge of CVS, its capabilities, and to a lesser extent its
limitations are beyond the scope of this document. See the CVS
website and the "References" section for more information. That said,
the following general rules should always be adhered to:

1. Code committed against HEAD should at least be tested and compile


for the developer committing changes. "Don't break it."

2. There is a STABLE branch that may only have code committed against
it that a) compiles on all relevant platforms, b) does not
detrimentally degrade performance, and c) runs correctly passing
available validation tests.

3. Branches should be used for experimental work that would otherwise


leave HEAD in an inconsistent, non-compiling, or untestable state.
Branches are not merged into HEAD until the code has been tested
for correct and proper functionality.

4. Commit and update frequently. Large or complicated changes should


be broken up into smaller succinct commits as best possible to make
reviewing easier. Commit working code early and commit often.

5. Be consistent and informative. Tags need to follow a consistent


naming convention. Commit messages need to be informative. Source
code changes should follow existing style and be usefully
commented.

TABLE OF CONTENTS
-----------------
Introduction
Table of Contents
Overview
Checking out sources
from HEAD
from STABLE
from a branch/revision
Checking in sources
commit messages
to HEAD
to STABLE
to a branch/revision
Tag naming convention
for releases
for branches
Making a release
creating a maintenance branch
applying release patches
Merging a branch
merging a branch into HEAD
merging HEAD into a branch
Making a branch
Usage Tips
References

OVERVIEW
--------

Code organizational sanity and consistency are of paramount


importance. As CVS can both help and hinder efforts to keep the
sources organized, the policy and guidelines outlined herein
overview the manner in which CVS should be used with this project.

This CVS policy and guidelines document should be used in


combination with a developer's guide that covers other aspects of
code contributions and developer behavior such as how and where to
provide patches, what coding styles should be used, and how to
make releases. Likewise, exact semantics of testing policy,
requirements for migrating code from HEAD to STABLE, basic CVS
usage, and release policy are outside the scope of this document.

The intent of this document is to cover the broad aspects of how


CVS is to be organized and used. This includes branch management,
tag naming conventions, checking sources in and out, and other
relevant usage policy.

CVS branches should be used to separate out the various types of


source code revisions. These include:

1) current or "active" sources


2) stable sources
3) releases
4) experimental sources

The CVS HEAD is for active development. A separate STABLE branch


exists to hold a revision of the sources that is validated and
tested across platforms. Releases should only made off of stable
revisions of the source code. When a release is made, a
maintenance branch may and should exist for making patch releases.
Finally, various experimental and developer undertakings that may
benefit by being isolated from changes to HEAD or STABLE, or would
likewise be disruptive to normal HEAD functionality, may live on
a branch of their own.

It's very important that the main CVS HEAD revision be a "mostly"
stable code base so that at any given time users may download the
latest sources, get the source code to compile with minimal
effort, and have the core components mostly function as expected.
See the "Checking in sources to HEAD" section for more details.

Some users and developers will need from time to time to obtain a
relatively recent version of the sources that is certain or at
least expected to "work". This is what the STABLE branch is for.
See the "Checking in sources to STABLE" section for more
information.

CHECKING OUT SOURCES


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

There are two basic ways to check out the sources: anonymously or
as a developer. Developers have full read-write access to the
source code. Anonymous users have read-only access; and the
version of the sources checked out may actually lag the most
recent commits by several hours.

Regardless of whether the sources are being checked out by a


developer or anonymously, CVS_RSH should be set to "ssh".

Anonymous users will need to login first:

cvs -d :pserver:[email protected]:/cvsroot/brlcad login

Once logged in, the access method for anonymous users will be via
:pserver: (provide an empty password if prompted). Developers
will checkout using the default implicit :ext: method and will
need to provide an authorized username. Be sure to use the "-P"
checkout option to remove (prune) empty directories. The "-z9"
global CVS option is encouraged to minimize network utilization.

FROM HEAD:

As anonymous:
cvs -z9 -d :pserver:[email protected]:/cvsroot/brlcad checkout -P
brlcad

As a developer:
cvs -z9 -d <username>@brlcad.cvs.sf.net:/cvsroot/brlcad checkout -P brlcad

FROM STABLE:

Checking out from STABLE is like checking out from any specific
revision or branch -- provide the tag name upon checkout:

As anonymous:
cvs -z9 -d :pserver:[email protected]:/cvsroot/brlcad checkout -P
-r STABLE brlcad

As a developer:
cvs -z9 -d <username>@brlcad.cvs.sf.net:/cvsroot/brlcad checkout -P -r STABLE
brlcad

FROM A BRANCH/REVISION:

The process for checking out a given revision number is pretty


much a matter of knowing which revision tag name is desired, and
then checking out with that symbolic tag name:
As anonymous:
cvs -z9 -d :pserver:[email protected]:/cvsroot/brlcad checkout -P
-r <tagname> brlcad

As a developer:
cvs -z9 -d <username>@brlcad.cvs.sf.net:/cvsroot/brlcad checkout -P -r
<tagname> brlcad

If the tag names are not known, you can check out HEAD or STABLE
and perform a "cvs log" on any file to see the known tag names:

cd brlcad
cvs status -v README

Once you find the revision or branch tag name in question, you can
"cvs update" to that revision:

cvs -z9 update -r <tagname>

See the CVS manual documentation for more information.

CHECKING IN SOURCES
-------------------

Commit access is generally provided on a case-by-case basis as the


need arises after careful consideration of the individual's
ability to follow the project's coding style, follow this CVS
commit policy, and work productively with the other developers.
If you have to ask for commit access, you probably won't get it.
So don't ask. Provide patches and interact with the existing
developers.

If you are given commit access, you are expected to


read and follow this policy and its guidelines as well as the
developer's guide.

COMMIT MESSAGES:

When code is committed to CVS, a commit message should be provided


that appropriately describes the change in a succinct and useful
manner. It's important to remember that CVS commit comments are
stored per-file. Care should be taken to not be vague,
undescriptive, or ambiguous often tailoring commit messages to
individual files even if the change was made as part of a larger
modification.

While the comments need to be descriptive and informative, they


should also be as short and to the point as possible. The CVS
commit comments are not the appropriate place for legal
disclaimers, usage documentation, extensive debugging details,
business politics, or mini novels of who/what/when/where/why.

They should be no more than a few lines long at most, normally


only consisting of a short single-line statement. CVS commit
comments are for documenting changes so that other developers may
derive a clue about what the change was without necessarily
needing to look at the actual source differences.
Instead of making generic statements about fixing or improving the
source code, succinctly describe the change in a manner that may
be useful for someone else reading the comment that is not
familiar with the change. If the changes are merely formatting or
whitespace adjustments, a simple commit message of "ws" or "M-x
indent-region" is generally understood and sufficient.

If a file is being moved/renamed, the comment should include both


where the file is moved from and where it was moved to in the
message, e.g. "moved from librt/bool.c to src/librt/bool.c".

TO HEAD:

It's very important that the main CVS HEAD revision be a "mostly"
stable code base so that at any given time users may download the
latest source, get it to compile with minimal effort, and have the
core components mostly function as expected. HEAD is where active
development takes places, so this necessarily means that there may
be small windows of opportunity where the sources do not compile,
but those should not persist. Likewise, since the developers
potentially and often have specific or relatively independent
development efforts, the CVS commits of one developer should be
made in a means that will have limited or understood impact on
other developers.

This minimally means that CVS commits need to at least work for
the developer committing the changes. If it's discovered that the
changes break other major supported platforms, the broken state
should not be allowed to linger. Effort and arrangements need to
be made to either resolve the problem promptly or the changes
should be reverted.

TO STABLE:

Code being committed to STABLE require special attention and just


a little more detail in their commit messages.

Some users and developers will need from time to time to obtain a
relatively recent version of the sources but a version that is
certain or at least expected to "work". This shall be known as
the STABLE branch. For code to make it to the STABLE branch, it
needs to pass several criteria and commits should be well
documented indicating the nature, purpose, and impact of the
change. These criteria include the following:

a) Compiles -- The code must compile on all supported platforms.


This generally requires coordination with other developers if
access to other platforms is limited.

b) Improves -- Without reasonable justification, the changes must


not degrade performance, be inconsistent in style or behavior
of the sources, or break support for existing functionality.

c) Passes -- The changes must successfully pass any available


validation tests. If the tests are flawed or simply require
modification, justification and explanation should be provided
along with fixes to the tests before submitting code that would
otherwise not pass validation.

TO A BRANCH/REVISION:

Checking in code to a branch other than STABLE generally do not


necessarily need to follow the same requirements of compiling
cleaning or "working" until those changes are merged back in to
either STABLE or HEAD unless the branch is a release maintenance
branch. Release maintenance branches generally follow the same
commit rules as checking into HEAD.

As it's not possible to commit against a non-branch checkout (such


as a release tag export like "rel-7-0"), changes to a revision
that is otherwise immutable can still be made by performing a
"diff" against a clean checkout of that same revision (unmodified)
and then applying the patch to a maintenance branch or to the CVS
HEAD. See the "Applying release patches" under "Making a release"
for examples.

TAG NAMING CONVENTIONS


----------------------
<keyword>[-<revision>][-<date>][-<comment>]

<keyword> ::= { rel, ansi, jra, sean, ppc, ... }

The <keyword> is normally something short and concise. For


release tags, it is "rel". Other branch keywords may indicate
functionality, developers, etc.

<revision> ::= <major>[-<minor>[-<patch>]] (e.g., 6-0-2 and 5-2)

The <revision> numbering convention is fairly standard and


common practice:

<major> is the major revision number and changes relatively


infrequently. Major releases contain significant
architectural changes and are not generally backwards
compatible with existing code or data to some extent.
They may require data and/or code to be converted in
order to upgrade.

<minor> is the minor revision number a usually changes on a


fairly regular basis. As new features are added and
releases are made, the minor revision number changes
to reflect those additions. Odd minor numbers
indicate a developer revision. Even minor numbers
indicate a release revision. Minor releases may or
may not be backwards compatible.

<patch> is the patch revision number and is used to make bug


fixes on an as-needed basis. These changes are not
usually as extensively tested as minor and major
releases, but they should always be backwards
compatible.

<date> := YYYYMMDD (e.g., 20021231)


When creating tags, the date a tag is made is sometimes noted
and useful or even recommended. The format of the date is
YYYYMMDD and should correspond to tag creation dates. Branch
and release tags should not include a date in the tag name.

<comment>

For branches the comment is "branch". For releases, it is


left blank. For other miscellaneous tags, the comment is up
to the person tagging.

Note that hyphens (-) are used, not underscores. Periods (.) are
never used because they upset CVS's branch naming.

Tag names (including branches) should be in lower case only.


Upper case is reserved for HEAD and STABLE.

Non-branch tags are used for 1) marking a release, 2) merging


branches, and 3) miscellaneous tags (e.g., to remember a specific
starting or stopping point).

FOR RELEASES:

Release tags are used to indicate a revision of the source


code that was made publicly available. It should match the
sources released, bugs and all, so that proper and useful
diffs may be made. The format for release tags is:

rel-<revision>

<revision> ::= <major>-<minor>[-<patch>]

The revision number should match the version reported by


the source code.

Examples: rel-6-0 rel-7-2-5

FOR BRANCHES:

Branches are symbolic tags that are used to denote and allow
separate isolated revisions of code. The following format
should be used for branch tags:

<keyword>[-<revision>]-branch

<keyword> ::= describes the purpose of the branch.

If the branch is a maintenance branch, the keyword should


match the revision's keyword and revision.

Examples: rel-7-0-branch ansi-branch photonmap-branch

FORMAT FOR MERGES:

When joining a branch that has a large set of changes into


HEAD, there should be a tag before and after the merge. When
joining HEAD into a branch, tagging is optional. Joins into
head should be tagged, though.

On HEAD before the merge, use the following tag format:

premerge[-<revision>][-<date>]-<comment>

Example: premerge-20040404-ansi

On HEAD after the merge, use the following tag format:

postmerge[-<revision>][-<date>]-<comment>

Example: postmerge-20040315-windows

The <comment> should be a simple identifying keyword. The


branch keyword being merged suffices quite well. A date is
preferred.

If development on a particular branch is considered "final",


it should be marked with a "freeze" tag on the branch:

<keyword>[-<revision>][-<date>]-freeze

Example: windows-20040315-freeze

If applying patches directly to the CVS HEAD where there is


potential to need to revert the changes, using "pre" and
"post" as the tag comment is appropriate.

<keyword>[-<revision>][-<date>]-pre
<keyword>[-<revision>][-<date>]-post

Examples: hartley-6-0-pre ctj-4-5-post offsite-5-3-pre

FORMAT FOR MISCELLANEOUS TAGS:

For everything else, the basic structure of the tags still


applies. Lower case, dash-separated, and hopefully succinctly
informative tag names should be used. Dates are highly
recommended as CVS tags are not associated by date, but rather
to the individual revision of a file.

<keyword>[-<revision>][-<date>][-<comment>]

When in doubt, tag. It's easy to remove or rename tags, but it


can be rather complicated to create one after the fact.

MAKING A RELEASE
----------------

Making a release is generally a matter of making sure that all


desired code changes are committed and well tested. Code
committed to HEAD should be well tested by performing any
validation steps required to migrate those changes to STABLE.
Once HEAD is verified, it may be joined into STABLE, which should
likewise be thoroughly tested.

Once all the code is verified, the release should be tagged:

cvs tag rel-<revision>

Revision numbers should follow a numbering convention consistent


with the developer guidelines. Minor and patch revision numbers
that are odd numbered are used to denote developer revisions of
the source code. Release tags should use even numbers for the
minor and patch revision numbers. See the "Tag naming convention"
section for more details.

CREATING A MAINTENANCE BRANCH:

If minor maintenance is expected to continue or development on


HEAD needs to continue in an incompatible manner, a maintenance
branch should be made:

cvs rtag -r rel-<revision> -b rel-<revision>-branch

That will create a branch named rel-<revision>-branch anchored at


the same revision of the sources as rel-<revision>.

APPLYING RELEASE PATCHES:

In general, unified diff patches should be requested from people


providing patches whenever possible. For people working with a
cvs checkout, generating a diff is generally a simple matter of
running:

cvs diff -u > my.patch

This will create a unified diff patch file called "my.patch" that
is trivially applied to a checkout using the patch command:

patch -p0 < my.patch

Assuming there have not been overlapping/conflicting changes,


patch should say on the first attempt that all chunks were
successfully applied. If not, there will be reject files that
will have changes that need to be manually reviewed and resolved..

Users who are perhaps working off of a source tarball instead of a


CVS checkout can fairly easily generate a unified diff patch by
comparing their modified tree against an unmodified source tree:

diff -u brlcad brlcad.modified > my.patch

In this example, brlcad is an unmodified top-level source


directory and "brlcad.modified" is a top-level source directory
that has been modified. That same patch file may then be applied
to a checkout and committed to CVS.

If there is an active maintenance branch that a patch was started


from, it is generally easier to apply the patch to the maintenance
branch first and then join the maintenance branch into HEAD per
the usual means to join branch changes into HEAD instead of
merging directly into the CVS HEAD. HEAD will have often changed
too significantly and may result in patch being unable to resolve
chunks. See the patch manual documentation for more details.

Failing any of the above, patches may also be applied manually.


This is often even desirable to become more familiar with the
changes being made providing an opportunity for a healthy peer
review.

MERGING A BRANCH
----------------
CVS branches can be both very useful or difficult. Proper usage
of branches generally requires a firm understanding of CVS
otherwise complications and mistakes are bound to happen as there
are several usage pitfalls. Following the directions shown below
should help avoid the pitfalls and assist in making effective use
of a CVS branch.

Regardless if the branch is a maintenance branch or the STABLE


branch, the fundamental "action" in performing a merge is called a
CVS join. You can join code committed to one branch revision into
another branch revision by passing the "-j" option to the cvs
update command. It's important to note that joins occur from code
that is already committed.

Once the code is joined, it may be committed to CVS. If you have


changes on a branch that have not yet been committed, they should
first be committed before attempting the join.

MERGING A BRANCH INTO HEAD:

Merging branches in CVS is generally a matter of "joining" in the


changes from one the branch revision into another branch revision.
HEAD can itself be considered a branch. If, for example, you have
a maintenance branch named "rel-7-0-branch" that has had changes
applied to it and you wish to apply those same changes to HEAD you
would checkout HEAD:

cvs -z9 -d <CVSROOT> checkout -kk -P brlcad

The join the changes from the desired branch:

cvs update -kk -dP


cvs tag premerge-<revision>-<date>-<comment>
cvs update -kk -dP -j rel-7-0-branch
[ resolve conflicts & test ]
cvs commit
cvs tag postmerge-<revision>-<date>-<comment>

The comment should contain or be the keyword of the branch being


merged in. For example, "premerge-20040315-windows" indicates a
merge that occurred on March 15th, 2004, from the windows-branch.

If there are any conflicts, they would of course need to be


manually resolved. Once any conflicts are resolved and the
sources are tested for functionality, the changes could then be
committed to HEAD. Be careful to notice any file additions or
deletions as CVS, generally speaking, will not manage those for
you until they are committed.

In both the checkout and the join update, the -kk flag was used to
cause CVS to not expand the CVS variables such as \$Revision\$ and
\$Id\$. If those keyword variables are expanded, you're likely to
have many conflicts depending on time-stamps.

If the branch being checked in an extensive set of changes,


testing is essential. It is also a good idea to warn other
developers of what you are planning to do. You should indicate
what parts of the system will be affected and coordinate in detail
with other developers as appropriate.

MERGING HEAD INTO A BRANCH:

Merging changes from HEAD into a branch (such as STABLE) is not


really any different than the scenario described for merging a
branch into HEAD. Again, HEAD itself can be simply considered a
branch too. For example with an existing branch checkout:

cvs update -kk


cvs update -kk -j HEAD
[resolve conflicts & test ]
cvs commit

The important step to realize is that your working checkout needs


to be the revision you want to join changes into. When in doubt,
commit all your changes to the appropriate branch, delete all your
sources, and checkout fresh. "cvs status README" will tell you
what revision you have checked out. It will be listed as a
"Sticky Tag".

MAKING A BRANCH
---------------
Making a branch is a matter of using the "-b" option when tagging.
Branch tags are special symbolic CVS tags that allow for isolated
changes and controlled merging of modifications.

CASE 1: You have no checked out source code revision:

If you want to use the latest sources on the CVS HEAD as the
starting point for your branch:

cvs rtag -b <keyword>-branch brlcad


cvs checkout -r <keyword>-branch brlcad

If you want to use some other tag as the starting point for
your branch:

cvs rtag -b -r <tag> <keyword>-branch brlcad


cvs checkout -r <keyword>-branch brlcad

CASE 2: You have a checked out revision with all changes committed
and you want to tag it and start using it as a branch:
cvs tag -b <keyword>-branch
cvs update -dP -r <keyword>-branch

CVS will denote the tag as a "sticky" tag to indicate which


version is currently checked out. You can verify this by using
'cvs status', for example:

cvs status README

To see all tags that have been set for a particular file in
addition to checkout status, use the "-v" status option:

cvs status -v README

or via the generally more detailed file log:

cvs log README

USAGE TIPS
----------
0) Checkout with the -P option to prune empty directories:

cvs checkout -P brlcad

1) Be sure to perform an "update -dP" to check for new directories


from time to time and to prune empty ones.

cvs update -dP

2) Update and commit frequently. Frequent updates are a good


thing. Perform them often to minimize conflicts.

4) A convenient way to check what files have been modified when


you are certain that you've not added files:

cvs -q update | grep -v \?

That performs a quiet update (the directory tree isn't output)


and ignores lines that have a question mark (normally build
files).

3) To avoid having to specify the repository for a checkout, you


can set your CVSROOT environment variable to the location of
the repository:

For anonymous users:


export CVSROOT=:pserver:[email protected]:/cvsroot/brlcad

For developers with accounts:


export CVSROOT=<username>@brlcad.cvs.sf.net:/cvsroot/brlcad

5) CVS does not manage directories so care must be taken when


creating new directories or moving things around. Do NOT add
directories that include non-static information as part of the
directory name. Examples include adding directories that
include a version in their name (e.g. libtcl8), indicate age
(e.g. newRt), or contain other volatile data.
6) If you need to move a directory, rethink why and try not to.
If you still need to move a directory, .. try to find another
way to cope. If you still REALLY need to move a directory, a
little find scripting can make it easy. In case you didn't get
the hint DO NOT MOVE/RENAME DIRECTORIES unless there's a _very_
good reason. This implicitly means that extra care and thought
should be made when naming new directories to be added to the
repository.

7) It is possible to move directories using a little find


scripting. Assuming you've not got build files cluttering
things up and are ready to simply move files to a new location
in CVS, an otherwise complicated task becomes mostly simple
with a few find scripts. Here is an example where a directory
./foo/ is moved to a new location ./src/foo2/:

cd foo
# copy the files to their new home
find . -type d -not -name CVS -exec mkdir -p ../src/foo2/{} \;
find . -type f -not -regex '.*/CVS/.*' -exec cp -p {} ../src/foo2/{} \;
cd ../src
# add the new directories to cvs
find foo2 -type d -not -name CVS -exec cvs add {} \;
find foo2 -type f -not -regex '.*/CVS/.*' -exec cvs add {} \;
# commit the new sources
cvs commit -m "moved from foo to src/foo" foo2
cd ..
# delete the old source subtree
find foo -type f -not -regex '.*/CVS/.*' -exec rm {} \;
find foo -type d -not -name CVS -exec rm -f {} \; -exec cvs delete {} \;
cvs commit -m "moved from foo to src/foo" foo
cvs update -P foo

If you don't have CVS keys set up and have too many files to
move, each find script could be passed to xargs so that only a
single password is prompted instead of one per file. Since
moving/renamed directories in CVS is "bad", though, that's left
as an exercise to the reader.

8) When renaming files, be sure to indicate both where the file


was moved from and where it was moved to and/or the name before
the move and the name after the move. Do this both on
committing the file deletion and on committing the file
addition. This way, people reading the file's log will know
where to find the rest of the file's history.

9) If experiencing trouble consolidating conflicts that involve


CVS "$" variables, set the keyword sticky flag which will tell
CVS to not perform the keyword variable expansions. Perform a
"cvs update -kk" and the conflicts should go away.

10) Denote binary files as binary in CVS via the


CVSROOT/cvswrappers administrative file or via the "-kb" option
when adding files. In the CVSROOT/cvswrappers file, the
following line would denote files ending in ".pix" as binary:

*.pix -k 'b'

You can likewise denote arbitrary files as binary via the "-kb"
option on commit:

cvs add -kb new_file_name_here

If the file has already been added to CVS, it may be


administratively marked as a binary file after the fact using
the "cvs admin" command:

cvs admin -kb some_existing_file


cvs update -A some_existing_file

REFERENCES
----------
This CVS policy and guidelines document was in part derived off
some of the principal ideas of other projects' usage of CVS such
as the Linux Documentation Project, the XFree86 DRI project, Zope,
FreeBSD, and AT&T's SML/NJ among others.

Version Management with CVS


https://www.cvshome.org/docs/manual/

CVS Best Practices


http://www.magic-cauldron.com/cm/cvs-bestpractices/index.html

XFree86 Direct Rendering Infrastructure CvsPolicy


http://dri.sourceforge.net/cgi-bin/moin.cgi/CvsPolicy
http://dri.sourceforge.net/doc/cvspolicy.txt

Zope
http://dev.zope.org/CVS/ZopeReleasePolicy

FreeBSD
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/cvs-tags.html

AT&T SML/NJ
http://www.smlnj.org/DEV/policy.html
http://cm.bell-labs.com/cm/cs/what/smlnj/DEV/policy.html

---
This document was initially written in 2002 and later almost
completely rewritten in 2004 by Christopher Sean Morrison.

You might also like