Changeset - da3582f113b9
[Not reviewed]
default
0 8 0
Nathan Brink (binki) - 14 years ago 2012-02-19 00:17:20
ohnobinki@ohnopublishing.net
Add support for Sunday, fixing bug #98.
8 files changed with 76 insertions and 45 deletions:
0 comments (0 inline, 0 general)
inc/class.schedule.php
Show inline comments
 
@@ -517,90 +517,93 @@ class Schedule
 

	
 

	
 
      if (!empty($parent_schedule))
 
        {
 
          echo '          <a class="button" href="' . htmlentities($parent_uri, ENT_QUOTES) . '" title="Parent schedule: ' . htmlentities($parent_schedule->getName()) . '">Parent</a>' . PHP_EOL;
 
        }
 

	
 
      echo '          <a class="button" href="input.php">Home</a>' . PHP_EOL
 
	. '        </p>'. PHP_EOL
 
	. '        <p class="centeredtext">Having problems? <a href="feedback.php">Let us know</a>.</p>' . PHP_EOL
 
	. '        <p class="centeredtext graytext"><em>Keyboard Shortcut: Left and right arrow keys switch between schedules</em></p>' . PHP_EOL;
 
    }		
 

	
 
    echo "\n";
 

	
 
    if($this->nPermutations > 0)
 
      {
 
	/*
 
	 * Figure out if we have to deal with Saturday and then deal
 
	 * with it.
 
	 *
 
	 * Also, ensure that our $time array is big enough for all of
 
	 * these courses.
 
	 */
 
	$max_day_plusone = 5;
 
	$dayloop_max = 5;
 
        $have_sunday = FALSE;
 
	$have_saturday = FALSE;
 

	
 
	$max_time = (int)max($time);
 
	$min_time = (int)min($time);
 
	$sort_time = FALSE;
 
	foreach ($this->courses as $course)
 
	  foreach ($course as $course_slot)
 
	  {
 
	    for ($si = 0; $si < $course_slot->sections_count(); $si ++)
 
              foreach ($course_slot->section_get_i($si)->getMeetings() as $meeting)
 
		{
 
		  /* Saturdayness */
 
		  /* Sundayness and Saturdayness */
 
                  if ($meeting->getDay(6))
 
                    $have_sunday = TRUE;
 
		  if ($meeting->getDay(5))
 
		    {
 
		      $max_day_plusone = 6;
 
		      $have_saturday = TRUE;
 
		    }
 
                    $have_saturday = TRUE;
 

	
 
		  /* very late / very early classes */
 
		  while ((int)ltrim($meeting->getEndTime(), '0') > $max_time)
 
		    {
 
		      $max_time += $max_time + 30;
 
		      while ($max_time % 100 >= 60)
 
			$max_time += 40; /* + 100 - 60 */
 
		      $time[] = $max_time;
 
		    }
 
		  while ((int)ltrim($meeting->getStartTime(), '0') < $min_time)
 
		    {
 
		      $max_time += 30;
 
		      while ($min_time % 100 < 30)
 
			$min_time -= 40; /* + 60 - 100 */
 
		      $min_time -= 30;
 
		      $time[] = $min_time;
 
		      $sort_time = TRUE;
 
		    }
 
		}
 
	  }
 
	/* ensure that early times are actually first ;-) */
 
	if ($sort_time)
 
	  sort($time);
 

	
 
        if ($have_saturday)
 
          $dayloop_max = 6;
 

	
 
        echo '    <div id="regDialog" title="Registration Codes">' . PHP_EOL
 
	  . '      <div id="regDialog-content"></div>' . PHP_EOL
 
	  . '      <p class="regDialog-disclaimer graytext">' . PHP_EOL
 
	  . '        <em>' . PHP_EOL
 
	  . '          Note: The registration information above corresponds to the sections' . PHP_EOL
 
	  . '          displayed on the currently selected tab.' . PHP_EOL
 
	  . '        </em>' . PHP_EOL
 
	  . '      </p>' . PHP_EOL
 
	  . '      <p class="regDialog-disclaimer graytext">' . PHP_EOL
 
	  . '        <em>' . PHP_EOL
 
	  . '          Disclaimer: You are responsible for' . PHP_EOL
 
	  . '          double-checking the information you get from and input into slate_permutate' . PHP_EOL
 
	  . '          when registering for classes. There is no guarantee that the harvested' . PHP_EOL
 
	  . '          information is correct or that slate_permutate will handle' . PHP_EOL
 
	  . '          the information you enter correctly.' . PHP_EOL
 
	  . '        </em>' . PHP_EOL
 
	  . '      </p>' . PHP_EOL
 
	  . '    </div>' . PHP_EOL;
 
	echo '<div id="tabs">' . "\n" .
 
               '<div id="show-box" class="show-buttons">
 
                  <form action="#"><p class="nospace">
 
                    <label><strong>Display:</strong></label>
 
                    <input id="show-course-title" name="show-course-title" type="checkbox" /><label for="show-course-title">Course Title</label>
 
                    <input id="show-prof" name="show-prof" type="checkbox" checked="checked" /><label for="show-prof">Professor</label>
 
@@ -658,69 +661,78 @@ class Schedule
 
	      continue;
 

	
 
	    /*
 
	     * Store a JSON list of courses, each with only the one
 
	     * section rendered in this permutation. This is used for
 
	     * the ``Registration Numbers'' dialog which noramlly
 
	     * shows users course synonyms.
 
	     */
 
	    $permutation_courses = array();
 

	
 
            /*
 
             * Count the number of credit hours in this particular
 
             * schedule.
 
             */
 
            $credit_hours = array();
 
            $have_credit_hours = FALSE;
 

	
 
	     echo  '      <div class="section" id="tabs-' . ($i+1) . "\">\n";
 
  
 
	    // Beginning of table
 
	    echo "        <table style=\"empty-cells:show;\" border=\"1\" cellspacing=\"0\">\n";
 
				
 
	    // Header row
 
	    echo "          <tr>\n"
 
	      . '            <td class="none permuteNum">' . ($i + 1) . "</td>\n"
 
	      . "            <td class=\"day\">Monday</td>\n"
 
              . '            <td class="none permuteNum">' . ($i + 1) . "</td>\n";
 
            if ($have_sunday)
 
              echo '            <td class="day">Sunday</td>' . PHP_EOL;
 
            echo "            <td class=\"day\">Monday</td>\n"
 
	      . "            <td class=\"day\">Tuesday</td>\n"
 
	      . "            <td class=\"day\">Wednesday</td>\n"
 
	      . "            <td class=\"day\">Thursday</td>\n"
 
	      . "            <td class=\"day\">Friday</td>\n";
 
	    if ($have_saturday)
 
	      echo "            <td class=\"day\">Saturday</td>\n";
 
	    echo "          </tr>\n";
 

	
 
	    $last_meeting = array();
 
	    $rowspan = array(0, 0, 0, 0, 0, 0);
 
	    $rowspan = array(0, 0, 0, 0, 0, 0, 0);
 
	    for($r = 0; $r < (count($time)-1); $r++)
 
	      {
 

	
 
		echo "          <tr>\n"
 
		  . "            <td class=\"time\">" . $this->prettyTime($time[$r]) . "</td>\n";
 

	
 
		/* currently, 0-5 = monday-saturday */
 
		for($dayLoop = 0; $dayLoop < $max_day_plusone; $dayLoop++)
 
		/*
 
                 * Currently, 6, 0-5 = sunday, monday-saturday. We use
 
                 * the trick that -1 through 5 mod 7 is
 
                 * sunday-saturday.
 
                 */
 
		for($dayLoop = $have_sunday ? -1 : 0; $dayLoop < $dayloop_max; $dayLoop = ($dayLoop + 1) % 7)
 
		{
 
                  if ($dayLoop < 0)
 
                    $dayLoop = 6;
 

	
 
		  /* Makes sure there is not a class already in progress */
 
		  if($rowspan[$dayLoop] <= 0)
 
		    {
 
		      for($j = 0; $j < count($this->courses); $j++)
 
			{
 
			  $course = $this->courses[$j];
 
			  foreach ($course as $course_slot)
 
			    {
 
			      $section_index = $this->storage[$i][$j];
 
			      $section = $course_slot->section_get_i($section_index);
 

	
 
			      /* iterate through all of a class's meeting times */
 
			      $meetings = $section->getMeetings();
 

	
 
				  /* find any meeting which are going on at this time */
 
				  $current_meeting = NULL;
 
				  foreach ($meetings as $meeting)
 
				    {
 
				      if ($meeting->getDay($dayLoop)
 
					  && $meeting->getStartTime() >= $time[$r]
 
					  && $meeting->getStartTime() < $time[$r+1])
 
					{
 
					  $current_meeting = $meeting;
 
					}
inc/class.section_meeting.inc
Show inline comments
 
@@ -25,107 +25,111 @@
 
 * A Calvin student might ask ``Why is there a need for a
 
 * SectionMeeting class? Doesn't every Section have a unique
 
 * prof/time/location?'' A Cedarville student would retort ``Huh?
 
 * Don't some of your classes have labs in addition to lecture? How do
 
 * you know that you have to go to both a lecture and lab -- and how
 
 * do you handle that some classes have different lecture times for
 
 * different days of the week?''. A Calvin section _is_ a unique
 
 * prof/time/location. At Cedarville, a Section refers to a prof and a
 
 * _set_ of time/location pairs. The generalization is to make each
 
 * Section support a list of meeting times/locations.
 
 */
 
class SectionMeeting
 
{
 
  private $time_start;
 
  private $time_end;
 
  private $days;
 
  private $location;
 
  private $instructor;
 

	
 
  /**
 
   * \brief
 
   *   Construct a SectionMeeting.
 
   *
 
   * \param $days
 
   *   A string of single-char day upon which a section meets. Monday
 
   *   is represented with 'm', Tuesday with 't', Wednesday with 'w',
 
   *   Thursday with 'h', and Friday with 'f'.
 
   *   A string of single-char day upon which a section meets. Sunday
 
   *   is represented with 'u', Monday with 'm', Tuesday with 't',
 
   *   Wednesday with 'w', Thursday with 'h', Friday with 'f', and
 
   *   Saturday with 's'.
 
   * \param $time_start
 
   *   The time of day when the section meeting starts. Use
 
   *   school_crawl_time_format() or ensure that the time is formatted
 
   *   in 24-hour, 0-padded, 4-digit form (HHMM).
 
   * \param $time_end
 
   *   The time of day when the section meeting ends.
 
   * \param $location
 
   *   Where the meeting occurs. Often a room number of some sort.
 
   * \param $type
 
   *   The type of meeting this is. For lectures, please use
 
   *   'lecture'. For labs, please use 'lab'. For others, use the
 
   *   school's notation.
 
   * \param $instructor
 
   *   The instructor for this section meeting.
 
   */
 
  public function __construct($days, $time_start, $time_end, $location = NULL, $type = 'lecture', $instructor = NULL)
 
  {
 
    $this->days_set($days);
 

	
 
    $this->time_start = $time_start;
 
    $this->time_end = $time_end;
 

	
 
    $this->location = $location;
 

	
 
    $this->type = $type;
 
    $this->instructor = $instructor;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Take a days of week string and store it into our $days of week array.
 
   *
 
   * \param $days_str
 
   *   The days of the week in a string format. One char per
 
   *   day. Mon-Sat is represented with 'm', 't', 'w', 'h', 'f', 's'.
 
   *   day. Sun-Sat is represented with 'u', 'm', 't', 'w', 'h', 'f',
 
   *   's'.
 
   */
 
  private function days_set($days_str)
 
  {
 
    $this->days = array(0 => FALSE, 1 => FALSE, 2 => FALSE, 3 => FALSE, 4 => FALSE, 5 => FALSE);
 
    $this->days = array(0 => FALSE, 1 => FALSE, 2 => FALSE, 3 => FALSE, 4 => FALSE, 5 => FALSE, 6 => FALSE);
 

	
 
    $days_str_strlen = strlen($days_str);
 
    for ($i = 0; $i < $days_str_strlen; $i ++)
 
      $this->days[self::day_atoi($days_str[$i])] = TRUE;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Convert a day letter to a day numeral.
 
   *
 
   * Works fine if you give the numeral as well.
 
   */
 
  private static function day_atoi($day_c)
 
  {
 
    static $day_atoi = array('m' => 0, 't' => 1, 'w' => 2, 'h' => 3, 'f' => 4, 's' => 5,
 
			     'M' => 0, 'T' => 1, 'W' => 2, 'H' => 3, 'F' => 4, 'S' => 5,
 
			      0  => 0,  1  => 1,  2  => 2,  3  => 3,  4  => 4,  5  => 5);
 
    static $day_atoi = array(
 
      'm' => 0, 't' => 1, 'w' => 2, 'h' => 3, 'f' => 4, 's' => 5, 'u' => 6,
 
      'M' => 0, 'T' => 1, 'W' => 2, 'H' => 3, 'F' => 4, 'S' => 5, 'U' => 6,
 
      0  => 0,  1  => 1,  2  => 2,  3  => 3,  4  => 4,  5  => 5, 6 => 6,
 
    );
 

	
 
    return $day_atoi[$day_c];
 
  }
 

	
 
  /**
 
   * \brief
 
   *   For Section::__wakeup().
 
   *
 
   * \param $instructor
 
   *   New instructor's name, a string.
 
   */
 
  public function instructor_set($instructor)
 
  {
 
    $this->instructor = $instructor;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Get the instructor's name.
 
   *
 
   * \return
 
   *   The instructor's name as a string or NULL if there is no given
 
   *   instructor.
 
   */
 
@@ -197,83 +201,83 @@ class SectionMeeting
 
   *
 
   * \param $that
 
   *   The other section for which I should check for conflicts.
 
   * \return
 
   *   TRUE if there is a conflict, FALSE otherwise.
 
   */
 
  public function conflictsWith(SectionMeeting $that)
 
  {
 
    /*
 
     * The two sections meetings can't conflict if the start/end times
 
     * don't overlap. Also, use >= or <= here so that one can say ``I
 
     * have gym from 10 through 11 and then latin from 11 though 12''.
 
     */	
 
    if ($this->getStartTime() >= $that->getEndTime()
 
	|| $this->getEndTime() <= $that->getStartTime())
 
      {
 
	return FALSE;
 
      }
 

	
 
    /*
 
     * Now we know that the sections meetings overlap in start/end
 
     * times. But if they don't both meet on the same day at least
 
     * once, they don't conflict.
 
     */
 
    for ($day = 0; $day < 6; $day ++)
 
    for ($day = 0; $day < 7; $day ++)
 
      {
 
	if ($this->getDay($day) && $that->getDay($day))
 
	  return TRUE;
 
      }
 

	
 
    /*
 
     * The sections meetings don't both share a day of the week.
 
     */
 
    return FALSE;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Return an array of JSON keys specific to this section meeting
 
   *   time.
 
   *
 
   * Currently, the AJAX UI doesn't recognize that a given section may
 
   * have multiple meeting times. Thus, we simulate this by having
 
   * multiple instances of the same section but just with different
 
   * times in the UI.
 
   */
 
  public function to_json_array()
 
  {
 
    static $daymap = array(0 => 'm', 1 => 't', 2 => 'w', 3 => 'h', 4 => 'f', 5 => 's');
 
    static $daymap = array(0 => 'm', 1 => 't', 2 => 'w', 3 => 'h', 4 => 'f', 5 => 's', 6 => 'u');
 

	
 
    $json_array = array(
 
			'time_start' => $this->time_start,
 
			'time_end' => $this->time_end,
 
			'days' => array(),
 
			'location' => $this->location,
 
			'instructor' => $this->instructor,
 
			'type' => $this->type,
 
			);
 

	
 
    for ($day = 0; $day < 6; $day ++)
 
    for ($day = 0; $day < 7; $day ++)
 
      $json_array['days'][$daymap[$day]] = $this->getDay($day);
 

	
 
    return $json_array;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Parse a JSON array into a SectionMeeting.
 
   *
 
   * \param $json_array
 
   *   The JSON array to parse.
 
   * \return
 
   *   A shiny, new SectionMeeting.
 
   */
 
  public static function from_json_array(array $json_array)
 
  {
 
    $days = '';
 
    foreach ($json_array['days'] as $day => $meets)
 
      if ($meets)
 
	$days .= $day;
 
    return new SectionMeeting($days, $json_array['time_start'], $json_array['time_end'], $json_array['location'], $json_array['type'], $json_array['instructor']);
 
  }
 
}
inc/school.crawl.inc
Show inline comments
 
@@ -144,56 +144,56 @@ function school_crawl_gmmktime(array $tm
 
  return gmmktime($tm['tm_hour'], $tm['tm_min'], $tm['tm_sec'],
 
		$tm['tm_mon'] + 1, $tm['tm_mday'], $tm['tm_year'] + 1900)
 
    + $timezone_offset;
 
}
 

	
 
/**
 
 * \brief
 
 *   Take an array of day names and assemble them into
 
 *   slate_permutate's internal (weird) representation of a set of
 
 *   weekdays.
 
 *
 
 * This function is intended to make it easy for one to take the
 
 * output of an explode() call. For example, to decode $days_str =
 
 * 'Monday, Tuesday, Friday', one would do
 
 * school_crawl_days_format($school_crawl_log, explode(', ', $days_str));
 
 *
 
 * \param $school_crawl_log
 
 *   A school_crawl_log handle to report errors to.
 
 * \param $days
 
 *   An array of day names. These may be common abbreviations or
 
 *   truncations (any truncations must be two chars long for
 
 *   simplicity. One-char representations are supported, however, but
 
 *   use 'm', 't', 'w', 'h', 'f' to distinguish Thursday and
 
 *   Tuesday. 'r' may also be used for Thursday.). Case does not
 
 *   matter. 's' is for Saturday, based on CCBCMD.
 
 *   matter. 's' is for Saturday, based on CCBCMD. 'u' is for Sunday.
 
 * \return
 
 *   slate_permutate's strange internal days representation.
 
 */
 
function school_crawl_days_format(array $school_crawl_log, $days)
 
{
 
  static $daymap_1 = array('m' => 'm', 't' => 't', 'w' => 'w', 'h' => 'h', 'r' => 'h', 'f' => 'f', 's' => 's');
 
  static $daymap_2 = array('th' => 'h');
 
  static $daymap_1 = array('u' => 'u', 'm' => 'm', 't' => 't', 'w' => 'w', 'h' => 'h', 'r' => 'h', 'f' => 'f', 's' => 's');
 
  static $daymap_2 = array('su' => 'u', 'th' => 'h');
 

	
 
  $my_days = array();
 
  foreach ($days as $day)
 
    {
 
      $day_orig = $day;
 
      $day = strtolower(substr(trim($day), 0, 2));
 

	
 
      /*
 
       * convert from two-char representation to one-char
 
       * representation.n
 
       */
 
      if (strlen($day) > 1)
 
	{
 
	  if (isset($daymap_2[$day]))
 
	    $day = $daymap_2[$day];
 
	  else
 
	    $day = substr($day, 0, 1);
 
	}
 
      if (isset($daymap_1[$day]))
 
	$my_days[$daymap_1[$day]] = TRUE;
 
      else
 
	school_crawl_logf($school_crawl_log, 5, "school_crawl_days_format() got invalid day specifier: `%s' => `%s'.",
 
			  $day_orig, $day);
 
    }
input.php
Show inline comments
 
@@ -292,104 +292,107 @@ if (!empty($_REQUEST['selectsemester']))
 
    <?php
 
      if ($sch)
 
        echo 'value="' . htmlentities($sch->getName(), ENT_QUOTES) . '"';
 
      elseif ($errors_fix)
 
        echo 'value="' . htmlentities($_POST['postData']['name'], ENT_QUOTES) . '"';
 
    ?> />
 
  <?php if (!empty($parent_schedule_id)): ?>
 
  <input type="hidden" name="postData[parent_schedule_id]" value="<?php echo htmlentities($parent_schedule_id, ENT_QUOTES); ?>" />
 
  <input type="hidden" name="postData[school]" value="<?php echo htmlentities($school['id']); ?>" />
 
  <input type="hidden" name="postData[semester]" value="<?php echo htmlentities($semester['id']); ?>" />
 
  <?php endif; ?>
 
</p>
 

	
 
<table id="container">
 
  <tr>
 
    <td>
 
      <table id="jsrows">
 
	<!-- Allow CSS to apply to entire rows at a time. -->
 
	<colgroup>
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col class="sunday<?php if (school_has_auto($inputPage->get_school())) echo ' collapsed';?>" />
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col />
 
	  <col class="saturday<?php if (school_has_auto($inputPage->get_school())) echo ' collapsed';?>" />
 
	  <col />
 
	  <col />
 
	</colgroup>
 
        <!-- Header -->
 
        <tr>
 
          <td>Class ID</td>
 
          <td class="center" id="letterNumber">Section</td>
 
          <td class="center">Prof</td>
 
          <td class="center">Start Time</td>
 
          <td class="center">End Time</td>
 
	  <td class="center">Su</td>
 
          <td class="center">M</td>
 
          <td class="center">Tu</td>
 
          <td class="center">W</td>
 
          <td class="center">Th</td>
 
          <td class="center">F</td>
 
	  <td class="center">S</td>
 
	  <td class="center">Sa</td>
 
          <td class="center"></td>
 
          <td class="center"></td>
 
        </tr>
 
      </table>
 
    </td>
 
  </tr>
 
</table>
 

	
 
<div class="credit-hours-total">
 
  <p>Credit Hours: <span class="credit-hours-total-value">0</span></p>
 
</div>
 

	
 
<div class="paddingtop">
 
  <input class="button olive" type="submit" value="Find a schedule" />
 
</div>
 

	
 
</form>
 

	
 
<?php 
 

	
 
/* Show/hide Advanced Options: <p><span id="showadvanced" style="margin-left: 1em;"><a href="#">Advanced</a></span></p> */ 
 
?>
 
<div id="showInstructions" style="width: 100%; text-align: center;"><a href="#">Detailed Instructions...</a></div>
 

	
 
<?php
 
$inputPage->showSchoolInstructions();
 
$inputPage->foot();
 

	
 
function input_course_js(Course $course, $whitespace = '  ')
 
{
 
  $title = $course->title_get();
 
  if (empty($title))
 
    $title = '';
 
  $js = $whitespace . 'class_last = add_class_n(' . json_encode($course->getName()) . ', '
 
    . json_encode($title) . ');' . PHP_EOL;
 

	
 
  foreach ($course as $course_slot)
 
    foreach ($course_slot as $section)
 
      {
 
	$meetings = $section->getMeetings();
 
      foreach ($meetings as $meeting)
 
	{
 
	  $js .= $whitespace . 'add_section_n(class_last, ' . json_encode($section->getLetter()) . ', '
 
	    . json_encode($section->getSynonym()) . ', '
 
	    . json_encode($meeting->getStartTime()) . ', '
 
	    . json_encode($meeting->getEndTime()) . ', '
 
	    . json_encode(array('m' => $meeting->getDay(0), 't' => $meeting->getDay(1), 'w' => $meeting->getDay(2), 'h' => $meeting->getDay(3), 'f' => $meeting->getDay(4),
 
	    . json_encode(array('u' => $meeting->getDay(6), 'm' => $meeting->getDay(0), 't' => $meeting->getDay(1),
 
				'w' => $meeting->getDay(2), 'h' => $meeting->getDay(3), 'f' => $meeting->getDay(4),
 
				's' => $meeting->getDay(5))) . ', '
 
	    . json_encode($meeting->instructor_get()) . ', '
 
	    . json_encode($meeting->getLocation()) . ', '
 
	    . json_encode($meeting->type_get()) . ', '
 
	    . json_encode($course_slot->id_get()) . ', '
 
	    . json_encode($section->credit_hours_get()) . ');' . PHP_EOL;
 
	}
 
    }
 

	
 
  return $js;
 
}
process.php
Show inline comments
 
@@ -10,79 +10,87 @@
 
 * (at your option) any later version.
 
 *
 
 * SlatePermutate is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with SlatePermutate.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
require_once('inc/schedule_store.inc');
 
require_once('inc/class.page.php');
 
include_once 'inc/class.schedule.php';
 
include_once('inc/class.course.inc');
 
include_once 'inc/class.section.php';
 

	
 
// Converts a 6-element day array into a string.
 
// Supports multiple modes, prettiness, and searching for different indicators
 
function arrayToDays($array, $mode = 'num', $pretty = false, $key = 1) {
 
	$outString = '';
 
	switch($mode)
 
	  {
 
		case 'short':
 
			$days = array('Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat');
 
		  $days = array('Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun');
 
			break;
 
		case 'long':
 
			$days = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
 
		  $days = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
 
			break;
 
		case 'num':
 
			$days = array('1','2','3','4','5');
 
		  $days = array('1','2','3','4','5', '6');
 
			break;
 
	  case 'alpha':
 
	    $days = array('m', 't', 'w', 'h', 'f', 's');
 
	    $days = array('m', 't', 'w', 'h', 'f', 's', 'u');
 
	    break;
 
		default:
 
			$outString = 'Invalid mode passed to arrayToDays()!';
 
			return $outString;
 
	}
 
	if(count($array) > 1){
 
		for($i = 0; $i < 6; $i ++)
 
		{
 
			if(isset($array[$i]) && $array[$i] == $key){
 
				$outString .= $days[$i];
 
				if($pretty)
 
					$outString .= ', ';
 
			}
 
		}
 
		/*
 
		 * Sunday is last in the array format (our input, the
 
		 * array indices used on the input.php page) but first
 
		 * in good/real formats:
 
		 */
 
		if (isset($array[$i]) && $array[$i] == $key)
 
		    $outString = $days[$i] . ($pretty ? ', ' : '') . $outString;
 

	
 
		if($pretty){
 
			$outString = substr($outString,0,strlen($outString) - 2); // Remove last comma and space
 
			$outString = substr($outString,0, strrpos( $outString, ' ')) . ' and' . substr($outString, strrpos( $outString, ' '), strlen($outString));
 
		}
 
	}
 
	else {
 
		for($i=0; $i < 6; $i++)
 
		for($i=0; $i < 7; $i++)
 
			if(isset($array[$i]))
 
				$outString = $days[$i];
 
	}
 
	return $outString;
 
}
 

	
 
function prettyTime($time){
 
	return substr($time,0,strlen($time)-2) . ":" . substr($time,strlen($time)-2, strlen($time));
 
}
 

	
 
/**
 
 * \brief
 
 *   Convert a multidimensional array to a set of <input />s.
 
 *
 
 * Currently just echos out the <input />s as they are created.
 
 *
 
 * \param $array
 
 *   The array to make into a set of <input />s.
 
 * \param $base
 
 *   The string to prefix. Normally the name of the array variable.
 
 * \param $blankness
 
 *   A string to insert at the beginning of each line before an <input
 
 *   /> for indentation's sake.
 
 */
school.d/hope.crawl.inc
Show inline comments
 
@@ -270,48 +270,50 @@ function hope_crawl_semester(array $scho
 

	
 
      if ($section_csv[$fields['M']] == 'TBA'
 
	  || $section_csv[$fields['Times']] == 'TBA')
 
	{
 
	  $semester->class_add(new Course($subject_id . '-' . $course_id,
 
					  $section_csv[$fields['Title']]));
 
	  school_crawl_logf($school_crawl_log, 8, "Course %s-%s-%s has a section meeting with a TBA time, adding dummy course.",
 
			    $subject_id, $course_id, $section_id);
 
	  continue;
 
	}
 

	
 
      if (preg_match(',(\\d\\d)/(\\d\\d)-(\\d\\d)/(\\d\\d),', $section_csv[$fields['Date']], $matches))
 
	{
 
	  list(, $m_start, $d_start, $m_end, $d_end) = $matches;
 
	  if ($m_start && $d_start && $m_end && $d_end)
 
	    {
 
	      $y_start = $y_end = $semester->year_get();
 
	      if ($m_end < $m_start)
 
		$y_end ++;
 
	      $semester->time_start_set_test(gmmktime(0, 0, 0, $m_start, $d_start, $y_start));
 
	      $semester->time_end_set_test(gmmktime(0, 0, 0, $m_end, $d_end, $y_end));
 
	    }
 
	}
 

	
 
      if (trim($section_csv[$fields['U']]))
 
	school_crawl_logf($school_crawl_log, 0, "Section %d has sunday.", $synonym);
 
      $days = school_crawl_days_format($school_crawl_log, array_filter(array_slice($section_csv, $fields['M'], 7), '_hope_crawl_days_filter'));
 
      list($time_start, $time_end) = explode('-', $section_csv[$fields['Times']]);
 
      if (strlen($time_start) != 4 || strlen($time_end) != 4)
 
	{
 
	  school_crawl_logf($school_crawl_log, 4, "Section meeting (synonym=%s) has invalidly-formatted start time (%s) or end time (%s). Skipping.",
 
			    $synonym, $time_start, $time_end);
 
	  continue;
 
	}
 

	
 
      /*
 
       * Guessing the type of section_meeting: `attribute' of NSL
 
       * seems to be associated with labs. Matches `lab', `lab.', `
 
       * lab', ` labo'..., etc.
 
       */
 
      $type = 'lecture';
 
      if (preg_match('/(^|[^a-z])lab($|o|[^a-z])/i', $title))
 
	$type = 'lab';
 

	
 
      $section_meeting = new SectionMeeting($days, $time_start, $time_end,
 
					    $location,
 
					    $type,
 
					    $instructor);
 
      $semester->section_meeting_add($subject_id,
 
				     $course_id,
school.d/umich.crawl.inc
Show inline comments
 
@@ -144,63 +144,62 @@ function umich_crawl_semester(array $sch
 

	
 
  $cookies = array();
 
  $uri = $semester->umich_csv_href;
 

	
 
  /* parse into lines and then each row needs to be individually parsed */
 
  $csv = str_getcsv(school_crawl_geturi($uri, $cookies, $school_crawl_log), PHP_EOL);
 

	
 
  $fields = array(
 
		  'Term' => FALSE /* $semester->season_get() . ' ' . $semester->year_get() */,
 
		  'Session' => FALSE /* "Regular Academic Session", "First 7 Week Session", "Second 7 Week Session" <-- half-semester support? */,
 
		  'Acad Group' => FALSE /* long version of the department sorta, more general than the subject field */,
 
		  'Class Nbr' => FALSE /* section synonym */,
 
		  'Subject' => FALSE /* "Mathematics (MATH)" */,
 
		  'Catalog Nbr' => FALSE /* "201", unqualified course_id */,
 
		  'Section' => FALSE /* You still reading these comments? */,
 
		  'Course Title' => FALSE /* for your sake, I hope you aren't */,
 
		  'Component' => FALSE /* "LAB", "LEC", "REC" -- i.e., meeting_type(?) */,
 
		  'Codes' => FALSE /* "P  W", "P   ", "P R ", "PI  ", "A   ", "P RW" ??????? (reminds me of ``svn status''). If flag[3] = 'W', then the class has a meeting times */,
 
		  'M' => FALSE /* if a day is enabled, it is set to itself. I.e., $row['M'] = 'M' or $row['M'] = '' */,
 
		  'T' => FALSE,
 
		  'W' => FALSE,
 
		  'TH' => FALSE,
 
		  'F' => FALSE,
 
		  'S' => FALSE,
 
		  'SU' => FALSE /* OK, we'll have to add Sunday support someday ;-) */,
 
		  'SU' => FALSE,
 
		  'Start Date' => FALSE /* yea! */,
 
		  'End Date' => FALSE /* "12/13/2011" */,
 
		  'Time' => FALSE /* "1230-130PM", "9-1030AM", "1130-1PM" */,
 
		  'Location' => FALSE,
 
		  'Instructor' => FALSE,
 
		  'Units' => FALSE /* As in credit hours */,
 
		  );
 
  $ignored_fields = array(
 
			  'Term' => TRUE,
 
			  'Session' => TRUE,
 
			  'Acad Group' => TRUE,
 
			  'Codes' => TRUE,
 
			  'SU' => TRUE,
 
			  );
 
    'Term' => TRUE,
 
    'Session' => TRUE,
 
    'Acad Group' => TRUE,
 
    'Codes' => TRUE,
 
  );
 

	
 
  foreach (str_getcsv($csv[0]) as $col_num => $col_name)
 
    if (isset($fields[$col_name]))
 
      $fields[$col_name] = $col_num;
 
    else
 
      school_crawl_logf($school_crawl_log, 6, "We do not recognize the %s column in the CSV file for %s.",
 
			$col_name, $semester);
 

	
 
  foreach ($fields as $field => $col_num)
 
    if ($col_num === FALSE
 
	&& empty($ignored_field[$field]))
 
      {
 
	school_crawl_logf($school_crawl_log, 2, "Unable to find column %s in CSV for %s. Skipping this semester.",
 
			  $field, $semester);
 
	return 1;
 
      }
 

	
 
  /* remove the row with heading from the CSV dataset */
 
  unset($csv[0]);
 

	
 
  /* Now actually parse some data :-). */
 
  $row_accumulation = array('Instructor' => '');
 
  foreach ($csv as $row)
 
    {
 
@@ -208,49 +207,49 @@ function umich_crawl_semester(array $sch
 
      $synonym = trim($row[$fields['Class Nbr']]);
 
      $course_id = trim($row[$fields['Catalog Nbr']]);
 

	
 
      if (!preg_match(';\(([A-Z]+)\)$;', $row[$fields['Subject']], $matches))
 
	{
 
	  school_crawl_logf($school_crawl_log, 5, "Unable to parse department string `%s'. Skipping section/course (synonym=%s).",
 
			    $row[$fields['Subject']], $synonym);
 
	  continue;
 
	}
 
      $dept = $matches[1];
 

	
 
      /**
 
       * \todo
 
       *   umich stores sometimes ranges of credit hours for courses,
 
       *   formatted like "1.00-3.00". This is generally done for ARR
 
       *   courses, where there is negotiation between the faculty and
 
       *   the student on how the course is arranged. slate_permutate
 
       *   should have a concept of a range of credit hours, then when
 
       *   calculating credit hours for the user it can present the
 
       *   total as a range... not that hard, but still a task ;-).
 
       */
 
      $credit_hours = (float)$row[$fields['Units']];
 

	
 
      $days = '';
 
      foreach (array('M' => 'm', 'T' => 't', 'W' => 'w', 'TH' => 'h', 'F' => 'f', 'S' => 's')
 
      foreach (array('SU' => 'u', 'M' => 'm', 'T' => 't', 'W' => 'w', 'TH' => 'h', 'F' => 'f', 'S' => 's')
 
	       as $field => $day)
 
	if (strlen(trim($row[$fields[$field]])))
 
	  $days .= $day;
 

	
 
      if (!preg_match(';^([0-9]+)-([0-9]+)([AP])M$;', $row[$fields['Time']], $matches))
 
	{
 
	  /*
 
	   * Some courses exist but only have sections which have ARR
 
	   * for their meeting times. I think this means sometimes
 
	   * that the student is to arrange the course meeting with
 
	   * the instructor, other times just that the course is
 
	   * planned but not scheduled yet. These courses should still
 
	   * show up in autocomplete even if they have no meeting
 
	   * times.
 
	   */
 

	
 
	  if ($row[$fields['Time']] != 'ARR')
 
	    /* Log an unanticipated Time value */
 
	    school_crawl_logf($school_crawl_log, 4, "Unable to parse meeting time: `%s'. Skipping section/meeting (synonym=%s).",
 
			      $row[$fields['Time']], $synonym);
 
	  /* ensure that the class is added nonetheless */
 
	  if ($semester->class_get($dept, $course_id) === NULL)
 
	    /**
 
	     * \todo
scripts/scheduleInput.js
Show inline comments
 
@@ -179,103 +179,106 @@ function add_section_n(cnum, name, synon
 
	genOptionHtml("0820", "8:20 am", etime) + genOptionHtml("0850", "8:50 am", etime) +
 
	genOptionHtml("0920", "9:20 am", etime) + genOptionHtml("0950", "9:50 am", etime) +
 
	genOptionHtml("1020", "10:20 am", etime) + genOptionHtml("1050", "10:50 am", etime) +
 
	genOptionHtml("1120", "11:20 am", etime) + genOptionHtml("1150", "11:50 am", etime) +
 
	genOptionHtml("1220", "12:20 pm", etime) + genOptionHtml("1250", "12:50 pm", etime) +
 
	genOptionHtml("1320", "1:20 pm", etime) + genOptionHtml("1350", "1:50 pm", etime) +
 
	genOptionHtml("1420", "2:20 pm", etime) + genOptionHtml("1450", "2:50 pm", etime) +
 
	genOptionHtml("1520", "3:20 pm", etime) + genOptionHtml("1550", "3:50 pm", etime) +
 
	genOptionHtml("1620", "4:20 pm", etime) + genOptionHtml("1650", "4:50 pm", etime) +
 
	genOptionHtml("1720", "5:20 pm", etime) + genOptionHtml("1750", "5:50 pm", etime) +
 
	genOptionHtml("1820", "6:20 pm", etime) + genOptionHtml("1850", "6:50 pm", etime) +
 
	genOptionHtml("1920", "7:20 pm", etime) + genOptionHtml("1950", "7:50 pm", etime) +
 
	genOptionHtml("2020", "8:20 pm", etime) + genOptionHtml("2050", "8:50 pm", etime) +
 
	genOptionHtml("2120", "9:20 pm", etime) + genOptionHtml('2150', '9:50 pm', etime);
 

	
 
    if (etime.length > 0)
 
    {
 
	var etime_end = etime.substr(2);
 
	var etime_begin = etime.substr(0, 2);
 
	if (etime_end != '50' && etime_end != '20'
 
	   || etime_begin < 7 || etime_begin > 21)
 
	    section_html = section_html + genOptionHtml(etime, prettyTime(etime), etime);
 
    }
 

	
 
    section_html = section_html + '</select></td>\
 
    section_html = section_html + '</select></td>\n\
 
<td class="cbrow"><input type="checkbox" title="Sunday" class="daysRequired" name="postData[' + cnum +'][' + snum + '][days][6]" value="1" ' + (days.u ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][0]" value="1" ' + (days.m ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][1]" value="1" ' + (days.t ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][2]" value="1" ' + (days.w ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][3]" value="1" ' + (days.h ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][4]" value="1" ' + (days.f ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][5]" value="1" ' + (days.s ? 'checked="checked"' : '') + ' /></td>' +
 
	'<td class="removeCell"><div><button class="gray section-meeting-delete">x</button></div></td><td class="emptyCell">' +
 
	'<input class="section-location-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][location]" />' +
 
	'<input class="section-type-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][type]" />' +
 
		'<input class="section-credit-hours-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][credit_hours]" />' +
 
	'</td></tr>';
 

	
 
    /*
 
     * Try to append this section to the last section in its
 
     * associated CourseSlot...
 
     */
 
    last_tr = jQuery('tr.class' + cnum + '.' + safe_css_class('slot-' + slot) + ':last');
 
    if (!last_tr.length)
 
    {
 
	/* Also append a a new ``we are this slot'' row... */
 
	course_add_slot_row(cnum, slot);
 
	last_tr = jQuery('tr.class' + cnum + ':last');
 
    }
 
    last_tr.after(section_html);
 
    sectionsOfClass[cnum] ++;
 

	
 
    var section_tr = jQuery('#tr-section-' + String(snum));
 
    /* store course_i in a place the newly added section will look for it */
 
    section_tr.data({course_i: cnum});
 

	
 
    /*
 
     * Store data into the newly created HTML. With this method we
 
     * have to _avoid_ escaping entities in the text we're setting as
 
     * values because the DOM stuff will escape it for us.
 
     */
 
    section_tr.find('.section-letter-entry').val(name);
 
    section_tr.find('.section-synonym-entry').val(synonym);
 
    section_tr.find('.section-slot-entry').val(slot);
 
    section_tr.find('.profName').val(instructor);
 
    section_tr.find('.section-location-entry').val(location);
 
    section_tr.find('.section-type-entry').val(type);
 
	section_tr.find('.section-credit-hours-entry').val(credit_hours);
 

	
 
    /* unhide the saturday columns if it's used by autocomplete data */
 
    /* unhide the saturday and sunday columns if they're used by autocomplete data */
 
	if (days.u)
 
		jQuery('#jsrows col.sunday').removeClass('collapsed');
 
    if (days.s)
 
	jQuery('#jsrows col.saturday').removeClass('collapsed');
 

	
 
	credit_hours_change(cnum);
 

	
 
    return last_section_i - 1;
 
}
 
function add_section(cnum)
 
{
 
    var section_i = add_section_n(cnum, '', '', '', '', {m: false, t: false, w: false, h: false, f: false, s: false}, '', '', '', 'default', -1);
 
    var section_i = add_section_n(cnum, '', '', '', '', {}, '', '', '', 'default', -1);
 
    if (cnum == slate_permutate_course_free)
 
	course_free_check(cnum);
 
    return section_i;
 
}
 

	
 
/**
 
 * Add a list of sections gotten via an AJAX call.
 
 */
 
function add_sections(cnum, data)
 
{
 
    var i;
 

	
 
    if (data.title)
 
	jQuery('.pclass' + cnum + ' .course-title-entry').val(data.title);
 

	
 
    /*
 
     * If the user enterred something iffy, correct him. Or do so
 
     * regardless ;-).
 
     */
 
    /* this data['class'] stuff is for the old JSON format we used... */
 
    if (data['class'])
 
	data.course = data['class'];
 
    if (data.course)
 
	jQuery('.className' + cnum).val(data.course);
 
@@ -319,94 +322,94 @@ function add_sections(cnum, data)
 
 */
 
function course_add_slot_row(course_i, slot_id)
 
{
 
    var extra_classes = '';
 

	
 
    if (!show_course_slots[course_i])
 
    {
 
	var aclass;
 
	/*
 
	 * Then check if this course has multiple slots and we should
 
	 * enable displaying them to the user.
 
	 */
 
	aclass = jQuery('.' + safe_css_class('class' + course_i) + '.section .section-slot-entry');
 
	if (aclass.length && aclass.val() != slot_id)
 
	{
 
	    enable_course_slots(course_i);
 
	}
 
    }
 
    if (!show_course_slots[course_i])
 
	extra_classes += ' tr-slot-id-hidden';
 

	
 
    jQuery('tr.class' + course_i + ':last').after(
 
	'<tr class="class' + course_i + ' tr-slot-id ' + safe_css_class('slot-' + slot_id) + extra_classes + '">\n' +
 
	    '  <td><span /></td>\n' +
 
	    '  <td colspan="10"><span class="slot-id-text" /></td>\n' +
 
	    '  <td colspan="11"><span class="slot-id-text" /></td>\n' +
 
	    '  <td colspan="2"><span /></td>\n' +
 
	    '</tr>\n'
 
    );
 
    jQuery('tr.class' + course_i + ':last .slot-id-text').text('The following are ' + slot_id + ' sections and will be scheduled as a group.');
 
}
 

	
 
/**
 
 * \brief
 
 *   Dynamically enable the displification of course slots to the
 
 *   user.
 
 *
 
 * \param course_i
 
 *   The particular course for which slot displification should be
 
 *   enabled.
 
 */
 
function enable_course_slots(course_i)
 
{
 
    show_course_slots[course_i] = true;
 

	
 
    jQuery('.' + safe_css_class('class' + course_i) + '.tr-slot-id-hidden').removeClass('tr-slot-id-hidden');
 
}
 

	
 
/**
 
 * \brief
 
 *   Adds a new class to the input.
 
 *
 
 * \param course_id
 
 *   The course_id.
 
 * \param title
 
 *   The human-friendly course title.
 
 * \return
 
 *   The javascript-local course entry identifying number.
 
 */
 
function add_class_n(course_id, title)
 
{
 
    /*
 
     * If we're adding a course entry form with preadded
 
     * content, first remove the empty course.
 
     */
 
    if (course_id.length && slate_permutate_course_free != -1)
 
	course_remove(slate_permutate_course_free);
 

	
 
    sectionsOfClass[classNum] = 0; // Initialize at 0
 
    course_ajax_requests[classNum] = false;
 
    jQuery('#jsrows').append('<tr id="tr-course-' + classNum + '" class="class class' + classNum + ' pclass' + classNum + '"><td class="nameTip"><input type="text" id="input-course-' + classNum + '" class="classRequired defText className'+classNum+' className" title="Class Name" name="postData[' + classNum + '][name]" /></td><td colspan="10"><input type="text" name="postData[' + classNum + '][title]" class="inPlace inPlace-enable course-title-entry input-submit-disable" /><span class="course-credit-hours course-credit-hours-' + classNum + '"></span></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"><button type="button" class="addSection gray">+</button></td></tr>');
 
    jQuery('#jsrows').append('<tr id="tr-course-' + classNum + '" class="class class' + classNum + ' pclass' + classNum + '"><td class="nameTip"><input type="text" id="input-course-' + classNum + '" class="classRequired defText className'+classNum+' className" title="Class Name" name="postData[' + classNum + '][name]" /></td><td colspan="11"><input type="text" name="postData[' + classNum + '][title]" class="inPlace inPlace-enable course-title-entry input-submit-disable" /><span class="course-credit-hours course-credit-hours-' + classNum + '"></span></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"><button type="button" class="addSection gray">+</button></td></tr>');
 

	
 
		/* store classNum as course_i into the <tr />: */
 
    var tr_course = jQuery('#tr-course-' + classNum);
 
    tr_course.data({course_i: classNum});
 
    tr_course.find('.course-title-entry').val(title);
 
    tr_course.find('.className').val(course_id);
 
	tr_course.find('.course-credit-hours-label').attr('for', 'course-credit-hours-entry-' + classNum);
 

	
 
		var class_elem = jQuery('.className' + classNum);
 

	
 
		class_elem.autocomplete({ source: 'auto.php?school=' + slate_permutate_school + '&semester=' + slate_permutate_semester });
 
		class_elem.bind('autocompleteselect', {class_num: classNum, class_elem: class_elem},
 
			function(event, ui)
 
			    {
 
				if (!ui.item)
 
				    return;
 

	
 
				if (ui.item.value.indexOf('-') != -1)
 
				    {
 
					course_autocomplete(event.data.class_num, ui.item.value);
 
				    }
 
				else
 
				    {
 
					/*
0 comments (0 inline, 0 general)