Internals

Definitions

pursuit

A representation of something you may do during your academic career to satisfy some set of requirements, and/or which may have some requirements of its own. Examples are: "COS 333 Advanced Programming Techniques", "CHE 199 Great Inventions That Changed the World", "History Major", "Program in Hellenic Studies", "Preparation for Medical School", "Foreign Language requirement", "Generic COS Departmental Course", and "Advanced Placement for MAT 103".

Each pursuit may be a member of zero or more groups, and may have its own prerequisites. A descriptive title like those in the examples above is associated with each pursuit.

Also associated with each pursuit is a list indicating what semesters the pursuit may or may not be added to in the schedule. Courses restricted to students of particular grade levels (freshman, sophomore, junior, senior) are accommodated for in this way In addition, this allows two special semesters to be reserved for pursuits other than classes (see "schedule"). Note: this is not a way to specify limitations on what specific years or seasons the course is offered, since students of different class years may be in different grade levels at the same time.

schedule

A representation of the potential academic career of a Princeton undergraduate, consisting of ten semesters internally numbered from 0 to 9. The first and last ones are only for advanced placement and programs, respectively. The others (numbered 1 to 8) represent the familiar eight semesters of Princeton's undergraduate education, and are intended for courses only.

semester

A slot in the schedule to which the user may add pursuits. See "schedule".

group

A collection of zero or more pursuits.

An integer variable whose value, zero or more, represents how many times a particular University requirement has been satisfied at a particular point in the schedule (the number of "credits" received so far for this requirement). Associated with each group is a technical code which is used in the prerequisite expressions.

At the beginning of the first semester (number 0) of the schedule, the values of all groups are zero. At the end of each semester, the value increases by one for each time the group is satisfied by a pursuit in that semester, whether the prerequisites for that pursuit have been satisfied or not. This mechanism is implemented in the Report Generator.

If user-specified pursuits are implemented later, there may be cases where the user will probably want to interact with group codes rather than descriptive titles, such as when editing prerequisite expressions.

Group Code Naming Rules and Conventions

Database Structure

+-----------------+
| Tables_in_db38  |
+-----------------+
| groups          |
| memberships     |
| offerings       |
| pursuits        |
| scheduleentries |
| schedules       |
| sections        |
| users           |
+-----------------+
Database Sructure

Database Tables

The following is a sketch of what tables and columns are needed in the database. The exact MySQL definitions will not be given here. Types are only guidelines and may be set to whatever is practical.

TableNameTypeDescription
Pursuits
PurID ID Primary key
PurTitle String Descriptive title
PurSem 10 characters Semesters (meaning grade levels, as opposed to years/ seasons) that this pursuit may be taken in, for instance "0001111110" to mean a course not open to freshmen. The first character is for AP credits and the last is for degrees and requirements.
PurPrereqString Prerequisite expression
PurURL String URL to a web page describing the pursuit if such was specified manually. For programs this will typically be a link to a page in the online Undergraduate Announcement, or a specific department page. Currently, this is not implemented yet.
PurDesc String A description of the pursuit in question obtained from the Registrar.
UsrID Foreign key The user that created this pursuit. This will be of importance in future versions of the software that allows user-specified pursuits. Pursuits created by the Import Scripts are assigned to a special super user named 'Registrar' who has a class year or '0000'.
PurRecurrentBooleanWhether or not the course should be assumed to be offered in years/seasons without an offering specified. This is not yet implemented.
Groups
GrpID ID Primary key
GrpTitleString Descriptive title
GrpCode String Group code. Every pursuit is a member of a group with it's own course code as the group code as well as other groups.
GrpIsCourse Boolean 1 if Group code is a course, 0 otherwise
Memberships (which pursuits are in which groups)
MemID ID Primary key
PurID Foreign key The pursuit being member of a group
GrpID Foreign key The group
Users
UsrID ID Primary key
UsrNetIdString The OIT NetID or another name of the user
UsrClassInteger The user's class year, e.g. "2007"
UsrLogCodeString Stores hash of a random variable which is stored in a cookie.
UsrPassHashString Stores the sha1 hash of the user's password
SchIDForeign key Schedule stored by the user
Offerings
OffID ID Primary key
PurID Foreign key The pursuit being offered.
OffYear Integer The year from which this offering's section information was taken, e.g. "2005".
OffSeason Character The season of from which this offering's section information was taken, e.g. "F" or "S".
Sections (currently not implemented)
SecID ID Primary key
OffID Foreign key The offering with which this section is associated.
SecType CharacterThe section type, e.g. "L", "B", "P".
SecNum String The section number, e.g. "01", "02"...
SecDays 7 booleans of some kind The days for which this section is scheduled.
SecTimeF Time of the day in some form Beginning time of the day
SecTimeT Time of the day in some form Ending time of the day
Schedules (saved by the user)
SchID ID Primary key
UsrID Foreign key The user that saved the schedule
SchTitleString The name chosen for the schedule
ScheduleEntries (one for each pursuit added to a saved schedule)
EntID ID Primary key
SchID Foreign key The schedule this entry was made into.
PurID Foreign key The pursuit added to the schedule.
EntSemNum Integer The semester the pursuit was added to.

