2007-10-30 22:31:13 +00:00
|
|
|
<?php
|
2008-08-05 22:43:14 +00:00
|
|
|
// This file is part of BOINC.
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2008 University of California
|
|
|
|
//
|
|
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
|
|
// under the terms of the GNU Lesser General Public License
|
|
|
|
// as published by the Free Software Foundation,
|
|
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// BOINC 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 Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
2007-10-30 22:31:13 +00:00
|
|
|
|
2008-01-28 22:42:05 +00:00
|
|
|
// Bolt course document API
|
|
|
|
|
2007-10-30 22:31:13 +00:00
|
|
|
error_reporting(E_ALL);
|
2007-12-04 22:16:37 +00:00
|
|
|
ini_set('display_errors', true);
|
2007-10-30 22:31:13 +00:00
|
|
|
ini_set('display_startup_errors', true);
|
|
|
|
|
|
|
|
abstract class BoltUnit {
|
2008-08-15 22:07:24 +00:00
|
|
|
public $name;
|
|
|
|
// Logical name. Changing this makes it a different unit.
|
|
|
|
// For items, this is the filename with query string;
|
|
|
|
// for structures, it must be specified with name()
|
2007-12-10 22:13:48 +00:00
|
|
|
public $title;
|
2008-08-15 22:07:24 +00:00
|
|
|
// Optional; used when showing course history outline.
|
2007-12-05 19:13:21 +00:00
|
|
|
public $is_item;
|
2008-10-27 21:30:55 +00:00
|
|
|
public $attrs; // course-defined
|
2007-10-30 22:31:13 +00:00
|
|
|
|
2007-12-05 19:13:21 +00:00
|
|
|
abstract function walk(&$iter, $incr, &$frac_done);
|
2007-10-30 22:31:13 +00:00
|
|
|
// multi-purpose function for traversing a course.
|
2007-12-05 19:13:21 +00:00
|
|
|
// Create entry in $iter->state if not there.
|
|
|
|
// Recurse to first child.
|
|
|
|
// If first child is an item, set $iter->item
|
|
|
|
// If incr is set
|
|
|
|
// the bottom-level non-item unit should increment.
|
|
|
|
// return value: true if the caller should increment
|
2007-11-29 02:56:10 +00:00
|
|
|
// frac_done: Fraction done (of this unit and any subunits)
|
2007-10-30 22:31:13 +00:00
|
|
|
}
|
|
|
|
|
2008-01-28 22:42:05 +00:00
|
|
|
// base class for exercise and lesson
|
2007-10-30 22:31:13 +00:00
|
|
|
//
|
|
|
|
class BoltItem extends BoltUnit {
|
|
|
|
public $filename;
|
2008-01-01 18:07:13 +00:00
|
|
|
public $query_string;
|
2008-10-27 21:30:55 +00:00
|
|
|
function __construct($filename, $title, $attrs) {
|
2008-01-01 18:07:13 +00:00
|
|
|
$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);
|
|
|
|
}
|
2008-08-15 22:07:24 +00:00
|
|
|
$this->name = $filename;
|
2007-12-10 22:13:48 +00:00
|
|
|
$this->title = $title;
|
2007-12-05 19:13:21 +00:00
|
|
|
$this->is_item = true;
|
2008-10-27 21:30:55 +00:00
|
|
|
$this->attrs = $attrs;
|
2007-10-30 22:31:13 +00:00
|
|
|
}
|
|
|
|
function begin() {
|
|
|
|
return array(new BoltFrame($this));
|
|
|
|
}
|
2007-12-05 19:13:21 +00:00
|
|
|
function walk(&$iter, $incr, &$frac_done) {
|
2007-10-30 22:31:13 +00:00
|
|
|
echo "SHOULDN'T BE HERE\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class BoltLesson extends BoltItem {
|
2007-11-29 23:26:49 +00:00
|
|
|
function is_exercise() {
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-30 22:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class BoltExercise extends BoltItem {
|
2008-10-23 20:35:39 +00:00
|
|
|
public $callback;
|
|
|
|
// called as func($student, $score, $query_string) after scoring
|
|
|
|
function __construct($filename, $title, $callback) {
|
|
|
|
parent::__construct($filename, $title);
|
|
|
|
$this->callback = $callback;
|
|
|
|
}
|
2007-11-29 23:26:49 +00:00
|
|
|
function is_exercise() {
|
|
|
|
return true;
|
|
|
|
}
|
2007-10-30 22:31:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-07 23:21:31 +00:00
|
|
|
// Base class for control structures (all units other than items).
|
|
|
|
// The state of a control structure has two parts:
|
|
|
|
// 1) a transient PHP object
|
|
|
|
// 2) a persistent "state record" (stored in JSON in the DB)
|
|
|
|
//
|
|
|
|
// The PHP object has the following properties:
|
2008-01-28 22:42:05 +00:00
|
|
|
// - a set of units
|
2008-02-07 23:21:31 +00:00
|
|
|
// - ordered: a flag for whether the set has been ordered yet
|
|
|
|
// - order($state_rec): a function for ordering this set,
|
|
|
|
// defined in the derived class
|
2008-01-28 22:42:05 +00:00
|
|
|
// (i.e., random, student-specific, or identity)
|
2008-02-07 23:21:31 +00:00
|
|
|
// This orders the set, sets "ordered", and adds info to the state rec
|
|
|
|
// saying how the ordering was done (e.g. RNG seed)
|
|
|
|
// - a number "ntoshow" for how many units to show
|
|
|
|
//
|
|
|
|
// The state record has the following items:
|
|
|
|
// - index: index into the unit array
|
|
|
|
// - nshown: for how many units completed so far
|
|
|
|
// - child_name: name of current child, or null
|
2008-01-28 22:42:05 +00:00
|
|
|
//
|
|
|
|
class BoltSet extends BoltUnit {
|
|
|
|
public $units;
|
2008-10-27 21:30:55 +00:00
|
|
|
function __construct($name, $units, $ntoshow, $attrs) {
|
2008-01-28 22:42:05 +00:00
|
|
|
$this->name = $name;
|
|
|
|
$this->is_item = false;
|
|
|
|
$this->units = $units;
|
|
|
|
$this->ntoshow = $ntoshow;
|
|
|
|
$this->ordered = false;
|
2008-10-27 21:30:55 +00:00
|
|
|
$this->attrs = $attrs;
|
2008-01-28 22:42:05 +00:00
|
|
|
}
|
2008-01-31 23:43:37 +00:00
|
|
|
|
2008-10-20 21:19:13 +00:00
|
|
|
// restart this unit - set its state record to an initial state
|
2008-02-07 23:21:31 +00:00
|
|
|
//
|
|
|
|
function restart(&$iter) {
|
|
|
|
$state_rec = $iter->state[$this->name];
|
|
|
|
if (!$state_rec) $state_rec = $this->init();
|
|
|
|
$state_rec['nshown'] = 0;
|
|
|
|
$state_rec['child_name'] = null;
|
|
|
|
$iter->state[$this->name] = $state_rec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize this unit (once per course)
|
|
|
|
//
|
|
|
|
function init(&$iter) {
|
|
|
|
$state_rec = array();
|
|
|
|
$state_rec['index'] = 0;
|
|
|
|
$iter->state[$this->name] = $state_rec;
|
|
|
|
return $state_rec;
|
|
|
|
}
|
|
|
|
|
|
|
|
function finished(&$iter) {
|
|
|
|
$this->restart($iter);
|
2008-01-31 23:43:37 +00:00
|
|
|
}
|
|
|
|
|
2008-01-28 22:42:05 +00:00
|
|
|
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'];
|
|
|
|
$nshown = $state_rec['nshown'];
|
|
|
|
if (!$this->ordered) {
|
2008-02-07 23:21:31 +00:00
|
|
|
$this->order($iter);
|
2008-01-28 22:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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['index'];
|
|
|
|
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) {
|
|
|
|
if ($child->is_item) {
|
|
|
|
$my_inc = true;
|
|
|
|
} else {
|
|
|
|
$my_inc = $child->walk($iter, $incr, $frac_done);
|
|
|
|
}
|
|
|
|
if ($my_inc) {
|
|
|
|
$nshown++;
|
|
|
|
if ($nshown == $this->ntoshow) {
|
|
|
|
$frac_done = 1;
|
2008-02-07 23:21:31 +00:00
|
|
|
$this->finished($iter);
|
2008-01-28 22:42:05 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
$i = ($i+1)%$n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// here if no state record; initialize
|
|
|
|
//
|
|
|
|
$i = 0;
|
|
|
|
$nshown = 0;
|
2008-02-07 23:21:31 +00:00
|
|
|
$this->init($iter);
|
|
|
|
$this->order($iter);
|
2008-01-28 22:42:05 +00:00
|
|
|
}
|
|
|
|
|
2008-02-07 23:21:31 +00:00
|
|
|
// at this point, $i is index of current child, $nshown is valid,
|
|
|
|
// and this unit has a record in the state array
|
2008-01-28 22:42:05 +00:00
|
|
|
//
|
|
|
|
$child = $this->units[$i];
|
|
|
|
$frac_done = $nshown/$n;
|
2008-02-07 23:21:31 +00:00
|
|
|
$state_rec = $iter->state[$this->name];
|
2008-01-28 22:42:05 +00:00
|
|
|
$state_rec['index'] = $i;
|
|
|
|
$state_rec['nshown'] = $nshown;
|
|
|
|
$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);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2008-02-22 20:09:23 +00:00
|
|
|
|
|
|
|
// return the name of our child, if we exist in the state
|
|
|
|
//
|
|
|
|
function get_child($state) {
|
|
|
|
if (array_key_exists($this->name, $state)) {
|
|
|
|
$state_rec = $state[$this->name];
|
|
|
|
$child_name = $state_rec['child_name'];
|
|
|
|
foreach($this->units as $c) {
|
|
|
|
if ($c->name == $child_name) {
|
|
|
|
return $c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2008-01-28 22:42:05 +00:00
|
|
|
}
|
|
|
|
|
2007-12-04 22:16:37 +00:00
|
|
|
function name($n) {
|
2007-12-10 22:13:48 +00:00
|
|
|
return array('name', $n);
|
|
|
|
}
|
|
|
|
|
|
|
|
function title($n) {
|
|
|
|
return array('title', $n);
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
|
2007-12-27 18:37:22 +00:00
|
|
|
function number($n) {
|
|
|
|
return array('number', $n);
|
|
|
|
}
|
|
|
|
|
2007-12-04 22:16:37 +00:00
|
|
|
function filename($n) {
|
2007-12-10 22:13:48 +00:00
|
|
|
return array('filename', $n);
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
|
2008-10-27 21:30:55 +00:00
|
|
|
function attrs($n) {
|
|
|
|
return array('attrs', $n);
|
|
|
|
}
|
|
|
|
|
2008-10-23 20:35:39 +00:00
|
|
|
function callback($n) {
|
|
|
|
return array('callback', $n);
|
|
|
|
}
|
|
|
|
|
2007-12-04 22:16:37 +00:00
|
|
|
function lesson() {
|
2008-08-15 22:07:24 +00:00
|
|
|
$filename = "";
|
2007-12-10 22:13:48 +00:00
|
|
|
$title = "";
|
2008-10-27 21:30:55 +00:00
|
|
|
$attrs = null;
|
|
|
|
|
2007-12-04 22:16:37 +00:00
|
|
|
$args = func_get_args();
|
|
|
|
foreach ($args as $arg) {
|
2007-12-10 22:13:48 +00:00
|
|
|
if (is_array($arg)) {
|
|
|
|
switch ($arg[0]) {
|
|
|
|
case 'title': $title = $arg[1]; break;
|
2008-08-15 22:07:24 +00:00
|
|
|
case 'filename': $filename = $arg[1]; break;
|
2008-10-27 21:30:55 +00:00
|
|
|
case 'attrs': $attrs = $arg[1]; break;
|
2008-08-15 22:07:24 +00:00
|
|
|
default: echo "Unrecognized lesson parameter: ", $arg[0], "\n"; break;
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
2007-12-10 22:13:48 +00:00
|
|
|
} else {
|
|
|
|
echo "unprocessed arg of class ".get_class($arg);
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-10 22:13:48 +00:00
|
|
|
if (!$title) {
|
2008-08-15 22:07:24 +00:00
|
|
|
$title = $filename;
|
2007-12-10 22:13:48 +00:00
|
|
|
}
|
2008-08-15 22:07:24 +00:00
|
|
|
if (!$filename) {
|
2007-12-04 22:16:37 +00:00
|
|
|
error_page("Missing filename in lesson");
|
|
|
|
}
|
2008-10-27 21:30:55 +00:00
|
|
|
return new BoltLesson($filename, $title, $attrs);
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function exercise() {
|
2008-08-15 22:07:24 +00:00
|
|
|
$filename = "";
|
2007-12-10 22:13:48 +00:00
|
|
|
$title = "";
|
2008-10-27 21:30:55 +00:00
|
|
|
$attrs = null;
|
|
|
|
|
2007-12-04 22:16:37 +00:00
|
|
|
$args = func_get_args();
|
2008-10-23 20:35:39 +00:00
|
|
|
$callback = null;
|
2007-12-04 22:16:37 +00:00
|
|
|
foreach ($args as $arg) {
|
2007-12-10 22:13:48 +00:00
|
|
|
if (is_array($arg)) {
|
|
|
|
switch ($arg[0]) {
|
|
|
|
case 'title': $title = $arg[1]; break;
|
2008-08-15 22:07:24 +00:00
|
|
|
case 'filename': $filename = $arg[1]; break;
|
2008-10-27 21:30:55 +00:00
|
|
|
case 'attrs': $attrs = $arg[1]; break;
|
2008-10-23 20:35:39 +00:00
|
|
|
case 'callback': $callback = $arg[1]; break;
|
2008-08-15 22:07:24 +00:00
|
|
|
default: echo "Unrecognized exercise parameter: ", $arg[0], "\n"; break;
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-15 22:07:24 +00:00
|
|
|
if (!$title) {
|
|
|
|
$title = $filename;
|
2007-12-10 22:13:48 +00:00
|
|
|
}
|
2008-08-15 22:07:24 +00:00
|
|
|
if (!$filename) {
|
2007-12-10 22:13:48 +00:00
|
|
|
error_page("Missing filename in lesson");
|
|
|
|
}
|
2008-10-27 21:30:55 +00:00
|
|
|
return new BoltExercise($filename, $title, $attrs, $callback);
|
2007-12-04 22:16:37 +00:00
|
|
|
}
|
|
|
|
|
2008-01-01 18:07:13 +00:00
|
|
|
require_once('../inc/bolt_seq.inc');
|
|
|
|
require_once('../inc/bolt_rnd.inc');
|
|
|
|
require_once('../inc/bolt_xset.inc');
|
2008-01-31 23:43:37 +00:00
|
|
|
require_once('../inc/bolt_select.inc');
|
2008-01-01 18:07:13 +00:00
|
|
|
|
2007-10-30 22:31:13 +00:00
|
|
|
?>
|