How to Use the Lunch Scheduler Drew McDermott [Revised 2006-10-03] Requires the following directories: lunch directory: Source (java) and data files (see below) lunch class directory: Class files for lunch program javutil source directory: Source files for various utilities javutil class directory: Class files for javutil (can be the same as the lunch class directory). To use the program: Make sure the lunch class directory and javutil class directory are in the classpath (by setting CLASSPATH or using a -classpath argument to java; see below). Data files: 1 lunch_people.dat (lunch directory) Format: Each line describes a person, thus: num / name / e-mail The number is arbitrary. The convention is to assign them in ascending order as new students arrive. A line in the file containing just the string "end" signals the end of the data. Further comments can appear below that point. Important convention: Students who are temporarily away have their data lines moved to the end of the file, and moved back when they come back. Nostalgic convention: Students who leave permanently, through graduation or otherwise, have their data lines moved to the end of the file, not just erased. 2 lunch_schedule.dat (lunch directory) This is a file containing a Lisp-style list of lists. Each element is a list of the form (n date note p1 ... pn) where 'date' and 'note' are strings, n is the number of attendees, and p1 ... pn are the id numbers of the attendees, from the lunch_people.dat file. If you're starting from scratch, this should be a file containing just (). The program will output new versions of this file, to be managed as explained below. You start from scratch every fall. If you're inheriting the program from someone else, you'll inherit lunch_schedule.dat, and the lunch program will then update it for you. 3 constraint file (lunch directory) See next section. Running the program: Execute java -classpath edu.yale.cs.lunch.Lunch -con [-attending n] (See the end of this readme file for what I actually type.) The constraint file tells the scheduler what sort of schedule to generate. It should be in the lunch directory, and have the following format: ((date1 -constraints1-) (date2 -constraints2-) ...) Each date is a string of the form "yyyy/mm/dd" indicating a day on which a lunch is to be scheduled. The lunch scheduler will generate a new schedule including a session for each of the given dates. Introducing new constraints on a lunch in the past will have no effect, but I often leave in dates of past lunches for the sake of continuity; the new schedule will include a bit of the old schedule and I can check to make sure they're consistent where they overlap. The output of the program is a new schedule embodied in two files: new_lunch_schedule.dat and new_lunch_roster.txt, explained below. Each constraint is one of the following: (note "") : A comment will be inserted in the new_lunch_roster file (skip "") : No session will be scheduled for the given date, but an entry for it will appear in the roster, together with the explanatory (time "string") : When the lunch is to start on the given date. If not specified, a random time between 12:20 PM and 12:40 PM is chosen. This time is essentially a joke; people wander into HGS when they can, which is fine. (attendees k) : Change the number of attendees at this session to k. (add p1 p2 ...) : Force persons p1, p2, etc. to be added to the list for that date. (del p1 p2 ...) : Force persons p1, p2, etc. to be deleted from the list for that date. (postpone date p1 p2 ...): Force persons p1, p2, ... to be postponed until the given date. If there's no session at that date, one will be created. The persons for add, del, and postpone constraints are specified using strings long enough to distinguish them from everyone else. Here is a sample constraint file: (("2002/02/27") ("2002/03/06" (del "Musharraf")) ("2002/03/13" (skip "Spring Break")) ("2002/03/20" (skip "Spring Break")) ("2002/03/27" (skip "Prospective Graduate Student Day this week; watch for further developments")) ("2002/04/03")) If run on March 5, it will discard all information about sessions before February 27. Sarit Musharraf, a hypothetical student, was originally scheduled for March 6, but can't make it. She's asked to be postponed. The program will postpone her to the earliest feasible date, in this case April 3. If the lunch_people.dat file has these two entries: 40 / Sarit Musharraf / sarit.musharraf@yale.edu ... 22 / Juan Saritsky / juan.saritsky@yale.edu ... then "Sarit" would not be an adequate label for Sarit Musharraf. In the worst case one would have to write "Sarit Musharraf" in full, but usually you can get away with much shorter strings such as "Juan" and "Mush". The optional -attending argument specifies how many people are to be scheduled for each new session. The default is 9. This argument CANNOT be used to change the attendees at existing sessions. Use the 'attendees' field in a constraint to change that. The file new_lunch_roster.txt is a human-readable file. Here's an example of a fragment of it: 2002/01/16 Lisa Malnick Melissa Koudelka Fanshi Zhao Karhan Akcoglu Kenneth Chin Vladislav Ruchinsky Liwen Huang Steven DeVries Andrew McCreight 2002/01/21 Note rare Monday session Dachuan Yu Todd Zickler Oleg Elkhunovich Fernando Flores Zhaozhong Ni Athos Gheorgiades Taijiao Jiang Mark Meras Friedrich Marx This was produced using a constraint file that began (("2002/01/16") ("2002/01/21" (note "Note rare Monday session") (add "Friedrich")) ("2002/01/30")) Annoying glitch: On my Windows system, the new_lunch_roster file has ^M's at the end of every line, at least when I look at it in emacs. I know that this is because of the difference between the Windows and Unix representations of newline, and I also know that there is some way to get emacs to cope with the difference automatically. But I haven't been able to figure it out, so I just do a query-replace to get rid of the ^M's. The file new_lunch_schedule.dat is in exactly the same format as lunch_schedule.dat . When you are happy with the new roster, you should save lunch_schedule.dat just in case and rename new_lunch_schedule.dat to lunch_schedule.dat . Then you're ready to do the next week's scheduling. MANAGING THE FILES Keeping track of all these files can be confusing, especially when revision requests come in and new_lunch_schedule.dat has to become lunch_schedule.dat. I adopt the following convention: The directory BIG/OFFICIAL/prog/lunch contains stable files with the following meanings: prev_lunch_roster.txt prev_lunch_schedule.dat - The files before the last bout of scheduling took place next_lunch_roster.txt next_lunch_schedule.dat - The output of the last bout of scheduling. Note that there may actually have been two or three cycles of revision between these two versions. Those cycles occur purely in the directory CVSified/prog/lunch, where the corresponding files are: lunch_roster.txt lunch_schedule.dat - The files given as input to the last run of Lunch new_lunch_roster.txt new_lunch_schedule.dat - The output of the last run of Lunch At the beginning of the week, the final roster (just this week's bit) and schedule from the next_* files are appended to the Record file (a stable record of the final outcome each week). Then the next_* files are copied to the CVSified directory with the next_ prefixes dropped. Then the next_* files are _renamed_, changing 'next_' to 'prev_' (staying in the OFFICIAL lunch directory). These steps overwrite lunch_roster.txt and lunch_schedule.dat in the CVSified direcotry, and prev_lunch_roster.txt and prev_lunch_schedule.dat in the OFFICIAL directory. At this point we've produced half of the stable configuration of the OFFICIAL lunch directory, namely, the inputs from last week that are supposed to produce the new schedule for this week. In the CVSified directory, the new_* files, if any, are deleted. (They should be redundant, since they are usually identical to the next_* files that were used to produce lunch_* files.) The Lunch program then produces the next round of new_* files. If the output is not satisfactory, further constraints are added, and the program run again, overwriting the unsatisfactory new_* files. (The program will ask if you really want to overwrite them, and you answer 'y'.) Sometimes it's necessary to rename the new_* files with new-less names and run a new set of constraints on them. When the results look good, the new_* files are moved to the OFFICIAL lunch directory, replacing 'new_' with 'next_'. The constraint file shoud be copied to current_constraint.dat in the OFFICIAL directory. At this point you can send messages to the faculty and students. It's usually best to do this in two waves: one at the beginning of the week and one early on the morning of the lunch, or late the night before. Sometimes I send separate messages to the students and the faculty. For the second wave, I usually send a redundant copy to the students who are actually on the roster for the lunch, just in case. (But watch out for this mailing-list gotcha: if you send to the mailing list AND a list of individual students the mailing list will think you are spamming and block the message. Send it out twice.) Now, if rescheduling requests come in, the next_* files are copied to the CVS directory without the 'new_' prefixes, and the Lunch program is run again, with constraints that satisfy the rescheduling requests. The results are then moved back to the OFFICIAL directory (with 'new_' ==> 'next_'). Once the dust settles, the directories and files will satisfy the loop invariant described above. After the event has occurred, any further requests for adjustment must be accommodated by twiddling with the schedule in later weeks. It's convenient to put those requests at the top of the next_lunch_roster.txt file. RECOMPILING Lunch.java I believe the program is stable and fairly bullet-proof, but you never know. If it's necessary to fix something and recompile, here's what to do: javac -d -classpath Lunch.java (all on one line, of course) If you use CVS to get the program, you will have to compile at least once. GETTING THE PROGRAM AND GETTING ORGANIZED The lunch system is now under public CVS control on cyndra.cs.yale.edu. Assuming you want to use CVS to get it, some more explanation is necessary about how to do that and how to work with what you get. First, be on a machine that can run CVS. The simplest thing to do is log into cyndra, the department compute server. It's a Linux machine with cvs built in. If you already love using CVS remotely, then the instructions vary a bit, but you can run the lunch program on any machine with a Java compiler. First, the instructions for cyndra. In your home directory, create a directory that will be under cvs control. Let's suppose we call it CVSLunch . Create a subdirectory CVSLunch/bin . In the CVSLunch directory type cvs -d /export/home/dvm/pubcvsroot co lunch then cvs -d /export/home/dvm/pubcvsroot co javutil Or set the environment variable CVSROOT to /export/home/dvm/pubcvsroot and omit the "-d /exp.../root" stuff Compile the system: In directory CVSLunch/javutil, do javac -d ../bin -classpath ../bin *.java In directory CVSLunch/lunch, do javac -d ../bin -classpath ../bin Lunch.java Now you can run the system as described above, by doing java -classpath ../bin edu.yale.cs.lunch.Lunch -con By adding CVSLunch/bin to the CLASSPATH environment variable, you can omit the "-classpath ../bin/..." stuff. But be careful on Windows: If you include a directory with spaces in its name (such as the evilly designed "Documents and Settings"), you will have trouble running in cygwin bash. At this point I am not sure how to compensate for this. One approach is to avoid cygwin bash and run under the Command Prompt window (in purely native mode, in other words). The other is to substitute (e.g.) Docume~1 for "Documents and Settings". For reasons I can't fathom, the classpath under cygwin can include only one path. You can't write ../bin:. or any of the variants above. [Some fathoming: It's apparently a Java feature that under Windows it uses ";" as the classpath separator. It will probably be happier if backslash is used, too.] If you're using CVS remotely: You probably already know how to vary the instructions above. All you do is replace /export/home/dvm/pubcvsroot wherever it occurs by YOURLOGIN@cyndra.cs.yale.edu:/export/home/dvm/pubcvsroot Of course, setting the CVSROOT environment variable to this value starts to look more attractive. KEEPING sources up-to-date: If you make any changes to the code, then when you have a stable copy go to the CVSLunch directory and execute: cvs ci -m "Your message here" I'm assuming that you have CVSROOT set appropriately. Otherwise, add the -d option (before the 'ci'). If someone else is also making changes to the system, you can get the latest sources by doing cvs update again in the CVSLunch directory, again with CVSROOT set appropriately. You will have to recompile after that. [Note: The edu.yale.cs nonsense was added in a fit of conformity. There's no real need for it. We could put everything in the 'lunch' package or no package at all and save a bit of typing.] Local Variables: mode:text End: