mirror of https://github.com/BOINC/boinc.git
remove Bossa and Bolt files.
These aren't part of BOINC. I moved them to new repos.
This commit is contained in:
parent
10769728db
commit
0f4960c6ba
|
@ -1,11 +0,0 @@
|
|||
alter table bolt_course
|
||||
add unique(name);
|
||||
|
||||
alter table bolt_enrollment
|
||||
add unique(user_id, course_id);
|
||||
|
||||
alter table bolt_view
|
||||
add index bv_cs(course_id, start_time);
|
||||
|
||||
alter table bolt_refresh
|
||||
add unique br_u(user_id, course_id, name);
|
|
@ -1,154 +0,0 @@
|
|||
create table bolt_user (
|
||||
user_id integer not null,
|
||||
birth_year integer not null,
|
||||
sex tinyint not null,
|
||||
flags integer not null,
|
||||
attrs text not null,
|
||||
-- project-defined. Use serialized PHP object
|
||||
primary key (user_id)
|
||||
);
|
||||
|
||||
create table bolt_course (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
short_name varchar(255) not null,
|
||||
name varchar(255) not null,
|
||||
description text not null,
|
||||
hidden tinyint not null,
|
||||
bossa_app_id integer not null,
|
||||
-- on completion, go to this Bossa app
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table bolt_enrollment (
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
last_view_id integer not null,
|
||||
-- ID of last study phase view
|
||||
mastery double not null
|
||||
);
|
||||
|
||||
-- Represents a view of an item;
|
||||
-- created when we show the item,
|
||||
-- and finalized when the user clicks on something to leave the page
|
||||
-- A special view is used to represent the end of a course;
|
||||
-- its mode is BOLT_MODE_FINISHED.
|
||||
--
|
||||
create table bolt_view (
|
||||
id integer not null auto_increment,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
item_name varchar(255) not null,
|
||||
-- name of the item
|
||||
state text not null,
|
||||
-- course state
|
||||
mode integer not null,
|
||||
-- distinguishes exercise show/answer
|
||||
phase integer not null,
|
||||
-- distinguishes study/review/refresh
|
||||
action integer not null,
|
||||
-- what the user clicked to leave page
|
||||
start_time integer not null,
|
||||
end_time integer not null,
|
||||
prev_view_id integer not null,
|
||||
-- for exercise answer views;
|
||||
-- refers to the original exercise view
|
||||
fraction_done double not null,
|
||||
result_id integer not null,
|
||||
-- if this was an exercise show, link to result record
|
||||
refresh_id integer not null,
|
||||
-- if unit was flagged for review, link to review record
|
||||
-- ?? remove?
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
-- represents the result of a single exercise
|
||||
--
|
||||
create table bolt_result (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
view_id integer not null,
|
||||
-- the display of exercise
|
||||
item_name varchar(255) not null,
|
||||
score double not null,
|
||||
response text not null,
|
||||
-- the query string containing user's responses
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
-- represents the result of a completed exercise set,
|
||||
-- where "completed" means the last exercise was scored.
|
||||
-- In theory this could be reconstructed from the individual exercise results,
|
||||
-- but this table makes it easier for analytics
|
||||
--
|
||||
create table bolt_xset_result (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
start_time integer not null,
|
||||
end_time integer not null,
|
||||
name varchar(255) not null,
|
||||
-- logical name of exercise set unit
|
||||
score double not null,
|
||||
-- weighted average score
|
||||
view_id integer not null,
|
||||
-- the view of the answer page of last exercise in set
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
-- represents the completion of a select structure
|
||||
--
|
||||
create table bolt_select_finished (
|
||||
id integer not null auto_increment,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
end_time integer not null,
|
||||
name varchar(255) not null,
|
||||
-- logical name of the select unit
|
||||
selected_unit varchar(255) not null,
|
||||
-- name of selected subunit
|
||||
view_id integer not null,
|
||||
-- the view of the last item
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
-- represents a refresh/repeat of an exercise set,
|
||||
-- either pending (not due yet),
|
||||
-- due but not started, or in progress.
|
||||
--
|
||||
create table bolt_refresh (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
course_id integer not null,
|
||||
name varchar(255) not null,
|
||||
-- logical name of result set unit
|
||||
last_view_id integer not null,
|
||||
-- if refresh is in progress, the last view
|
||||
xset_result_id integer not null,
|
||||
-- most recent result for this exercise set
|
||||
due_time integer not null,
|
||||
-- when refresh will be due
|
||||
count integer not null,
|
||||
-- index into intervals array
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table bolt_question (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
user_id integer not null,
|
||||
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
|
||||
primary key (id)
|
||||
);
|
|
@ -1,10 +0,0 @@
|
|||
alter table bossa_app
|
||||
add unique(name),
|
||||
add unique(short_name);
|
||||
|
||||
alter table bossa_job
|
||||
add index bj_conf_needed(app_id, calibration, priority_0);
|
||||
|
||||
alter table bossa_job_inst
|
||||
add index bji_job(job_id),
|
||||
add index bji_user(user_id);
|
|
@ -1,63 +0,0 @@
|
|||
create table bossa_app (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
name varchar(255) not null,
|
||||
short_name varchar(255) not null,
|
||||
description varchar(255) not null,
|
||||
long_jobs tinyint not null,
|
||||
hidden tinyint not null,
|
||||
bolt_course_id integer not null,
|
||||
time_estimate integer not null,
|
||||
time_limit integer not null,
|
||||
calibration_frac double not null,
|
||||
info text,
|
||||
-- app-specific info, JSON
|
||||
primary key(id)
|
||||
) engine = InnoDB;
|
||||
|
||||
create table bossa_job (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
app_id integer not null,
|
||||
batch_id integer not null,
|
||||
state integer not null,
|
||||
info text,
|
||||
calibration tinyint not null,
|
||||
priority_0 double not null,
|
||||
-- add more as needed
|
||||
-- for calibration jobs, init to random and decrement on each view
|
||||
primary key(id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table bossa_job_inst (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
app_id integer not null,
|
||||
job_id integer not null,
|
||||
user_id integer not null,
|
||||
batch_id integer not null,
|
||||
finish_time integer not null,
|
||||
timeout integer not null,
|
||||
calibration tinyint not null,
|
||||
info text,
|
||||
primary key(id)
|
||||
) engine=InnoDB;
|
||||
|
||||
create table bossa_user (
|
||||
user_id integer not null,
|
||||
category integer not null,
|
||||
flags integer not null,
|
||||
-- debug, show_all
|
||||
info text,
|
||||
-- Project-dependent info about users ability and performance.
|
||||
primary key(user_id)
|
||||
) engine = InnoDB;
|
||||
|
||||
create table bossa_batch (
|
||||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
name varchar(255) not null,
|
||||
app_id integer not null,
|
||||
calibration tinyint not null,
|
||||
primary key(id)
|
||||
) engine = InnoDB;
|
|
@ -1,381 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// Bolt course document API
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
abstract class BoltUnit {
|
||||
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()
|
||||
public $title;
|
||||
// Optional; used when showing course history outline.
|
||||
public $is_item;
|
||||
public $attrs; // course-defined
|
||||
|
||||
abstract function walk(&$iter, $incr, &$frac_done);
|
||||
// multi-purpose function for traversing a course.
|
||||
// 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
|
||||
// frac_done: Fraction done (of this unit and any subunits)
|
||||
}
|
||||
|
||||
// base class for exercise and lesson
|
||||
//
|
||||
class BoltItem extends BoltUnit {
|
||||
public $filename;
|
||||
public $query_string;
|
||||
function __construct($filename, $title, $attrs) {
|
||||
$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 = $filename;
|
||||
$this->title = $title;
|
||||
$this->is_item = true;
|
||||
$this->attrs = $attrs;
|
||||
}
|
||||
function begin() {
|
||||
return array(new BoltFrame($this));
|
||||
}
|
||||
function walk(&$iter, $incr, &$frac_done) {
|
||||
echo "SHOULDN'T BE HERE\n";
|
||||
}
|
||||
}
|
||||
|
||||
class BoltLesson extends BoltItem {
|
||||
function is_exercise() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class BoltExercise extends BoltItem {
|
||||
public $callback;
|
||||
// called as func($student, $score, $query_string) after scoring
|
||||
public $weight;
|
||||
public $has_answer_page;
|
||||
|
||||
function __construct(
|
||||
$filename, $title, $attrs, $callback, $weight, $has_answer_page
|
||||
) {
|
||||
parent::__construct($filename, $title, $attrs);
|
||||
$this->callback = $callback;
|
||||
$this->weight = $weight;
|
||||
$this->has_answer_page = $has_answer_page;
|
||||
}
|
||||
function is_exercise() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
// - a set of units
|
||||
// - 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
|
||||
// (i.e., random, student-specific, or identity)
|
||||
// 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
|
||||
//
|
||||
class BoltSet extends BoltUnit {
|
||||
public $units;
|
||||
function __construct($name, $units, $ntoshow, $attrs) {
|
||||
$this->name = $name;
|
||||
$this->is_item = false;
|
||||
$this->units = $units;
|
||||
$this->ntoshow = $ntoshow;
|
||||
$this->ordered = false;
|
||||
$this->attrs = $attrs;
|
||||
}
|
||||
|
||||
// restart this unit - set its state record to an initial state
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
$this->order($iter);
|
||||
}
|
||||
|
||||
// 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;
|
||||
$this->finished($iter);
|
||||
return true;
|
||||
} else {
|
||||
$i = ($i+1)%$n;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// here if no state record; initialize
|
||||
//
|
||||
$i = 0;
|
||||
$nshown = 0;
|
||||
$this->init($iter);
|
||||
$this->order($iter);
|
||||
}
|
||||
|
||||
// at this point, $i is index of current child, $nshown is valid,
|
||||
// and this unit has a record in the state array
|
||||
//
|
||||
$child = $this->units[$i];
|
||||
$frac_done = $nshown/$n;
|
||||
$state_rec = $iter->state[$this->name];
|
||||
$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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function name($n) {
|
||||
return array('name', $n);
|
||||
}
|
||||
|
||||
function title($n) {
|
||||
return array('title', $n);
|
||||
}
|
||||
|
||||
function number($n) {
|
||||
return array('number', $n);
|
||||
}
|
||||
|
||||
function filename($n) {
|
||||
return array('filename', $n);
|
||||
}
|
||||
|
||||
function has_answer_page($n) {
|
||||
return array('has_answer_page', $n);
|
||||
}
|
||||
|
||||
function attrs($n) {
|
||||
return array('attrs', $n);
|
||||
}
|
||||
|
||||
function callback($n) {
|
||||
return array('callback', $n);
|
||||
}
|
||||
|
||||
function lesson() {
|
||||
$filename = "";
|
||||
$title = "";
|
||||
$attrs = null;
|
||||
|
||||
$args = func_get_args();
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
switch ($arg[0]) {
|
||||
case 'title': $title = $arg[1]; break;
|
||||
case 'filename': $filename = $arg[1]; break;
|
||||
case 'attrs': $attrs = $arg[1]; break;
|
||||
default: echo "Unrecognized lesson parameter: ", $arg[0], "\n"; break;
|
||||
}
|
||||
} else {
|
||||
echo "unprocessed arg of class ".get_class($arg);
|
||||
}
|
||||
}
|
||||
if (!$title) {
|
||||
$title = $filename;
|
||||
}
|
||||
if (!$filename) {
|
||||
error_page("Missing filename in lesson");
|
||||
}
|
||||
return new BoltLesson($filename, $title, $attrs);
|
||||
}
|
||||
|
||||
function exercise() {
|
||||
$filename = "";
|
||||
$title = "";
|
||||
$attrs = null;
|
||||
$weight = 1;
|
||||
$has_answer_page = true;
|
||||
|
||||
$args = func_get_args();
|
||||
$callback = null;
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
switch ($arg[0]) {
|
||||
case 'title': $title = $arg[1]; break;
|
||||
case 'filename': $filename = $arg[1]; break;
|
||||
case 'attrs': $attrs = $arg[1]; break;
|
||||
case 'callback': $callback = $arg[1]; break;
|
||||
case 'weight': $weight = $arg[1]; break;
|
||||
case 'has_answer_page': $has_answer_page = $arg[1]; break;
|
||||
default: echo "Unrecognized exercise parameter: ", $arg[0], "\n"; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$title) {
|
||||
$title = $filename;
|
||||
}
|
||||
if (!$filename) {
|
||||
error_page("Missing filename in lesson");
|
||||
}
|
||||
return new BoltExercise(
|
||||
$filename, $title, $attrs, $callback, $weight, $has_answer_page
|
||||
);
|
||||
}
|
||||
|
||||
function item_attrs() {
|
||||
global $item;
|
||||
return $item->attrs;
|
||||
}
|
||||
|
||||
function student_sex() {
|
||||
global $user;
|
||||
return $user->bolt->sex;
|
||||
}
|
||||
|
||||
function student_age() {
|
||||
global $user;
|
||||
if (!$user->bolt->birth_year) return -1;
|
||||
$date = getdate();
|
||||
$this_year = $date["year"];
|
||||
return $this_year - $user->bolt->birth_year;
|
||||
}
|
||||
|
||||
function student_country() {
|
||||
global $user;
|
||||
return $user->country;
|
||||
}
|
||||
|
||||
function student_name() {
|
||||
global $user;
|
||||
return $user->name;
|
||||
}
|
||||
|
||||
function student_attrs() {
|
||||
global $user;
|
||||
return unserialize($user->bolt->attrs);
|
||||
}
|
||||
|
||||
function set_student_attrs($attrs) {
|
||||
global $user;
|
||||
$attrs = serialize($attrs);
|
||||
$user->bolt->update("attrs='$attrs'");
|
||||
}
|
||||
|
||||
require_once('../inc/bolt_seq.inc');
|
||||
require_once('../inc/bolt_rnd.inc');
|
||||
require_once('../inc/bolt_xset.inc');
|
||||
require_once('../inc/bolt_select.inc');
|
||||
|
||||
?>
|
|
@ -1,168 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// represents a categorization of students
|
||||
//
|
||||
abstract class Categorization {
|
||||
abstract function name();
|
||||
// returns descriptive name
|
||||
abstract function categories();
|
||||
// returns list of categories
|
||||
abstract function categorize($user);
|
||||
// returns a student's category
|
||||
}
|
||||
|
||||
class CatSex extends Categorization {
|
||||
function name() {
|
||||
return "Sex";
|
||||
}
|
||||
function categories() {
|
||||
return array ("Male", "Female", "Unknown");
|
||||
}
|
||||
function categorize($user) {
|
||||
switch ($user->bolt->sex) {
|
||||
case 1: return "Male";
|
||||
case 2: return "Female";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$x = localtime(time(), true);
|
||||
$this_year = 1900 + $x['tm_year'];
|
||||
|
||||
class CatAge20 extends Categorization {
|
||||
function name() {
|
||||
return "Age (20-year groups)";
|
||||
}
|
||||
function categories() {
|
||||
return array("0-19", "20-39", "40-59", "60-79", "80+", "Unknown");
|
||||
}
|
||||
function categorize($user) {
|
||||
if (!$user->bolt->birth_year) return "Unknown";
|
||||
global $this_year;
|
||||
$n = $this_year - $user->bolt->birth_year;
|
||||
if ($n < 20) return "0-19";
|
||||
if ($n < 40) return "20-39";
|
||||
if ($n < 60) return "40-59";
|
||||
if ($n < 80) return "60-79";
|
||||
return "80+";
|
||||
}
|
||||
}
|
||||
|
||||
$categorizations = array(new CatSex(), new CatAge20());
|
||||
|
||||
function lookup_categorization($name) {
|
||||
global $categorizations;
|
||||
foreach ($categorizations as $c) {
|
||||
if ($c->name() == $name) return $c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function filter_form($sel_name, $sel_cat) {
|
||||
global $categorizations;
|
||||
$checked = (!$sel_name || $sel_name == "none")?"checked":"";
|
||||
echo "
|
||||
Filter by:
|
||||
<ul>
|
||||
<li><input type=radio name=filter value=none $checked> None
|
||||
";
|
||||
foreach ($categorizations as $c) {
|
||||
$name = $c->name();
|
||||
$cats = $c->categories();
|
||||
echo "
|
||||
<li> $name
|
||||
<ul>
|
||||
";
|
||||
foreach ($cats as $x) {
|
||||
$checked = ($sel_name == $name && $sel_cat == $x) ? "checked":"";
|
||||
echo "
|
||||
<li> <input type=radio name=filter value=\"$name:$x\" $checked> $x
|
||||
";
|
||||
}
|
||||
echo "</ul>";
|
||||
}
|
||||
echo "</ul>";
|
||||
}
|
||||
|
||||
function breakdown_form($sel_name) {
|
||||
global $categorizations;
|
||||
$checked = (!$sel_name || $sel_name == "none")?"checked":"";
|
||||
echo "
|
||||
Break down by:
|
||||
<ul>
|
||||
<li><input type=radio name=breakdown value=none $checked> None
|
||||
";
|
||||
foreach ($categorizations as $c) {
|
||||
$name = $c->name();
|
||||
$checked = ($sel_name == $name)?"checked":"";
|
||||
echo "
|
||||
<li> <input type=radio name=breakdown value=\"$name\" $checked> $name
|
||||
";
|
||||
}
|
||||
echo "</ul>";
|
||||
}
|
||||
|
||||
// return filter and breakdown info for URLs
|
||||
//
|
||||
function filter_url() {
|
||||
global $filter, $filter_cat, $breakdown, $breakdown_cat;
|
||||
|
||||
$x = "";
|
||||
if ($filter && $filter_cat) {
|
||||
$x .= "&filter=".$filter->name.":$filter_cat";
|
||||
}
|
||||
if ($breakdown && $breakdown_cat) {
|
||||
$x .= "&breakdown=".$breakdown->name.":$breakdown_cat";
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
||||
// get filter and breakdown from form vars
|
||||
//
|
||||
function get_filters_from_form() {
|
||||
global $breakdown, $breakdown_cat, $filter, $filter_cat;
|
||||
|
||||
$breakdown_cat = null;
|
||||
$breakdown_info = get_str('breakdown', true);
|
||||
if ($breakdown_info && $breakdown_info != 'none') {
|
||||
$arr = explode(":", $breakdown_info);
|
||||
$breakdown_name = $arr[0];
|
||||
if (count($arr) == 2) {
|
||||
$breakdown_cat = $arr[1];
|
||||
}
|
||||
$breakdown = lookup_categorization($breakdown_name);
|
||||
if (!$breakdown) error_page("unknown breakdown $breakdown_name");
|
||||
} else {
|
||||
$breakdown = null;
|
||||
}
|
||||
$filter_info = get_str('filter', true);
|
||||
if ($filter_info && $filter_info != "none") {
|
||||
$arr = explode(":", $filter_info);
|
||||
$filter_name = $arr[0];
|
||||
$filter_cat = $arr[1];
|
||||
$filter = lookup_categorization($filter_name);
|
||||
if (!$filter) error_page("unknown filter $filter_name");
|
||||
} else {
|
||||
$filter_cat = "";
|
||||
$filter = null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,325 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/db_conn.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
define('BOLT_PHASE_STUDY', 1);
|
||||
// sequential progress through course
|
||||
define('BOLT_PHASE_REVIEW', 2);
|
||||
// review and repeat of an exercise set
|
||||
define('BOLT_PHASE_REFRESH', 3);
|
||||
// timed repeat of exercise set, and possibly review and repeat
|
||||
|
||||
define('BOLT_MODE_LESSON', 1);
|
||||
define('BOLT_MODE_SHOW', 2);
|
||||
define('BOLT_MODE_SCORE', 3);
|
||||
define('BOLT_MODE_ANSWER', 4);
|
||||
define('BOLT_MODE_FINISHED', 5);
|
||||
|
||||
define('BOLT_ACTION_NONE', 0);
|
||||
define('BOLT_ACTION_NEXT', 1);
|
||||
define('BOLT_ACTION_PREV', 2);
|
||||
define('BOLT_ACTION_SUBMIT', 3);
|
||||
define('BOLT_ACTION_QUESTION', 4);
|
||||
define('BOLT_ACTION_COURSE_HOME', 5);
|
||||
define('BOLT_ACTION_REVIEW', 6);
|
||||
define('BOLT_ACTION_REPEAT', 7);
|
||||
|
||||
define('BOLT_COURSE_NOT_STARTED', 1);
|
||||
define('BOLT_COURSE_STARTED', 2);
|
||||
define('BOLT_COURSE_FINISHED', 3);
|
||||
|
||||
// bits in bolt_user.flags
|
||||
define('BOLT_FLAGS_DEBUG', 1); // print debugging info in output pages
|
||||
define('BOLT_FLAGS_SHOW_ALL', 2); // show hidden courses
|
||||
|
||||
class BoltDb extends DbConn {
|
||||
static $instance;
|
||||
|
||||
static function get() {
|
||||
if (web_stopped()) {
|
||||
if ($generating_xml) {
|
||||
xml_error(-183);
|
||||
} else {
|
||||
page_head("Page not available");
|
||||
echo "This page requires database access.
|
||||
Our database server is temporarily shut down for maintenance.
|
||||
Please try again later.
|
||||
";
|
||||
page_tail();
|
||||
}
|
||||
exit();
|
||||
}
|
||||
if (!isset($instance)) {
|
||||
$config = get_config();
|
||||
$name = parse_config($config, '<bolt_db_name>');
|
||||
if (!$name) {
|
||||
$name = parse_config($config, '<db_name>');
|
||||
$user = parse_config($config, '<db_user>');
|
||||
$passwd = parse_config($config, '<db_passwd>');
|
||||
$host = parse_config($config, '<db_host>');
|
||||
} else {
|
||||
$user = parse_config($config, '<bolt_db_user>');
|
||||
$passwd = parse_config($config, '<bolt_db_passwd>');
|
||||
$host = parse_config($config, '<bolt_db_host>');
|
||||
}
|
||||
if ($host == null) {
|
||||
$host = "localhost";
|
||||
}
|
||||
$instance = new DbConn();
|
||||
$retval = $instance->init_conn($user, $passwd, $host, $name, true);
|
||||
if (!$retval) $instance = null;
|
||||
}
|
||||
if (!$instance) {
|
||||
error_page("no DB conn");
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
static function escape_string($string) {
|
||||
$db = self::get();
|
||||
return $db->base_escape_string($string);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltUser {
|
||||
static $cache;
|
||||
static function lookup_userid($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup('bolt_user', 'BoltUser', "user_id=$id");
|
||||
}
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->insert('bolt_user', $clause);
|
||||
}
|
||||
static function lookup(&$user) {
|
||||
if (!$user) return;
|
||||
if (isset($user->bolt)) return;
|
||||
if (isset(self::$cache[$user->id])) {
|
||||
$bolt = self::$cache[$user->id];
|
||||
} else {
|
||||
$bolt = self::lookup_userid($user->id);
|
||||
if (!$bolt) {
|
||||
self::insert("(user_id) values ($user->id)");
|
||||
$bolt = self::lookup_userid($user->id);
|
||||
}
|
||||
self::$cache[$user->id] = $bolt;
|
||||
}
|
||||
$user->bolt = $bolt;
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
$clause = "$clause where user_id=$this->user_id";
|
||||
return $db->update_aux('bolt_user', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltCourse {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
$ret = $db->insert('bolt_course', $clause);
|
||||
if (!$ret) return $ret;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_course', 'BoltCourse');
|
||||
}
|
||||
static function lookup_name($name) {
|
||||
$db = BoltDb::get();
|
||||
$name = BoincDb::escape_string($name);
|
||||
return $db->lookup('bolt_course', 'BoltCourse', "short_name='$name'");
|
||||
}
|
||||
static function enum() {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_course', 'BoltCourse');
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->update($this, 'bolt_course', $clause);
|
||||
}
|
||||
function doc_file() {
|
||||
$sn = $this->short_name;
|
||||
return "../inc/$sn.inc";
|
||||
}
|
||||
}
|
||||
|
||||
class BoltEnrollment {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->insert('bolt_enrollment', $clause);
|
||||
}
|
||||
static function lookup($user_id, $course_id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup('bolt_enrollment', 'BoltEnrollment', "user_id=$user_id and course_id=$course_id");
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->update_aux('bolt_enrollment', "$clause where user_id=$this->user_id and course_id=$this->course_id");
|
||||
}
|
||||
static function delete($user_id, $course_id) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_enrollment', "user_id=$user_id and course_id=$course_id");
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_enrollment', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltView {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
$ret = $db->insert('bolt_view', $clause);
|
||||
if (!$ret) return null;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_view', 'BoltView');
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->update($this, 'bolt_view', $clause);
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_view', 'BoltView', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_view', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltResult {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
$ret = $db->insert('bolt_result', $clause);
|
||||
if (!$ret) return null;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_result', 'BoltResult');
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_result', 'BoltResult', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_result', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltXsetResult {
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_xset_result', 'BoltXsetResult');
|
||||
}
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
$ret = $db->insert('bolt_xset_result', $clause);
|
||||
if (!$ret) return null;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_xset_result', 'BoltXsetResult', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_xset_result', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltRefreshRec {
|
||||
static function lookup_id($id) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup_id($id, 'bolt_refresh', 'BoltRefreshRec');
|
||||
}
|
||||
function lookup($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->lookup('bolt_refresh', 'BoltRefreshRec', $clause);
|
||||
}
|
||||
static function replace($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->replace('bolt_refresh', $clause);
|
||||
}
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
$ret = $db->insert('bolt_refresh', $clause);
|
||||
if (!$ret) return null;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_refresh', 'BoltRefreshRec', $clause);
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->update($this, 'bolt_refresh', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_refresh', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltSelectFinished {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->insert('bolt_select_finished', $clause);
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_select_finished', 'BoltSelectFinished', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_select_finished', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
class BoltQuestion {
|
||||
static function insert($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->insert('bolt_question', $clause);
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BoltDb::get();
|
||||
return $db->enum('bolt_question', 'BoltQuestion', $clause);
|
||||
}
|
||||
static function delete_aux($clause) {
|
||||
$db = BoltDb::get();
|
||||
$db->delete_aux('bolt_question', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move this somewhere else, and think about whether it's correct
|
||||
//
|
||||
function bolt_course_status($course_id, $user_id) {
|
||||
$e = BoltEnrollment::lookup($user_id, $course_id);
|
||||
if (!$e) return BOLT_COURSE_NOT_STARTED;
|
||||
$view = BoltView::lookup_id($e->last_view_id);
|
||||
if ($view->fraction_done == 1) return BOLT_COURSE_FINISHED;
|
||||
return BOLT_COURSE_STARTED;
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,347 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// Bolt exercise API
|
||||
|
||||
// The following is a global var accessed by exercise functions.
|
||||
//
|
||||
$bolt_ex = null;
|
||||
$bolt_ex->mode = 0; // input: SHOW/SCORE/ANSWER
|
||||
$bolt_ex->index = 0; // input: sequence of this exercise in file
|
||||
$bolt_ex->score = 0; // input/output: cumulative score (if mode = SCORE)
|
||||
$bolt_ex->weight = 0; // input/output: cumulative weight
|
||||
$bolt_ex->query_string = ""; // user's response (if SCORE or ANSWER)
|
||||
|
||||
function weight($w) {
|
||||
return array('weight', $w);
|
||||
}
|
||||
|
||||
function exclusive_choice() {
|
||||
global $bolt_ex;
|
||||
$weight = 1;
|
||||
|
||||
$choices = array();
|
||||
$args = func_get_args();
|
||||
foreach ($args as $arg) {
|
||||
if (is_string($arg)) {
|
||||
$choices[] = $arg;
|
||||
} else if (is_array($arg)) {
|
||||
switch ($arg[0]) {
|
||||
case 'weight': $weight = $arg[1]; break;
|
||||
default: echo "bad arg to exclusive_choice()";
|
||||
}
|
||||
} else {
|
||||
echo "bad arg to exclusive_choice()";
|
||||
}
|
||||
}
|
||||
|
||||
parse_str($bolt_ex->query_string);
|
||||
|
||||
switch ($bolt_ex->mode) {
|
||||
case BOLT_MODE_SHOW:
|
||||
shuffle($choices);
|
||||
$i = 0;
|
||||
start_table();
|
||||
foreach ($choices as $choice) {
|
||||
row2($choice, "<input name=q_$bolt_ex->index type=radio value=$i>");
|
||||
$i++;
|
||||
}
|
||||
end_table();
|
||||
break;
|
||||
case BOLT_MODE_SCORE:
|
||||
$right_ans = $choices[0];
|
||||
shuffle($choices);
|
||||
$key = "q_$bolt_ex->index";
|
||||
if (isset($$key)) {
|
||||
$response = $$key;
|
||||
if ($choices[$response] == $right_ans) {
|
||||
$bolt_ex->score += 1;
|
||||
}
|
||||
}
|
||||
$bolt_ex->weight += $weight;
|
||||
break;
|
||||
case BOLT_MODE_ANSWER:
|
||||
$right_ans = $choices[0];
|
||||
shuffle($choices);
|
||||
$key = "q_$bolt_ex->index";
|
||||
if (isset($$key)) {
|
||||
$response = $$key;
|
||||
} else {
|
||||
$response = -1;
|
||||
}
|
||||
$i = 0;
|
||||
start_table();
|
||||
foreach ($choices as $choice) {
|
||||
$x = "<td><br></td>";
|
||||
if ($response == $i) {
|
||||
if ($choice == $right_ans) {
|
||||
$x = "<td bgcolor=#88ff88>Right</a>";
|
||||
} else {
|
||||
$x = "<td bgcolor=#ff8888>You chose this answer</a>";
|
||||
}
|
||||
} else {
|
||||
if ($choice == $right_ans) {
|
||||
$x = "<td>Right answer</td>";
|
||||
}
|
||||
}
|
||||
echo "<tr><td width=50% class=fieldname>$choice $x </tr>";
|
||||
$i++;
|
||||
}
|
||||
end_table();
|
||||
break;
|
||||
}
|
||||
$bolt_ex->index++;
|
||||
}
|
||||
|
||||
function inclusive_choice() {
|
||||
global $bolt_ex;
|
||||
$weight = 1;
|
||||
|
||||
$choices = array();
|
||||
$args = func_get_args();
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
$choices[] = $arg;
|
||||
} else if (is_object($arg)) {
|
||||
if (get_class($arg) == 'BoltWeight') {
|
||||
$weight = $arg->weight;
|
||||
} else {
|
||||
echo "bad arg to inclusive_choice()";
|
||||
}
|
||||
} else {
|
||||
echo "bad arg to inclusive_choice()";
|
||||
}
|
||||
}
|
||||
|
||||
parse_str($bolt_ex->query_string);
|
||||
|
||||
switch ($bolt_ex->mode) {
|
||||
case BOLT_MODE_SHOW:
|
||||
shuffle($choices);
|
||||
$i = 0;
|
||||
start_table();
|
||||
foreach ($choices as $choice) {
|
||||
$c = $choice[0];
|
||||
row2("<input name=q_".$bolt_ex->index."_$i type=checkbox>", $c);
|
||||
$i++;
|
||||
}
|
||||
end_table();
|
||||
break;
|
||||
case BOLT_MODE_SCORE:
|
||||
$i = 0;
|
||||
$n = count($choices);
|
||||
$score = 0;
|
||||
shuffle($choices);
|
||||
foreach ($choices as $choice) {
|
||||
$key = "q_".$bolt_ex->index."_$i";
|
||||
$response = isset($$key);
|
||||
$r = $choice[1];
|
||||
$correct = ($r && $response) || (!$r && !$response);
|
||||
if ($correct) $score += 1./$n;
|
||||
$i++;
|
||||
}
|
||||
$bolt_ex->score += $score;
|
||||
$bolt_ex->weight += $weight;
|
||||
break;
|
||||
case BOLT_MODE_ANSWER:
|
||||
$i = 0;
|
||||
$n = count($choices);
|
||||
shuffle($choices);
|
||||
start_table();
|
||||
table_header("Choice", "Correct?", "Your answer");
|
||||
foreach ($choices as $choice) {
|
||||
$c = $choice[0];
|
||||
$key = "q_".$bolt_ex->index."_$i";
|
||||
$response = isset($$key);
|
||||
$r = $choice[1];
|
||||
$correct = ($r && $response) || (!$r && !$response);
|
||||
$color = $correct?"#88ff88":"#ff8888";
|
||||
table_row($c, $r?"yes":"no",
|
||||
array($response?"yes":"no", "bgcolor=$color")
|
||||
);
|
||||
$i++;
|
||||
}
|
||||
end_table();
|
||||
break;
|
||||
}
|
||||
$bolt_ex->index++;
|
||||
}
|
||||
|
||||
function image_rect($img, $rect) {
|
||||
global $bolt_ex;
|
||||
|
||||
parse_str($bolt_ex->query_string);
|
||||
|
||||
switch ($bolt_ex->mode) {
|
||||
case BOLT_MODE_SHOW:
|
||||
echo "<input type=image name=pic_$bolt_ex->index src=$img>
|
||||
";
|
||||
break;
|
||||
case BOLT_MODE_SCORE:
|
||||
$x = get_int("pic_".$bolt_ex->index."_x");
|
||||
$y = get_int("pic_".$bolt_ex->index."_y");
|
||||
$right = true;
|
||||
if ($x < $rect[0]) $right = false;
|
||||
if ($x > $rect[1]) $right = false;
|
||||
if ($y < $rect[2]) $right = false;
|
||||
if ($y > $rect[3]) $right = false;
|
||||
if ($right) {
|
||||
$bolt_ex->score += 1;
|
||||
}
|
||||
$bolt_ex->weight += $weight;
|
||||
break;
|
||||
case BOLT_MODE_ANSWER:
|
||||
$x = get_int("pic_".$bolt_ex->index."_x");
|
||||
$y = get_int("pic_".$bolt_ex->index."_y");
|
||||
$right = true;
|
||||
if ($x < $rect[0]) $right = false;
|
||||
if ($x > $rect[1]) $right = false;
|
||||
if ($y < $rect[2]) $right = false;
|
||||
if ($y > $rect[3]) $right = false;
|
||||
$cx = $rect[0];
|
||||
$cy = $rect[2];
|
||||
$sizex = $rect[1]-$rect[0];
|
||||
$sizey = $rect[3]-$rect[2];
|
||||
$ax = $x-4;
|
||||
$ay = $y-4;
|
||||
$color = $right?"green":"red";
|
||||
if ($right) {
|
||||
echo "The point you selected (shown in green) is correct.";
|
||||
} else {
|
||||
echo "The point you selected (shown in red) is not correct.";
|
||||
}
|
||||
echo "
|
||||
<div style=\"position:relative; \">
|
||||
<span style=\"width:".$sizex."px;height:".$sizey."px;position:absolute;top:".$cy.";left:".$cx.";color:white;border-style:solid;border-width:3px\"><br></span>
|
||||
<span style=\"width:8;height:8;position:absolute;top:".$ay.";left:".$ax.";color:$color;border-style:solid;border-width:4px\"><br></span>
|
||||
<img src=$img align=left>
|
||||
</div>
|
||||
<br clear=all>
|
||||
";
|
||||
break;
|
||||
}
|
||||
$bolt_ex->index++;
|
||||
}
|
||||
|
||||
class BoltFitbField {
|
||||
public $textarea, $nrows, $ncols;
|
||||
function __construct($textarea, $nrows, $ncols) {
|
||||
$this->textarea = $textarea;
|
||||
$this->nrows = $nrows;
|
||||
$this->ncols = $ncols;
|
||||
}
|
||||
}
|
||||
|
||||
function field($n) {
|
||||
return new BoltFitbField(false, 1, $n);
|
||||
}
|
||||
|
||||
function box($nr, $nc) {
|
||||
return new BoltFitbField(true, $nr, $nc);
|
||||
}
|
||||
|
||||
class BoltFitbAnswer {
|
||||
public $type; // 0=constant, 1=regexp, 2=func
|
||||
public $ans;
|
||||
function __construct($type, $ans) {
|
||||
$this->type = $type;
|
||||
$this->ans = $ans;
|
||||
}
|
||||
}
|
||||
|
||||
function answer($ans) {
|
||||
return new BoltFitbAnswer(0, $ans);
|
||||
}
|
||||
|
||||
function answer_regexp($ans) {
|
||||
return new BoltFitbAnswer(1, $ans);
|
||||
}
|
||||
|
||||
function answer_func($ans) {
|
||||
return new BoltFitbAnswer(2, $ans);
|
||||
}
|
||||
|
||||
function fitb() {
|
||||
global $bolt_ex;
|
||||
$args = func_get_args();
|
||||
$field = new BoltFitbField(false, 1, 20);
|
||||
$answer = null;
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
$choices[] = $arg;
|
||||
} else if (is_object($arg)) {
|
||||
if (get_class($arg) == 'BoltFitbField') {
|
||||
$field = $arg;
|
||||
} else if (get_class($arg) == 'BoltFitbAns') {
|
||||
$answer = $arg;
|
||||
} else {
|
||||
echo "bad arg to fitb()";
|
||||
}
|
||||
} else {
|
||||
echo "bad arg to fitb()";
|
||||
}
|
||||
}
|
||||
|
||||
switch ($bolt_ex->mode) {
|
||||
case BOLT_MODE_SHOW:
|
||||
if ($field->textarea) {
|
||||
echo "<textarea name=q_".$bolt_ex->index." nrows=$field->nrows ncols=$field->ncols>
|
||||
</textarea>
|
||||
";
|
||||
} else {
|
||||
echo "<input name=q_".$bolt_ex->index." length=$field->ncols>";
|
||||
}
|
||||
break;
|
||||
case BOLT_MODE_SCORE:
|
||||
if (!$answer) break;
|
||||
$bolt_ex->score = 0;
|
||||
$key = "q_".$bolt_ex->index;
|
||||
if (isset($$key)) {
|
||||
$response = $$key;
|
||||
} else {
|
||||
$response = "";
|
||||
}
|
||||
switch ($answer->type) {
|
||||
case 0:
|
||||
if ($response == $answer->ans) {
|
||||
$bolt_ex->score = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (preg_match('/'.$answer->ans.'/', $response)) {
|
||||
$bolt_ex->score = 1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
$bolt_ex->score = call_user_func($answer->ans, $response);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BOLT_MODE_ANSWER:
|
||||
$key = "q_".$bolt_ex->index;
|
||||
if (isset($$key)) {
|
||||
$response = $$key;
|
||||
} else {
|
||||
$response = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
$bolt_ex->index++;
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
class BoltRandom extends BoltSet {
|
||||
public $units;
|
||||
function __construct($name, $units, $number, $attrs) {
|
||||
parent::__construct($name, $units, $number, $attrs);
|
||||
}
|
||||
|
||||
function order(&$iter) {
|
||||
$state_rec = $iter->state[$this->name];
|
||||
if ($state_rec) {
|
||||
if (array_key_exists('seed', $state_rec)) {
|
||||
$seed = $state_rec['seed'];
|
||||
} else {
|
||||
$seed = ((double)microtime()*1000000);
|
||||
$state_rec['seed'] = $seed;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
}
|
||||
} else {
|
||||
$state_rec = $this->init();
|
||||
$seed = ((double)microtime()*1000000);
|
||||
$state_rec['seed'] = $seed;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
}
|
||||
srand($seed);
|
||||
shuffle($this->units);
|
||||
$this->ordered = true;
|
||||
}
|
||||
}
|
||||
|
||||
function random() {
|
||||
$args = func_get_args();
|
||||
$units = array();
|
||||
$name = "";
|
||||
$number = 0;
|
||||
$attrs = null;
|
||||
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;
|
||||
case 'attrs': $attrs = $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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($number == 0) $number = count($units);
|
||||
return new BoltRandom($name, $units, $number, $attrs);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// An iterator represents a user's position in a course.
|
||||
// Its state is stored in the database,
|
||||
// and the course may change underneath it.
|
||||
//
|
||||
// A state in a course is described by an associative array
|
||||
// mapping logical names to state structures.
|
||||
// Typically this includes the logical name of the current child
|
||||
// and info such as a sequence index.
|
||||
// This is kind of like a "call stack",
|
||||
// except that it can contain units not currently active.
|
||||
|
||||
//
|
||||
class BoltIter {
|
||||
public $top; // topmost unit
|
||||
public $state;
|
||||
public $xset; // exercise set, if any
|
||||
|
||||
// the following are temps
|
||||
public $item; // current item
|
||||
public $frac_done; // fraction done
|
||||
|
||||
function __construct($top) {
|
||||
$this->top = $top;
|
||||
$this->state = array();
|
||||
}
|
||||
|
||||
function decode_state($encoded_state) {
|
||||
$this->state = unserialize($encoded_state);
|
||||
}
|
||||
|
||||
function encode_state() {
|
||||
return serialize($this->state);
|
||||
}
|
||||
|
||||
// get current item and fraction done
|
||||
//
|
||||
function at() {
|
||||
$this->xset = null;
|
||||
$this->top->walk($this, false, $this->frac_done);
|
||||
}
|
||||
|
||||
// move to the next item, and return it in $this->item
|
||||
// (null if course finished)
|
||||
//
|
||||
function next() {
|
||||
$this->top->walk($this, true, $this->frac_done);
|
||||
}
|
||||
}
|
||||
|
||||
function enum_course($course) {
|
||||
$iter = new BoltIter($course);
|
||||
while (1) {
|
||||
$x = $iter->at();
|
||||
if (!$x) break;
|
||||
echo "at: $x->url\n";
|
||||
$x = $iter->next();
|
||||
if (!$x) break;
|
||||
echo "next: $x->filename\n";
|
||||
}
|
||||
echo "course over\n";
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,88 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
function select_cmp($a, $b) {
|
||||
if ($a->value == $b->value) return 0;
|
||||
return ($a->value < $b->value)?1:-1;
|
||||
}
|
||||
|
||||
class BoltSelect extends BoltSet {
|
||||
public $valuator;
|
||||
|
||||
function __construct($name, $units, $valuator, $attrs) {
|
||||
$this->valuator = $valuator;
|
||||
parent::__construct($name, $units, 1, $attrs);
|
||||
}
|
||||
|
||||
function order() {
|
||||
global $student;
|
||||
foreach ($this->units as $u) {
|
||||
$func = $this->valuator;
|
||||
$u->value = $func($student, $u);
|
||||
}
|
||||
usort($this->units, 'select_cmp');
|
||||
$this->ordered = true;
|
||||
}
|
||||
|
||||
function finished($iter) {
|
||||
global $user;
|
||||
global $course;
|
||||
global $view;
|
||||
|
||||
$state_rec = $iter->state[$this->name];
|
||||
$child_name = $state_rec['child_name'];
|
||||
$now = time();
|
||||
BoltSelectFinished::insert("(user_id, course_id, end_time, name, selected_unit, view_id) values ($user->id, $course->id, $now, '$this->name', '$child_name', $view->id)");
|
||||
parent::finished($iter);
|
||||
}
|
||||
}
|
||||
|
||||
function valuator($n) {
|
||||
return array('valuator', $n);
|
||||
}
|
||||
|
||||
function select() {
|
||||
$args = func_get_args();
|
||||
$units = array();
|
||||
$name = "";
|
||||
$attrs = null;
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
switch ($arg[0]) {
|
||||
case 'name': $name = $arg[1]; break;
|
||||
case 'title': $title = $arg[1]; break;
|
||||
case 'valuator': $valuator = $arg[1]; break;
|
||||
case 'attrs': $attrs = $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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$valuator) {
|
||||
error_page("missing valuator");
|
||||
}
|
||||
return new BoltSelect($name, $units, $valuator, $attrs);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
class BoltSequence extends BoltSet {
|
||||
function __construct($name, $units, $attrs) {
|
||||
parent::__construct($name, $units, count($units), $attrs);
|
||||
}
|
||||
|
||||
function order() {
|
||||
$this->ordered = true;
|
||||
}
|
||||
|
||||
function restart(&$iter) {
|
||||
$state_rec = $iter->state[$this->name];
|
||||
if (!$state_rec) $state_rec = $this->init();
|
||||
$state_rec['nshown'] = 0;
|
||||
$state_rec['index'] = 0;
|
||||
$state_rec['child_name'] = null;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
}
|
||||
}
|
||||
|
||||
function sequence() {
|
||||
$args = func_get_args();
|
||||
$units = array();
|
||||
$name = "";
|
||||
$attrs = null;
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
switch ($arg[0]) {
|
||||
case 'name': $name = $arg[1]; break;
|
||||
case 'title': $title = $arg[1]; break;
|
||||
case 'attrs': $attrs = $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, $attrs);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,229 +0,0 @@
|
|||
<?php
|
||||
|
||||
// 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/>.
|
||||
|
||||
|
||||
|
||||
////// 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);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,110 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// Utililty functions for student pages
|
||||
|
||||
function info_incomplete($user) {
|
||||
if (!$user->bolt->birth_year) return true;
|
||||
if (!$user->bolt->sex) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function birth_year_select($user) {
|
||||
$this_year = date("Y");
|
||||
$x = "<select name=birth_year>\n";
|
||||
for ($i=$this_year-100; $i<$this_year; $i++) {
|
||||
$s = ($i == $user->bolt->birth_year)?"selected":"";
|
||||
$x .= "<option value=$i $s>$i</option>\n";
|
||||
}
|
||||
$s = (!$user->bolt->birth_year)?"selected":"";
|
||||
$x .= "<option value=$0 $s>Unspecified</option>\n";
|
||||
$x .= "</select>\n";
|
||||
return $x;
|
||||
}
|
||||
|
||||
function sex_select($user) {
|
||||
$x = "<select name=sex>\n";
|
||||
$s = ($user->bolt->sex == 0)?"selected":"";
|
||||
$x .= "<option value=0 $s>Unspecified</option>\n";
|
||||
$s = ($user->bolt->sex == 1)?"selected":"";
|
||||
$x .= "<option value=1 $s>Male</option>\n";
|
||||
$s = ($user->bolt->sex == 2)?"selected":"";
|
||||
$x .= "<option value=2 $s>Female</option>\n";
|
||||
$x .= "</select>\n";
|
||||
return $x;
|
||||
}
|
||||
|
||||
function request_info($user, $course) {
|
||||
page_head("About you");
|
||||
echo "
|
||||
You may optionally tell us some facts about yourself.
|
||||
This information will help us improve this course,
|
||||
and will be kept private.
|
||||
<p>
|
||||
<form action=bolt_sched.php>
|
||||
<input type=hidden name=action value=update_info>
|
||||
<input type=hidden name=course_id value=$course->id>
|
||||
";
|
||||
start_table();
|
||||
row2("Birth year", birth_year_select($user));
|
||||
row2("Sex", sex_select($user));
|
||||
row2("", "<input class=\"btn btn-default\" type=submit value=OK>");
|
||||
end_table();
|
||||
echo "</form>\n";
|
||||
page_tail();
|
||||
}
|
||||
|
||||
//////////// show refresh schedule //////////////
|
||||
|
||||
function show_refresh($r) {
|
||||
echo "<tr>
|
||||
<td>$r->name</td>
|
||||
<td>".time_str($r->due_time)."</td>
|
||||
<td>
|
||||
";
|
||||
if ($r->last_view_id) {
|
||||
echo "
|
||||
<a href=bolt_sched.php?course_id=$r->course_id&refresh_id=$r->id&action=start>Restart</a>
|
||||
| <a href=bolt_sched.php?course_id=$r->course_id&refresh_id=$r->id&action=resume>Resume</a>
|
||||
";
|
||||
} else {
|
||||
echo "
|
||||
<a href=bolt_sched.php?course_id=$r->course_id&refresh_id=$r->id&action=start>Start</a>
|
||||
";
|
||||
}
|
||||
echo "
|
||||
</td>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
|
||||
function show_refreshes() {
|
||||
global $user;
|
||||
global $course;
|
||||
|
||||
$refreshes = BoltRefreshRec::enum("user_id=$user->id and course_id=$course->id");
|
||||
if (!count($refreshes)) return;
|
||||
start_table();
|
||||
echo "<tr><th colspan=3>Refresh schedule</th></tr>\n";
|
||||
foreach ($refreshes as $r) {
|
||||
show_refresh($r);
|
||||
}
|
||||
end_table();
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,230 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
|
||||
// Utility functions for admin pages
|
||||
|
||||
require_once("../inc/util_ops.inc");
|
||||
|
||||
// get names of units of a given type
|
||||
|
||||
function units_of_type($unit, $type) {
|
||||
$names = array();
|
||||
if (get_class($unit) == $type) {
|
||||
$names[] = $unit->name;
|
||||
}
|
||||
if (is_subclass_of($unit, "BoltSet")) {
|
||||
foreach ($unit->units as $u) {
|
||||
$n = units_of_type($u, $type);
|
||||
$names = array_merge($names, $n);
|
||||
}
|
||||
}
|
||||
return array_unique($names);
|
||||
}
|
||||
|
||||
// show a menu of select units
|
||||
//
|
||||
function choose_select($top_unit) {
|
||||
echo "<select name=select_name>
|
||||
<option selected> ---
|
||||
";
|
||||
$names = units_of_type($top_unit, "BoltSelect");
|
||||
foreach ($names as $n) {
|
||||
echo "<option> $n";
|
||||
}
|
||||
echo "</select>";
|
||||
}
|
||||
|
||||
// show a menu of exercise sets
|
||||
//
|
||||
function choose_xset($top_unit) {
|
||||
echo "<select name=xset_name>
|
||||
<option selected> ---
|
||||
";
|
||||
$names = units_of_type($top_unit, "BoltExerciseSet");
|
||||
foreach ($names as $n) {
|
||||
echo "<option> $n";
|
||||
}
|
||||
echo "</select>";
|
||||
}
|
||||
|
||||
// Find a unit of given name
|
||||
//
|
||||
function lookup_unit($top_unit, $name) {
|
||||
if ($top_unit->name == $name) return $top_unit;
|
||||
if (is_subclass_of($top_unit, "BoltSet")) {
|
||||
foreach ($top_unit->units as $child) {
|
||||
$u = lookup_unit($child, $name);
|
||||
if ($u) return $u;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
////// Statistics
|
||||
|
||||
// compute the mean and stdev of an array
|
||||
//
|
||||
function mean_stdev($array, &$mean, &$stdev) {
|
||||
$n = 0;
|
||||
$m = 0;
|
||||
$m2 = 0;
|
||||
|
||||
foreach ($array as $x) {
|
||||
$n++;
|
||||
$delta = $x - $m;
|
||||
$m += $delta/$n;
|
||||
$m2 += $delta*($x-$m);
|
||||
}
|
||||
$mean = $m;
|
||||
$stdev = sqrt($m2/($n-1));
|
||||
}
|
||||
|
||||
// approximate the 90% confidence interval for the mean of an array
|
||||
//
|
||||
function conf_int_90($array, &$lo, &$hi) {
|
||||
$n = count($array);
|
||||
mean_stdev($array, $mean, $stdev);
|
||||
|
||||
// I'm too lazy to compute the t distribution
|
||||
$t_90 = 1.7;
|
||||
$d = $t_90 * $stdev / sqrt($n);
|
||||
$lo = $mean - $d;
|
||||
$hi = $mean + $d;
|
||||
}
|
||||
|
||||
function test_stats() {
|
||||
$a = array(1,1,1,1,0,1,1,1,3, 1, 1, 1, 1);
|
||||
mean_stdev($a, $mean, $stdev);
|
||||
echo "mean: $mean stdev: $stdev\n";
|
||||
conf_int_90($a, $lo, $hi);
|
||||
echo "lo $lo hi $hi\n";
|
||||
}
|
||||
|
||||
//////////// graph drawing
|
||||
|
||||
function compare_bar($title, $n, $width, $lo, $hi) {
|
||||
$x1 = $width*$lo;
|
||||
$x2 = $width*($hi-$lo);
|
||||
$a1 = number_format($lo*100);
|
||||
$a2 = number_format($hi*100);
|
||||
return "
|
||||
<tr>
|
||||
<td>$title<br><p class=\"text-muted\">($n students)</p></td>
|
||||
<td>
|
||||
<table class=bolt_bar width=$width><tr class=bolt_bar>
|
||||
<td class=bolt_bar1 width=$x1 bgcolor=lightgray align=right>$a1</td>
|
||||
<td class=bolt_bar2 width=$x2 bgcolor=black></td>
|
||||
<td class=bolt_bar1 bgcolor=lightgray>$a2</td>
|
||||
</tr></table>
|
||||
</td>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
|
||||
function compare_bar_insuff($title, $width) {
|
||||
return "
|
||||
<tr>
|
||||
<td>$title</td>
|
||||
<td>
|
||||
<table class=bolt_bar width=$width><tr class=bolt_bar>
|
||||
<td class=bolt_bar1 bgcolor=lightgray>Insufficient data</td>
|
||||
</tr></table>
|
||||
</td>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
|
||||
function outcome_graph($x, $width) {
|
||||
$n = $x[0]+$x[1]+$x[2];
|
||||
if (!$n) return empty_cell();
|
||||
$x0 = $width*$x[1]/$n;
|
||||
$x1 = $width*$x[0]/$n;
|
||||
$x2 = $width*$x[2]/$n;
|
||||
if ($x[1]/$n>0.05) {
|
||||
$t0 = number_format(100*$x[1]/$n)."%";
|
||||
} else {
|
||||
$t0 = "";
|
||||
}
|
||||
$s = "<td>
|
||||
<table class=bolt_bar><tr>
|
||||
";
|
||||
if ($x0) {
|
||||
$s .= "<td class=bolt_bar height=10 width=$x0 bgcolor=#88ff88><p class=\"text-muted\">$t0</p></td>
|
||||
";
|
||||
}
|
||||
if ($x1) {
|
||||
$s .= "<td class=bolt_bar height=10 width=$x1 bgcolor=#ff8888><br></td>
|
||||
";
|
||||
}
|
||||
if ($x2) {
|
||||
$s .= "<td class=bolt_bar height=10 width=$x2 bgcolor=#ffff88><br></td>
|
||||
";
|
||||
}
|
||||
$s .= "</tr></table>
|
||||
</td>
|
||||
";
|
||||
return $s;
|
||||
}
|
||||
|
||||
function time_graph($t, $w) {
|
||||
if ($t == 0) return "<td>---</td>";
|
||||
$x = (log10($t)+2)*$w/4;
|
||||
$t = number_format($t, 1);
|
||||
return "<td>
|
||||
<table class=bolt_bar><tr>
|
||||
<td class=bolt_bar height=10 width=$x bgcolor=#ffffcc><p class=\"text-muted\">$t sec</p></td>
|
||||
</tr></table>
|
||||
</td>";
|
||||
}
|
||||
|
||||
function score_graph($t, $w) {
|
||||
if ($t == 0) return "<td>---</td>";
|
||||
$x = $t*$w;
|
||||
$y = (1-$t)*$w;
|
||||
$t = number_format($t*100);
|
||||
$s = "<td>
|
||||
<table class=bolt_bar><tr>
|
||||
";
|
||||
if ($x) {
|
||||
$s .= "<td class=bolt_bar height=10 width=$x bgcolor=#ffffcc><p class=\"text-muted\">$t%</p></td>
|
||||
";
|
||||
}
|
||||
if ($y) {
|
||||
$s .= "<td class=bolt_bar width=$y bgcolor=gray></td>
|
||||
";
|
||||
}
|
||||
$s .= "</tr></table></td>
|
||||
";
|
||||
return $s;
|
||||
}
|
||||
|
||||
function empty_cell() {
|
||||
return "<td><br></td>";
|
||||
}
|
||||
|
||||
function empty_row() {
|
||||
return "<tr><td><br></td></tr>";
|
||||
}
|
||||
|
||||
function bolt_style() {
|
||||
echo "
|
||||
<link rel=\"stylesheet\" type=\"text/css\" href=\"".URL_BASE."bolt.css\">
|
||||
";
|
||||
}
|
||||
?>
|
|
@ -1,209 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
class BoltExerciseSet extends BoltRandom {
|
||||
public $repeats;
|
||||
public $refresh;
|
||||
public $weight;
|
||||
public $callback;
|
||||
|
||||
function __construct(
|
||||
$name, $units, $number, $repeats, $refresh, $attrs, $callback, $weight
|
||||
) {
|
||||
parent::__construct($name, $units, $number, $attrs);
|
||||
|
||||
$this->repeats = $repeats;
|
||||
$this->refresh = $refresh;
|
||||
$this->callback = $callback;
|
||||
$this->weight = $weight;
|
||||
}
|
||||
|
||||
// called when an exercise in this set has just been graded.
|
||||
// - record the score in our state structure
|
||||
// - return true if this was last exercise in the set
|
||||
// - if so, also return a structure saying what navigation info to show:
|
||||
// - review
|
||||
// - repeat now
|
||||
// - next
|
||||
//
|
||||
function xset_record_score(
|
||||
&$iter, $score, $view_id, &$avg_score, &$repeat
|
||||
) {
|
||||
global $course;
|
||||
global $user;
|
||||
|
||||
$nav_info = null;
|
||||
$state_rec = $iter->state[$this->name];
|
||||
$nshown = $state_rec['nshown'];
|
||||
$state_rec['scores'][$nshown] = $score;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
$is_last = ($nshown+1 == $this->ntoshow);
|
||||
if (!$is_last) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this exercise set is now "completed".
|
||||
// - create exercise_set_result record
|
||||
// - optionally create or update bolt_refresh record
|
||||
//
|
||||
$total_score = 0;
|
||||
for ($i=0; $i<$nshown+1; $i++) {
|
||||
$total_score += $state_rec['scores'][$i];
|
||||
}
|
||||
$avg_score = $total_score/($nshown+1);
|
||||
|
||||
$repeat = null;
|
||||
$least = 2;
|
||||
foreach ($this->repeats as $r) {
|
||||
if ($avg_score < $r->score && $r->score<$least) {
|
||||
$repeat = $r;
|
||||
$least = $r->score;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function walk(&$iter, $incr, &$frac_done) {
|
||||
$iter->xset = $this;
|
||||
// see if we're doing a review
|
||||
//
|
||||
if (array_key_exists($this->name, $iter->state)) {
|
||||
$state_rec = $iter->state[$this->name];
|
||||
$child_name = $state_rec['child_name'];
|
||||
foreach ($this->repeats as $r) {
|
||||
if ($r->unit && ($r->unit->name == $child_name)) {
|
||||
// we're doing a review
|
||||
//
|
||||
$child = $r->unit;
|
||||
if ($incr) {
|
||||
if ($child->is_item) {
|
||||
$my_inc = true;
|
||||
} else {
|
||||
$my_inc = $child->walk($iter, $incr, $frac_done);
|
||||
}
|
||||
if ($my_inc) {
|
||||
// we're done with review. do exercises again
|
||||
//
|
||||
$state_rec['child_name'] = null;
|
||||
$state_rec['nshown'] = 0;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
}
|
||||
} else {
|
||||
if ($child->is_item) {
|
||||
$iter->item = $child;
|
||||
} else {
|
||||
$child->walk($iter, false, $f);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::walk($iter, $incr, $frac_done);
|
||||
}
|
||||
|
||||
function start_review(&$iter, $unit_name) {
|
||||
foreach ($this->repeats as $r) {
|
||||
if ($r->unit->name == $unit_name) {
|
||||
$state_rec = $iter->state[$this->name];
|
||||
$state_rec['child_name'] = $unit_name;
|
||||
$iter->state[$this->name] = $state_rec;
|
||||
if (!$r->unit->is_item) {
|
||||
$r->unit->restart($iter);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
$callback = null;
|
||||
$name = "";
|
||||
$number = 0;
|
||||
$attrs = null;
|
||||
$weight = 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;
|
||||
case 'attrs': $attrs = $arg[1]; break;
|
||||
case 'callback': $callback = $arg[1]; break;
|
||||
case 'weight': $weight = $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 "Can't include object of type ".get_class($arg)." within an exercise set.";
|
||||
}
|
||||
} else {
|
||||
echo "Unexpected arg to exercise_set(): "; print_r($arg);
|
||||
}
|
||||
}
|
||||
|
||||
if ($number == 0) $number = count($units);
|
||||
return new BoltExerciseSet(
|
||||
$name, $units, $number, $repeats, $refresh, $attrs, $callback, $weight
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
function bossa_job_create(
|
||||
$app_id, $batch_id, $info, $calibration
|
||||
) {
|
||||
$job = new BossaJob;
|
||||
$info = serialize($info);
|
||||
if ($calibration) {
|
||||
$priority = drand();
|
||||
$c = 1;
|
||||
} else {
|
||||
$priority = 1;
|
||||
$c = 0;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$int_max = 2147483647;
|
||||
$clause = "(create_time, app_id, batch_id, state, info, calibration, priority_0) values ($now, $app_id, $batch_id, 1, '$info', $c, $priority)";
|
||||
return $job->insert($clause);
|
||||
}
|
||||
|
||||
function bossa_batch_create($appid, $name, $calibration) {
|
||||
$now = time();
|
||||
$c = $calibration?"1":"0";
|
||||
return BossaBatch::insert("(create_time, app_id, name, calibration) values ($now, $appid, '$name', $c)");
|
||||
}
|
||||
|
||||
function bossa_app_lookup($name) {
|
||||
$name = BoincDb::escape_string($name);
|
||||
$app = BossaApp::lookup("short_name='$name'");
|
||||
if (!$app) return 0;
|
||||
return $app->id;
|
||||
}
|
||||
|
||||
function bossa_lookup_job($instid, &$job, &$inst, &$user) {
|
||||
$inst = BossaJobInst::lookup_id($instid);
|
||||
if (!$inst) return false;
|
||||
$job = BossaJob::lookup_id($inst->job_id);
|
||||
$user = BoincUser::lookup_id($inst->user_id);
|
||||
BossaUser::lookup($user);
|
||||
return true;
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,291 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/db_conn.inc");
|
||||
require_once("../inc/util_basic.inc");
|
||||
|
||||
class BossaDb extends DbConn {
|
||||
public static $instance;
|
||||
|
||||
static function get() {
|
||||
if (!isset($instance)) {
|
||||
$config = get_config();
|
||||
$name = parse_config($config, '<bossa_db_name>');
|
||||
if (!$name) {
|
||||
$name = parse_config($config, '<db_name>');
|
||||
$user = parse_config($config, '<db_user>');
|
||||
$passwd = parse_config($config, '<db_passwd>');
|
||||
$host = parse_config($config, '<db_host>');
|
||||
} else {
|
||||
$user = parse_config($config, '<bossa_db_user>');
|
||||
$passwd = parse_config($config, '<bossa_db_passwd>');
|
||||
$host = parse_config($config, '<bossa_db_host>');
|
||||
}
|
||||
if ($host == null) {
|
||||
$host = "localhost";
|
||||
}
|
||||
$instance = new DbConn();
|
||||
$retval = $instance->init_conn($user, $passwd, $host, $name, true);
|
||||
if (!$retval) return null;
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
static function escape_string($string) {
|
||||
$db = self::get();
|
||||
return $db->base_escape_string($string);
|
||||
}
|
||||
static function start_transaction() {
|
||||
//echo "start transaction\n";
|
||||
return;
|
||||
$db = BossaDb::get();
|
||||
$db->do_query("start transaction");
|
||||
}
|
||||
static function commit() {
|
||||
//echo "commit\n";
|
||||
return;
|
||||
$db = BossaDb::get();
|
||||
$db->do_query("commit");
|
||||
}
|
||||
}
|
||||
|
||||
// use this as a local to ensure that transaction is committed
|
||||
// regardless of exceptions
|
||||
//
|
||||
class BossaTransaction {
|
||||
function __construct() {
|
||||
BossaDb::start_transaction();
|
||||
}
|
||||
function __destruct() {
|
||||
BossaDb::commit();
|
||||
}
|
||||
}
|
||||
|
||||
class BossaUser {
|
||||
static $cache;
|
||||
static function lookup_userid($id) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup('bossa_user', 'BossaUser', "user_id=$id");
|
||||
}
|
||||
static function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->insert('bossa_user', $clause);
|
||||
}
|
||||
static function lookup(&$user) {
|
||||
if (!$user) return;
|
||||
if (isset($user->bossa)) return;
|
||||
if (isset(self::$cache[$user->id])) {
|
||||
$bossa = self::$cache[$user->id];
|
||||
} else {
|
||||
$bossa = self::lookup_userid($user->id);
|
||||
if (!$bossa) {
|
||||
self::insert("(user_id) values ($user->id)");
|
||||
$bossa = self::lookup_userid($user->id);
|
||||
}
|
||||
self::$cache[$user->id] = $bossa;
|
||||
}
|
||||
$user->bossa = $bossa;
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BossaDb::get();
|
||||
$clause = "$clause where user_id=$this->user_id";
|
||||
return $db->update_aux('bossa_user', $clause);
|
||||
}
|
||||
|
||||
// app-callable:
|
||||
//
|
||||
function get_opaque_data() {
|
||||
return unserialize($this->info);
|
||||
}
|
||||
function set_opaque_data($info) {
|
||||
$info = serialize($info);
|
||||
$this->update("info='$info'");
|
||||
}
|
||||
}
|
||||
|
||||
class BossaApp {
|
||||
static function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->insert('bossa_app', $clause);
|
||||
}
|
||||
|
||||
static function lookup($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup('bossa_app', 'BossaApp', $clause);
|
||||
}
|
||||
|
||||
static function lookup_id($id) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup_id($id, 'bossa_app', 'BossaApp');
|
||||
}
|
||||
|
||||
static function enum() {
|
||||
$db = BossaDb::get();
|
||||
return $db->enum('bossa_app', 'BossaApp');
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->update($this, 'bossa_app', $clause);
|
||||
}
|
||||
}
|
||||
|
||||
// values for bossa_job.state
|
||||
//
|
||||
define("BOSSA_JOB_EMBARGOED", 0);
|
||||
define("BOSSA_JOB_IN_PROGRESS", 1);
|
||||
define("BOSSA_JOB_DONE", 2);
|
||||
define("BOSSA_JOB_INCONCLUSIVE", 3);
|
||||
|
||||
class BossaJob {
|
||||
static function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
$ret = $db->insert('bossa_job', $clause);
|
||||
if (!$ret) return 0;
|
||||
return $db->insert_id();
|
||||
}
|
||||
function update($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->update($this, 'bossa_job', $clause);
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup_id($id, 'bossa_job', 'BossaJob');
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->enum('bossa_job', 'BossaJob', $clause);
|
||||
}
|
||||
static function count($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->count('bossa_job', $clause);
|
||||
}
|
||||
|
||||
// app-callable:
|
||||
//
|
||||
function get_opaque_data() {
|
||||
return unserialize($this->info);
|
||||
}
|
||||
function set_priority($x) {
|
||||
return $this->update("priority_0=$x");
|
||||
}
|
||||
function get_instances() {
|
||||
return BossaJobInst::enum("job_id = $this->id");
|
||||
}
|
||||
function get_finished_instances() {
|
||||
return BossaJobInst::enum("job_id = $this->id and finish_time>0");
|
||||
}
|
||||
function set_state($s) {
|
||||
$this->update("state=$s");
|
||||
}
|
||||
}
|
||||
|
||||
class BossaJobInst {
|
||||
function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
$ret = $db->insert('bossa_job_inst', $clause);
|
||||
if (!$ret) return 0;
|
||||
return $db->insert_id();
|
||||
}
|
||||
|
||||
static function lookup_id($id) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup_id($id, 'bossa_job_inst', 'BossaJobInst');
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->enum('bossa_job_inst', 'BossaJobInst', $clause);
|
||||
}
|
||||
|
||||
function update($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->update($this, 'bossa_job_inst', $clause);
|
||||
}
|
||||
|
||||
// Assign a job from the given app to the given user.
|
||||
// Returns the job instance or NULL.
|
||||
//
|
||||
static function assign($app, $user) {
|
||||
$db = BossaDb::get();
|
||||
|
||||
// first look for unfinished jobs previously assigned to this user
|
||||
//
|
||||
$job = $db->lookup("bossa_job_inst", "BossaJobInst",
|
||||
"app_id=$app->id and user_id=$user->id and finish_time=0 limit 1"
|
||||
);
|
||||
if ($job) return $job;
|
||||
|
||||
if ($app->calibration_frac && drand() < $app->calibration_frac) {
|
||||
$job = $db->lookup("bossa_job", "BossaJob", "app_id=$app->id and (select count(*) from ".$db->db_name.".bossa_job_inst where job_id=bossa_job.id and user_id=$user->id) = 0 and state=1 and calibration=1 order by priority_0 desc limit 1");
|
||||
if (!$job) return null;
|
||||
$job->update("priority_0=priority_0-1");
|
||||
} else {
|
||||
if (isset($user->bossa->category)) {
|
||||
$prio = "priority_".$user->bossa->category;
|
||||
} else {
|
||||
$prio = "priority_0";
|
||||
}
|
||||
// skips jobs for which this user
|
||||
// has already been assigned an instance
|
||||
//
|
||||
$job = $db->lookup("bossa_job", "BossaJob", "app_id=$app->id and (select count(*) from ".$db->db_name.".bossa_job_inst where job_id=bossa_job.id and user_id=$user->id) = 0 and state=1 and calibration=0 order by $prio desc limit 1");
|
||||
if (!$job) return null;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$clause = "(create_time, app_id, job_id, user_id, batch_id, calibration) values ($now, $app->id, $job->id, $user->id, $job->batch_id, $job->calibration)";
|
||||
$id = BossaJobInst::insert($clause);
|
||||
return BossaJobInst::lookup_id($id);
|
||||
}
|
||||
function delete_aux($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->delete_aux('bossa_job_inst', $clause);
|
||||
}
|
||||
|
||||
// app-callable functions
|
||||
//
|
||||
function set_opaque_data($info) {
|
||||
$info = serialize($info);
|
||||
return $this->update("info='$info'");
|
||||
}
|
||||
function get_opaque_data() {
|
||||
return unserialize($this->info);
|
||||
}
|
||||
function get_user() {
|
||||
$user = BoincUser::lookup_id($this->user_id);
|
||||
BossaUser::lookup($user);
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
class BossaBatch {
|
||||
function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
$ret = $db->insert('bossa_batch', $clause);
|
||||
if (!$ret) return 0;
|
||||
return $db->insert_id();
|
||||
}
|
||||
static function enum($clause) {
|
||||
$db = BossaDb::get();
|
||||
return $db->enum('bossa_batch', 'BossaBatch', $clause);
|
||||
}
|
||||
static function lookup_id($id) {
|
||||
$db = BossaDb::get();
|
||||
return $db->lookup_id($id, 'bossa_batch', 'BossaBatch');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/bossa.inc");
|
||||
|
||||
// Bossa example #1.
|
||||
// Show the user an image and ask them to click on the ellipse
|
||||
// This version does no replication.
|
||||
|
||||
function job_show($job, $inst, $user) {
|
||||
$info = $job->get_opaque_data($job);
|
||||
$path = $info->path;
|
||||
page_head("Find the Ellipse");
|
||||
echo "
|
||||
<form method=get action=bossa_job_finished.php>
|
||||
Click on the center of the ellipse.
|
||||
If you don't see one, click here:
|
||||
<input class=\"btn btn-default\" type=submit name=submit value=None>
|
||||
<br><br>
|
||||
<input type=hidden name=bji value=$inst->id>
|
||||
<input type=image name=pic src=$path>
|
||||
</form>
|
||||
";
|
||||
page_tail();
|
||||
}
|
||||
|
||||
function job_issued($job, $inst, $user) {
|
||||
$job->set_priority(0);
|
||||
}
|
||||
|
||||
function job_finished($job, $inst) {
|
||||
$response = new stdClass;
|
||||
if (get_str('submit', true)) {
|
||||
$response->have_ellipse = 0;
|
||||
} else {
|
||||
$response->have_ellipse = 1;
|
||||
$response->cx = get_int('pic_x');
|
||||
$response->cy = get_int('pic_y');
|
||||
}
|
||||
$inst->set_opaque_data($response);
|
||||
$job->set_state(BOSSA_JOB_DONE);
|
||||
}
|
||||
|
||||
function job_timed_out($job, $inst, $user) {
|
||||
$job->set_priority(1);
|
||||
}
|
||||
|
||||
function job_summary($job) {
|
||||
$info = $job->get_opaque_data();
|
||||
return "<a href=".URL_BASE."$info->path>View image</a>";
|
||||
}
|
||||
|
||||
function instance_summary($info) {
|
||||
if ($info->have_ellipse) {
|
||||
return "($info->cx, $info->cy)";
|
||||
} else {
|
||||
return "no ellipse";
|
||||
}
|
||||
}
|
||||
|
||||
function user_summary($user) {
|
||||
return "";
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,135 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/bossa.inc");
|
||||
|
||||
// Bossa example #2.
|
||||
// Show the user an image and ask them to click on the ellipse
|
||||
// This version does replication;
|
||||
// a job is considered done if either
|
||||
// - 2 instances are positive and match within +- 20 pixels
|
||||
// - 2 instances are negative
|
||||
// - there are 10 finished instances
|
||||
// (in which case the job is marked as inconclusive)
|
||||
|
||||
function job_show($job, $inst, $user) {
|
||||
$info = $job->get_opaque_data($job);
|
||||
$path = $info->path;
|
||||
echo "
|
||||
<h2>Find the Ellipse!</h2>
|
||||
<form method=get action=bossa_job_finished.php>
|
||||
Click on the center of the ellipse.
|
||||
If you don't see one, click here:
|
||||
<input class=\"btn btn-default\" type=submit name=submit value=None>
|
||||
<br><br>
|
||||
<input type=hidden name=bji value=$inst->id>
|
||||
<input type=image name=pic src=$path>
|
||||
</form>
|
||||
";
|
||||
}
|
||||
|
||||
function job_issued($job, $inst, $user) {
|
||||
$insts = $job->get_instances();
|
||||
if (count($insts) == 1) {
|
||||
$job->set_priority(2);
|
||||
} else {
|
||||
$job->set_priority(0);
|
||||
}
|
||||
}
|
||||
|
||||
function job_finished($job, $inst) {
|
||||
// record the user's response
|
||||
//
|
||||
$response = null;
|
||||
if (get_str('submit', true)) {
|
||||
$response->have_ellipse = 0;
|
||||
} else {
|
||||
$response->have_ellipse = 1;
|
||||
$response->cx = get_int('pic_x');
|
||||
$response->cy = get_int('pic_y');
|
||||
}
|
||||
$inst->set_opaque_data($response);
|
||||
|
||||
// see whether we have a consensus
|
||||
//
|
||||
$insts = $job->get_finished_instances();
|
||||
$n = count($insts);
|
||||
|
||||
$results = null;
|
||||
foreach ($insts as $inst) {
|
||||
$results[] = $inst->get_opaque_data();
|
||||
}
|
||||
for ($i=0; $i<$n-1; $i++) {
|
||||
$r1 = $results[$i];
|
||||
for ($j=$i+1; $j<$n; $j++) {
|
||||
$r2 = $results[$j];
|
||||
if (compatible($r1, $r2)) {
|
||||
$job->set_state(BOSSA_JOB_DONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no consensus - see whether we've reached replication limit
|
||||
//
|
||||
if ($n >= 10) {
|
||||
$job->set_state(BOSSA_JOB_INCONCLUSIVE);
|
||||
return;
|
||||
}
|
||||
|
||||
// still looking for consensus - get another instance
|
||||
//
|
||||
$job->set_priority(2);
|
||||
}
|
||||
|
||||
// two results are compatible if neither found an ellipse,
|
||||
// or they both did and centers are within 20 pixels
|
||||
//
|
||||
function compatible($r1, $r2) {
|
||||
if ($r1->have_ellipse) {
|
||||
if ($r2->have_ellipse) {
|
||||
$dx = ($r1->cx - $r2->cx);
|
||||
$dy = ($r1->cy - $r2->cy);
|
||||
$dsq = $dx*$dx + $dy*$dy;
|
||||
return ($dsq < 400);
|
||||
} else return false;
|
||||
} else {
|
||||
return !$r2->have_ellipse;
|
||||
}
|
||||
}
|
||||
|
||||
function job_timed_out($job, $inst, $user) {
|
||||
$job->set_priority(2);
|
||||
}
|
||||
|
||||
function job_summary($job) {
|
||||
$info = $job->get_opaque_data();
|
||||
return "<a href=".URL_BASE."$info->path>View image</a>";
|
||||
}
|
||||
|
||||
function instance_summary($info) {
|
||||
if ($info->have_ellipse) {
|
||||
return "ellipse ($info->cx, $info->cy)";
|
||||
} else {
|
||||
return "no ellipse";
|
||||
}
|
||||
}
|
||||
|
||||
function user_summary($user) {
|
||||
return "";
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// Bossa example #3 - calibration jobs.
|
||||
// We maintain the following for each user:
|
||||
// nneg # of negative calibration jobs shown
|
||||
// nneg_err # of errors
|
||||
// npos
|
||||
// npos_err
|
||||
//
|
||||
// from these we derive
|
||||
// neg_err_rate
|
||||
// pos_err_rate
|
||||
//
|
||||
// a job is considered done if either
|
||||
// - N instances are positive and match within +- 20 pixels,
|
||||
// and prod(pos_err_rate)<PROB_LIMIT
|
||||
// - N instances are negative
|
||||
// and prod(neg_err_rate)<PROB_LIMIT
|
||||
// - there are 10 finished instances
|
||||
// (in which case the job is marked as inconclusive)
|
||||
|
||||
require_once("../inc/bossa.inc");
|
||||
|
||||
define("PROB_LIMIT", 1e-3);
|
||||
|
||||
function job_show($job, $inst, $user) {
|
||||
$info = $job->get_opaque_data();
|
||||
$path = $info->path;
|
||||
page_head("Find the Ellipse");
|
||||
echo "
|
||||
<form method=get action=bossa_job_finished.php>
|
||||
Click on the center of the ellipse.
|
||||
If you don't see one, click here:
|
||||
<input type=submit name=submit value=None>
|
||||
<br><br>
|
||||
<input type=hidden name=bji value=$inst->id>
|
||||
<input type=image name=pic src=$path>
|
||||
</form>
|
||||
";
|
||||
page_tail();
|
||||
}
|
||||
|
||||
function job_issued($job, $inst, $user) {
|
||||
$insts = $job->get_instances();
|
||||
if (count($insts) > 1) {
|
||||
$job->set_priority(0);
|
||||
}
|
||||
}
|
||||
|
||||
function job_finished($job, $inst, $user) {
|
||||
$response = null;
|
||||
if (get_str('submit', true)) {
|
||||
$response->have_ellipse = 0;
|
||||
} else {
|
||||
$response->have_ellipse = 1;
|
||||
$response->cx = get_int('pic_x');
|
||||
$response->cy = get_int('pic_y');
|
||||
}
|
||||
$inst->set_opaque_data($response);
|
||||
|
||||
// if this is a calibration job, update user's opaque data
|
||||
//
|
||||
if ($job->calibration) {
|
||||
$b = $user->bossa;
|
||||
$info = $job->get_opaque_data();
|
||||
$answer = $info->answer;
|
||||
$u = $b->get_opaque_data();
|
||||
if (!$u) {
|
||||
$u->npos = 0;
|
||||
$u->npos_err = 0;
|
||||
$u->nneg = 0;
|
||||
$u->nneg_err = 0;
|
||||
}
|
||||
if (compatible($response, $answer)) {
|
||||
if ($answer->have_ellipse) {
|
||||
$u->npos++;
|
||||
} else {
|
||||
$u->nneg++;
|
||||
}
|
||||
} else {
|
||||
if ($answer->have_ellipse) {
|
||||
$u->npos++;
|
||||
$u->npos_err++;
|
||||
} else {
|
||||
$u->nneg++;
|
||||
$u->nneg_err++;
|
||||
}
|
||||
}
|
||||
$b->set_opaque_data($u);
|
||||
return;
|
||||
}
|
||||
|
||||
// now see if job is done
|
||||
//
|
||||
$insts = $job->get_finished_instances();
|
||||
$n = count($insts);
|
||||
|
||||
$results = null;
|
||||
$users = null;
|
||||
foreach ($insts as $inst) {
|
||||
$results[] = $inst->get_opaque_data();
|
||||
$u = $inst->get_user();
|
||||
$users[] = $u->bossa->get_opaque_data();
|
||||
}
|
||||
|
||||
// see if there's a negative consensus
|
||||
//
|
||||
$prob = 1;
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$r = $results[$i];
|
||||
if ($r1->have_ellipse) continue;
|
||||
$u = $users[$i];
|
||||
$prob *= $u->neg_err_rate;
|
||||
}
|
||||
if ($prob < PROB_LIMIT) {
|
||||
$job->set_state(BOSSA_JOB_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
// see if there's a positive consensus
|
||||
//
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$r1 = $results[$i];
|
||||
$u = $users[$i];
|
||||
$prob = $u->pos_error_rate;
|
||||
for ($j=0; $j<$n; $j++) {
|
||||
if ($j == $i) continue;
|
||||
$r2 = $results[$j];
|
||||
if (compatible($r1, $r2)) {
|
||||
$u2 = $users[$j];
|
||||
$prob *= $u2->pos_err_rate;
|
||||
}
|
||||
}
|
||||
if ($prob < PROB_LIMIT) {
|
||||
$job->set_state(BOSSA_JOB_DONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// see if there are too many instances without a consensus
|
||||
//
|
||||
if ($n >= 10) {
|
||||
$job->set_state(BOSSA_JOB_INCONCLUSIVE);
|
||||
return;
|
||||
}
|
||||
|
||||
// still looking for consensus - get another instance
|
||||
//
|
||||
$job->set_priority(2);
|
||||
|
||||
}
|
||||
|
||||
// two results are compatible if neither found an ellipse,
|
||||
// or they both did and centers are within 20 pixels
|
||||
//
|
||||
function compatible($r1, $r2) {
|
||||
if ($r1->have_ellipse) {
|
||||
if ($r2->have_ellipse) {
|
||||
$dx = ($r1->cx - $r2->cx);
|
||||
$dy = ($r1->cy - $r2->cy);
|
||||
$dsq = $dx*$dx + $dy*$dy;
|
||||
return ($dsq < 400);
|
||||
} else return false;
|
||||
} else {
|
||||
return !$r2->have_ellipse;
|
||||
}
|
||||
}
|
||||
|
||||
function job_timed_out($job, $inst, $user) {
|
||||
$job->set_priority(1);
|
||||
}
|
||||
|
||||
function job_summary($job) {
|
||||
$info = $job->get_opaque_data();
|
||||
return "<a href=".URL_BASE."$info->path>(view image)</a>";
|
||||
}
|
||||
|
||||
function instance_summary($info) {
|
||||
if ($info->have_ellipse) {
|
||||
return "ellipse ($info->cx, $info->cy)";
|
||||
} else {
|
||||
return "no ellipse";
|
||||
}
|
||||
}
|
||||
|
||||
function user_summary($user) {
|
||||
$b = $user->bossa;
|
||||
$info = $b->get_opaque_data();
|
||||
if ($info) {
|
||||
if ($info->npos) {
|
||||
$pos_err = $info->npos_err/$info->npos;
|
||||
} else {
|
||||
$pos_err = "---";
|
||||
}
|
||||
if ($info->nneg) {
|
||||
$neg_err = $info->nneg_err/$info->nneg;
|
||||
} else {
|
||||
$neg_err = "---";
|
||||
}
|
||||
return "error rate: positive $pos_err ($info->npos_err/$info->npos),
|
||||
negative $neg_err ($info->nneg_err/$info->nneg)
|
||||
";
|
||||
} else {
|
||||
return "No data";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,189 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/bossa.inc");
|
||||
|
||||
function job_show($job, $inst, $user) {
|
||||
$output = $inst->get_opaque_data();
|
||||
$features = $output->features;
|
||||
$input = $job->get_opaque_data();
|
||||
$path = $input->path;
|
||||
|
||||
show_style();
|
||||
echo "
|
||||
<script>
|
||||
function image_clicked() {
|
||||
if (document.forms.main.type.value == 'none') {
|
||||
alert('Please select a feature type');
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<form name=main onsubmit=\"javascript: return image_clicked()\" action=bossa_example4.php>
|
||||
<div style=\"position:relative; top:60; \">
|
||||
<input type=hidden name=action value=add>
|
||||
<input type=hidden name=bji value=\"$inst->id\">
|
||||
<input type=image name=pic src=$path>
|
||||
";
|
||||
$size = 100;
|
||||
$size2 = 50;
|
||||
$i = 0;
|
||||
foreach ($features as $f) {
|
||||
$cx = $f->x - $size2;
|
||||
$cy = $f->y - $size2;
|
||||
echo "
|
||||
<span style=\"width:".$size."px;height:".$size."px;position:absolute;top:".$cy.";left:".$cx.";color:white;border-style:solid;border-width:1px\">
|
||||
";
|
||||
$c = $f->comment?"($f->comment)":"";
|
||||
echo "
|
||||
<span class=link>
|
||||
<a href=\"javascript: void(0)\">
|
||||
<img border=0 align = left src=example4_images/info_icon.png>
|
||||
<span>
|
||||
$f->type $c
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
";
|
||||
echo "
|
||||
<a href=bossa_example4.php?bji=$inst->id&action=delete&index=$i><img border=0 align=right src=example4_images/close_button.jpg></a>
|
||||
</span>
|
||||
";
|
||||
$i++;
|
||||
}
|
||||
echo "
|
||||
</div>
|
||||
";
|
||||
control_bar($features, $inst);
|
||||
echo "
|
||||
</form>
|
||||
";
|
||||
}
|
||||
|
||||
function job_issued($job, $inst, $user) {
|
||||
$job->set_priority(0);
|
||||
}
|
||||
|
||||
function job_finished($job, $inst) {
|
||||
}
|
||||
|
||||
function job_timed_out($job, $inst, $user) {
|
||||
$job->set_priority(1);
|
||||
}
|
||||
|
||||
function job_summary($job) {
|
||||
$info = $job->get_opaque_data();
|
||||
return "<a href=".URL_BASE."$info->path>View image</a>";
|
||||
}
|
||||
|
||||
function instance_summary($opaque_data) {
|
||||
$features = $opaque_data->features;
|
||||
$x = "";
|
||||
foreach ($features as $f) {
|
||||
$c = $f->comment?"($f->comment)":"";
|
||||
$x .= "$f->type $c <br>";
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
||||
function user_summary($user) {
|
||||
return "";
|
||||
}
|
||||
|
||||
function show_style() {
|
||||
echo "
|
||||
<style type=\"text/css\">
|
||||
|
||||
body {
|
||||
font: 15px \"Trebuchet MS\", sans-serif;
|
||||
}
|
||||
|
||||
span.link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
span.link a span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
span.link a:hover {
|
||||
font-size: 99%;
|
||||
font-color: #000000;
|
||||
}
|
||||
|
||||
span.link a:hover span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
margin-left: -10px;
|
||||
width: 175px; padding: 5px;
|
||||
z-index: 100;
|
||||
color: #000000;
|
||||
background: #ffffcc;
|
||||
font: 12px \"Arial\", sans-serif;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
";
|
||||
}
|
||||
|
||||
function select_type() {
|
||||
echo "
|
||||
<select name=type>
|
||||
<option value=none> select feature type
|
||||
<option> Tooth
|
||||
<option> Skull
|
||||
<option> Other
|
||||
</select>
|
||||
";
|
||||
}
|
||||
|
||||
function control_bar($features, $inst) {
|
||||
if (count($features)) {
|
||||
$str1 = "any more";
|
||||
$str2 = "another";
|
||||
} else {
|
||||
$str1 = "any";
|
||||
$str2 = "a";
|
||||
}
|
||||
echo "
|
||||
<div style=\"position:absolute; top:0px; left:0px; padding-top: 10px; padding-left: 20px; width:100%; background-color:white\">
|
||||
<input type=hidden name=bji value=\"$inst->id\">
|
||||
If you see $str2 feature:
|
||||
";
|
||||
select_type();
|
||||
echo "
|
||||
<script>
|
||||
function clear_comment() {
|
||||
document.forms.main.comment.value = '';
|
||||
}
|
||||
</script>
|
||||
<input name=comment onfocus=\"javascript: clear_comment()\" size=30 value=\"enter comment (optional)\">
|
||||
and click on its center.
|
||||
<br>
|
||||
If you don't see $str1 features, click
|
||||
<a href=bossa_job_finished.php?bji=$inst->id>DONE</a>
|
||||
</div>
|
||||
";
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
function show_next_job($app, $user) {
|
||||
$inst = BossaJobInst::assign($app, $user);
|
||||
if ($inst) {
|
||||
$job = BossaJob::lookup_id($inst->job_id);
|
||||
$file = "../inc/$app->short_name.inc";
|
||||
require_once($file);
|
||||
job_issued($job, $inst, $user);
|
||||
job_show($job, $inst, $user);
|
||||
} else {
|
||||
page_head("No jobs available");
|
||||
echo "
|
||||
Sorry, no jobs are available right now.
|
||||
<p>
|
||||
Please try again later.
|
||||
";
|
||||
page_tail();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,414 +0,0 @@
|
|||
/* General */
|
||||
|
||||
a, a:link, a:visited, a:active {
|
||||
color: #0069A1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
body {
|
||||
background-image: url("img/gray_gradient.png");
|
||||
background-repeat: repeat-x;
|
||||
background-color: white;
|
||||
font-family: Verdana, Arial, Sans Serif;
|
||||
font-size: 13px;
|
||||
margin: 5px 10px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font-size: x-large;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #203C66;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
h3, h4 { font-weight: bold; }
|
||||
|
||||
hr {
|
||||
size: 0px;
|
||||
border-top: 2px solid #e8e8e8;
|
||||
margin: 8px 2px;
|
||||
}
|
||||
|
||||
.table {
|
||||
padding: 4px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.table-bordered {
|
||||
border: 2px solid #e8e8e8;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #c0c0c0;
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
td.bordered {
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
td.indent { border-left: 4px solid white; }
|
||||
|
||||
th, td.heading {
|
||||
font-weight: bold;
|
||||
margin: 4px 0px;
|
||||
padding: 8px;
|
||||
background-color: #d8d8d8;
|
||||
}
|
||||
|
||||
td.fieldname {
|
||||
background-color: #eeeeee;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
margin: 2px 0px;
|
||||
}
|
||||
|
||||
td.fieldvalue {
|
||||
margin: 2px 0px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
td.fieldname_error {
|
||||
background-color: #ff8888;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td.fieldvalue_error {
|
||||
background-color: #ff8888;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.navbar {
|
||||
border: 0px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
td.friend {
|
||||
background-color: #e8e8e8;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.row0 {
|
||||
background-color: #d9d9d9;
|
||||
text-align: left;
|
||||
}
|
||||
.row1 {
|
||||
background-color: #eeeeee;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.highlighted_row0 {
|
||||
background-color: #b9d9f9;
|
||||
text-align: left;
|
||||
}
|
||||
.highlighted_row1 {
|
||||
background-color: #ceeefe;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.row_hd0 { background-color: #cffacf; }
|
||||
|
||||
.row_hd1 { background-color: #defade; }
|
||||
|
||||
tr.message { background-color: #e0e0e0; }
|
||||
|
||||
input[type="text"], select, textarea, .btn {
|
||||
border: 1px solid #d8d8d8;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
padding: 2px 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input[type="button"], input[type="submit"], input.btn {
|
||||
margin: 2px 0px;
|
||||
background: #d4d0c8;
|
||||
margin-right: 0.6em;
|
||||
color: #203C66;
|
||||
border: 1px solid #a8a8a8;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* IE6 doesn't understand [type=XXXX] so we factor this out into its own */
|
||||
.btn {
|
||||
margin: 2px 0px;
|
||||
background: #d4d0c8;
|
||||
margin-right: 0.6em;
|
||||
white-space: nowrap;
|
||||
color: #203C66;
|
||||
border: 1px solid #a8a8a8;
|
||||
font-size: 0.9em;
|
||||
font-weight: normal;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #edece8;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
input[type="button"]:hover, input[type="submit"]:hover, input.btn:hover, .forum_toplinks a:hover {
|
||||
background: #edece8;
|
||||
}
|
||||
|
||||
.actionlist {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.actionlist li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
img { border: 0px; }
|
||||
|
||||
img.userimg { border: 0px; }
|
||||
|
||||
/* Main Page */
|
||||
|
||||
#news {
|
||||
background-color: #dff0ff;
|
||||
border: 2px solid #add8e6;
|
||||
padding: 10px;
|
||||
margin: 4px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
}
|
||||
|
||||
#news h2, #uotd h2, #mainnav h2 {
|
||||
margin-top: 0px;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#news h3 {
|
||||
color: #666666;
|
||||
font-size: 1em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#news p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
#uotd {
|
||||
background-color: #d3d3d3;
|
||||
border: 2px solid #eeeeee;
|
||||
padding: 10px;
|
||||
margin: 4px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
}
|
||||
|
||||
/* Forum */
|
||||
|
||||
td.category , tr.subtitle{
|
||||
background-color: #dddddd;
|
||||
border: 0px;
|
||||
font-weight: bold;
|
||||
margin: 6px 0px;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
margin: 4px 2px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
td.postheader {
|
||||
background-color: #eeeeee;
|
||||
height: 24px;
|
||||
margin-left: 4px;
|
||||
padding-left: 8px;
|
||||
-moz-border-radius: 0px 0px 10px 10px;
|
||||
-webkit-border-radius: 0px 0px 10px 10px;
|
||||
}
|
||||
|
||||
td.postbody {
|
||||
font-size: 9pt;
|
||||
margin-left: 4px;
|
||||
background: transparent url('img/75pct_white.png');
|
||||
}
|
||||
|
||||
td.postfooter {
|
||||
background-color: #eeeeee;
|
||||
height: 26px;
|
||||
margin-left: 4px;
|
||||
padding-left: 8px;
|
||||
-moz-border-radius: 10px 10px 0px 0px;
|
||||
-webkit-border-radius: 10px 10px 0px 0px;
|
||||
}
|
||||
|
||||
tr.helpdeskseparator { height: 10pt; }
|
||||
|
||||
tr.postseparator {
|
||||
background-color: #c8c8c8;
|
||||
border: 1px solid #aaaaaa;
|
||||
margin: 4px 0px;
|
||||
}
|
||||
|
||||
td.threadline { text-align: left; }
|
||||
|
||||
td.numbers {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.numbers {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td.lastpost {
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-info, .description {
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.authorcol {
|
||||
width: 136px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.authorcol {
|
||||
border: 1px solid #c8c8c8;
|
||||
background-color: white;
|
||||
padding: 8px 5px;
|
||||
width: 120px;
|
||||
margin-left: 2px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
}
|
||||
|
||||
.authorinfo img {
|
||||
border: 1px solid #a8a8a8;
|
||||
margin: 3px 9px;
|
||||
}
|
||||
|
||||
.authorcol input { margin: 4px 10px; }
|
||||
|
||||
blockquote.postbody {
|
||||
border-left: 2px solid #0089e1;
|
||||
background-color: #f5fffa;
|
||||
padding: 2px 6px;
|
||||
margin: 0px 6px 0px 10px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#thread {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.forum_toplinks td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
span.page_title {
|
||||
font-size: 24px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
p.text-muted, span.note {
|
||||
font-weight: normal;
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
span.news_date {
|
||||
color: #646464;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
span.news_title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.inboxunread {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.highlight {
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
.nobr{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: "Courier New", courier, monospace;
|
||||
display: block;
|
||||
margin-left: 5em;
|
||||
border-left: 3px solid #ccaaaa;
|
||||
padding-left: 1em;
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
p.text-danger, .error {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.notice {
|
||||
color: #009900;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#preview {
|
||||
border: 2px solid #cccccc;
|
||||
background-color: #eeeeee;
|
||||
margin: 1em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
#preview .header {
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
/* Server Status Page */
|
||||
|
||||
td.running { background-color: #9aff4f; }
|
||||
|
||||
td.notrunning { background-color: #feff6f; }
|
||||
|
||||
td.disabled { background-color: #ff4f4f; }
|
||||
|
||||
/* IE hack */
|
||||
|
||||
* html body .code {
|
||||
white-space: normal;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/bolt_db.inc");
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bolt_util.inc");
|
||||
|
||||
page_head("Courses");
|
||||
|
||||
$user = get_logged_in_user(false);
|
||||
if ($user) {
|
||||
BoltUser::lookup($user);
|
||||
}
|
||||
|
||||
$courses = BoltCourse::enum();
|
||||
start_table();
|
||||
table_header(
|
||||
"Course", "Status"
|
||||
);
|
||||
foreach ($courses as $course) {
|
||||
if ($course->hidden && !($user->bolt->flags&BOLT_FLAG_SHOW_ALL)) {
|
||||
continue;
|
||||
}
|
||||
$e = $user?BoltEnrollment::lookup($user->id, $course->id):null;
|
||||
if ($e) {
|
||||
$start = date_str($e->create_time);
|
||||
$view = BoltView::lookup_id($e->last_view_id);
|
||||
$ago = time_diff(time() - $view->start_time);
|
||||
$pct = number_format($view->fraction_done*100, 0);
|
||||
$status = "Started $start
|
||||
<br>Last visit: $ago ago
|
||||
<br>$pct% done
|
||||
";
|
||||
if ($view->fraction_done < 1) {
|
||||
$status .= "<br><a href=bolt_sched.php?course_id=$course->id&action=resume>Resume</a>
|
||||
";
|
||||
}
|
||||
$status .= "<br><a href=bolt_sched.php?course_id=$course->id&action=start>Restart</a>
|
||||
| <a href=bolt_course.php?course_id=$course->id>History</a>
|
||||
";
|
||||
} else {
|
||||
$status = "
|
||||
<a href=bolt_sched.php?course_id=$course->id&action=start>Start</a>
|
||||
";
|
||||
}
|
||||
row2_init("<b>$course->name</b>
|
||||
<br><p class=\"text-muted\">$course->description</p>",
|
||||
$status
|
||||
);
|
||||
show_refreshes();
|
||||
echo "</td></tr>\n";
|
||||
}
|
||||
end_table();
|
||||
page_tail();
|
||||
|
||||
?>
|
|
@ -1,63 +0,0 @@
|
|||
table.bolt_bar {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
//border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
|
||||
td.bolt_bar {
|
||||
border: 1px solid #aaaaaa;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
span.green {
|
||||
padding: 2px;
|
||||
background-color: #88ff88;
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
}
|
||||
span.yellow {
|
||||
padding: 2px;
|
||||
background-color: #ffff88;
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
}
|
||||
span.red {
|
||||
padding: 2px;
|
||||
background-color: #ff8888;
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
td.bolt_bar1 {
|
||||
padding: 0;
|
||||
margin: 0px 0px;
|
||||
font-size: 0.9em;
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
td.bolt_bar2 {
|
||||
padding: 0;
|
||||
margin: 0px 0px;
|
||||
font-size: 0.9em;
|
||||
background-color: #44bb44;
|
||||
}
|
||||
|
||||
tr.bolt_head1 {
|
||||
background-color: #ccccff;
|
||||
font-weight: bold;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
|
||||
}
|
||||
|
||||
tr.bolt_head2 {
|
||||
background-color: #cccccc;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
}
|
||||
|
||||
span.bolt_small {
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
$user = get_logged_in_user();
|
||||
|
||||
function phase_name($phase) {
|
||||
switch ($phase) {
|
||||
case BOLT_PHASE_STUDY: return "study";
|
||||
case BOLT_PHASE_REVIEW: return "review";
|
||||
case BOLT_PHASE_REFRESH: return "refresh";
|
||||
default: return "unknown phase: $phase";
|
||||
}
|
||||
}
|
||||
|
||||
function mode_name($mode) {
|
||||
switch ($mode) {
|
||||
case BOLT_MODE_LESSON: return "lesson";
|
||||
case BOLT_MODE_SHOW: return "exercise";
|
||||
case BOLT_MODE_ANSWER: return "answer page";
|
||||
case BOLT_MODE_FINISHED: return "course completed";
|
||||
default: return "unknown mode: $mode";
|
||||
}
|
||||
}
|
||||
|
||||
function action_name($action) {
|
||||
switch ($action) {
|
||||
case BOLT_ACTION_NONE: return "None";
|
||||
case BOLT_ACTION_NEXT: return "Next";
|
||||
case BOLT_ACTION_PREV: return "Previous";
|
||||
case BOLT_ACTION_SUBMIT: return "Submit";
|
||||
case BOLT_ACTION_QUESTION: return "Question";
|
||||
case BOLT_ACTION_COURSE_HOME: return "Course home";
|
||||
default: return "unknown: $action";
|
||||
}
|
||||
}
|
||||
|
||||
function show_view($view) {
|
||||
if ($view->end_time) {
|
||||
$d = $view->end_time - $view->start_time;
|
||||
$dur = "$d seconds";
|
||||
} else {
|
||||
$dur = "---";
|
||||
}
|
||||
|
||||
if ($view->result_id) {
|
||||
$result = BoltResult::lookup_id($view->result_id);
|
||||
$qs = str_replace("action=answer", "action=answer_page", $result->response);
|
||||
$score = number_format($result->score*100);
|
||||
$x = "<br>Score: $score%
|
||||
<br><a href=bolt_sched.php?$qs>Answer page</a>";
|
||||
}
|
||||
echo "<tr>
|
||||
<td valign=top>$view->id</td>
|
||||
<td valign=top>".time_str($view->start_time)."</td>
|
||||
<td valign=top>$dur</td>
|
||||
<td valign=top>$view->item_name</td>
|
||||
<td valign=top>".mode_name($view->mode)." $x</td>
|
||||
";
|
||||
//<td valign=top>".phase_name($view->phase)."</td>
|
||||
echo "
|
||||
<td valign=top>".action_name($view->action)."</td>
|
||||
</tr>
|
||||
";
|
||||
}
|
||||
|
||||
function show_views() {
|
||||
global $user;
|
||||
global $course;
|
||||
|
||||
$views = BoltView::enum("user_id=$user->id and course_id=$course->id order by id");
|
||||
start_table();
|
||||
|
||||
table_header("ID", "Time", "Duration", "Item", "Mode",
|
||||
// "Phase",
|
||||
"Action");
|
||||
foreach ($views as $view) {
|
||||
show_view($view);
|
||||
}
|
||||
end_table();
|
||||
}
|
||||
|
||||
require_once("../inc/bolt_db.inc");
|
||||
require_once("../inc/bolt_util.inc");
|
||||
|
||||
$course_id = get_int('course_id');
|
||||
$course = BoltCourse::lookup_id($course_id);
|
||||
if (!$course) error_page("No such course");
|
||||
page_head("Your history in $course->name");
|
||||
|
||||
show_views();
|
||||
show_refreshes();
|
||||
|
||||
echo "
|
||||
<a href=bolt_sched.php?course_id=$course_id&action=resume>Resume course</a>
|
||||
<p>
|
||||
";
|
||||
|
||||
page_tail();
|
||||
?>
|
|
@ -1,136 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/bolt.inc");
|
||||
|
||||
function part2() {
|
||||
return sequence(
|
||||
name('inner seq'),
|
||||
lesson(
|
||||
name('lesson 3'),
|
||||
filename('bolt_sample_lesson.php?n=3')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function basic_review() {
|
||||
return sequence(
|
||||
lesson(
|
||||
name('lesson 1'),
|
||||
filename('bolt_sample_lesson.php?n=1')
|
||||
),
|
||||
lesson(
|
||||
name('lesson 2'),
|
||||
filename('bolt_sample_lesson.php?n=2')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function int_review() {
|
||||
return lesson(
|
||||
name('lesson 2'),
|
||||
filename('bolt_sample_lesson.php?n=2')
|
||||
);
|
||||
}
|
||||
|
||||
function my_rand($student, $unit) {
|
||||
return rand();
|
||||
}
|
||||
|
||||
function sample_select() {
|
||||
return select(
|
||||
name('sample select'),
|
||||
valuator('my_rand'),
|
||||
lesson(
|
||||
name('lesson 1'),
|
||||
filename('bolt_sample_lesson.php?n=1')
|
||||
),
|
||||
lesson(
|
||||
name('lesson 2'),
|
||||
filename('bolt_sample_lesson.php?n=2')
|
||||
),
|
||||
lesson(
|
||||
name('lesson 3'),
|
||||
filename('bolt_sample_lesson.php?n=3')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function sample_random() {
|
||||
return random(
|
||||
name('first lessons'),
|
||||
number(2),
|
||||
lesson(
|
||||
name('lesson 1'),
|
||||
filename('bolt_sample_lesson.php?n=1')
|
||||
),
|
||||
lesson(
|
||||
name('lesson 2'),
|
||||
filename('bolt_sample_lesson.php?n=2')
|
||||
),
|
||||
lesson(
|
||||
name('lesson 3'),
|
||||
filename('bolt_sample_lesson.php?n=3')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function xset_with_review() {
|
||||
return exercise_set(
|
||||
name('exercise set 1'),
|
||||
number(2),
|
||||
exercise(
|
||||
name('exercise 1'),
|
||||
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')
|
||||
),
|
||||
repeat(.3, basic_review(), REVIEW),
|
||||
repeat(.7, int_review(), REVIEW|REPEAT),
|
||||
repeat(1, null, REPEAT|NEXT),
|
||||
refresh(array(7, 14, 28))
|
||||
);
|
||||
}
|
||||
|
||||
function sample_xset() {
|
||||
return exercise_set(
|
||||
name('sample exercise set'),
|
||||
number(1),
|
||||
exercise(
|
||||
name('exercise 1'),
|
||||
filename('bolt_sample_exercise.php?n=1')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return sequence(
|
||||
name('course'),
|
||||
// sample_random(),
|
||||
// xset_with_review(),
|
||||
sample_select(),
|
||||
sample_xset(),
|
||||
part2()
|
||||
);
|
||||
|
||||
?>
|
|
@ -1,661 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
// Bolt scheduler.
|
||||
// GET args:
|
||||
// course_id: course ID
|
||||
// action: see commands below
|
||||
|
||||
require_once("../inc/bolt.inc");
|
||||
require_once("../inc/bolt_sched.inc");
|
||||
require_once("../inc/bolt_db.inc");
|
||||
require_once("../inc/bolt_ex.inc");
|
||||
require_once("../inc/bolt_util.inc");
|
||||
require_once("../inc/util.inc");
|
||||
|
||||
function debug_show_state($state, $tag) {
|
||||
global $user;
|
||||
global $refresh;
|
||||
if ($user->bolt->flags&BOLT_FLAGS_DEBUG) {
|
||||
echo "$tag state: <pre>"; print_r($state); echo "</pre>\n";
|
||||
if ($refresh) {
|
||||
echo "<p>Refresh ID: $refresh->id<p>";
|
||||
}
|
||||
echo "<hr>\n";
|
||||
}
|
||||
}
|
||||
function debug_show_item($item) {
|
||||
global $user;
|
||||
if ($user->bolt->flags&BOLT_FLAGS_DEBUG) {
|
||||
echo "Item:<pre>"; print_r($item); echo "</pre>\n";
|
||||
echo "<hr>\n";
|
||||
}
|
||||
}
|
||||
|
||||
function update_info() {
|
||||
global $user;
|
||||
$sex = get_int('sex');
|
||||
$birth_year = get_int('birth_year');
|
||||
$user->bolt->update("sex=$sex, birth_year=$birth_year");
|
||||
}
|
||||
|
||||
// The user clicked something on a page.
|
||||
// Look up the view record (the ID is in the URL) and update it
|
||||
// with the action and the time.
|
||||
// Return the record.
|
||||
//
|
||||
function finalize_view($view_id, $action) {
|
||||
global $user;
|
||||
if (!$view_id) return null;
|
||||
$view = BoltView::lookup_id($view_id);
|
||||
if (!$view) {
|
||||
error_page("no view");
|
||||
}
|
||||
if ($view->user_id != $user->id) {
|
||||
error_page("wrong user");
|
||||
}
|
||||
if (!$view->end_time) {
|
||||
$now = time();
|
||||
$view->update("end_time=$now, action=$action");
|
||||
}
|
||||
return $view;
|
||||
}
|
||||
|
||||
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($iter, $mode, $prev_view_id) {
|
||||
global $user;
|
||||
global $course;
|
||||
|
||||
$now = time();
|
||||
$item = $iter->item;
|
||||
if (!$item) {
|
||||
$item = null;
|
||||
$item->name = '--end--';
|
||||
}
|
||||
$state = $iter->encode_state();
|
||||
debug_show_state($iter->state, "Ending");
|
||||
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)");
|
||||
}
|
||||
|
||||
function page_header() {
|
||||
global $course;
|
||||
echo "<html><head>
|
||||
<title>$course->name</title>
|
||||
<link rel=stylesheet type=text/css href=bolt.css>
|
||||
</head><body>
|
||||
";
|
||||
if (function_exists('bolt_header')) bolt_header();
|
||||
}
|
||||
|
||||
function page_footer() {
|
||||
if (function_exists('bolt_footer')) bolt_footer();
|
||||
echo "</body></html>";
|
||||
}
|
||||
|
||||
// show a page saying the course has been completed
|
||||
//
|
||||
function show_finished_page($view_id, $prev_view_id) {
|
||||
global $course;
|
||||
global $url_args;
|
||||
|
||||
page_header("Course completed");
|
||||
if ($course->bossa_app_id) {
|
||||
require_once("../inc/bossa_db.inc");
|
||||
$app = BossaApp::lookup_id($course->bossa_app_id);
|
||||
echo "
|
||||
Congratulations - you have completed the training for $course->name.
|
||||
<p>
|
||||
You may now
|
||||
<a href=bossa_get_job.php?bossa_app_id=$course->bossa_app_id>do work</a>.
|
||||
";
|
||||
} else {
|
||||
echo "Congratulations - you have completed this course.";
|
||||
$links[] = "<a href=bolt_sched.php?$url_args&action=prev&view_id=$view_id><img src=img/prev.gif></a>";
|
||||
$up_link = "<a href=bolt_sched.php?$url_args&action=course_home&view_id=$view_id>Course home page</a>";
|
||||
show_nav($links, $up_link, $view_id);
|
||||
}
|
||||
page_footer();
|
||||
}
|
||||
|
||||
function show_refresh_finished() {
|
||||
page_header("Refresh completed");
|
||||
echo "<a href=bolt.php>Return to courses</a>";
|
||||
page_footer();
|
||||
}
|
||||
|
||||
function show_nav($links, $up_link, $view_id) {
|
||||
global $course;
|
||||
|
||||
echo "<p><center>
|
||||
<table width=60%><tr>
|
||||
";
|
||||
foreach ($links as $link) {
|
||||
echo "<td align=center>$link</td>\n";
|
||||
}
|
||||
echo "</tr></table> </center>
|
||||
<hr>
|
||||
<br>
|
||||
<form action=bolt_sched.php>
|
||||
<input type=hidden name=course_id value=$course->id>
|
||||
<input type=hidden name=action value=question>
|
||||
<input type=hidden name=view_id value=$view_id>
|
||||
<textarea name=question cols=60 onfocus=\"this.value=''\">Enter question or comment here</textarea>
|
||||
<br>
|
||||
<input class=\"btn btn-default\" type=submit value=Submit>
|
||||
</form>
|
||||
<p>
|
||||
$up_link
|
||||
";
|
||||
}
|
||||
|
||||
// show an item (lesson, exercise, answer page)
|
||||
//
|
||||
function show_item($iter, $view_id, $prev_view_id, $mode, $repeat=null) {
|
||||
global $user;
|
||||
global $course;
|
||||
global $bolt_ex;
|
||||
global $refresh;
|
||||
global $url_args;
|
||||
|
||||
$item = $iter->item;
|
||||
page_header();
|
||||
$bolt_query_string = $item->query_string;
|
||||
|
||||
$links = array();
|
||||
if ($prev_view_id) {
|
||||
$links[] = "<a href=bolt_sched.php?$url_args&action=prev&view_id=$view_id><img src=img/prev.gif></a>";
|
||||
}
|
||||
|
||||
$next = "<a href=bolt_sched.php?$url_args&action=next&view_id=$view_id><img src=img/next.gif border=0></a>";
|
||||
|
||||
if ($item->is_exercise()) {
|
||||
$bolt_ex->mode = $mode;
|
||||
$bolt_ex->index = 0;
|
||||
switch ($mode) {
|
||||
case BOLT_MODE_SHOW:
|
||||
echo "
|
||||
<form action=bolt_sched.php>
|
||||
<input type=hidden name=view_id value=$view_id>
|
||||
<input type=hidden name=course_id value=$course->id>
|
||||
<input type=hidden name=action value=answer>
|
||||
";
|
||||
if ($refresh) {
|
||||
echo "
|
||||
<input type=hidden name=refresh_id value=$refresh->id>
|
||||
";
|
||||
}
|
||||
srand($view_id);
|
||||
require($item->filename);
|
||||
if (function_exists('bolt_divide')) bolt_divide();
|
||||
$next = "<input type=image src=img/next.gif value=OK></form>";
|
||||
break;
|
||||
case BOLT_MODE_ANSWER:
|
||||
require($item->filename);
|
||||
if (function_exists('bolt_divide')) bolt_divide();
|
||||
$score_pct = number_format($bolt_ex->score*100);
|
||||
echo "Score: $score_pct%";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
require_once($item->filename);
|
||||
if (function_exists('bolt_divide')) bolt_divide();
|
||||
}
|
||||
|
||||
if ($repeat) {
|
||||
$avg = number_format($repeat->avg_score*100, 0);
|
||||
echo "<p>Score on this exercise set: $avg%";
|
||||
if ($repeat->flags & REVIEW) {
|
||||
//echo "<pre>";
|
||||
//print_r($repeat);
|
||||
//echo "</pre>";
|
||||
$name = urlencode($repeat->unit->name);
|
||||
$r = "<a href=bolt_sched.php?$url_args&action=review&view_id=$view_id&unit_name=$name>Review, then repeat exercises</a>";
|
||||
$links[] = $r;
|
||||
}
|
||||
if ($repeat->flags & REPEAT) {
|
||||
$r = "<a href=bolt_sched.php?$url_args&action=repeat&view_id=$view_id>Repeat exercises</a>";
|
||||
$links[] = $r;
|
||||
}
|
||||
if ($repeat->flags & NEXT) {
|
||||
$links[] = $next;
|
||||
}
|
||||
} else {
|
||||
$links[] = $next;
|
||||
}
|
||||
|
||||
$up_link = "<a href=bolt_sched.php?$url_args&action=course_home&view_id=$view_id>Course home page</a>";
|
||||
show_nav($links, $up_link, $view_id);
|
||||
|
||||
page_footer();
|
||||
|
||||
if ($refresh) {
|
||||
$refresh->update("last_view_id=$view_id");
|
||||
} else {
|
||||
$e = new BoltEnrollment();
|
||||
$e->user_id = $user->id;
|
||||
$e->course_id = $course->id;
|
||||
$e->update("last_view_id=$view_id");
|
||||
}
|
||||
}
|
||||
|
||||
// Show the student the results of an old exercise; no navigation items
|
||||
//
|
||||
function show_answer_page($iter, $score) {
|
||||
global $bolt_ex;
|
||||
|
||||
$bolt_ex->mode = BOLT_MODE_ANSWER;
|
||||
$bolt_ex->index = 0;
|
||||
|
||||
$item = $iter->item;
|
||||
page_header();
|
||||
$bolt_query_string = $item->query_string;
|
||||
require_once($item->filename);
|
||||
if (function_exists('bolt_divide')) bolt_divide();
|
||||
$score_pct = number_format($score*100);
|
||||
echo "Score: $score_pct%";
|
||||
page_footer();
|
||||
}
|
||||
|
||||
function start_course() {
|
||||
global $user;
|
||||
global $course;
|
||||
global $course_doc;
|
||||
|
||||
BoltEnrollment::delete($user->id, $course->id);
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->at();
|
||||
|
||||
$now = time();
|
||||
$mode = default_mode($iter->item);
|
||||
$view_id = create_view($iter, $mode, 0);
|
||||
BoltEnrollment::insert("(create_time, user_id, course_id, last_view_id) values ($now, $user->id, $course->id, $view_id)");
|
||||
show_item($iter, $view_id, 0, $mode);
|
||||
}
|
||||
|
||||
function start_refresh() {
|
||||
global $course_doc;
|
||||
global $refresh;
|
||||
|
||||
$xset_result = BoltXsetResult::lookup_id($refresh->xset_result_id);
|
||||
if (!$xset_result) error_page("Exercise set result not found");
|
||||
$view = BoltView::lookup_id($xset_result->view_id);
|
||||
if (!$view) error_page("view not found");
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
$xset = $iter->xset;
|
||||
if (!$xset || $xset->name != $xset_result->name) {
|
||||
error_page("missing exercise set");
|
||||
}
|
||||
$xset->restart($iter);
|
||||
$iter->at();
|
||||
$mode = default_mode($iter->item);
|
||||
$view_id = create_view($iter, $mode, 0);
|
||||
show_item($iter, $view_id, 0, $mode);
|
||||
}
|
||||
|
||||
function show_next($iter, $view) {
|
||||
global $refresh, $user, $course;
|
||||
$iter->next();
|
||||
|
||||
if ($refresh) {
|
||||
$iter->at();
|
||||
if (!$iter->xset) {
|
||||
// if we're doing a refresh and are no longer in an xset,
|
||||
// we must have finished the refresh
|
||||
//
|
||||
show_refresh_finished();
|
||||
$refresh->update('count=count+1');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($iter->item) {
|
||||
$state = $iter->encode_state();
|
||||
$mode = default_mode($iter->item);
|
||||
$view_id = create_view($iter, $mode, $view->id);
|
||||
show_item($iter, $view_id, $view->id, $mode);
|
||||
} else {
|
||||
// course finished
|
||||
$iter->frac_done = 1;
|
||||
$fin_view_id = create_view($iter, BOLT_MODE_FINISHED, $view->id);
|
||||
$e = new BoltEnrollment();
|
||||
$e->user_id = $user->id;
|
||||
$e->course_id = $course->id;
|
||||
$e->update("last_view_id=$fin_view_id");
|
||||
show_finished_page($fin_view_id, $view->id);
|
||||
}
|
||||
}
|
||||
|
||||
$user = get_logged_in_user();
|
||||
BoltUser::lookup($user);
|
||||
$course_id = get_int('course_id');
|
||||
$refresh_id = get_int('refresh_id', true);
|
||||
$refresh = null;
|
||||
$url_args = "course_id=$course_id";
|
||||
if ($refresh_id) {
|
||||
$refresh = BoltRefreshRec::lookup_id($refresh_id);
|
||||
if (!$refresh) error_page("No such refresh");
|
||||
if ($refresh->user_id != $user->id) error_page("Wrong user");
|
||||
if ($refresh->course_id != $course_id) error_page("Wrong course");
|
||||
$url_args .= "&refresh_id=$refresh_id";
|
||||
}
|
||||
$course = BoltCourse::lookup_id($course_id);
|
||||
if (!$course) {
|
||||
error_page("no such course");
|
||||
}
|
||||
$view_id = get_int('view_id', true);
|
||||
$action = sanitize_tags(get_str('action', true));
|
||||
$course_doc = require_once($course->doc_file());
|
||||
|
||||
switch ($action) {
|
||||
case 'start':
|
||||
if (info_incomplete($user)) {
|
||||
request_info($user, $course);
|
||||
exit();
|
||||
}
|
||||
if ($refresh) {
|
||||
start_refresh();
|
||||
exit();
|
||||
}
|
||||
$e = BoltEnrollment::lookup($user->id, $course_id);
|
||||
if ($e) {
|
||||
page_header();
|
||||
echo "You are already enrolled in $course->name.
|
||||
<p>
|
||||
Are you sure you want to start over from the beginning?
|
||||
<p>
|
||||
";
|
||||
show_button(
|
||||
"bolt_sched.php?action=start_confirm&$url_args",
|
||||
"Yes",
|
||||
"Start this course from the beginning"
|
||||
);
|
||||
show_button(
|
||||
"bolt_sched.php?action=resume&$url_args",
|
||||
"Resume",
|
||||
"Resume course from current position"
|
||||
);
|
||||
page_footer();
|
||||
exit();
|
||||
}
|
||||
// fall through
|
||||
case 'start_confirm':
|
||||
start_course();
|
||||
break;
|
||||
case 'update_info':
|
||||
update_info();
|
||||
start_course();
|
||||
break;
|
||||
case 'prev':
|
||||
$view = finalize_view($view_id, BOLT_ACTION_PREV);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
if ($view->prev_view_id) {
|
||||
$view = BoltView::lookup_id($view->prev_view_id);
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
$mode = $view->mode;
|
||||
if ($mode == BOLT_MODE_ANSWER) {
|
||||
$v2 = BoltView::lookup_id($view->prev_view_id);
|
||||
$result = BoltResult::lookup_id($v2->result_id);
|
||||
srand($v2->id);
|
||||
$bolt_ex->score = $result->score;
|
||||
$bolt_ex->query_string = $result->response;
|
||||
}
|
||||
$view_id = create_view($iter, $mode, $view->prev_view_id);
|
||||
show_item($iter, $view_id, $view->prev_view_id, $mode);
|
||||
} else {
|
||||
error_page("At start of course");
|
||||
}
|
||||
break;
|
||||
case 'next': // "next" button in lesson or exercise answer page
|
||||
$view = finalize_view($view_id, BOLT_ACTION_NEXT);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
show_next($iter, $view);
|
||||
break;
|
||||
case 'answer': // submit answer in exercise
|
||||
$view = finalize_view($view_id, BOLT_ACTION_SUBMIT);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
|
||||
debug_show_item($iter->item);
|
||||
$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(); // buffer output to avoid showing exercise text
|
||||
require($item->filename);
|
||||
ob_end_clean();
|
||||
|
||||
$bolt_ex->score /= $bolt_ex->index;
|
||||
|
||||
if ($item->callback) {
|
||||
call_user_func(
|
||||
$item->callback, $bolt_ex->score, $bolt_ex->query_string
|
||||
);
|
||||
}
|
||||
|
||||
// make a record of the result
|
||||
|
||||
$qs = BoltDb::escape_string($_SERVER['QUERY_STRING']);
|
||||
$now = time();
|
||||
$result_id = BoltResult::insert(
|
||||
"(create_time, user_id, course_id, view_id, item_name, score, response)
|
||||
values ($now, $user->id, $course->id, $view->id, '$view->item_name', $bolt_ex->score, '$qs')"
|
||||
);
|
||||
$view->update("result_id=$result_id");
|
||||
|
||||
// If this is part of an exercise set, call its callback function
|
||||
//
|
||||
$repeat = null;
|
||||
$xset = $iter->xset;
|
||||
if ($xset) {
|
||||
$is_last = $xset->xset_record_score(
|
||||
$iter, $bolt_ex->score, $view->id, $avg_score, $repeat
|
||||
);
|
||||
if ($repeat) $repeat->avg_score = $avg_score;
|
||||
if ($is_last) {
|
||||
// if the exercise set if finished, make or update DB records
|
||||
//
|
||||
if ($xset->callback) {
|
||||
call_user_func($xset->callback, $avg_score);
|
||||
}
|
||||
$now = time();
|
||||
$id = BoltXsetResult::insert("(create_time, user_id, course_id, name, score, view_id) values ($now, $user->id, $course->id, '$xset->name', $avg_score, $view_id)");
|
||||
$refresh_intervals = $xset->refresh;
|
||||
if ($refresh_intervals) {
|
||||
$refresh_rec = BoltRefreshRec::lookup(
|
||||
"user_id=$user->id and course_id=$course->id and name='$xset->name'"
|
||||
);
|
||||
if ($refresh_rec) {
|
||||
$count = $refresh_rec->count;
|
||||
$n = count($refresh_intervals->intervals);
|
||||
if ($count >= $n) {
|
||||
$count = $n - 1;
|
||||
}
|
||||
$due_time = time() + $refresh_intervals->intervals[$count]*86400;
|
||||
$refresh_rec->update("create_time=$now, xset_result_id=$id, due_time=$due_time");
|
||||
} else {
|
||||
$due_time = time() + $refresh_intervals->intervals[0]*86400;
|
||||
BoltRefreshRec::insert(
|
||||
"(user_id, course_id, name, create_time, xset_result_id, due_time, count) values ($user->id, $course->id, '$xset->name', $now, $id, $due_time, 0)"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show the answer page
|
||||
|
||||
if ($item->has_answer_page) {
|
||||
srand($view_id);
|
||||
$view_id = create_view($iter, BOLT_MODE_ANSWER, $view->id);
|
||||
show_item($iter, $view_id, $view->id, BOLT_MODE_ANSWER, $repeat);
|
||||
} else {
|
||||
show_next($iter, $view);
|
||||
}
|
||||
break;
|
||||
case 'answer_page':
|
||||
$view = BoltView::lookup_id($view_id);
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
if ($iter->item->name != $view->item_name) {
|
||||
error_page("Exercise no longer exists in course");
|
||||
}
|
||||
$result = BoltResult::lookup_id($view->result_id);
|
||||
srand($view_id);
|
||||
$bolt_ex->query_string = $result->response;
|
||||
show_answer_page($iter, $result->score);
|
||||
break;
|
||||
case 'course_home':
|
||||
$view = finalize_view($view_id, BOLT_ACTION_COURSE_HOME);
|
||||
Header("Location: bolt.php");
|
||||
break;
|
||||
case 'review':
|
||||
// user chose to do review then repeat an exercise set
|
||||
//
|
||||
$view = finalize_view($view_id, BOLT_ACTION_REVIEW);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
if (!$iter->xset) {
|
||||
echo "NO XSET"; exit;
|
||||
}
|
||||
$xset = $iter->xset;
|
||||
$unit_name = sanitize_tags(get_str('unit_name'));
|
||||
$found = $xset->start_review($iter, $unit_name);
|
||||
if (!$found) {
|
||||
echo "REVIEW UNIT MISSING"; exit;
|
||||
}
|
||||
$iter->at();
|
||||
$mode = default_mode($iter->item);
|
||||
$view_id = create_view($iter, $mode, $view->id);
|
||||
show_item($iter, $view_id, $view->id, $mode);
|
||||
break;
|
||||
case 'repeat':
|
||||
// user chose to repeat an exercise set
|
||||
//
|
||||
$view = finalize_view($view_id, BOLT_ACTION_REPEAT);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
if (!$iter->xset) {
|
||||
echo "NO XSET"; exit;
|
||||
}
|
||||
$xset = $iter->xset;
|
||||
$xset->restart($iter);
|
||||
$iter->at();
|
||||
$mode = default_mode($iter->item);
|
||||
$view_id = create_view($iter, $mode, $view->id);
|
||||
show_item($iter, $view_id, $view->id, $mode);
|
||||
break;
|
||||
case 'resume':
|
||||
// user chose to resume a course or refresh
|
||||
//
|
||||
if ($refresh) {
|
||||
if ($refresh->last_view_id) {
|
||||
$view = BoltView::lookup_id($refresh->last_view_id);
|
||||
} else {
|
||||
start_refresh();
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
$view = null;
|
||||
$e = BoltEnrollment::lookup($user->id, $course_id);
|
||||
if ($e) {
|
||||
$view = BoltView::lookup_id($e->last_view_id);
|
||||
}
|
||||
if (!$view) {
|
||||
start_course();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($view->mode == BOLT_MODE_FINISHED) {
|
||||
show_finished_page($view->id, $view->prev_view_id);
|
||||
break;
|
||||
}
|
||||
$iter = new BoltIter($course_doc);
|
||||
$iter->decode_state($view->state);
|
||||
$iter->at();
|
||||
$mode = $view->mode;
|
||||
if ($view->item_name == $iter->item->name && ($mode == BOLT_MODE_ANSWER)) {
|
||||
// if we're returning to an answer page,
|
||||
// we need to look up the user's responses and the score.
|
||||
//
|
||||
$view_orig = BoltView::lookup_id($view->prev_view_id);
|
||||
$result = BoltResult::lookup_id($view_orig->result_id);
|
||||
srand($view_orig->id);
|
||||
$bolt_ex->query_string = $result->response;
|
||||
$bolt_ex->score = $result->score;
|
||||
$bolt_ex->index = 0;
|
||||
$view_id = create_view($iter, $mode, $view_orig->id);
|
||||
show_item($iter, $view_id, $view_orig->id, $mode);
|
||||
} else {
|
||||
$view_id = create_view($iter, $mode, $view->id);
|
||||
show_item($iter, $view_id, $view->id, $mode);
|
||||
}
|
||||
break;
|
||||
case 'question':
|
||||
$view = finalize_view($view_id, BOLT_ACTION_QUESTION);
|
||||
debug_show_state(unserialize($view->state), "Initial");
|
||||
$now = time();
|
||||
$question = BoltDb::escape_string(get_str('question'));
|
||||
BoltQuestion::insert("(create_time, user_id, course_id, name, mode, question, state) values ($now, $user->id, $course->id, '$view->item_name', $view->mode, '$question', 0)");
|
||||
page_header();
|
||||
echo "
|
||||
Thanks; we have recorded your question.
|
||||
Questions help us improve this course.
|
||||
We aren't able to individually respond to all questions.
|
||||
Responses are delivered as private messages.
|
||||
<p>
|
||||
<a href=bolt_sched.php?$url_args&action=resume>Resume course</a>
|
||||
";
|
||||
page_footer();
|
||||
break;
|
||||
default:
|
||||
error_page("unknown action: $action");
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/bolt_db.inc");
|
||||
|
||||
function show_app($app) {
|
||||
global $user;
|
||||
if ($app->bolt_course_id) {
|
||||
if ($user) {
|
||||
switch (bolt_course_status($app->bolt_course_id, $user->id)) {
|
||||
case BOLT_COURSE_NOT_STARTED:
|
||||
$x = "<a href=bolt_sched.php?action=start&course_id=$app->bolt_course_id>Take training course</a>";
|
||||
break;
|
||||
case BOLT_COURSE_STARTED:
|
||||
$x = "<a href=bolt_sched.php?action=resume&course_id=$app->bolt_course_id>Finish training course</a>";
|
||||
break;
|
||||
case BOLT_COURSE_FINISHED:
|
||||
$x = "<a href=bossa_get_job.php?bossa_app_id=$app->id>Get job</a>";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$x = "<a href=bolt_sched.php?action=start&course_id=$app->bolt_course_id>Take training course</a>";
|
||||
}
|
||||
} else {
|
||||
$x = "<a href=bossa_get_job.php?bossa_app_id=$app->id>Get job</a>";
|
||||
}
|
||||
$est = number_format($app->time_estimate/60., 2);
|
||||
$limit = number_format($app->time_limit/60., 2);
|
||||
row2("$app->name<br><p class=\"text-muted\">$app->description<br>Time: $est min. average, $limit min limit</p>", $x);
|
||||
}
|
||||
|
||||
function show_apps() {
|
||||
$apps = BossaApp::enum();
|
||||
foreach ($apps as $app) {
|
||||
if ($app->hidden) continue;
|
||||
show_app($app);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
page_head("Bossa apps");
|
||||
start_table();
|
||||
show_apps();
|
||||
end_table();
|
||||
page_tail();
|
||||
}
|
||||
|
||||
$user = get_logged_in_user();
|
||||
|
||||
main();
|
||||
|
||||
?>
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa.inc");
|
||||
require_once("../inc/bossa_example4.inc");
|
||||
|
||||
function handle_add($job, $inst) {
|
||||
$f = null;
|
||||
$f->x = get_int('pic_x');
|
||||
$f->y = get_int('pic_y');
|
||||
$f->type = sanitize_tags(get_str('type'));
|
||||
$c = sanitize_tags(get_str('comment', true));
|
||||
if (strstr($c, "(optional)")) $c = "";
|
||||
$f->comment = $c;
|
||||
$output = $inst->get_opaque_data();
|
||||
$output->features[] = $f;
|
||||
$inst->set_opaque_data($output);
|
||||
header("location: bossa_example4.php?bji=$inst->id");
|
||||
}
|
||||
|
||||
function handle_delete($job, $inst, $index) {
|
||||
$output = $inst->get_opaque_data();
|
||||
$features = $output->features;
|
||||
array_splice($features, $index, 1);
|
||||
$output->features = $features;
|
||||
$inst->set_opaque_data($output);
|
||||
header("location: bossa_example4.php?bji=$inst->id");
|
||||
}
|
||||
|
||||
$bji = get_int("bji");
|
||||
if (!bossa_lookup_job($bji, $job, $inst, $u)) {
|
||||
error_page("No such instance");
|
||||
}
|
||||
$user = get_logged_in_user();
|
||||
if ($u->id != $user->id) {
|
||||
error_page("Not your job");
|
||||
}
|
||||
|
||||
$action = get_str("action", true);
|
||||
switch ($action) {
|
||||
case "add":
|
||||
handle_add($job, $inst);
|
||||
break;
|
||||
case "delete":
|
||||
$index = get_int("index");
|
||||
handle_delete($job, $inst, $index);
|
||||
break;
|
||||
default:
|
||||
job_show($job, $inst, $user);
|
||||
break;
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/bossa_impl.inc");
|
||||
|
||||
$user = get_logged_in_user();
|
||||
BossaUser::lookup($user);
|
||||
|
||||
$bossa_app_id = get_int('bossa_app_id');
|
||||
$app = BossaApp::lookup_id($bossa_app_id);
|
||||
|
||||
if (!$app) {
|
||||
error_page("no such app: $bossa_app_id");
|
||||
}
|
||||
|
||||
{
|
||||
$trans = new BossaTransaction();
|
||||
show_next_job($app, $user);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
// 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/>.
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/bossa_impl.inc");
|
||||
|
||||
$user = get_logged_in_user();
|
||||
$inst = BossaJobInst::lookup_id(get_int('bji'));
|
||||
if (!$inst) {
|
||||
error_page("No such job instance");
|
||||
}
|
||||
if ($inst->user_id != $user->id) {
|
||||
error_page("Bad user ID");
|
||||
}
|
||||
if ($inst->finish_time) {
|
||||
error_page("You already finished this job");
|
||||
}
|
||||
$job = BossaJob::lookup_id($inst->job_id);
|
||||
if (!$job) {
|
||||
error_page("No such job");
|
||||
}
|
||||
|
||||
$app = BossaApp::lookup_id($job->app_id);
|
||||
$file = "../inc/$app->short_name.inc";
|
||||
require_once($file);
|
||||
|
||||
{
|
||||
$trans = new BossaTransaction();
|
||||
|
||||
$now = time();
|
||||
$inst->update("finish_time=$now, timeout=0");
|
||||
|
||||
BossaUser::lookup($user);
|
||||
job_finished($job, $inst, $user);
|
||||
show_next_job($app, $user);
|
||||
}
|
||||
|
||||
?>
|
Loading…
Reference in New Issue