diff --git a/bolt_checkin_notes.txt b/bolt_checkin_notes.txt index fea18b94fd..75764bb7e3 100644 --- a/bolt_checkin_notes.txt +++ b/bolt_checkin_notes.txt @@ -271,3 +271,20 @@ David Oct 30 2008 user/ bolt.css bolt_sched.php + +David Oct 30 2008 + - moved snapshot code to its own file + - added link to questions in Map + - added "mode" to question table + + db/ + bolt_schema.sql + html/ + inc/ + bolt_snap.inc + bolt_util.inc + ops/ + bolt_map.php + bolt_compare.php + user/ + bolt_sched.php diff --git a/db/bolt_schema.sql b/db/bolt_schema.sql index c5419c50f4..8e04e56f9b 100644 --- a/db/bolt_schema.sql +++ b/db/bolt_schema.sql @@ -145,6 +145,8 @@ create table bolt_question ( course_id integer not null, name varchar(255) not null, -- logical name of item where question was asked + mode integer not null, + -- distinguishes exercise show/answer question text not null, state integer not null, -- whether question has been handled diff --git a/html/inc/bolt_snap.inc b/html/inc/bolt_snap.inc new file mode 100644 index 0000000000..78f9d2e9c8 --- /dev/null +++ b/html/inc/bolt_snap.inc @@ -0,0 +1,229 @@ +. + + + +////// stuff related to snapshots +// +// There are 2 kinds of snapshots: "compare" and "map". +// +// A "compare snapshot" is a condensed representation of the results +// for a particular select/xset pair. +// Namely, it's an array whose elements contain +// bolt_user: the user +// xset_result: the user's first completion of the xset +// select_finished: the user's last completion of the select before this +// +// A "map snapshot" is: +// - an assoc array "views" mapping unit name to a list of views +// - an assoc array "results" mapping unit name to a list of results +// - an assoc array "xset_results" mapping unit name to a list of xset results +// - an assoc array "questions" mapping unit name to a list of questions +// - an assoc array "users" mapping user ID to user record +// + + +function compare_snapshot_filename($course_id, $select_name, $xset_name) { + @mkdir("../bolt_snap"); + $x = urlencode($course_id."_".$select_name."_".$xset_name); + return "../bolt_snap/compare_snapshot_$x"; +} + +function write_compare_snapshot($course_id, $select_name, $xset_name, $dur) { + $now = time(); + $start = $now - $dur*86400; + $xrs = BoltXsetResult::enum( + "course_id=$course_id and name='$xset_name' and create_time >= $start" + ); + $sfs = BoltSelectFinished::enum( + "course_id=$course_id and name='$select_name' and end_time >= $start" + ); + + // make an array $a, keyed by user ID, of earliest xset result + // + $a = array(); + foreach ($xrs as $xr) { + $uid = $xr->user_id; + if (!array_key_exists($uid, $a) || $xr->create_time < $a[$uid]->xr->create_time) { + $x = null; + $x->xr = $xr; + $a[$uid] = $x; + } + } + + // now scan select finishes, and for each user find last one before xset + // + foreach ($sfs as $sf) { + $uid = $sf->user_id; + if (!array_key_exists($uid, $a)) { + echo "no xset result"; + continue; + } + $x = $a[$uid]; + $xr = $x->xr; + if ($sf->end_time > $xr->create_time) { + //echo "select finish is too late"; + continue; + } + if (!isset($x->sf) || $sf->end_time > $x->sf->end_time) { + $x->sf = $sf; + $a[$uid] = $x; + } + } + + // cull array elements for which we didn't find a select finish. + // Look up user records for other elements. + // + foreach ($a as $uid=>$x) { + if (!isset($x->sf)) { + unset($a[$uid]); + } else { + $user = BoincUser::lookup_id($uid); + BoltUser::lookup($user); + $x->user = $user; + $a[$uid] = $x; + } + } + + $filename = compare_snapshot_filename($course_id, $select_name, $xset_name); + $f = fopen($filename, "w"); + + $s = null; + $s->recs = $a; + $s->dur = $dur; + $s->time = $now; + fwrite($f, serialize($s)); + fclose($f); + return $s; +} + +function read_compare_snapshot($course_id, $select_name, $xset_name) { + $filename = compare_snapshot_filename($course_id, $select_name, $xset_name); + $f = @fopen($filename, "r"); + if (!$f) return null; + $x = fread($f, filesize($filename)); + fclose($f); + return unserialize($x); +} + + +function map_snapshot_filename($course_id) { + return "../bolt_snap/map_snapshot_".$course_id; +} + +function write_map_snapshot($course_id, $dur) { + $now = time(); + $start = $now - $dur*86400; + + $views = array(); + $results = array(); + $xset_results = array(); + $users = array(); + $questions = array(); + + $vs = BoltView::enum("course_id=$course_id and start_time>$start"); + foreach ($vs as $v) { + if (array_key_exists($v->item_name, $views)) { + $x = $views[$v->item_name]; + $x[] = $v; + $views[$v->item_name] = $x; + } else { + $views[$v->item_name] = array($v); + } + if (!array_key_exists($v->user_id, $users)) { + $user = BoincUser::lookup_id($v->user_id); + BoltUser::lookup($user); + $users[$v->user_id] = $user; + } + } + + $rs = BoltResult::enum("course_id=$course_id and create_time>$start"); + foreach ($rs as $r) { + if (array_key_exists($r->item_name, $results)) { + $x = $results[$r->item_name]; + $x[] = $r; + $results[$r->item_name] = $x; + } else { + $results[$r->item_name] = array($r); + } + if (!array_key_exists($r->user_id, $users)) { + $user = BoincUser::lookup_id($r->user_id); + BoltUser::lookup($user); + $users[$r->user_id] = $user; + } + } + + $xrs = BoltXsetResult::enum("course_id=$course_id and create_time>$start"); + foreach ($xrs as $xr) { + if (array_key_exists($xr->name, $xset_results)) { + $x = $xset_results[$xr->name]; + $x[] = $xr; + $xset_results[$xr->name] = $x; + } else { + $xset_results[$xr->name] = array($xr); + } + if (!array_key_exists($xr->user_id, $users)) { + $user = BoincUser::lookup_id($xr->user_id); + BoltUser::lookup($user); + $users[$xr->user_id] = $user; + } + } + $qs = BoltQuestion::enum("course_id=$course_id and create_time>$start"); + foreach ($qs as $q) { + if (array_key_exists($q->name, $questions)) { + $x = $questions[$q->name]; + $x[] = $q; + $questions[$q->name] = $x; + } else { + $questions[$q->name] = array($q); + } + if (!array_key_exists($q->user_id, $users)) { + $user = BoincUser::lookup_id($q->user_id); + BoltUser::lookup($user); + $users[$q->user_id] = $user; + } + } + + $y = null; + $y->views = $views; + $y->results = $results; + $y->xset_results = $xset_results; + $y->users = $users; + $y->questions = $questions; + $y->dur = $dur; + $y->time = $now; + + $filename = map_snapshot_filename($course_id); + $f = fopen($filename, "w"); + fwrite($f, serialize($y)); + fclose($f); + + return $y; +} + +function read_map_snapshot($course_id) { + $filename = map_snapshot_filename($course_id); + $f = @fopen($filename, "r"); + if (!$f) return null; + $x = fread($f, filesize($filename)); + fclose($f); + return unserialize($x); +} + +?> diff --git a/html/inc/bolt_util.inc b/html/inc/bolt_util.inc index 2fc262fa8a..b9420f9a8b 100644 --- a/html/inc/bolt_util.inc +++ b/html/inc/bolt_util.inc @@ -126,191 +126,6 @@ function request_info($user, $course) { page_tail(); } -////// stuff related to snapshots - -function compare_snapshot_filename($course_id, $select_name, $xset_name) { - @mkdir("../bolt_snap"); - $x = urlencode($course_id."_".$select_name."_".$xset_name); - return "../bolt_snap/compare_snapshot_$x"; -} - -// a "snapshot" is a condensed representation of the results -// for a particular select/xset pair. -// Namely, it's an array whose elements contain -// bolt_user: the user -// xset_result: the user's first completion of the xset -// select_finished: the user's last completion of the select before this - -function write_compare_snapshot($course_id, $select_name, $xset_name, $dur) { - $now = time(); - $start = $now - $dur*86400; - $xrs = BoltXsetResult::enum( - "course_id=$course_id and name='$xset_name' and create_time >= $start" - ); - $sfs = BoltSelectFinished::enum( - "course_id=$course_id and name='$select_name' and end_time >= $start" - ); - - // make an array $a, keyed by user ID, of earliest xset result - // - $a = array(); - foreach ($xrs as $xr) { - $uid = $xr->user_id; - if (!array_key_exists($uid, $a) || $xr->create_time < $a[$uid]->xr->create_time) { - $x = null; - $x->xr = $xr; - $a[$uid] = $x; - } - } - - // now scan select finishes, and for each user find last one before xset - // - foreach ($sfs as $sf) { - $uid = $sf->user_id; - if (!array_key_exists($uid, $a)) { - echo "no xset result"; - continue; - } - $x = $a[$uid]; - $xr = $x->xr; - if ($sf->end_time > $xr->create_time) { - //echo "select finish is too late"; - continue; - } - if (!isset($x->sf) || $sf->end_time > $x->sf->end_time) { - $x->sf = $sf; - $a[$uid] = $x; - } - } - - // cull array elements for which we didn't find a select finish. - // Look up user records for other elements. - // - foreach ($a as $uid=>$x) { - if (!isset($x->sf)) { - unset($a[$uid]); - } else { - $user = BoincUser::lookup_id($uid); - BoltUser::lookup($user); - $x->user = $user; - $a[$uid] = $x; - } - } - - $filename = compare_snapshot_filename($course_id, $select_name, $xset_name); - $f = fopen($filename, "w"); - - $s = null; - $s->recs = $a; - $s->dur = $dur; - $s->time = $now; - fwrite($f, serialize($s)); - fclose($f); - return $s; -} - -function read_compare_snapshot($course_id, $select_name, $xset_name) { - $filename = compare_snapshot_filename($course_id, $select_name, $xset_name); - $f = @fopen($filename, "r"); - if (!$f) return null; - $x = fread($f, filesize($filename)); - fclose($f); - return unserialize($x); -} - - -function map_snapshot_filename($course_id) { - return "../bolt_snap/map_snapshot_".$course_id; -} - -// a "map snapshot" is: -// - an assoc array "views" mapping unit name to a list of views -// - an assoc array "results" mapping unit name to a list of results -// - an assoc array "xset_results" mapping unit name to a list of xset results -// - an assoc array "users" mapping user ID to user record -// -function write_map_snapshot($course_id, $dur) { - $now = time(); - $start = $now - $dur*86400; - - $views = array(); - $results = array(); - $xset_results = array(); - $users = array(); - - $vs = BoltView::enum("course_id=$course_id and start_time>$start"); - foreach ($vs as $v) { - if (array_key_exists($v->item_name, $views)) { - $x = $views[$v->item_name]; - $x[] = $v; - $views[$v->item_name] = $x; - } else { - $views[$v->item_name] = array($v); - } - if (!array_key_exists($v->user_id, $users)) { - $user = BoincUser::lookup_id($v->user_id); - BoltUser::lookup($user); - $users[$v->user_id] = $user; - } - } - - $rs = BoltResult::enum("course_id=$course_id and create_time>$start"); - foreach ($rs as $r) { - if (array_key_exists($r->item_name, $results)) { - $x = $results[$r->item_name]; - $x[] = $r; - $results[$r->item_name] = $x; - } else { - $results[$r->item_name] = array($r); - } - if (!array_key_exists($r->user_id, $users)) { - $user = BoincUser::lookup_id($r->user_id); - BoltUser::lookup($user); - $users[$r->user_id] = $user; - } - } - - $xrs = BoltXsetResult::enum("course_id=$course_id and create_time>$start"); - foreach ($xrs as $xr) { - if (array_key_exists($xr->name, $xset_results)) { - $x = $xset_results[$xr->name]; - $x[] = $xr; - $xset_results[$xr->name] = $x; - } else { - $xset_results[$xr->name] = array($xr); - } - if (!array_key_exists($xr->user_id, $users)) { - $user = BoincUser::lookup_id($xr->user_id); - BoltUser::lookup($user); - $users[$xr->user_id] = $user; - } - } - - $y = null; - $y->views = $views; - $y->results = $results; - $y->xset_results = $xset_results; - $y->users = $users; - $y->dur = $dur; - $y->time = $now; - - $filename = map_snapshot_filename($course_id); - $f = fopen($filename, "w"); - fwrite($f, serialize($y)); - fclose($f); - - return $y; -} - -function read_map_snapshot($course_id) { - $filename = map_snapshot_filename($course_id); - $f = @fopen($filename, "r"); - if (!$f) return null; - $x = fread($f, filesize($filename)); - fclose($f); - return unserialize($x); -} - ////// Statistics // compute the mean and stdev of an array diff --git a/html/ops/bolt_compare.php b/html/ops/bolt_compare.php index 9104b05508..dcfcd0fc3b 100644 --- a/html/ops/bolt_compare.php +++ b/html/ops/bolt_compare.php @@ -33,6 +33,7 @@ require_once("../inc/bolt_db.inc"); require_once("../inc/bolt_util.inc"); require_once("../inc/bolt.inc"); require_once("../inc/bolt_cat.inc"); +require_once("../inc/bolt_snap.inc"); function compare_case( $title, $select_unit, $snap, $filter, $filter_cat, $breakdown, $breakdown_cat diff --git a/html/ops/bolt_map.php b/html/ops/bolt_map.php index 1f157d6f17..cfac79354f 100644 --- a/html/ops/bolt_map.php +++ b/html/ops/bolt_map.php @@ -49,6 +49,7 @@ require_once("../inc/bolt_db.inc"); require_once("../inc/bolt_cat.inc"); require_once("../inc/bolt_util.inc"); require_once("../inc/bolt.inc"); +require_once("../inc/bolt_snap.inc"); // the following are to minimize argument passing @@ -108,7 +109,8 @@ function spaces($level) { return $x; } -// used to filter arrays of views or xset_results +// filter arrays of anything that has a user_id field +// (view, xset_result, question) // function filter_array($array) { global $snap, $filter, $filter_cat, $breakdown, $breakdown_cat; @@ -171,6 +173,20 @@ function outcomes($views) { return $x; } +function get_nquestions($unit, $mode) { + global $snap; + + if (array_key_exists($unit->name, $snap->questions)) { + $a = filter_array($snap->questions[$unit->name]); + $n = 0; + foreach ($a as $q) { + if ($q->mode == $mode) $n++; + } + return $n; + } + return 0; +} + function get_views($unit, $mode) { global $snap; @@ -217,7 +233,7 @@ $rownum = 0; function show_unit_row($unit, $class, $level, $is_answer) { global $breakdown, $breakdown_cat; - global $rownum; + global $rownum, $course_id; $a = $is_answer?" (answer)":""; $j = ($rownum++)%2; @@ -243,21 +259,36 @@ function show_unit_row($unit, $class, $level, $is_answer) { } switch ($class) { case "BoltLesson": - $views = get_views($unit, BOLT_MODE_LESSON); + $mode = BOLT_MODE_LESSON; + $views = get_views($unit, $mode); $n = count($views); $out = outcomes($views); $t = avg_time($views); echo "