Skip to content

Instantly share code, notes, and snippets.

@laughinghan
Created August 25, 2010 16:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laughinghan/549772 to your computer and use it in GitHub Desktop.
Save laughinghan/549772 to your computer and use it in GitHub Desktop.
Better Schedule Search for Berkeley
<?php
/*
* schedule.php
*
*
* Created by Jay on 12/4/09, based on Han's Better Schedule Search.
* Gift-Economy license. See en.wikipedia.org/wiki/Gift_economy
*
*/
#global specifying what semester the search is for
$semester = false;
#global debug mode
$debug = false;
/*************
* parse
*
* This function contains all the DOM stuff. It grabs all the info we need
* from the DOM objects and loads them into the array $info. $info is passed
* by reference for optimization purposes.
*
* Parameters:
* DOMNodeList $trs: contains a list of the table rows in an individual course
* view in Schedule Search.
*
* array &$info: the array into which to load the info for the current course.
*
*
* Return: false if the course is cancelled, true otherwise.
*
*/
function parse($trs, &$info)
{
global $debug;
if ($debug)
echo "<p>piece(\$trs: $trs->length): ";
global $semester;
$info = array();
$matches = array();
if ($debug)
echo "parsing status";
//grab the status first, so we can abort if it's 'CANCELLED'
$info['status'] = trim(strip_tags($trs->item(4)->lastChild->lastChild->lastChild->nodeValue));
if(preg_match('/^CANCELLED/',$info['status'])) //don't display cancelled classes.
return false;
if ($debug)
echo ", parsing ccn";
//Course Control Number
$info['ccn'] = trim(strip_tags($trs->item(5)->lastChild->lastChild->firstChild->wholeText));
if ($debug)
echo ", parsing books";
//"View Books" link
$view_books_node = $trs->item(4)->nextSibling;
if ($view_books_node->nodeName == 'form') {
$info['books'] = $view_books_node->getAttribute('action').'?'.http_build_query(array(
'bookstore_id-1' => $view_books_node->nextSibling->getAttribute('value'),
'term_id-1' => $view_books_node->nextSibling->nextSibling->getAttribute('value'),
'div-1' => $view_books_node->nextSibling->nextSibling->nextSibling->getAttribute('value'),
'crn-1' => $view_books_node->nextSibling->nextSibling->nextSibling->nextSibling->getAttribute('value')
));
}
if ($debug)
echo ", parsing units";
//Units
$info['units'] = trim(strip_tags($trs->item(6)->lastChild->lastChild->lastChild->wholeText));
if(preg_match('/^Summer/',$semester)) { //Summer Session
if ($debug)
echo ", parsing summer session";
$info['session'] = trim(strip_tags($trs->item(7)->lastChild->lastChild->lastChild->wholeText));
}
else //Final Exam Group and info
{
if ($debug)
echo ", parsing final exam group";
$info['final'] = trim(strip_tags($trs->item(7)->lastChild->lastChild->lastChild->wholeText));
if($info['final'] == '' || $info['final'] == 'NONE' || $info['final'] == 'TBA')
$info['final'] = false;
else
{
preg_match('/(\d+):\s+(.+)$/',$info['final'],$matches);
$info['final'] = array('group' => $matches[1],
'time' => $matches[2]
);
$info['final']['time'] = preg_replace('/[^A-Z0-9-,]+/',' ',$info['final']['time']);
}
}
if ($debug)
echo ", parsing restrictions";
//Restrictions
$info['restrictions'] = trim(strip_tags($trs->item(8)->lastChild->lastChild->lastChild->wholeText));
$info['bad'] = (preg_match('/^CURRENTLY/',$info['restrictions']) === 1);
if ($debug)
echo ", parsing note";
//Note
$info['note'] = preg_replace('/[^A-Z0-9!@#$%^&*()_\-+="\',.\/;<>?:[\]\\| `~]/i','',trim($trs->item(9)->lastChild->lastChild->lastChild->nodeValue));
$info['edd'] = strpos($info['note'],'EARLY DROP DEADLINE')!==false;
if($n =& $info['note'])
if($r =& $info['restrictions'])
if(preg_match('/^Summer/',$semester))
$r = "Summer Fees: $r | Note: $n";
else
$r = "Restrictions: $r | Note: $n";
else
$r = "Note: $n";
elseif($r =& $info['restrictions'])
if(preg_match('/^Summer/',$semester))
$r = 'Summer Fees: '.$r;
else
$r = 'Restrictions: '.$r;
unset($info['note']);
if ($debug)
echo ", parsing designation and website";
//Course designation and website
$info['desig'] = $trs->item(0)->lastChild->lastChild->lastChild;
if(($info['site'] = $info['desig']->getElementsByTagName('a')->item(0)) !== null) //handle the "Course Website" case; this will be null if there is no link
{
$info['desig'] = $info['desig']->firstChild;
$info['site'] = trim(strip_tags($info['site']->getAttribute('href'))); //grab the url
}
$info['desig'] = trim($info['desig']->nodeValue);
if ($debug)
echo ", parsing title";
//Course Title
$info['title'] = trim($trs->item(1)->lastChild->nodeValue);
if(strlen($info['title']) > 40)
$info['title'] = substr($info['title'],0,40).'&hellip;';
if ($debug)
echo ", parsing catalog";
//Catalog URL
$catalog_node = $trs->item(0)->nextSibling;
if ($catalog_node->nodeName == 'form') {
//hardcode because URL is now relative
$info['catalog_url'] = 'http://osoc.berkeley.edu/catalog/gcc_search_sends_request'.'?'.http_build_query(array(
'p_dept_cd' => $catalog_node->childNodes->item(0)->getAttribute('value'),
'p_title' => $catalog_node->childNodes->item(1)->getAttribute('value'),
'p_number' => $catalog_node->childNodes->item(2)->getAttribute('value')
));
}
if ($debug)
echo ", parsing time and location";
//Time and location
$info['time'] = trim(strip_tags($trs->item(2)->lastChild->lastChild->lastChild->wholeText));
$info['time'] = explode(',',$info['time']);
$info['location'] = trim($info['time'][1]);
if($info['location'] == null)
$info['location'] = '';
$info['time'] = $info['time'][0];
$info['time'] = preg_replace('/\s+/',' ',$info['time']);
if ($debug)
echo ", parsing instructor";
//Instructor
$info['instructor'] = preg_replace('/[^A-Z, ]/','',trim(strip_tags($trs->item(3)->lastChild->lastChild->lastChild->wholeText)));
$info['instructor'] = str_replace(' ','&nbsp;',$info['instructor']);
if ($debug)
echo ", parsing enrollment";
//Enrollment
$info['enrollment'] = trim(strip_tags($trs->item(10)->lastChild->lastChild->nodeValue));
if(strpos($info['enrollment'],'DEPT'))
$info['enrollment'] = array();
else
{
preg_match('/Limit:(\d+)\s+Enrolled:(\d+)\s+Waitlist:(\d+)\s+Avail\s+Seats:(\d+)/',$info['enrollment'],$matches);
$info['enrollment'] = array('limit' => (int) $matches[1],
'enrolled' => (int) $matches[2],
'waitlist' => (int) $matches[3],
'available' => (int) $matches[4]);
if($info['enrollment']['limit'] == 0)
$info['fullness'] = "NOT OPEN";
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']/8)
$info['fullness'] = 'Empty';
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']*3/8)
$info['fullness'] = '<big>&frac14;</big>Full';
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']*5/8)
$info['fullness'] = '<big>&frac12;</big>Full';
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']*7/8)
$info['fullness'] = '<big>&frac34;</big>Full';
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit'])
$info['fullness'] = 'Near Full';
else
{
$info['fullness'] = "FULL".($info['enrollment']['waitlist'] ? " (".$info['enrollment']['waitlist'].")" : '');
if(!$info['bad'] and $info['enrollment']['limit'] > 0 and $info['enrollment']['enrolled']==$info['enrollment']['limit'])
$info['bad'] = true;
}
}
$info['enrollment']['asof'] = trim(strip_tags($trs->item(10)->firstChild->lastChild->lastChild->lastChild->wholeText));
$info['enrollment']['asof'] = substr($info['enrollment']['asof'],14,-3);
if ($debug)
echo ", parsing infobears URL";
//InfoBears URL
if($trs->item(11))
$info['infobears_url'] = 'http://infobears.berkeley.edu:3400/osc?'.http_build_query(array(
'_InField1' => $trs->item(11)->previousSibling->previousSibling->previousSibling->getAttribute('value'),
'_InField2' => $trs->item(11)->previousSibling->previousSibling->getAttribute('value'),
'_InField3' => $trs->item(11)->previousSibling->getAttribute('value')
));
if ($debug)
echo ", parsing RateMyProfessor URL";
//RateMyProfessor URL
$dept = implode('+',array_slice(explode(' ',$info['desig']),0,-4));
$prof = urlencode(substr($info['instructor'],0,strpos($info['instructor'],',')));
if($prof)
$info['ratemyprof_url'] = 'http://www.ratemyprofessors.com/SelectTeacher.jsp?sid=1072&the_dept='.$dept.'&letter='.$prof;
else
$info['ratemyprof_url'] = false;
if($prof && ($dept === 'COMPUTER+SCIENCE' || $dept === 'ELECTRICAL+ENGINEERING'))
$info['hkncoursesurveys_url'] = 'https://hkn.eecs.berkeley.edu/coursesurveys/search?q='.$prof;
else
$infp['hkncoursesurveys_url'] = false;
//Make sure we're set up to add sections if necessary
$info['sections'] = array();
if ($debug)
echo "</p>";
return true;
}
/***********
* piece
*
* This function loads a single class listing into an array $x. This will detect
* if we are looking at a lecture or a secondary section, and nest $x accordingly.
* Sections will be stored in an indexed array called $x[$j]['sections'], where $j
* is the index of the lecture corresponding to the given section.
*
* Parameters:
*
* DOMNodeList $trs: A list of the table rows for the given course. See 'parse'.
*
* array $x: The array into which we will load the course info.
*
*/
function piece($trs, &$x)
{
global $debug;
if ($debug)
echo "<p>piece(\$trs: $trs->length, \$x: $x)</p>";
$lec = ($trs->item(0)->lastChild->lastChild->hasAttribute('color')) ? true : false; //if OSOC colors the title blue, then it's a lecture. LOL
if($lec)
{
$j = count($x);
$x[$j] = array();
$t = parse($trs,$x[$j]);
if($t===false) //it's a cancelled course
unset($x[$j]); //so don't display it
}
else //it's a discussion or a lab, so add it under the current lecture, according to $x
{
$j = count($x) - 1;
$k = count($x[$j]['sections']);
$x[$j]['sections'][$k] = array();
if(parse($trs, $x[$j]['sections'][$k])===false){
unset($x[$j]['sections'][$k]);
if(count($x[$j]['sections'])==0){
unset($x[$j]['sections']);
if(count($x[$j])==0)
unset($x[$j]);
}
}
}
/*
if($debug){
echo '<pre>';
//var_dump(debug_backtrace());
var_dump($x);
echo '</pre>';
}*/
}
define('OSOC_BASE', 'http://osoc.berkeley.edu/OSOC/osoc?');
/***********
* load_results
*
*/
function load_results($query,&$x)
{
$url = OSOC_BASE.http_build_query($query);
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$unparsed_html = curl_exec ($ch);
curl_close ($ch);
global $debug;
if ($debug) {
echo '<p>url:', $url, '<p>strlen(html):', strlen($unparsed_html);
echo '<h3>Unparsed HTML of Search Results: <a href="javascript:void(0)" onclick="$(this).parent().next().toggle()">Show/Hide</a></h3><pre>';
echo htmlspecialchars($unparsed_html);
echo '</pre>';
}
$dom = new DOMDocument('1.0','iso-8859-1');
$dom->strictErrorChecking = false;
$dom->validateOnParse = true;
@$dom->loadHTML($unparsed_html);
//stupidstupidstupid invalid html. Suppressing errors with @. Poor coding practice, but hey, it's not my html.
$tables = $dom->getElementsByTagName('body')->item(0)->getElementsByTagName('table');
//grab all the table dom elements. Each contains a separate class entry.
if ($tables->length == 1) {
$x['noResults']=true;//$dom->getElementsByTagName('body')->item(0)->getElementsByTagName('p')->item(2)->nodeValue;
return;
}
if ($debug)
echo '<p>not noResults</p>';
$GLOBALS['semester'] = $dom->getElementsByTagName('b')->item(3)->nodeValue;
preg_match('/(\d*) matches/',$dom->getElementsByTagName('b')->item(3)->previousSibling->nodeValue,&$GLOBALS['num_matches']);
$GLOBALS['num_matches'] = $GLOBALS['num_matches'][0];
if ($debug)
echo '<p>parsed semester and num_matches</p>';
for($i = 1; $i < $tables->length - 1; ++$i) //cycle through the tables
{
if ($debug) {
echo "<p>about to parse piece $i</p>";
$rows = $tables->item($i)->getElementsByTagName('tr')->length;
echo "<p>\$rows: $rows, \$x: $x, \$debug: $debug</p>";
}
piece($tables->item($i)->getElementsByTagName('tr'), $x); //load the course info into $x
}
if ($debug)
echo '<p>next, next_results_link</p>';
$next_results_link = $tables->item(0)->childNodes->item(1)->childNodes->item(2)->childNodes->item(2)->childNodes->item(2)->childNodes->item(1)->getAttribute('href');
$next_results_link = str_replace(' ','+',$next_results_link);
if ($debug)
echo "<p>$next_results_link</p>";
if($next_results_link and !strstr($next_results_link,'http://schedule.berkeley.edu/'))
{
if($query['p_start_row'])
$query['p_start_row'] += 100;
else
$query['p_start_row'] = 101;
load_results($query, $x);
}
}
?>
<!DOCTYPE html>
<html>
<head>
<?
/*
IMPORTANT!!! Chance 'Current Info' link to be all semesters, not just Fall 2010.
To Do: Make entire tbody clickable, allow selective hiding of secondary sections, put CSS and JS into separate, cacheable files.
*/
?>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" charset="UTF-8">
<title>Better Schedule Search</title>
<style type="text/css">
body{
font:9pt Verdana;
color:black;
background-color:white;
}
#title{
color:black;
text-decoration:none;
}
#title:hover{
color:mediumblue;
text-decoration:underline;
}
#newSearch{
float:right;
position:relative;
bottom:2pt; /* This actually makes it 2pts lower than the bottom of the title, but it looks better because of the optical illusion of the wide spacing with the text near it. */
}
#stupidIE,#noJS,#loading,tr.more>td td:first-child,tr.sec,tr.more,span.hidden{
display:none;
}
#stupidIE,#noResults>p:first-child{
font-size:10.5pt;
}
#searchResults, #searchResults table{
border:none;
border-collapse:collapse;
width:100%;
}
#searchResults th{
text-align:left;
padding:1pt 2pt 0;
background-color:mediumblue;
color:white;
font-weight:bold;
font-size:10pt;
}
#searchResults>tbody:hover,
#searchResults>tbody.selected:hover{
-webkit-box-shadow: #68B4DF 0 0 3px 2px;
-moz-box-shadow: #68B4DF 0 0 3px 2px;
box-shadow: #68B4DF 0 0 3px 2px;
}
tr.sec tbody:hover{
background-color:#FFFDE0;
}
tbody.bg0{
background-color:#FFF;
}
tbody.bg1,tbody.bg3{
background-color:#E8F8FF;
}
tbody.bg2{
background-color:#D4F4FF;
}
#searchResults>tbody.selected{
display:table-row-group !important; /*don't want to hide this when hiding bad results*/
-webkit-box-shadow: black 0 0 0 2px;
-moz-box-shadow: black 0 0 0 2px;
box-shadow: black 0 0 0 2px;
}
tr.sec tbody.selected,tr.sec tbody.selected tbody{
background-color:#FFFDC0;
}
tr.bad,tr.bad+tr+tr{
color:gray;
}
tbody.selected>tr{
color:black;
}
#searchResults td{
margin:0;
padding:1pt 2pt;
line-height:11pt;
}
#searchResults td:first-child,tr.more>td+td,tr.sec>td+td{
width:1px; /* Not literally, just minimizes width as per the standardized table layout algorithm. */
}
#searchResults td[colspan="7"]{
padding:0 2pt 3pt 2pt;
}
#badResults td{
padding:2pt !important;
}
#searchResults td.time,#searchResults th.time,#searchResults td.units,#searchResults th.units{
text-align:center;
}
td.bad{
font-weight:bold;
color:red;
}
td.edd{
font-weight:bold;
color:black; /*I don't want .bad to make it gray*/
}
#searchResults>tbody>tr:first-child,#searchResults tr.sec>td>table>tbody>tr:first-child{
cursor:pointer;
}
#searchResults td.restrictions a[href="javascript:void(0)"]{
color:mediumblue;
text-decoration:none;
}
#searchResults td.restrictions:hover a[href="javascript:void(0)"]{
text-decoration:underline;
}
big,img{
font-size:125%;
vertical-align:middle;
border:none;
}
form {
text-align: center;
}
form input {
width: 20em;
}
form label {
font-size: 1.5em;
}
form table {
margin: 0 auto;
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
if($.browser.msie)
$('p#stupidIE').show();
if(history.navigationMode)
history.navigationMode='fast';
$('table#searchResults>tbody>tr:first-child,table#searchResults tr.sec>td>table>tbody>tr:first-child').live('click',function(){
var tr = $(this);
tr.children().eq(0).html(tr.nextAll().toggle().parent().toggleClass('selected').hasClass('selected')?'&#9660;':'&#9654;');
var restr = tr.next().find('td.restrictions');
if (restr.length && restr.height() > 1.5*restr.parent().prev().height() && restr.find('a[href="javascript:void(0)"]').length == 0)
restr.append(' <a href="javascript:void(0)">&laquo;less</a>');
});
$('table#searchResults td.restrictions:has(a[href="javascript:void(0)"])').live('click',function(){
var parent = $(this), me = parent.find('a[href="javascript:void(0)"]');
if (me.next().length) {
me.remove();
parent.html(parent.text()+' <a href="javascript:void(0)">&laquo;less</a>');
} else {
var stdHeight = 1.5*me.height();
me.remove();
var html = parent.html();
var i = Math.floor(html.length*stdHeight/parent.height());
for (; parent.height() > stdHeight; i -= 4)
parent.html(html.slice(0, i));
parent.html(html.slice(0, i));
me.html('&hellip;&raquo;');
parent.append(me).append('<span class="hidden">' + html.slice(i) + '</span>');
}
});
var x = $('table#searchResults>tbody');
if(x.length == 1)
x.children().eq(0).click();
});
function searchFormOnSubmit(e){
var q = queryDeptCourseNumberFromDesig($.trim($('#designation').val()));
$.each(e.elements,function(){if(this.name != 'IGNORE_ME' && this.value)q+='&'+this.name+'='+this.value;});
location.search = q;
}
function queryDeptCourseNumberFromDesig(str) {
var desig = str.split(/\s+/);
if (desig.length === 1) {
desig = desig[0];
var i = desig.search(/\d/); //index of the first digit
if (i === -1)
return '?p_dept=' + desig;
else
if (/^[chnr]?\d+[a-z]?$/i.test(desig))
return '?p_course=' + desig;
else
return '?p_dept=' + desig.slice(0,i) + '&p_course=' + desig.slice(i);
}
var last = desig[-1 + desig.length];
if (/\d/.test(last))
return '?p_dept=' + desig.slice(0,-1).join('+') + '&p_course=' + last;
else
return '?p_dept=' + desig.join('+');
}
function testQueryDeptCourseNumberFromDesig() {
assert('cs160', '?p_dept=cs&p_course=160');
assert('cs 160', '?p_dept=cs&p_course=160');
assert('comp sci 160', '?p_dept=comp+sci&p_course=160');
assert('math 1a', '?p_dept=math&p_course=1a');
assert('physics', '?p_dept=physics');
assert('r1b', '?p_course=r1b');
}
function assert(inp, expected) {
var result = queryDeptCourseNumberFromDesig(inp);
console.log(((result === expected) ? 'passed' : 'failed') + ': "' + inp + '" -> "' + result + ((result === expected) ? '"' : '", expected "' + expected + '"'));
}
$(function() {
var shown = false, text = {
'true': 'Hide Advanced Options',
'false': 'Show Advanced Options'
};
$('#show-advanced-options').click(function(e) {
shown = !shown;
$(this).text(text[shown]);
$('form table').toggle(shown);
});
});
</script>
</head>
<body>
<div>
<p id="newSearch"><a href=".">New Search</a></p>
<h1><a id="title" href="." title="New Search">Better Schedule Search</a></h1>
</div>
<p>By Jay and <a href="mailto:laughinghan@berkeley.edu">Han (laughinghan@berkeley.edu)</a>, powered by <b><a href="http://jquery.com">jQuery</a></b>.</p>
<pre id="debug"></pre>
<p id="stupidIE">It seems you are using Microsoft Internet Explorer. If so this probably will not work. Try <a href="http://my.opera.com/community/download.pl?ref=yhwhan&p=opera_desktop">Opera</a> instead.</p>
<script type="text/javascript">
document.write('<p id="loading">Loading</p><div id="noJS">');
</script>
<p>It seems you cannot or do not wish to use JavaScript. If so this will not work for you. <a href="http://schedule.berkeley.edu/">Try the original Online Schedule of Classes instead.</a></p>
<script type="text/javascript">
document.write('</div>');
</script>
<?php if($_GET):
$x = array();
global $debug;
$debug = isset($_GET['debug']);
if ($debug)
unset($_GET['debug']);
load_results($_GET, $x, $debug);
if ($x['noResults']) {
?>
<div id="noResults">
<p>No results.</p>
<p>I'm sorry, but apparently there are no classes that match your search criteria.</p>
<p>Not my fault, just what Berkeley's servers are telling me. <a href="<?php echo OSOC_BASE.http_build_query($_GET)?>">See for yourself</a>.</p>
</div>
<?php
} else {
if ($debug) {
echo '<h3>Table of Search Results as an Array: <a href="javascript:void(0)" onclick="$(this).parent().next().toggle()">Show/Hide</a></h3><pre>';
var_dump($x);
echo '</pre>';
}
?>
<p><big><?php echo $num_matches?> matches for <?php echo $semester?>:</big></p>
<table id="searchResults">
<thead>
<tr>
<th>&nbsp;
<th>Designation
<th>Title
<th>Instructor
<th class="time"><?php echo preg_match('/^Summer/',$semester)?'Session':'Time'?>
<th class="units">Units
<th colspan=2>&nbsp;
</thead>
<?php foreach ($x as $i => $c) { flush(); ?>
<tbody class="bg<?php echo $i%4?>">
<tr<?php echo $c['bad'] ? ' class="bad"' : ''?>>
<td>&#9654;
<td><?php echo $c['desig']?>
<td><?php echo $c['title']?>
<td><?php echo $c['instructor']?>
<td class="time"><?php echo $c['session']?$c['session']:$c['time']?>
<td class="units"><?php echo $c['units']?>
<td<?php
if($c['bad'])
echo ' class="bad"';
if($w=$c['enrollment']['waitlist'])
echo ' title="Waitlist of '.$w.'"';
?>><?php echo $c['fullness']?>
<td<?php echo $c['edd']?' class="edd">EDD':'>' ?>
</tr>
<tr class="more">
<td></td>
<td colspan=7><table>
<tr>
<td></td>
<td>CCN: <?php echo $c['ccn']?>
<td><?php if ($k=&$c['location']) echo 'Room: '.$k;?>
<td>As&nbsp;of&nbsp;<?php echo $c['enrollment']['asof']?>: <?php if($c['enrollment']['limit'] !== null) echo 'Seats:'.$c['enrollment']['limit']; else echo 'SEE DEPT';?><?php if($c['enrollment']['enrolled']) echo ' Taken:'.$c['enrollment']['enrolled']; if($c['enrollment']['available']) echo ' Available:'.$c['enrollment']['available']; if($w) echo ' Waitlist:'.$w ?>
</tr>
<tr>
<td></td>
<td colspan=2><?php echo $c['status']?$c['status'].' ':''?><a target="_blank" href="<?php echo $c['infobears_url']?>">Current Info</a>
| <a target="_blank" href="<?php echo $c['catalog_url']?>">Catalog Description</a>
<?php if($c['site']){echo '| <a target="_blank" href="'.$c['site'].'">Course Website</a>';}?>
<?php if($c['books']){echo '| <a target="_blank" href="'.$c['books'].'">View Books</a>';}?>
<?php if($c['ratemyprof_url']){echo '| <a target="_blank" href="'.$c['ratemyprof_url'].'">Rate My Professor</a>';}?>
<?php if($c['hkncoursesurveys_url']){echo '| <a target="_blank" href="'.$c['hkncoursesurveys_url'].'">HKN Course Surveys</a>';}?>
<td colspan=2><?php echo $c['session']?"Time: $c[time]":''?><?php echo $c['final']?'Final Exam Group '.$c['final']['group'].': '.$c['final']['time']:''?>
</tr>
<?php echo $k=&$c['restrictions'] ? '<tr><td></td><td colspan="5" class="restrictions">'.$k.'</td></tr>' : '' ?>
</table>
</tr>
<?php if($c['sections']) { ?>
<tr>
<td></td>
<td colspan=7><?php echo count($c['sections'])?> secondary sections
</tr>
<tr class="sec">
<td></td>
<td colspan=7><table>
<?php foreach($c['sections'] as $s) { //loop over the sections as $s?>
<tbody>
<tr<?php echo $s['bad'] ? ' class="bad'.($s['edd'] ? ' edd':'').'"' : ''?>>
<td>&#9654;
<td><?php echo $s['desig']?>
<td><?php echo $s['instructor']?>
<td class="time"><?php echo $s['time']?>
<td><?php echo $s['location']?>
<td<?php echo $s['bad']?' class="bad"':''?><?php echo ($w=$s['enrollment']['waitlist'])?' title="Waitlist of '.$w.'"':''?>><?php echo $s['fullness']?>
</tr>
<tr class="more">
<td></td>
<td colspan=7><table>
<tr>
<td></td>
<td>CCN: <?php echo $s['ccn']?>
<td><?php echo $s['status']?$s['status'].' ':''?><?php echo $s['infobears_url'] ? '<a target="_blank" href="'.$s['infobears_url'].'">Current Info</a>' : '' ?><?php if($s['ratemyprof_url']){echo '| <a target="_blank" href="'.$s['ratemyprof_url'].'">Rate My Professor';}?>
<td>As&nbsp;of&nbsp;<?php echo $s['enrollment']['asof']?>: <?php if($s['enrollment']['limit'] !== null) echo 'Seats:'.$s['enrollment']['limit']; else echo 'SEE DEPT';?><?php if($s['enrollment']['enrolled']) echo ' Taken:'.$s['enrollment']['enrolled']; if($s['enrollment']['available']) echo ' Available:'.$s['enrollment']['available']; if($w) echo ' Waitlist:'.$w ?>
</tr>
<?php echo $k=&$s['restrictions'] ? '<tr><td></td><td colspan=5 class="restrictions">'.$k.'</td></tr>' : '' ?>
</table>
</tr>
</tbody>
<?php } //ends foreach of sections ?>
</table>
</tr>
<?php } //ends if($c['sections']) ?>
</tbody>
<?php } //ends foreach of lectures ?>
</table>
<p>For comparison, see <a target="_blank" href="<?php echo OSOC_BASE.http_build_query($_GET)?>">your exact same search using the original Online Schedule of Classes</a>.</p>
<?php
} //ends if no results
else:
?>
<div id="searchForm">
<form onsubmit="searchFormOnSubmit(this);return false;">
<p>Semester: <SELECT NAME="p_term" tabindex=15 onchange="if($(this).val()=='SU')$('#session').show();else $('#session').hide();">
<option value="SP">Spring or -- Choose a Different Semester --
<option value="FL">Fall
<option value="SU">Summer
</select></p>
<p><label for="designation">Search By Dept./Course Number, e.g. "Math 1a", or "Physics", or "R1B"</label><br><input type="text" id="designation" name="IGNORE_ME" tabindex=1 style="font-size: 2em; width: 90%; max-width: 30em" autofocus></p>
<p><label for="p_title">Or Search By Title, e.g. "Calculus", "Quantum Mechanics"</label><br><INPUT TYPE="TEXT" id="p_title" NAME=p_title tabindex=2 style="font-size: 2em; width: 90%; max-width: 30em"></p>
<p><a href="javascript:;" id="show-advanced-options" style="float:right">Show Advanced Options</a></p>
<table width="590" cellpadding="0" cellspacing="2" border="0" style="display:none">
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; Course Classifications</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<SELECT NAME="p_classif" tabindex=16><option value="">-- Choose a Course Classification --
<option value="L">lower division (numbered 1 through 99)
<option value="U">upper division (100-199)
<option value="G">graduate (200-299)
<option value="P">professional (300-399)
<option value="M">special study for master's exam (601)
<option value="D">special study for doctoral qualifying exam (602)
<option value="O">Other
</select></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; Department Name</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<SELECT NAME="p_deptname" tabindex=17><option value="">-- Choose a Department Name --
<option>Aerospace Studies
<option>African American Studies
<option>Afrikaans
<option>Agricultural and Environmental Chemistry
<option>Agricultural and Resource Economics and Policy
<option>Altaic
<option>American Studies
<option>Ancient History and Mediterranean Archaeology
<option>Anthropology
<option>Applied Science and Technology
<option>Arabic
<option>Architecture
<option>Asian American Studies Program
<option>Asian Studies
<option>Astronomy
<option>Bengali
<option>Bioengineering
<option>Biology
<option>Biophysics
<option>Buddhist Studies
<option>Business Administration Undergraduate Program
<option>Business Administration Doctoral Program
<option>Catalan
<option>Celtic Studies
<option>Chemical Engineering
<option>Chemistry
<option>Chicano Studies Program
<option>Chinese
<option>City and Regional Planning
<option>Civil and Environmental Engineering
<option>Classics
<option>Cognitive Science
<option>College Writing Program
<option>Comparative Biochemistry
<option>Comparative Literature
<option>Computational and Genomic Biology
<option>Computer Science
<option>Critical Theory Graduate Group
<option>Cuneiform
<option>Demography
<option>Development Studies
<option>Dutch
<option>Earth and Planetary Science
<option>East Asian Languages and Cultures
<option>East European Studies
<option>Economics
<option>Education
<option>Egyptian
<option>Electrical Engineering
<option>Energy and Resources Group
<option>Engineering
<option>English
<option>Environmental Design
<option>Environmental Economics and Policy
<option>Environmental Science, Policy, and Management
<option>Environmental Sciences
<option>Ethnic Studies
<option>Ethnic Studies Graduate Group
<option>Eurasian Studies
<option>Film Studies
<option>Folklore
<option>French
<option>Gender and Women's Studies
<option>Geography
<option>German
<option>Graduate Student Professional Development Program
<option>Greek
<option>Health and Medical Sciences
<option>Hebrew
<option>Hindi-Urdu
<option>History
<option>History of Art
<option>Indigenous Languages of the Americas
<option>Industrial Engineering and Operations Research
<option>Information
<option>Integrative Biology
<option>Interdisciplinary Studies Field Major
<option>International and Area Studies
<option>Iranian
<option>Italian Studies
<option>Japanese
<option>Jewish Studies
<option>Journalism
<option>Khmer
<option>Korean
<option>Landscape Architecture
<option>Language Proficiency Program
<option>Latin
<option>Latin American Studies
<option>Law
<option>Legal Studies
<option>Lesbian, Gay, Bisexual and Transgender Studies
<option>Letters and Science
<option>Linguistics
<option>Malay/Indonesian
<option>Materials Science and Engineering
<option>Mathematics
<option>Mechanical Engineering
<option>Media Studies
<option>Medieval Studies
<option>Middle Eastern Studies
<option>Military Affairs
<option>Military Science
<option>Molecular and Cell Biology
<option>Music
<option>Nanoscale Science and Engineering
<option>Native American Studies
<option>Natural Resources
<option>Naval Science
<option>Near Eastern Studies
<option>Neuroscience
<option>New Media
<option>Nuclear Engineering
<option>Nutritional Sciences and Toxicology
<option>Optometry
<option>Peace and Conflict Studies
<option>Persian
<option>Philosophy
<option>Physical Education
<option>Physics
<option>Plant and Microbial Biology
<option>Political Economy of Industrial Societies
<option>Political Science
<option>Portuguese
<option>Practice of Art
<option>Psychology
<option>Public Health
<option>Public Policy
<option>Punjabi
<option>Religious Studies
<option>Rhetoric
<option>Sanskrit
<option>Scandinavian
<option>Science and Mathematics Education
<option>Semitics
<option>Slavic Languages and Literatures
<option>Social Welfare
<option>Sociology
<option>South and Southeast Asian Studies
<option>South Asian
<option>Southeast Asian
<option>Spanish
<option>Statistics
<option>Tagalog
<option>Tamil
<option>Thai
<option>Theater, Dance, and Performance Studies
<option>Tibetan
<option>Turkish
<option>Undergraduate and Interdisciplinary Studies
<option>Vietnamese
<option>Vision Science
<option>Visual Studies
<option>Yiddish
</select></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; Course Prefixes/Suffixes</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<SELECT NAME="p_presuf" style="width:2.3in" tabindex=18><option value="">-- Choose a Course Prefix/Suffix --
<option value="C">C prefix - cross-listed
<option value="H">H prefix - honors
<option value="N">N prefix - Summer Session not equivalent to regular session with the same number
<option value="R">R prefix - meets reading and composition requirement
<option value="AC">AC suffix - meets American Cultures requirement
</select></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER" id="session" style="display:none">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; Summer Session</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<SELECT NAME="p_session" tabindex=19>
<option value="">-- Choose a Session -- </option>
<option value="A">A - 1st 6 Week </option>
<option value="B">B - 10 Week </option>
<option value="C">C - 8 Week </option>
<option value="D">D - 2nd 6 Week </option>
<option value="E">E - 3 Week </option>
<option value="O">O - Other </option>
</select></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#instr">Instructor Name</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_instr VALUE="" tabindex=4>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
SMITH, GREEN</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#exam">Final Exam Group</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_exam VALUE="" tabindex=5>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
7, 22, NONE, TBA</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#ccn">Course Control Number</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE=TEXT NAME=p_ccn VALUE="" tabindex=6>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
00507, 12345</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#day">Day(s) of the Week</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_day VALUE="" tabindex=7>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
M, TuTh, MTWTF</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#hour">Hour(s)</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_hour VALUE="" tabindex=8>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
930-11, 10, 2-5</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://registrar.berkeley.edu/Scheduling/bldgabb.html">Building Name</A></B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_bldg VALUE="" tabindex=9>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
DWINELLE, GPB, NORTH GATE</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#units">Units/Credit</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_units VALUE="" tabindex=10>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
2, .5, 1-10</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#restrict">Restrictions</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_restr VALUE="" tabindex=11>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
NONE, FR, GR, CLASS ENTRY CODE REQ</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#info">Additional Information</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_info VALUE="" tabindex=12>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
SWIMMING, AMERICAN CULTURES</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<TR VALIGN="CENTER">
<TD>&nbsp;</TD>
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B>
&nbsp; <A HREF="http://schedule.berkeley.edu/about.html#status">Status/Last Changed</B></FONT></TD>
<TD ALIGN="LEFT" NOWRAP>&nbsp;<INPUT TYPE="TEXT" NAME=p_updt VALUE="" tabindex=13>&nbsp;
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B>
UPDATED, ADDED, CANCELLED</B></FONT></TD>
<TD>&nbsp;</TD>
</TR>
<tr><td>&nbsp;</td></tr>
</TABLE>
<button tabindex=14><big>Search</big></button>
</FORM>
</div>
<?php endif; ?>
<p>&copy;Copyleft 2010 Jay, <a href="mailto:laughinghan@berkeley.edu">Han</a>, <a href="http://berkeley.edu">UC Berkeley</a>: <a href="http://gist.github.com/549772">View Source On GitHub</a> <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution License</a>. <a href="http://jquery.com">Powered by jQuery</a></p>
</body>
</html>
@jneen
Copy link

jneen commented Aug 28, 2011

dude. jayferd/better-schedule-search

@laughinghan
Copy link
Author

laughinghan commented Aug 28, 2011 via email

@jneen
Copy link

jneen commented Aug 30, 2011

It mostly does... :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment