mirror of https://github.com/BOINC/boinc.git
- fixed bug in upgrade
svn path=/trunk/boinc/; revision=14451
This commit is contained in:
parent
945b160992
commit
dddd1fc501
|
@ -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
|
||||
|
|
12616
checkin_notes
12616
checkin_notes
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,9 @@
|
|||
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)
|
||||
);
|
||||
|
|
|
@ -75,290 +75,18 @@ class BoltIter {
|
|||
}
|
||||
}
|
||||
|
||||
class BoltSequence extends BoltUnit {
|
||||
public $units;
|
||||
function __construct($n, $u) {
|
||||
$this->name = $n;
|
||||
$this->units = $u;
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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($n, $u, $n) {
|
||||
$this->name = $n;
|
||||
$this->units = $u;
|
||||
$this->is_item = false;
|
||||
$this->number = $n;
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BoltExerciseSet extends BoltUnit {
|
||||
public $units;
|
||||
public $reviews;
|
||||
function __construct($n, $u, $n, $r) {
|
||||
$this->name = $n;
|
||||
$this->units = $u;
|
||||
$this->is_item = false;
|
||||
$this->number = $n;
|
||||
$this->shuffled = false;
|
||||
$this->reviews = $r;
|
||||
}
|
||||
|
||||
// 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($score, &$nav_info) {
|
||||
}
|
||||
|
||||
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];
|
||||
$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 BoltItem extends BoltUnit {
|
||||
public $filename;
|
||||
public $query_string;
|
||||
function __construct($name, $title, $filename) {
|
||||
$this->filename = $filename;
|
||||
$p = strpos($filename, '?');
|
||||
if ($p === false) {
|
||||
$this->filename = $filename;
|
||||
$this->query_string = null;
|
||||
} else {
|
||||
$this->filename = substr($filename, 0, $p);
|
||||
$this->query_string = substr($filename, $p+1);
|
||||
}
|
||||
$this->name = $name;
|
||||
$this->title = $title;
|
||||
$this->is_item = true;
|
||||
|
@ -383,22 +111,6 @@ class BoltExercise extends BoltItem {
|
|||
}
|
||||
}
|
||||
|
||||
class BoltRefreshInterval {
|
||||
public $intervals;
|
||||
function __construct($i) {
|
||||
$this->intervals = $i;
|
||||
}
|
||||
}
|
||||
|
||||
class BoltReview {
|
||||
public $score;
|
||||
public $unit;
|
||||
function __construct($s, $u) {
|
||||
$this->score = $s;
|
||||
$this->unit = $u;
|
||||
}
|
||||
}
|
||||
|
||||
function name($n) {
|
||||
return array('name', $n);
|
||||
}
|
||||
|
@ -415,17 +127,6 @@ function filename($n) {
|
|||
return array('filename', $n);
|
||||
}
|
||||
|
||||
function refresh_interval($i) {
|
||||
return array('refresh_interval', $i);
|
||||
}
|
||||
|
||||
function review($s, $u) {
|
||||
return new BoltReview($s, $u);
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
}
|
||||
|
||||
function lesson() {
|
||||
$name = "";
|
||||
$file = "";
|
||||
|
@ -482,82 +183,6 @@ function exercise() {
|
|||
return new BoltExercise($name, $title, $file);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function exercise_set() {
|
||||
$args = func_get_args();
|
||||
$units = array();
|
||||
$reviews = 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 if (get_class($arg) == "BoltReview") {
|
||||
$reviews[] = $arg;
|
||||
} else {
|
||||
echo "Unrecognized arg: ";
|
||||
print_r($arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new BoltExerciseSet($name, $units, $number, $reviews);
|
||||
}
|
||||
|
||||
function enum_course($course) {
|
||||
$iter = new BoltIter($course);
|
||||
while (1) {
|
||||
|
@ -571,4 +196,8 @@ function enum_course($course) {
|
|||
echo "course over\n";
|
||||
}
|
||||
|
||||
require_once('../inc/bolt_seq.inc');
|
||||
require_once('../inc/bolt_rnd.inc');
|
||||
require_once('../inc/bolt_xset.inc');
|
||||
|
||||
?>
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,101 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,184 @@
|
|||
<?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')
|
||||
),
|
||||
refresh(array(7, 14, 28)),
|
||||
review(.3, basic_review()),
|
||||
review(.7, int_review())
|
||||
exercise(
|
||||
name('exercise 2'),
|
||||
filename('bolt_sample_exercise.php?n=2')
|
||||
),
|
||||
exercise(
|
||||
name('exercise 3'),
|
||||
filename('bolt_sample_exercise.php?n=3')
|
||||
),
|
||||
repeat(.3, basic_review(), REVIEW),
|
||||
repeat(.7, int_review(), REVIEW|REPEAT),
|
||||
repeat(1, null, REPEAT|NEXT),
|
||||
refresh(array(7, 14, 28))
|
||||
),
|
||||
part2()
|
||||
);
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
<?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()
|
||||
|
|
Loading…
Reference in New Issue