Commit dddd1fc5 authored by David Anderson's avatar David Anderson

- fixed bug in upgrade


svn path=/trunk/boinc/; revision=14451
parent 945b1609
......@@ -27,3 +27,19 @@ David Dec 27 2007
- preliminary implementation of exercise_set
inc/bolt.inc
David Jan 1 2008
- split control structure into separate files
- allow passing query strings to items
db/
bolt_schema.sql
html/
inc/
bolt.inc
bolt_rnd.inc
bolt_seq.inc
bolt_xset.inc
user/
bolt_course_sample.php
bolt_sched.php
This diff is collapsed.
This diff is collapsed.
create table bolt_user (
user_id integer not null,
user_id integer not null,
birth_year integer not null,
sex smallint not null,
sex tinyint not null,
debug tinyint not null,
-- if nonzero, print debug info everywhere
attrs text not null,
primary key (user_id)
);
......
This diff is collapsed.
<?php
// state for random unit is:
// seed The RNG seed used to shuffle
// i index of current child
// number_shown number of units shown so far (not necessarily the
// same as i on 2nd and later pass through this unit)
// child_name name of current child
class BoltRandom extends BoltUnit {
public $units;
function __construct($name, $units, $number) {
$this->name = $name;
$this->units = $units;
$this->number = $number;
$this->is_item = false;
$this->shuffled = false;
}
function walk(&$iter, $incr, &$frac_done) {
$n = count($this->units);
if (array_key_exists($this->name, $iter->state)) {
$state_rec = $iter->state[$this->name];
$child_name = $state_rec['child_name'];
$number_shown = $state_rec['number_shown'];
if (!$this->shuffled) {
srand($state_rec['seed']);
shuffle($this->units);
$this->shuffled = true;
}
// look up unit by name
//
$child = null;
for ($i=0; $i<$n; $i++) {
$c = $this->units[$i];
if ($c->name == $child_name) {
$child = $c;
break;
}
}
// if not there, look up by index
//
if (!$child) {
$i = $state_rec['i'];
if ($i >= $n) {
// and if index is too big, use last unit
//
$i = $n-1;
}
$child = $this->units[$i];
}
// at this point, $child is the current unit, and $i is its index
//
if ($incr) {
$my_inc = false;
if ($child->is_item) {
$my_inc = true;
} else {
$my_inc = $child->walk($iter, $incr, $frac_done);
}
if ($my_inc) {
$i = ($i+1)%$n;
$number_shown++;
if ($number_shown >= $this->number) {
$frac_done = 1;
$state_rec['i'] = $i;
$state_rec['number_shown'] = 0;
$state_rec['child_name'] = null;
$iter->state[$this->name] = $state_rec;
return true;
}
}
}
} else {
$i = 0;
$number_shown = 0;
$state_rec = null;
$seed = ((double)microtime()*1000000);
srand($seed);
shuffle($this->units);
$state_rec['seed'] = $seed;
}
$child = $this->units[$i];
$frac_done = $number_shown/$this->number;
$state_rec['i'] = $i;
$state_rec['number_shown'] = $number_shown;
$state_rec['child_name'] = $child->name;
$iter->state[$this->name] = $state_rec;
if ($child->is_item) {
$iter->item = $child;
} else {
$child->walk($iter, false, $f);
$frac_done += $f*(1/$number);
}
}
}
function random() {
$args = func_get_args();
$units = array();
$name = "";
$number = 1;
foreach ($args as $arg) {
if (is_array($arg)) {
switch ($arg[0]) {
case 'name': $name = $arg[1]; break;
case 'title': $title = $arg[1]; break;
case 'number': $number = $arg[1]; break;
default: echo "Unrecognized array arg: ", $arg[0], "\n"; break;
}
} else if (is_object($arg)) {
if (is_subclass_of($arg, "BoltUnit")) {
$units[] = $arg;
} else {
echo "Unrecognized arg: ";
print_r($arg);
}
}
}
return new BoltRandom($name, $units, $number);
}
?>
<?php
class BoltSequence extends BoltUnit {
public $units;
function __construct($name, $units) {
$this->name = $name;
$this->units = $units;
$this->is_item = false;
}
function walk(&$iter, $incr, &$frac_done) {
$n = count($this->units);
if (array_key_exists($this->name, $iter->state)) {
$state_rec = $iter->state[$this->name];
$child_name = $state_rec['child_name'];
// look up unit by name
//
$child = null;
for ($i=0; $i<$n; $i++) {
$c = $this->units[$i];
if ($c->name == $child_name) {
$child = $c;
break;
}
}
// if not there, look up by index
//
if (!$child) {
$i = $state_rec['i'];
if ($i >= $n) {
// and if index is too big, use last unit
//
$i = $n-1;
}
$child = $this->units[$i];
}
// at this point, $child is the current unit, and $i is its index
//
if ($incr) {
$my_inc = false;
if ($child->is_item) {
$my_inc = true;
} else {
$my_inc = $child->walk($iter, $incr, $frac_done);
}
if ($my_inc) {
$i++;
if ($i == $n) {
$frac_done = 1;
$state_rec['i'] = 0;
$state_rec['child_name'] = null;
$iter->state[$this->name] = $state_rec;
return true;
}
}
}
} else {
$i = 0;
}
$child = $this->units[$i];
$frac_done = $i/$n;
$state_rec = null;
$state_rec['i'] = $i;
$state_rec['child_name'] = $child->name;
$iter->state[$this->name] = $state_rec;
if ($child->is_item) {
$iter->item = $child;
} else {
$child->walk($iter, false, $f);
$frac_done += $f*(1/$n);
}
}
}
function sequence() {
$args = func_get_args();
$units = array();
$name = "";
foreach ($args as $arg) {
if (is_array($arg)) {
switch ($arg[0]) {
case 'name': $name = $arg[1]; break;
case 'title': $title = $arg[1]; break;
default: echo "Unrecognized array arg: ", $arg[0], "\n"; break;
}
} else if (is_object($arg)) {
if (is_subclass_of($arg, "BoltUnit")) {
$units[] = $arg;
} else {
echo "Unrecognized arg: ";
print_r($arg);
}
}
}
return new BoltSequence($name, $units);
}
?>
<?php
class BoltExerciseSet extends BoltUnit {
public $units;
public $repeats;
public $state_rec;
function __construct($name, $units, $number, $repeats) {
$this->name = $name;
$this->units = $units;
$this->number = $number;
$this->repeats = $repeats;
$this->is_item = false;
$this->shuffled = false;
}
// the scheduler calls this when an exercise in this set
// has just been graded.
// - record the score
// - if this is the last exercise in the set,
// create exercise_set_result record
// and optionally create or update bolt_refresh record
// - return a structure saying what navigation info to show:
// - review
// - repeat now
// - next
//
function xset_callback($iter, $score, &$is_last, &$nav_info) {
$state_rec = $iter->state[$this->name];
$number_shown = $state_rec['number_shown'];
$state_rec['scores'][$number_shown] = $score;
if ($number_shown == $this->number) {
$is_last = false;
return;
}
$is_last = true;
BoincResult::insert("");
BoincRefresh::replace("");
}
function walk(&$iter, $incr, &$frac_done) {
$iter->xset = $this;
$n = count($this->units);
if (array_key_exists($this->name, $iter->state)) {
$state_rec = $iter->state[$this->name];
$this->state_rec = $state_rec;
$child_name = $state_rec['child_name'];
$number_shown = $state_rec['number_shown'];
if (!$this->shuffled) {
srand($state_rec['seed']);
shuffle($this->units);
$this->shuffled = true;
}
// look up unit by name
//
$child = null;
for ($i=0; $i<$n; $i++) {
$c = $this->units[$i];
if ($c->name == $child_name) {
$child = $c;
break;
}
}
// if not there, look up by index
//
if (!$child) {
$i = $state_rec['i'];
if ($i >= $n) {
// and if index is too big, use last unit
//
$i = $n-1;
}
$child = $this->units[$i];
}
// at this point, $child is the current unit, and $i is its index
//
if ($incr) {
$my_inc = false;
if ($child->is_item) {
$my_inc = true;
} else {
$my_inc = $child->walk($iter, $incr, $frac_done);
}
if ($my_inc) {
$i = ($i+1)%$n;
$number_shown++;
if ($number_shown >= $this->number) {
$frac_done = 1;
$state_rec['i'] = $i;
$state_rec['number_shown'] = 0;
$state_rec['child_name'] = null;
$iter->state[$this->name] = $state_rec;
return true;
}
}
}
} else {
$i = 0;
$number_shown = 0;
$state_rec = null;
$seed = ((double)microtime()*1000000);
srand($seed);
shuffle($this->units);
$state_rec['seed'] = $seed;
}
$child = $this->units[$i];
$frac_done = $number_shown/$this->number;
$state_rec['i'] = $i;
$state_rec['number_shown'] = $number_shown;
$state_rec['child_name'] = $child->name;
$iter->state[$this->name] = $state_rec;
if ($child->is_item) {
$iter->item = $child;
} else {
$child->walk($iter, false, $f);
$frac_done += $f*(1/$number);
}
}
}
class BoltRefresh{
public $intervals;
function __construct($i) {
$this->intervals = $i;
}
}
class BoltRepeat {
public $score;
public $unit;
public $flags;
function __construct($s, $u, $f) {
$this->score = $s;
$this->unit = $u;
$this->flags = $f;
}
}
define('REVIEW', 1);
define('REPEAT', 2);
define('NEXT', 4);
function repeat($s, $u, $f) {
return new BoltRepeat($s, $u, $f);
}
function refresh($a) {
return new BoltRefresh($a);
}
function exercise_set() {
$args = func_get_args();
$units = array();
$repeats = array();
$refresh = null;
$name = "";
$number = 1;
foreach ($args as $arg) {
if (is_array($arg)) {
switch ($arg[0]) {
case 'name': $name = $arg[1]; break;
case 'title': $title = $arg[1]; break;
case 'number': $number = $arg[1]; break;
default: echo "Unrecognized array arg: ", $arg[0], "\n"; break;
}
} else if (is_object($arg)) {
if (get_class($arg) == "BoltExercise") {
$units[] = $arg;
} else if (get_class($arg) == "BoltRepeat") {
$repeats[] = $arg;
} else if (get_class($arg) == "BoltRefresh") {
$refresh= $arg;
} else {
echo "Unrecognized object arg: ";
print_r($arg);
}
}
}
return new BoltExerciseSet($name, $units, $number, $repeats, $refresh);
}
?>
......@@ -7,7 +7,7 @@ function part2() {
name('inner seq'),
lesson(
name('lesson 3'),
filename('bolt_sample_lesson3.php')
filename('bolt_sample_lesson.php?n=3')
)
);
}
......@@ -16,11 +16,11 @@ function basic_review() {
return sequence(
lesson(
name('lesson 1'),
filename('bolt_sample_lesson1.php')
filename('bolt_sample_lesson.php?n=1')
),
lesson(
name('lesson 2'),
filename('bolt_sample_lesson2.php')
filename('bolt_sample_lesson.php?n=2')
)
);
}
......@@ -28,7 +28,7 @@ function basic_review() {
function int_review() {
return lesson(
name('lesson 2'),
filename('bolt_sample_lesson2.php')
filename('bolt_sample_lesson.php?n=2')
);
}
......@@ -39,25 +39,36 @@ return sequence(
number(2),
lesson(
name('lesson 1'),
filename('bolt_sample_lesson1.php')
filename('bolt_sample_lesson.php?n=1')
),
lesson(
name('lesson 2'),
filename('bolt_sample_lesson2.php')
filename('bolt_sample_lesson.php?n=2')
),
lesson(
name('lesson 3'),
filename('bolt_sample_lesson3.php')
filename('bolt_sample_lesson.php?n=3')
)
),
exercise_set(
name('exercise set 1'),
number(2),
exercise(
name('exercise 1'),
filename('bolt_sample_exercise1.php')
filename('bolt_sample_exercise.php?n=1')
),
exercise(
name('exercise 2'),
filename('bolt_sample_exercise.php?n=2')
),
exercise(
name('exercise 3'),
filename('bolt_sample_exercise.php?n=3')
),
refresh(array(7, 14, 28)),
review(.3, basic_review()),
review(.7, int_review())
repeat(.3, basic_review(), REVIEW),
repeat(.7, int_review(), REVIEW|REPEAT),
repeat(1, null, REPEAT|NEXT),
refresh(array(7, 14, 28))
),
part2()
);
......
<?php
// Bolt scheduler. GET args:
// course_id: course ID
// action:
// 'start' or none: show current (or first) item,
// and prompt for user info if any missing
// 'next': go to next lesson
// answers:
// JSON represenation of exercise answers
// Bolt scheduler.
// GET args:
// course_id: course ID
// action: see commands below
require_once("../inc/bolt.inc");
require_once("../inc/bolt_db.inc");
......@@ -33,9 +29,11 @@ function update_info() {
$user->bolt->update("sex=$sex, birth_year=$birth_year");
}
$course_doc = require_once($course->doc_file);
// The user clicked something on a view page.
// Make a record of it, and of the time
//
function finalize_view($user, $view_id, $action) {
if (!$view_id) return null;
$view = BoltView::lookup_id($view_id);
......@@ -56,6 +54,8 @@ function default_mode($item) {
return $item->is_exercise()?BOLT_MODE_SHOW:BOLT_MODE_LESSON;
}
// A page is being shown to the user; make a record of it
//
function create_view($user, $course, $iter, $mode, $prev_view_id) {
$now = time();
$item = $iter->item;
......@@ -64,9 +64,14 @@ function create_view($user, $course, $iter, $mode, $prev_view_id) {
$item->name = '--end--';
}
$state = $iter->encode_state();
if ($user->bolt->debug) {
echo "<pre>Ending state: "; print_r($iter->state); echo "</pre>\n";
}
return BoltView::insert("(user_id, course_id, item_name, start_time, mode, state, fraction_done, prev_view_id) values ($user->id, $course->id, '$item->name', $now, $mode, '$state', $iter->frac_done, $prev_view_id)");
}
// show a page saying the course has been completed
//
function show_finished_page($course, $view_id, $prev_view_id) {
page_head(null);
if (function_exists('bolt_header')) bolt_header("Course completed");
......@@ -85,14 +90,18 @@ function show_finished_page($course, $view_id, $prev_view_id) {
if (function_exists('bolt_footer')) bolt_footer();
}
// show an item (lesson, exercise, answer page)
//
function show_item($iter, $user, $course, $view_id, $prev_view_id, $mode) {
global $bolt_ex_mode;
global $bolt_ex_index;
global $bolt_ex_score;
global $bolt_query_string;
$item = $iter->item;
page_head(null);
if (function_exists('bolt_header')) bolt_header($item->title);
$bolt_query_string = $item->query_string;
if ($item->is_exercise()) {
$bolt_ex_mode = $mode;
......@@ -153,6 +162,7 @@ function show_item($iter, $user, $course, $view_id, $prev_view_id, $mode) {
function show_answer_page($iter, $score) {
global $bolt_ex_mode;
global $bolt_ex_index;
global $bolt_query_string;
$bolt_ex_mode = BOLT_MODE_ANSWER;
$bolt_ex_index = 0;
......@@ -160,6 +170,7 @@ function show_answer_page($iter, $score) {
$item = $iter->item;
page_head(null);
if (function_exists('bolt_header')) bolt_header($item->title);
$bolt_query_string = $item->query_string;
require_once($item->filename);
if (function_exists('bolt_divide')) bolt_divide();
$score_pct = number_format($score*100);
......@@ -226,8 +237,16 @@ case 'next': // "next" button in lesson or exercise answer page
$iter = new BoltIter($course_doc);
$iter->decode_state($view->state);
if ($user->bolt->debug) {
echo "<pre>Initial state: "; print_r($iter->state); echo "</pre>\n";
}
$iter->next();
if ($user->bolt->debug) {
echo "<pre>Item: "; print_r($iter->item); echo "</pre>\n";
}
if ($iter->item) {
$state = $iter->encode_state();
$mode = default_mode($iter->item);
......@@ -242,21 +261,32 @@ case 'next': // "next" button in lesson or exercise answer page
break;
case 'answer': // submit answer in exercise
$view = finalize_view($user, $view_id, BOLT_ACTION_SUBMIT);
if ($user->bolt->debug) {
echo "<pre>State: $view->state</pre>\n";
}
$iter = new BoltIter($course_doc);
$iter->decode_state($view->state);
$iter->at();
if ($user->bolt->debug) {
echo "<pre>Item: "; print_r($iter->item); echo "</pre>\n";
}
$item = $iter->item;
if (!$item->is_exercise()) {
print_r($item);
error_page("expected an exercise");
}
if ($view->item_name != $item->name) {
error_page("unexpected name");
}
// compute the score
$bolt_ex_query_string = $_SERVER['QUERY_STRING'];
$bolt_ex_mode = BOLT_MODE_SCORE;
$bolt_ex_index = 0;
$bolt_ex_score = 0;
$bolt_query_string = $item->query_string;
srand($view_id);
ob_start(); // turn on output buffering
require($item->filename);
......@@ -264,12 +294,17 @@ case 'answer': // submit answer in exercise
$bolt_ex_score /= $bolt_ex_index;
// make a record of the result
$qs = BoltDb::escape_string($_SERVER['QUERY_STRING']);
$result_id = BoltResult::insert(
"(view_id, score, response)
values ($view->id, $bolt_ex_score, '$qs')"
);
$view->update("result_id=$result_id");
// show the answer page
srand($view_id);
$view_id = create_view($user, $course, $iter, BOLT_MODE_ANSWER, $view->id);
show_item($iter, $user, $course, $view_id, $view->id, BOLT_MODE_ANSWER);
......
......@@ -33,6 +33,7 @@ except getopt.GetoptError, e:
home = os.path.expanduser('~')
options.project_root = os.path.join(home, 'projects')
options.web_only = False
for o,a in opts:
if o == '--help': usage()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment