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.
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.
A slot in the schedule to which the user may add pursuits. See "schedule".
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.
[A-Z]
, [a-z]
,
[0-9]
and underscore '_
'. The first character may
not be a digit [0-9]
. Codes must be at least three characters
long. There is no upper length limitation.
gen
prefix, e.g. genCourse
, genHA
.
cos333
or psy259a
.
gen
prefix followed by the
distribution area abbreviation in upper case, e.g. genHA
,
genST
, genSTX
.
Major
or
Certificate
, respectively. If there is more than one possible
major or certificate within a particular department, append a sensible
suffix, e.g. cosMajorAB
vs. cosMajorBSE
(if a
distinction should even be made for these two). For other kinds of
requirements, make up other sensible names (e.g. genGenEduBSE
).
Gr
or another sensible second prefix,
e.g. cheGrBio
, cheGrEnt
, cheGrEnv
.
Abbreviations like the ones above (for "Bioengineering and Biotechnology"
or "Entrepreneurship and Management" etc.) are acceptable if they make
complicated prerequisite expressions more readable.
+-----------------+ | Tables_in_db38 | +-----------------+ | groups | | memberships | | offerings | | pursuits | | scheduleentries | | schedules | | sections | | users | +-----------------+
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.
Table | Name | Type | Description |
---|---|---|---|
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. | |
PurPrereq | String | 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'. | |
PurRecurrent | Boolean | Whether 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 | |
GrpTitle | String | 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 | |
UsrNetId | String | The OIT NetID or another name of the user | |
UsrClass | Integer | The user's class year, e.g. "2007" | |
UsrLogCode | String | Stores hash of a random variable which is stored in a cookie. | |
UsrPassHash | String | Stores the sha1 hash of the user's password | |
SchID | Foreign 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 | Character | The 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 | |
SchTitle | String | 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. |
This folder contains all the text files available online at the Registrar's website
This folder contains all the manually specified major, degree requirements, etc. Any file which specifies a requirement has the extension .req
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:
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.
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.
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:
This function authenticates the user, connects to the ldap server and uses the user id to retrieve user information, and sets up the session cookie.
This function is responsible for authenticating the user. Currently we are not able to securely use the ldap server for authentication, so instead, the first time a user logs in, a new user is added to the database, and the sha1 hash of the password they enter is stored in the database. For users that already exist in the database, authentication succeeds when the password entered on login matched the password stored in the database.
This function returns a User object for the user currently logged in by retrieving information from the previously stored session cookie.
These are used to create a new schedule, copy a schedule, and remove a schedule for the associated user. All three of these functions will update the current schedule of the user (the schedule that is on display). These functions are used by the php pages associated with the links to create new, copy, and delete schedules from the main page (index.php).
This will retrieve from the database and return all of the semesters for which there is offerings information in the database. It is used by index.php to generate the list of offer ins available for searching.
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.
This file contains the Group class for which each instance will represent a row in the groups database table.
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.
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.
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.
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.
This file used for testing purposes only.
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.
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:
getMissingExpression()
: Get a readable report of missing prerequisites. Currently this report may contain some HTML tags, though in the future this markup should strictly happen in the front-end in order to further separate presentation from storage. The string returned may contain two special markup sequences: "[[S[
n]]]
" denotes semester number n, while "[[C[
groupcode]]]
" denotes a group with code groupcode. The client should replace these with the corresponding semester/group titles before displaying the report to the user.
isSatisfied()
: Whether or not the prerequisites have been satisfied completely or not.
getErrorLine()
: In case of a prerequisite expression syntax error, returns the line number on which the parser stopped.
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.
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.
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.
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.
ADT representing a single group code, and the number of times it has been satisfied after each semester in the schedule.
PHP interface classes, as described above.
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.
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.
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.
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.
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.
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:
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 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.
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
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
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.
This script deletes the cookie storing the user's login information, and redirects back to the login page.
Prints nicely formatted information about a given pursuit via a GET parameter, purID, that specifies the ID of the pursuit to be printed.
A PEAR library to convert PHP to JSON and vis versa.
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.
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 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.
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.
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.
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.
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.
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.)