Administrative Files (admin folder)

This folder contains all files needed to create the database and to import all course and requirement information. It downloads the course files from the Registrar's website, takes the relevant information and inserts it into the database.

Database Interfaces (db folder)

This folder contains the php files which serve as an interface to the database. A brief description of each of the interfaces is given here:

dbsetup.php

This file contains the code to connect to the database and to setup the ldap server. The dbSetup() function specifies the server information for database connection.

dbtable.php

This file contains the abstract class DBTable, which is the parent of each of the classes that represent some information in the database. It contains two member variables $db, and $id which store the mysqli database object, and the integer value of the primary key of a row in the database. It contains a default constructor, __construct($db, $id), which sets the two member variables to the specified values. The getID() function returns the member variable $id. simpleQuery() takes in an SQL query as a string. It performs the query and will return result of the query as an array of strings. The ith item in this array will be the contents of the ith row of data obtained by the query (if multiple fields were selected, their values are separated by spaces)
The classes that extend DBTable are: Group, Pursuit, PursuitSearch, Schedule, Semester, and User.

user.php

This file contains the User class, where one instance represents a row in the users table of the database. It contains functions that enable all processing that would be necessary for a user including login, authentication, creating new, copying, and deleting schedules, and getting and setting other user-related data from the database. The more important functions are described here:

pursuit.php

This file contains the Pursuit class, for which each instance corresponds to one row in the pursuits table of the database. Functions enable retrieval of pursuit information including the pursuit title, URL, description, code (if it is a cross-listed course, the getCode() function will return the first three associated course codes that it finds separated by '/'), offering information, and prereq string. pushData($data) returns all relevant information about the pursuit for searchpane.php and schedulepane.php.

group.php

This file contains the Group class for which each instance will represent a row in the groups database table.

pursuitsearch.php

The PursuitSearch class continued in this file builds up a search for pursuits by limiting the results to those containing a particular keyword (in the course title or description), or related to a particular group, semester, offering, or code. The search is done by building up an SQL query based on the selected criteria. getResults() is the function that will actually return the search results as a php array of Pursuit objects. Note that temporarily, the number of results returned is limited to 100 because the Prototype library sends JSON data as a header, which has a limited size.

schedule.php

This file contains the Schedule class, corresponding to a given schedule in the database. Each schedule contains 10 semesters (AP credits, 8 academic semesters, requirements), and getSemesters() returns all semesters associated with a Schedule as an array. The function repgenQuery() is called by the report generator to get all of information it needs from the given schedule, formatted as needed.

semester.php

This file contains class Semester. It contains a member variable $semesterNo which corresponds to a semester number (EntSemNum in the scheduleentries database table). The functions in this class include those to add, remove, and get the pursuits in the semester.

(logging.php)

Provides logging function for debugging. Any message recorded using the function error($msg) is recorded in logging.txt along with the date and time that it was logged.

(driver.php)

This file used for testing purposes only.

Report Generator (/repgen/ folder)

The Report Generator handles parsing, evaluation, and printing of prerequisite expressions (see Install). It processes a single schedule and, for each pursuit in the schedule, generates a readable report that tells what prerequisites the user is still missing for that pursuit. The Report Generator is accessed through ordinary PHP functions, but the underlying module is written in C, with a yacc-generated parser.

Interfaces

PHP interface

The Report Generator is accessed through the PHP classes PrereqReport and PrereqReportGenerator. A PrereqReport object contains a report on a specific Pursuit in the schedule. To generate a set of reports for the pursuits in a given schedule, the client calls $prg = PrereqReportGenerator::makeReports($schedule) to get a new PrereqReportGenerator object. The client may then call $rep = $prg->getReport($pursuit) on this object to get the PrereqReport for any particular pursuit in the schedule used to create the report. Some of the methods available on PrereqReport are:

Internal repgen module interface

The Report Generator module itself is a single executable: "repgen" on UNIX or "repgen.exe" on Windows servers. In normal use it takes all its input from the stdin and prints all its output to stdout. There is also an interactive mode which may be used for debugging, accessible by running "repgen -i". The input/ output format is, while human-readable, designed to minimize the amount of interface code needed to pass information between the PHP classes and the repgen executable. In particular, the input format is such that it can be generated directly from two SQL query result sets. The input is a list of group codes that have been satisfied by given semesters as well as a list of pursuits, with prerequisite expressions, that have been taken in each semester in the schedule. The exact format is specified in detail in the comments of repgen.c and prereqreportgenerator.php.

A significant effort was made in making the report generator interface robust. It has been thoroughly designed and tested to avoid memory leaks. Prerequisite expression strings are passed in quoted form, and special characters are escaped and handled appropriately. The report generator handles errors in two levels: in the input format as a whole and in individual prerequisite expressions. The first case should never happen and would be an indication of programming error in the internal interfaces; such errors result in assertion failures. Any stderr output from the report generator, such as assert fail messages, are appended to the file repgenerror.log. The second case is that of syntax errors in prerequisite expressions. These are handled gracefully by returning the line number within the expression at which the parser stopped, and continuing processing as if the expression had otherwise been valid.

Classes/ADTs and sources

repgen.c

Main module of the executable. Handles command line arguments, input/output, and the interactive mode. Builds a SymbolTable of satisfied Code objects from the input, and calls Parse_readPrex to read in prerequisite expressions that needs to be processed.

Parse (parse.y/h)

Defines the yacc-generated parser and implements a lexical analyser for reading prerequisite expression tokens. Also provides repgen.c with functions for handling quoted/escaped input, in particular, group codes. Parse_readPrex() invokes the yacc parser and returns a Prex object containing the parse tree of the expression read.

Prex (prex.c/h)

ADT representing the parse tree of a prerequisite expression, with methods for resolving credits for satisfied group code, simplifying the resulting expression, and printing the expression in a readable form. Each Prex object can be either a leaf or a node; leaves represent group codes and nodes represent operators. Nodes store subexpressions in a List object. Any Prex in the parse tree evaluates to a constant value which denotes how many times the subexpression has been satisfied. Only three different operators are used internally: PTYPE_AND, PTYPE_ATMOST, and PTYPE_ATLEAST. The first require each of its subexpressions to evaluate to non-zero in order to be satisfied, the latter two work by taking the sum of all subexpressions and applying a limit ("at least X of" or "at most X from").

Simplification of prerequisite expressions happen by moving constant terms upwards in the tree, eliminating satisfied subexpressions, and collapsing redundant operator chains. Please see presentation slides for illustrations on how the evaluation and simplification of prerequisite expressions happen in prex.c.

Code (code.c/h)

ADT representing a single group code, and the number of times it has been satisfied after each semester in the schedule.

prereqreport.php, prereqreportgenerator.php

PHP interface classes, as described above.

SymTable, List (symtable.c/h, list.c/h)

Very simple implementations of a hash symbol table and a linked list ADT. Each class has a foreach macro for iterating through all elements. The symbol table does not own its keys, instead, upon creation it takes a pointer to a function that can be used to retrieve the key from objects in the table.

