Created
August 25, 2010 16:01
-
-
Save laughinghan/549772 to your computer and use it in GitHub Desktop.
Better Schedule Search for Berkeley
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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).'…'; | |
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(' ',' ',$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>¼</big>Full'; | |
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']*5/8) | |
$info['fullness'] = '<big>½</big>Full'; | |
else if($info['enrollment']['enrolled'] < $info['enrollment']['limit']*7/8) | |
$info['fullness'] = '<big>¾</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')?'▼':'▶'); | |
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)">«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)">«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('…»'); | |
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:[email protected]">Han ([email protected])</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> | |
<th>Designation | |
<th>Title | |
<th>Instructor | |
<th class="time"><?php echo preg_match('/^Summer/',$semester)?'Session':'Time'?> | |
<th class="units">Units | |
<th colspan=2> | |
</thead> | |
<?php foreach ($x as $i => $c) { flush(); ?> | |
<tbody class="bg<?php echo $i%4?>"> | |
<tr<?php echo $c['bad'] ? ' class="bad"' : ''?>> | |
<td>▶ | |
<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 of <?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>▶ | |
<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 of <?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> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B> | |
Course Classifications</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <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> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B> | |
Department Name</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <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> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B> | |
Course Prefixes/Suffixes</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <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> </TD> | |
</TR> | |
<TR VALIGN="CENTER" id="session" style="display:none"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial, sans-serif" SIZE="1" COLOR="HHHHHH"><B> | |
Summer Session</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <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> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#instr">Instructor Name</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_instr VALUE="" tabindex=4> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
SMITH, GREEN</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#exam">Final Exam Group</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_exam VALUE="" tabindex=5> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
7, 22, NONE, TBA</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#ccn">Course Control Number</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE=TEXT NAME=p_ccn VALUE="" tabindex=6> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
00507, 12345</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#day">Day(s) of the Week</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_day VALUE="" tabindex=7> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
M, TuTh, MTWTF</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#hour">Hour(s)</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_hour VALUE="" tabindex=8> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
930-11, 10, 2-5</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://registrar.berkeley.edu/Scheduling/bldgabb.html">Building Name</A></B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_bldg VALUE="" tabindex=9> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
DWINELLE, GPB, NORTH GATE</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#units">Units/Credit</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_units VALUE="" tabindex=10> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
2, .5, 1-10</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#restrict">Restrictions</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_restr VALUE="" tabindex=11> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
NONE, FR, GR, CLASS ENTRY CODE REQ</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="CCCCCC" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#info">Additional Information</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_info VALUE="" tabindex=12> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
SWIMMING, AMERICAN CULTURES</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<TR VALIGN="CENTER"> | |
<TD> </TD> | |
<TD WIDTH="170" BGCOLOR="E6E6E6" NOWRAP><FONT FACE="Verdana, Helvetica, Arial" SIZE="1" COLOR="HHHHHH"><B> | |
<A HREF="http://schedule.berkeley.edu/about.html#status">Status/Last Changed</B></FONT></TD> | |
<TD ALIGN="LEFT" NOWRAP> <INPUT TYPE="TEXT" NAME=p_updt VALUE="" tabindex=13> | |
<FONT face="Helvetica, Arial, sans-serif" size="1" color="336699"><B> | |
UPDATED, ADDED, CANCELLED</B></FONT></TD> | |
<TD> </TD> | |
</TR> | |
<tr><td> </td></tr> | |
</TABLE> | |
<button tabindex=14><big>Search</big></button> | |
</FORM> | |
</div> | |
<?php endif; ?> | |
<p>©Copyleft 2010 Jay, <a href="mailto:[email protected]">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> |
Author
laughinghan
commented
Aug 28, 2011
via email
it doesn't work yet does it?
Han
…On Sat, Aug 27, 2011 at 6:18 PM, jayferd < ***@***.***>wrote:
dude. github.com/jayferd/better-schedule-search
##
Reply to this email directly or view it on GitHub:
https://gist.github.com/549772
It mostly does... :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment