club3 is a program to schedule a series of meetings of the
club3.tar.bz2 (version 20090823).
Unpack it to create a directory
which contains a shell script called
club3. Put a copy of or soft link to
club3 in your
lisp contains several Lisp files, the main file
club3.lisp. If you move
club3.lisp to a different
location, you must ensure that all the other
.lisp files in the
lisp subdirectory move with it, as code in
that they are in the same directory as itself.
club3 sets and uses an environment variable
identify the directory containing
club3.lisp. Change it to suit you.
club3 also sets and uses an environment variable
LISP to identify
your Common Lisp system. Change to suit you.
*Optional:* You may compile
club3.lisp (using the Common Lisp function
club3.lisp need be explicitly compiled — it will
take care of compiling the other
In a directory that contains all the data relevant to your club, call
club3 with the argument
The data in the current directory serves as input to both calls, and
influences the result. This input data consists of an init file
club3rc.lisp and a subdirectory
past-schedules which contains the
scheduling history of the club. For an example, see
examples/articulators in the distribution.
% club3 schedules
generates schedules. (I.e., type
club3 schedules at your Unix
The schedules consist of a
.txt file for each date
in the calendar (see below), and an HTML file
that lists the schedules as an easy-to-read and -print table. For a
saved example, see
.txt files can be inserted into
below) to influence the course of future schedules (created by future
club3 schedules). Before putting a
.txt file into
past-schedules, it is a good idea to edit this file by hand to ensure
that it accurately records the members who actually performed the roles
(since club members typically negotiate substitutions up to the very
last minute because of unforeseen circumstances).
% club3 profiles
generates member profiles in a subdirectory called
index.html file. Example:
The init file
club3rc.lisp is essential. At the very least, it must
use the operators
calendar to respectively list
the members in the club; the type of meeting lineups used; and the
calendar dates for which schedules are desired.
Other operators such as
number-of-trials are optional: However it is useful
to invoke some or all of them so that the generated schedules are both
equitable and feasible.
club-name help make the output
schedules more readable.
members lists the members in the club, a symbol for each
(members andrew brad charlie dan eileen fran george hilary ian judy
kim lori marcia nelson oliver prasad rick stephanie theresa
ulrich vanessa willy xavier yul zoe)
lineups introduces the various prescribed lineups for the
club’s meetings. Each lineup is a list whose first element is a keyword
describing the type of meeting, and whose second element is a list of
(tm word joke poet speaker speaker speaker
ge eval eval eval topics)))
Roles can repeat: the above lineup allows for three
speakers and three
The first lineup is considered the default lineup (even if it wasn’t
lineups can take more arguments if different
lineups are possible (for different meetings).
(lineups (:default ...)
(tm word joke poet speaker speaker ge eval eval topics)))
This specifies a meeting of type
:topics-tuesday, which differs from the
:default meeting in that its lineup has only two
speakers and two
(The purpose of this meeting is plausibly to allow more time for
than is possible in a
A type of meeting called
:superset may be optionally added. This
specifies the list of roles that will be specified in the HTML table
club3 schedules for a sequence of meetings, which may be
of different type. The idea is to list all the roles possible in all
the meetings, and have the column for each meeting fill only the row
that is relevant to it.
calendar contains a series of dates for which meetings need
to be scheduled. Each date is given as a dotted integer YYYY.MM.DD; thus,
2009.02.24 is 2009 Feb 24.
If the type of meeting to be held on a particular date differs from the
:default type of meeting, then the date is enclosed as the first element
in a list whose second element is the type of meeting. E.g.
The type of meeting is typically one of the keywords introduced by the
lineups operator (see above). However, it can be anything. If it isn’t one
of the keywords introduced by
lineups, then no schedule is presumed
for that date. (This is useful to mark certain dates for special
activities that do not require scheduling, or have been scheduled by
availability operator contains exceptional information about the
temporal availability of the members. By default, members are assumed
to be always available. To override this for any member, that member’s
symbol is associated with an expression denoting
when that member is available.
Availability expressions are given in prefix notation using operators
until whose arguments
are dates or the results of other operations.
or are also allowed, but can only operate on the results of
other operations (i.e. not directly on dates). [Use
on if you find
yourself wanting to use
or directly on dates. E.g.,
(not (on 2009.03.17)).]
Dates are either in YYYY.MM.DD format or the keyword
:further-notice (= ∞).
(availabilty (kim (not (between 2009.03.10 2009.03.21))))
kim will not be available from March 3 to 21, 2009
(availability (kim ...)
(theresa (not (until :further-notice))))
theresa will not be available until further notice.
(availability (kim ...)
(kumaran (and (not (on 2009.02.24 2009.04.28
(not (between 2009.03.10
kumaran will not be available on Feb 24, April 28, May 26, and
June 30 of 2009; and also between March 10 and 31 of 2009.
role-difficulty operator, you can identify specific roles to
:hard. By default, all roles are
considered to be
:easy. Example entries:
(role-difficulty (speaker :intermediate)
By default, every member is considered to be capable of doing all and
:easy roles To modify this, use the
expertise operator. Each
argument is a list whose first element is the member name and whose
subsequent elements are the additional roles they can tackle beyond the
:easy roles. E.g.,
(expertise (rick topics eval))
If you entered
:hard instead of a role name, all roles
that are intermediate or hard, respectively, are intended.
(expertise (rick ...)
:all stands for *all* roles. Thus to encode the fact that
bash can do anything:
(expertise (rick ...)
You may also enter a list such as
(- speaker topics) instead of a role.
This requests that the
topics roles be removed from that
(expertise (rick ...)
(judyk (- speaker topics)))
By default, all members are supposed to exhibit the same moderate level
of eagerness to be scheduled. However, using the
you can add an eagerness level to a member. Each argument consists of
the member name followed by a number between 0 and 3 inclusive: 0 for
inactive; 1 for taking it slow; 2 for normal (the default); and 3 for
fast track. E.g.
(eagerness (joseph 3)
theresa is inactive,
judyk wants to take it slow, and
wants the fast track.
club3 uses a system that ascribes demerits to each member for a role on
any day (based on history, availability, etc). Since a lineup is filled
in a certain order, earlier roles may beat out later roles in getting
their best-suited members, leading to overall higher demerits.
tries to counter this by picking among eligible members using an
geometrically decaying distribution among them, so a member with higher
demerits could still snag a role.
club3 then generates more, different
lineups, to see if another lineup with fewer overall demerits
club3 generates 400 trial lineups for each meeting date, and
picks the best among them.
club3 output will also indicate the ordinal
n of the eventually picked lineup, so you get an idea if the number of
trials is reasonable. (If
n is too close to 400, and the best lineup
was updated many times, perhaps more trials are needed.)
To change the number of trials, use the
number-of-trials operator, e.g.,
The symbol used for each member is typically capitalized when printing
out schedules or profiles; thus,
charlie becomes “Charlie” and
becomes “Marcia”. However, in certain cases, naive capitalization may
be inaccurate or unsightly. For instance, if there are several members
with the same (first) name, the
members operator may have used an
initial to disambiguate, e.g.,
judyp for two different Judys.
To properly capitalize them in the output schedule (so the Judys don’t
judge you), use the
(full-names (judyk “Judy K”)
(judyp “Judy P”))
You may add more complicated names:
(full-names (judyk ...)
(kelvin “William Thomson, First Baron Kelvin”))
For routine scheduling, however, a first name, sometimes enhanced with a disambiguating initial, is usually enough.
lineups uses abbreviated symbols for each role. When printing out the
schedule as an HTML file, the roles are capitalized, and if there are
multiple instances of a role in a meeting, each role instance gets a number suffix
(e.g. “Speaker #2”). If you want the printed name for a role to be
different than the mere capitalization of the role symbol, you may use
role-names operator, e.g.
(role-names (tm “Toastmaster”)
The name of the club is set using the operator
club-name. This name is
used to title the schedules.
(club-name “The Articulators”)
past-schedules contains the schedules (the
generated for previous calendars — i.e. by previous calls to
club3 schedules. While optional,
past-schedules is useful to maintain, as
it provides the historical information necessary to ensure that no
member is over- or underscheduled.
club3 runs on any Common Lisp in a Unix-like environment, e.g.
SBCL. (On Windows, you can get a Unix
environment via Cygwin, which also