The symbol table is used to store and look up group codes (of class Code). The linked list is used to store subexpressions (of class Prex).

symtest.c and listtest.c are for debugging only.

User Interface (/gui/ folder)

The user interface consists of a mixture of HTML, CSS, Javascript, and PHP. From this point on, we will assume that you know at least basic HTML, PHP, Javascript, and CSS syntax, or we won't have time to get anywhere. If you are unfamiliar with any of these basic languages, SitePoint is an excellent resource.

Overview

The user interface consists of three main display panels that each have their own source code and function: the Admin Bar, the Schedule Pane, and the Search Pane. We will roughly outline them here: (for a fancier, prettier description with pictures, see the End-User Documentation and tutorial)

Next, we briefly outline the basic process by which the user conducts all of its interactions.

  1. Once logged in, the user visits the (publicly accessible) /gui/ subdirectory of the Plan-O-Matic folder, accessing file index.php.
  2. index.php outputs a skeletal HTML page, consisting mostly of div and span blocks, with a few display items containing information about the user retrieved using the PHP User interface. It also contains all the search tabs, although many parts of the search bar will be hidden by default. Once everything finishes loading, index.php runs js/gui.js to start filling the schedule in with content.
  3. This is where it begins to get tricky. After setting up the status bar to display the status of current AJAX requests, gui.js calls two important functions: schedulePane.setup() and searchPane.setup(). These look for the div tags with id's "schedulepane" and "searchpane", respectively. Once they're found, schedulePane.setup() requests JSON formatted data about the user's current schedule from schedulepane.php and creates all the javascript objects necessary to hold, manipulate, and display that information. searchPane.setup() adds all the javascript event handlers needed to make functioning tabs and readies the search bar to send AJAX requests for search results whenever the user presses "enter" on the keyboard.
  4. Now, the page remains static until the user triggers one of the events carefully planned for by the schedulePane and searchPane javascript objects. There are two basic operations that the user will repeat over and over again:
  5. If the user wants to create or delete schedules, clicking the links opens a new window to newschedule.php or deleteschedule.php. These submit POST data to themselves, updating the database and triggering a refresh of index.php with the updated schedule information added. Selecting schedules is handled by gui.js, which instructs schedulePane to reload with a new default schedule whenever the drop-down list in the Admin Bar changes.

Now you should have a basic grasp of how the interface is put together. The next section include summarizes of the important details of each file in the /gui/ folder with regards to the GUI.

PHP: /gui/

login.php

Straightforward implementation of a standard PHP login page, consisting of an HTML form with a POST action to submit to itself. Technically, it sends the username and password to itself as plaintext--but you should only be connecting over a secure HTTPS connection, so this is encrypted by the server.

index.php

Creates the backbone of the user interface, linking to all .css style files and the numerous .js files required by the GUI. The main div tags of portent are:

schedulepane.php

There are four main functions of schedulepane.php: performing atomic update actions on entries in the schedule (add, delete), selecting new default schedules, converting database entries into JSON, and parsing prerequisite expressions from the report generator to enable searches triggered by clicking on requirements (Active Search(tm) Technology.)

Input:

Output:

Regardless of whether or not the optional input parameters are specified, schedulepane.php will output all relevant attributes of the semesters and their pursuits of the current schedule in JSON format. This is performed after any optional database updates to display the most current information to the user. The JSON is passed in a HTTP header, "X-JSON", so that the Prototype javascript library will automatically evaluate the JSON in a safe environment. (NOTE: This is a known flaw in the architecture that was discovered after our demo when we expanded testing to many users. Headers are limited in size, and with too many courses/prerequisites being passed the header is simply rejected. We will fix this as soon as humanly possible.)

searchpane.php

searchpane.php handles all of the I/O for getting search results from the database; it takes in search parameters and incrementally constructions an appropriate PursuitSearch object, which performs the actual database search. Then searchpane.php retrieves relevant data about returned pursuits and passes them as JSON in the "X-JSON" header. (Note: see above for description of JSON bug.)

Input:

Output:

JSON data corresponding to pursuit information in the "X-JSON" header.

newschedule.php

Straightforward, tiny script to generate the "Enter a name for your new schedule" popup. Reloads the index page with the new, blank schedule in the schedulepane

copyschedule.php

Straightforward, tiny script to generate the "Please enter a name for the copy of this schedule" popup. Reloads the index page with the new, copied schedule in the schedulepane

deleteschedule.php

Straightforward, tiny script to generate the "Are you sure you want to delete this schedule?" popup. Reloads the index page with another of the user's schedules.

logoff.php

This script deletes the cookie storing the user's login information, and redirects back to the login page.

pursuitinfo.php

Prints nicely formatted information about a given pursuit via a GET parameter, purID, that specifies the ID of the pursuit to be printed.

JSON.php

A PEAR library to convert PHP to JSON and vis versa.

debugger.php

This is a useful tool for checking prerequisite expressions; it allows a developer to quickly update a given pursuit's prerequisite expression and see the simplified output instantaneously. However, it is quite basic and requires a pursuit ID (not code) to be entered by hand. Until you know what you are doing, you should probably stay away from this, but it will be helpful once you are familiar with the database structure.

Javascript: /gui/js/

The javascript code in this program makes extensive use of the Prototype (core functions) and Scriptaculous (GUI effects) javascript libraries, to the extent that the code will be completely unreadable without at least a basic understanding of the Prototype library. SitePoint has an excellent Prototype tutorial, with links to more information.

common.js

common.js contains definitions of the Javascript classes that do not relate directly to one of the main components (Search Pane, Schedule Pane, or Admin Bar). The most useful classes are Pursuit and Semester, which handle the display and processing of their sister classes in PHP; for example, the createNode method will create a new DOM element in memory with all necessary styling attributes to be displayed properly once given a visible parent.

The classes in common.js are for the most part straightforward: to add a pursuit to a semester, use the Semester.addPursuit() method, etc...Furthermore, like all Scriptaculous and Prototype classes, Semester and Pursuit take an optional options structure containing parameters that wish to be override from the default values during creation. Most of the time, these default values will suffice.

Note: The DeleteButton class is not used in the current version of the scheduler, but may be helpful in the future; it simply wraps the functionality of a "delete" button that may be added to pursuits.

schedulepane.js

This javascript file contains the definition of the schedulePane object, which holds and displays an array of Semester objects which are build from the JSON data sent from schedulepane.php. The most important methods are the saveAction() method, which starts an AJAX request to save adding or deleting a schedule entry, and changeSchedule, which reloads and redraws the Schedule Pane for a different schedule, again using AJAX requests.

searchpane.js

This file contains the javascript definitions for the searchPane object. The constructor for this object is quite large, as many options need to be set by hand: for instance, tabs have to act as links, the page images need to act as links, a lot of bookkeeping variables are initialized to keep track handles to important HTML elements, and so forth. Because of this, it is important to remember that changing index.php without updating searchpane.js may lead to dangerous conflicts if the id of important HTML elements are changed.

The important methods in this object should be fairly self-explanatory: showPage() shows a page of results; runSearch() runs a new search, and so forth. Each search starts a new AJAX request which clears the current list of results and builds a new one based off the new search when completed.

gui.js

This is the most unstructured of the javascript files. It sets up the status box to respond to Prototype's AJAX requests and keep the user informed, as well as calling the setup() routines to initialize searchPane and schedulePane. It also makes the select schedule drop-down list work.

collapsible.js

Creating a new Collapsible will add event handlers to appropriate HTML elements within the specified element to make the element collapse and expand when clicked on. Optional parameters specify closed and open styles; optional function parameters allow arbitrary functions to be called on expansion/collapse. This can be used in many situations.

dragdrop.js

Originally part of the Scriptaculous library, but we modified it to add extra functionality to the Droppable class under time pressure, as attempting to extend it is difficult to do with javascript's somewhat mangled class handling. Do not overwrite this file with a new version of Scriptaculous. (Note: We don't know a solution to this problem yet; even if you extended Droppable, you'd have to override so many functions that it would no longer be compatible anyway; a more complicated wrapping is necessary.)

All other javascript files are part of the Prototype or Scriptaculous libraries and should not be modified.