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->update_info($response);
if ($job->calibration) {
$b = $user->bossa;
$info = $job->get_info();
$answer = $info->answer;
$u = $b->get_info();
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->update_info($u);
return;
}
// see if job is done
//
$insts = $job->get_finished_instances();
$n = count($insts);
$results = null;
$users = null;
foreach ($insts as $inst) {
$results[] = $inst->get_info();
$u = $inst->get_user();
$users[] = $u->bossa->get_info();
}
// 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->update_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->update_state(BOSSA_JOB_DONE);
return;
}
}
// see if there are too many instances without a consensus
//
if ($n >= 10) {
$job->update_state(BOSSA_JOB_INCONCLUSIVE);
return;
}
}
function user_summary($user) {
$b = $user->bossa;
$info = $b->get_info();
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";
}
}