--- loncom/homework/grades.pm	2007/06/13 17:20:12	1.399.2.1
+++ loncom/homework/grades.pm	2007/06/22 22:50:30	1.417
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.399.2.1 2007/06/13 17:20:12 albertel Exp $
+# $Id: grades.pm,v 1.417 2007/06/22 22:50:30 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -41,7 +41,6 @@ use Apache::Constants qw(:common);
 use Apache::lonlocal;
 use Apache::lonenc;
 use String::Similarity;
-use lib '/home/httpd/lib/perl';
 use LONCAPA;
 
 use POSIX qw(floor);
@@ -180,7 +179,7 @@ sub showResourceInfo {
 		if (exists($partsseen{$partID})) {
 		    $result.="<td>&nbsp;</td>";
 		} else {
-		    $result.="<td><input type='checkbox' name='vPart' value='$partID' checked='on' /></td>";
+		    $result.="<td><input type='checkbox' name='vPart' value='$partID' checked='checked' /></td>";
 		}
 		$partsseen{$partID}=1;
 	    }
@@ -618,7 +617,7 @@ sub verifyreceipt {
 	    if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) {
 		$contents.='<tr bgcolor="#ffffe6"><td>&nbsp;'."\n".
 		    '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
-		    '\')"; TARGET=_self>'.$$fullname{$_}.'</a>&nbsp;</td>'."\n".
+		    '\');" target="_self">'.$$fullname{$_}.'</a>&nbsp;</td>'."\n".
 		    '<td>&nbsp;'.$uname.'&nbsp;</td>'.
 		    '<td>&nbsp;'.$udom.'&nbsp;</td>';
 		if ($receiptparts) {
@@ -708,16 +707,16 @@ LISTJAVASCRIPT
     &commonJSfunctions($request);
     $request->print($result);
 
-    my $checkhdgrade = ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked' : '';
-    my $checklastsub = $checkhdgrade eq '' ? 'checked' : '';
+    my $checkhdgrade = ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked="checked"' : '';
+    my $checklastsub = $checkhdgrade eq '' ? 'checked="checked"' : '';
     my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'.
 	"\n".$table.
-	'&nbsp;<b>View Problem Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
+	'&nbsp;<b>View Problem Text: </b><label><input type="radio" name="vProb" value="no" checked="checked" /> no </label>'."\n".
 	'<label><input type="radio" name="vProb" value="yes" /> one student </label>'."\n".
 	'<label><input type="radio" name="vProb" value="all" /> all students </label><br />'."\n".
 	'&nbsp;<b>View Answer: </b><label><input type="radio" name="vAns" value="no"  /> no </label>'."\n".
 	'<label><input type="radio" name="vAns" value="yes" /> one student </label>'."\n".
-	'<label><input type="radio" name="vAns" value="all" checked="on" /> all students </label><br />'."\n".
+	'<label><input type="radio" name="vAns" value="all" checked="checked" /> all students </label><br />'."\n".
 	'&nbsp;<b>Submissions: </b>'."\n";
     if ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) {
 	$gradeTable.='<label><input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> essay part only </label>'."\n";
@@ -763,7 +762,7 @@ LISTJAVASCRIPT
 	'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n".
 	'value="Next->" /> <br />'."\n";
     $gradeTable.=&check_buttons();
-    $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="on" />Check For Plagiarism</label>';
+    $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="checked" />Check For Plagiarism</label>';
     my ($classlist, undef, $fullname) = &getclasslist($getsec,'1');
     $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'.
 	'<table border="0"><tr bgcolor="#e6ffff">';
@@ -1501,7 +1500,7 @@ sub gradeBox {
 	$result.= '<td><span style="white-space: nowrap;"><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
 	    'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','.
 	    $thisweight.')" value="'.$thisweight.'" '.
-	    ($score eq $thisweight ? 'checked':'').' /> '.$thisweight."</label></span></td>\n";
+	    ($score eq $thisweight ? 'checked="checked"':'').' /> '.$thisweight."</label></span></td>\n";
 	$result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
         $thisweight += $increment;
 	$ctr++;
@@ -1519,9 +1518,9 @@ sub gradeBox {
 	'onChange="javascript:clearRadBox(this.form,\''.$counter.'_'.$partid.'\')" >'."\n";
     if ($$record{'resource.'.$partid.'.solved'} eq 'excused') {
 	$result.='<option></option>'.
-	    '<option selected="on">excused</option>';
+	    '<option selected="selected">excused</option>';
     } else {
-	$result.='<option selected="on"></option>'.
+	$result.='<option selected="selected"></option>'.
 	    '<option>excused</option>';
     }
     $result.='<option>reset status</option></select>'."\n";
@@ -1793,10 +1792,10 @@ sub submission {
 #
 	    $request->print(<<KEYWORDS);
 &nbsp;<b>Keyword Options:</b>&nbsp;
-<a href="javascript:keywords(document.SCORE)"; TARGET=_self>List</a>&nbsp; &nbsp;
+<a href="javascript:keywords(document.SCORE);" target="_self">List</a>&nbsp; &nbsp;
 <a href="#" onMouseDown="javascript:getSel(); return false"
  CLASS="page">Paste Selection to List</a>&nbsp; &nbsp;
-<a href="javascript:kwhighlight()"; TARGET=_self>Highlight Attribute</a><br /><br />
+<a href="javascript:kwhighlight();" target="_self">Highlight Attribute</a><br /><br />
 KEYWORDS
 #
 # Load the other essays for similarity check
@@ -1922,7 +1921,7 @@ KEYWORDS
 			' <b>Collaborative submission by:</b> '.
 			'<a href="javascript:viewSubmitter(\''.
 			$env{"form.$uname:$udom:$partid:submitted_by"}.
-			'\')"; TARGET=_self>'.
+			'\');" target="_self">'.
 			$$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a><br />';
 		    $request->print($submitby);
 		    next;
@@ -2000,7 +1999,7 @@ KEYWORDS
     if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) {
 	my $toGrade.='<input type="button" value="Grade Student" '.
 	    'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''
-	    .$counter.'\');" TARGET=_self> &nbsp;'."\n" if (&canmodify($usec));
+	    .$counter.'\');" target="_self" /> &nbsp;'."\n" if (&canmodify($usec));
 	$toGrade.='</td></tr></table></td></tr></table>'."\n";
 	if (($env{'form.command'} eq 'submission') || 
 	    ($env{'form.command'} eq 'processGroup' && $counter == $total)) {
@@ -2024,7 +2023,7 @@ KEYWORDS
 	$result='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n".
 	    '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";
 	$result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
-	    ',\''.$msgfor.'\')"; TARGET=_self>'.
+	    ',\''.$msgfor.'\');" target="_self">'.
 	    &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a><label> ('.
 	    &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'.
 	    '<img src="'.$request->dir_config('lonIconsURL').
@@ -2076,18 +2075,18 @@ KEYWORDS
 	my $endform='<table border="0"><tr><td>'."\n";
 	$endform.='<input type="button" value="Save & Next" '.
 	    'onClick="javascript:checksubmit(this.form,\'Save & Next\','.
-	    $total.','.scalar(@partlist).');" TARGET=_self> &nbsp;'."\n";
+	    $total.','.scalar(@partlist).');" target="_self" /> &nbsp;'."\n";
 	my $ntstu ='<select name="NTSTU">'.
 	    '<option>1</option><option>2</option>'.
 	    '<option>3</option><option>5</option>'.
 	    '<option>7</option><option>10</option></select>'."\n";
 	my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1');
-	$ntstu =~ s/<option>$nsel</<option selected="on">$nsel</;
+	$ntstu =~ s/<option>$nsel</<option selected="selected">$nsel</;
 	$endform.=$ntstu.'student(s) &nbsp;&nbsp;';
 	$endform.='<input type="button" value="Previous" '.
-	    'onClick="javascript:checksubmit(this.form,\'Previous\');" TARGET=_self> &nbsp;'."\n".
+	    'onClick="javascript:checksubmit(this.form,\'Previous\');" target="_self" /> &nbsp;'."\n".
 	    '<input type="button" value="Next" '.
-	    'onClick="javascript:checksubmit(this.form,\'Next\');" TARGET=_self> &nbsp;';
+	    'onClick="javascript:checksubmit(this.form,\'Next\');" target="_self" /> &nbsp;';
 	$endform.='(Next and Previous (student) do not save the scores.)'."\n" ;
         $endform.="<input type='hidden' value='".&get_increment().
             "' name='increment' />";
@@ -2565,7 +2564,7 @@ sub handback_files {
             	                                $newflg.'_'.$part_resp.'_returndoc'.$file_counter,
             	                                $save_file_name);
                     if ($result !~ m|^/uploaded/|) {
-                        $request->print('<span class="LC_error">An errror occured ('.$result.
+                        $request->print('<span class="LC_error">An error occurred ('.$result.
                         ') while trying to upload '.$newflg.'_'.$part_resp.'_returndoc'.$file_counter.'</span><br />');
                     } else {
                         # mark the file as read only
@@ -3028,7 +3027,7 @@ sub viewgrades {
 	$result.= '</td><td><select name="SELVAL_'.$partid.'"'.
 	    'onChange="javascript:writeRadText(\''.$partid.'\','.
 		$weight{$partid}.')"> '.
-	    '<option selected="on"> </option>'.
+	    '<option selected="selected"> </option>'.
 	    '<option>excused</option>'.
 	    '<option>reset status</option></select></td>'.
             '<td><label><input type="checkbox" name="FORCE_'.$partid.'" /> Override "Correct"</label></td></tr>'."\n";
@@ -3037,7 +3036,7 @@ sub viewgrades {
     $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n".
 	'<input type="hidden" name="totalparts" value="'.$ctsparts.'" />';
     $result.='<input type="button" value="Revert to Default" '.
-	'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self>';
+	'onClick="javascript:resetEntry('.$ctsparts.');" target="_self" />';
 
     #table listing all the students in a section/class
     #header of table
@@ -3088,7 +3087,7 @@ sub viewgrades {
     $result.='</table></td></tr></table>';
     $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";
     $result.='<input type="button" value="Save" '.
-	'onClick="javascript:submit();" TARGET=_self /></form>'."\n";
+	'onClick="javascript:submit();" target="_self" /></form>'."\n";
     if (scalar(%$fullname) eq 0) {
 	my $colspan=3+scalar(@parts);
 	$result='<span class="LC_warning">There are no students in section "'.$env{'form.section'}.
@@ -3108,7 +3107,7 @@ sub viewstudentgrade {
 	'<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'.
 	"\n".$ctr.'&nbsp;</td><td>&nbsp;'.
 	'<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
-	'\')"; TARGET=_self>'.$fullname.'</a> '.
+	'\');" target="_self">'.$fullname.'</a> '.
 	'<span class="LC_internal_info">('.$uname.($env{'user.domain'} eq $udom ? '' : ':'.$udom).')</span></td>'."\n";
     $student=~s/:/_/; # colon doen't work in javascript for names
     foreach my $apart (@$parts) {
@@ -3146,8 +3145,8 @@ sub viewstudentgrade {
 	    $result.='&nbsp;<select name="'.
 		'GD_'.$student.'_'.$part.'_solved" '.
 		'onChange="javascript:changeOneScore(\''.$part.'\',\''.$student.'\')" >'."\n";
-	    $result.= (($status eq 'excused') ? '<option> </option><option selected="on">excused</option>' 
-		: '<option selected="on"> </option><option>excused</option>')."\n";
+	    $result.= (($status eq 'excused') ? '<option> </option><option selected="selected">excused</option>' 
+		: '<option selected="selected"> </option><option>excused</option>')."\n";
 	    $result.='<option>reset status</option>';
 	    $result.="</select>&nbsp;</td>\n";
 	} else {
@@ -3848,7 +3847,7 @@ LISTJAVASCRIPT
     foreach (@$titles) {
 	my ($minder,$showtitle) = ($_ =~ /(\d+)\.(.*)/);
 	$result.='<option value="'.$ctr.'" '.
-	    ($$symbx{$_} =~ /$curpage$/ ? 'selected="on"' : '').
+	    ($$symbx{$_} =~ /$curpage$/ ? 'selected="selected"' : '').
 	    '>'.$showtitle.'</option>'."\n";
 	$ctr++;
     }
@@ -3863,12 +3862,12 @@ LISTJAVASCRIPT
     $result.='<input type="hidden" name="page" />'."\n".
 	'<input type="hidden" name="title" />'."\n";
 
-    $result.='&nbsp;<b>View Problems Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
+    $result.='&nbsp;<b>View Problems Text: </b><label><input type="radio" name="vProb" value="no" checked="checked" /> no </label>'."\n".
 	'<label><input type="radio" name="vProb" value="yes" /> yes </label>'."<br />\n";
 
     $result.='&nbsp;<b>Submission Details: </b>'.
 	'<label><input type="radio" name="lastSub" value="none" /> none</label>'."\n".
-	'<label><input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions</label>'."\n".
+	'<label><input type="radio" name="lastSub" value="datesub" checked="checked" /> by dates and submissions</label>'."\n".
 	'<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
 
     $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
@@ -4384,7 +4383,7 @@ sub getSequenceDropDown {
     foreach (@$titles) {
 	my ($minder,$showtitle) = ($_ =~ /(\d+)\.(.*)/);
 	$result.='<option value="'.$$symbx{$_}.'" '.
-	    ($$symbx{$_} =~ /$curpage$/ ? 'selected="on"' : '').
+	    ($$symbx{$_} =~ /$curpage$/ ? 'selected="selected"' : '').
 	    '>'.$showtitle.'</option>'."\n";
 	$ctr++;
     }
@@ -4412,7 +4411,7 @@ sub scantron_uploads {
     my $result=	'<select name="scantron_selectfile">';
     $result.="<option></option>";
     foreach my $filename (sort(&scantron_filenames())) {
-	$result.="<option".($filename eq $file2grade ? ' selected="on"':'').">$filename</option>\n";
+	$result.="<option".($filename eq $file2grade ? ' selected="selected"':'').">$filename</option>\n";
     }
     $result.="</select>";
     return $result;
@@ -4963,7 +4962,7 @@ sub remember_current_skipped {
 sub check_for_error {
     my ($r,$result)=@_;
     if ($result ne 'ok' && $result ne 'not_found' ) {
-	$r->print("An error occured ($result) when trying to Remove the existing corrections.");
+	$r->print("An error occurred ($result) when trying to Remove the existing corrections.");
     }
 }
 
@@ -5425,7 +5424,7 @@ sub scantron_get_correction {
 	    if ($closest > 0) {
 		foreach my $testcode (@{$closest}) {
 		    my $checked='';
-		    if (!$i) { $checked=' checked="on" '; }
+		    if (!$i) { $checked=' checked="checked" '; }
 		    $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_closest_$i' $checked /> Use the similar CODE <b><tt>".$testcode."</tt></b> instead.</label><input type='hidden' name='scantron_CODE_closest_$i' value='$testcode' />");
 		    $r->print("\n<br />");
 		    $i++;
@@ -5433,7 +5432,7 @@ sub scantron_get_correction {
 	    }
 	}
 	if ($$scan_record{'scantron.CODE'}=~/\S/ ) {
-	    my $checked; if (!$i) { $checked=' checked="on" '; }
+	    my $checked; if (!$i) { $checked=' checked="checked" '; }
 	    $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_unfound' $checked /> Use the CODE <b><tt>".$$scan_record{'scantron.CODE'}."</tt></b> that is was on the paper, ignoring the error.</label>");
 	    $r->print("\n<br />");
 	}
@@ -6033,38 +6032,38 @@ GRADINGMENUJS
     if (ref($sections)) {
 	foreach (sort (@$sections)) {
 	    $result.='<option value="'.$_.'" '.
-		($saveSec eq $_ ? 'selected="on"':'').'>'.$_.'</option>'."\n";
+		($saveSec eq $_ ? 'selected="selected"':'').'>'.$_.'</option>'."\n";
 	}
     }
-    $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</option></select> &nbsp; ';
+    $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="selected"' : ''). '>all</option></select> &nbsp; ';
 
-    $result.=&mt('Student Status').':</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
+    $result.=&mt('Student Status').':'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
 
     $result.='</td></tr>';
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td><label>'.
 	'<input type="radio" name="radioChoice" value="submission" '.
-	($saveCmd eq 'submission' ? 'checked' : '').' /> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
+	($saveCmd eq 'submission' ? 'checked="checked"' : '').' /> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
 	'</label> <select name="submitonly">'.
 	'<option value="yes" '.
-	($saveSub eq 'yes' ? 'selected="on"' : '').' />'.&mt('with submissions').'</option>'.
+	($saveSub eq 'yes' ? 'selected="selected"' : '').'>'.&mt('with submissions').'</option>'.
 	'<option value="queued" '.
-	($saveSub eq 'queued' ? 'selected="on"' : '').' />'.&mt('in grading queue').'</option>'.
+	($saveSub eq 'queued' ? 'selected="selected"' : '').'>'.&mt('in grading queue').'</option>'.
 	'<option value="graded" '.
-	($saveSub eq 'graded' ? 'selected="on"' : '').' />'.&mt('with ungraded submissions').'</option>'.
+	($saveSub eq 'graded' ? 'selected="selected"' : '').'>'.&mt('with ungraded submissions').'</option>'.
 	'<option value="incorrect" '.
-	($saveSub eq 'incorrect' ? 'selected="on"' : '').' />'.&mt('with incorrect submissions').'</option>'.
+	($saveSub eq 'incorrect' ? 'selected="selected"' : '').'>'.&mt('with incorrect submissions').'</option>'.
 	'<option value="all" '.
-	($saveSub eq 'all' ? 'selected="on"' : '').' />'.&mt('with any status').'</option></select></td></tr>'."\n";
+	($saveSub eq 'all' ? 'selected="selected"' : '').'>'.&mt('with any status').'</option></select></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
 	'<label><input type="radio" name="radioChoice" value="viewgrades" '.
-	($saveCmd eq 'viewgrades' ? 'checked' : '').' /> '.
+	($saveCmd eq 'viewgrades' ? 'checked="checked"' : '').' /> '.
 	'<b>Current Resource:</b> For all students in selected section or course</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.
 	'<label><input type="radio" name="radioChoice" value="pickStudentPage" '.
-	($saveCmd eq 'pickStudentPage' ? 'checked' : '').' /> '.
+	($saveCmd eq 'pickStudentPage' ? 'checked="checked"' : '').' /> '.
 	'The <b>complete</b> set/page/sequence: For one student</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"><td><br />'.
@@ -6078,6 +6077,10 @@ GRADINGMENUJS
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'3\',\'csvform\');" value="'.&mt('Upload').'" />'.
 	' '.&mt('scores from file').' </td></tr>'."\n";
 
+    $result.='<tr bgcolor="#ffffe6"><td>'.
+        '<input type="button" onClick="javascript:checkChoice(this.form,\'6\',\'processclicker\');" value="'.&mt('Process').'" />'.
+        ' '.&mt('clicker file').' </td></tr>'."\n";
+
     $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'.
 	'" value="'.&mt('Grade').'" /> scantron forms</td></tr>'."\n";
@@ -6097,9 +6100,9 @@ GRADINGMENUJS
 	'<input type="button" onClick="javascript:this.form.command.value=\'codelist\';this.form.action=\'/adm/pickcode\';this.form.submit();'.
 	'" value="'.&mt('View').'" /> saved CODEs.</td></tr>'."\n";
 
-    $result.='</form></td></tr></table>'."\n".
+    $result.='</table>'."\n".
 	'</td></tr></table>'."\n".
-	'</td></tr></table>'."\n";
+	'</td></tr></table></form>'."\n";
     return $result;
 }
 
@@ -6125,6 +6128,420 @@ sub init_perm {
     }
 }
 
+sub gather_clicker_ids {
+    my %clicker_ids;
+
+    my $classlist = &Apache::loncoursedata::get_classlist();
+
+    # Set up a couple variables.
+    my $username_idx = &Apache::loncoursedata::CL_SNAME();
+    my $domain_idx   = &Apache::loncoursedata::CL_SDOM();
+
+    foreach my $student (keys(%$classlist)) {
+
+        my $username = $classlist->{$student}->[$username_idx];
+        my $domain   = $classlist->{$student}->[$domain_idx];
+        my $clickers =
+	    (&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1];
+        foreach my $id (split(/\,/,$clickers)) {
+            $id=~s/^[\#0]+//;
+            if (exists($clicker_ids{$id})) {
+		$clicker_ids{$id}.=','.$username.':'.$domain;
+            } else {
+		$clicker_ids{$id}=$username.':'.$domain;
+            }
+        }
+    }
+    return %clicker_ids;
+}
+
+sub gather_adv_clicker_ids {
+    my %clicker_ids;
+    my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'};
+    my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
+    my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum);
+    foreach my $element (sort(keys(%coursepersonnel))) {
+        foreach my $person (split(/\,/,$coursepersonnel{$element})) {
+            my ($puname,$pudom)=split(/\:/,$person);
+            my $clickers =
+		(&Apache::lonnet::userenvironment($pudom,$puname,'clickers'))[1];
+            foreach my $id (split(/\,/,$clickers)) {
+		$id=~s/^[\#0]+//;
+		if (exists($clicker_ids{$id})) {
+		    $clicker_ids{$id}.=','.$puname.':'.$pudom;
+		} else {
+		    $clicker_ids{$id}=$puname.':'.$pudom;
+		}
+            }
+        }
+    }
+    return %clicker_ids;
+}
+
+sub clicker_grading_parameters {
+    return ('gradingmechanism' => 'scalar',
+            'upfiletype' => 'scalar',
+            'specificid' => 'scalar',
+            'pcorrect' => 'scalar',
+            'pincorrect' => 'scalar');
+}
+
+sub process_clicker {
+    my ($r)=@_;
+    my ($symb)=&get_symb($r);
+    if (!$symb) {return '';}
+    my $result=&checkforfile_js();
+    $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb);
+    my ($table) = &showResourceInfo($symb,$env{'form.probTitle'});
+    $result.=$table;
+    $result.='<br /><table width="100%" border="0"><tr><td bgcolor="#777777">'."\n";
+    $result.='<table width="100%" border="0"><tr bgcolor="#e6ffff"><td>'."\n";
+    $result.='&nbsp;<b>'.&mt('Specify a file containing the clicker information for this resource').
+        '.</b></td></tr>'."\n";
+    $result.='<tr bgcolor=#ffffe6><td>'."\n";
+# Attempt to restore parameters from last session, set defaults if not present
+    my %Saveable_Parameters=&clicker_grading_parameters();
+    &Apache::loncommon::restore_course_settings('grades_clicker',
+                                                 \%Saveable_Parameters);
+    if (!$env{'form.pcorrect'}) { $env{'form.pcorrect'}=100; }
+    if (!$env{'form.pincorrect'}) { $env{'form.pincorrect'}=100; }
+    if (!$env{'form.gradingmechanism'}) { $env{'form.gradingmechanism'}='attendance'; }
+    if (!$env{'form.upfiletype'}) { $env{'form.upfiletype'}='iclicker'; }
+
+    my %checked;
+    foreach my $gradingmechanism ('attendance','personnel','specific') {
+       if ($env{'form.gradingmechanism'} eq $gradingmechanism) {
+          $checked{$gradingmechanism}="checked='checked'";
+       }
+    }
+
+    my $upload=&mt("Upload File");
+    my $type=&mt("Type");
+    my $attendance=&mt("Award points just for participation");
+    my $personnel=&mt("Correctness determined from response by course personnel");
+    my $specific=&mt("Correctness determined from response with clicker ID(s)"); 
+    my $pcorrect=&mt("Percentage points for correct solution");
+    my $pincorrect=&mt("Percentage points for incorrect solution");
+    my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
+						   ('iclicker' => 'i>clicker'));
+
+    $result.=<<ENDUPFORM;
+<script type="text/javascript">
+function sanitycheck() {
+// Accept only integer percentages
+   document.forms.gradesupload.pcorrect.value=Math.round(document.forms.gradesupload.pcorrect.value);
+   document.forms.gradesupload.pincorrect.value=Math.round(document.forms.gradesupload.pincorrect.value);
+// Find out grading choice
+   for (i=0; i<document.forms.gradesupload.gradingmechanism.length; i++) {
+      if (document.forms.gradesupload.gradingmechanism[i].checked) {
+         gradingchoice=document.forms.gradesupload.gradingmechanism[i].value;
+      }
+   }
+// By default, new choice equals user selection
+   newgradingchoice=gradingchoice;
+// Not good to give more points for false answers than correct ones
+   if (Math.round(document.forms.gradesupload.pcorrect.value)<Math.round(document.forms.gradesupload.pincorrect.value)) {
+      document.forms.gradesupload.pcorrect.value=document.forms.gradesupload.pincorrect.value;
+   }
+// If new choice is attendance only, and old choice was correctness-based, restore defaults
+   if ((gradingchoice=='attendance') && (document.forms.gradesupload.waschecked.value!='attendance')) {
+      document.forms.gradesupload.pcorrect.value=100;
+      document.forms.gradesupload.pincorrect.value=100;
+   }
+// If the values are different, cannot be attendance only
+   if ((Math.round(document.forms.gradesupload.pcorrect.value)!=Math.round(document.forms.gradesupload.pincorrect.value)) &&
+       (gradingchoice=='attendance')) {
+       newgradingchoice='personnel';
+   }
+// Change grading choice to new one
+   for (i=0; i<document.forms.gradesupload.gradingmechanism.length; i++) {
+      if (document.forms.gradesupload.gradingmechanism[i].value==newgradingchoice) {
+         document.forms.gradesupload.gradingmechanism[i].checked=true;
+      } else {
+         document.forms.gradesupload.gradingmechanism[i].checked=false;
+      }
+   }
+// Remember the old state
+   document.forms.gradesupload.waschecked.value=newgradingchoice;
+}
+</script>
+<form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
+<input type="hidden" name="symb" value="$symb" />
+<input type="hidden" name="command" value="processclickerfile" />
+<input type="hidden" name="probTitle" value="$env{'form.probTitle'}" />
+<input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
+<input type="file" name="upfile" size="50" />
+<br /><label>$type: $selectform</label>
+<br /><label>$attendance: <input type="radio" name="gradingmechanism" value="attendance" $checked{'attendance'} onClick="sanitycheck()" /></label>
+<br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" $checked{'personnel'} onClick="sanitycheck()" /></label>
+<br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" $checked{'specific'} onClick="sanitycheck()" /></label>
+<input type="text" name="specificid" value="$env{'form.specificid'}" size="20" />
+<input type="hidden" name="waschecked" value="$env{'form.gradingmechanism'}" />
+<br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="$env{'form.pcorrect'}" onChange="sanitycheck()" /></label>
+<br /><label>$pincorrect: <input type="text" name="pincorrect" size="4" value="$env{'form.pincorrect'}" onChange="sanitycheck()" /></label>
+<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="$upload" />
+</form>
+ENDUPFORM
+    $result.='</td></tr></table>'."\n".
+             '</td></tr></table><br /><br />'."\n";
+    $result.=&show_grading_menu_form($symb);
+    return $result;
+}
+
+sub process_clicker_file {
+    my ($r)=@_;
+    my ($symb)=&get_symb($r);
+    if (!$symb) {return '';}
+
+    my %Saveable_Parameters=&clicker_grading_parameters();
+    &Apache::loncommon::store_course_settings('grades_clicker',
+                                              \%Saveable_Parameters);
+
+    my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
+    if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) {
+	$result.='<span class="LC_error">'.&mt('You need to specify a clicker ID for the correct answer').'</span>';
+	return $result.&show_grading_menu_form($symb);
+    }
+    my %clicker_ids=&gather_clicker_ids();
+    my %correct_ids;
+    if ($env{'form.gradingmechanism'} eq 'personnel') {
+	%correct_ids=&gather_adv_clicker_ids();
+    }
+    if ($env{'form.gradingmechanism'} eq 'specific') {
+	foreach my $correct_id (split(/[\s\,]/,$env{'form.specificid'})) {;
+	   $correct_id=~tr/a-z/A-Z/;
+	   $correct_id=~s/\s//gs;
+	   $correct_id=~s/^[\#0]+//;
+           if ($correct_id) {
+	      $correct_ids{$correct_id}='specified';
+           }
+        }
+    }
+    if ($env{'form.gradingmechanism'} eq 'attendance') {
+	$result.=&mt('Score based on attendance only');
+    } else {
+	my $number=0;
+	$result.='<p><b>'.&mt('Correctness determined by the following IDs').'</b>';
+	foreach my $id (sort(keys(%correct_ids))) {
+	    $result.='<br /><tt>'.$id.'</tt> - ';
+	    if ($correct_ids{$id} eq 'specified') {
+		$result.=&mt('specified');
+	    } else {
+		my ($uname,$udom)=split(/\:/,$correct_ids{$id});
+		$result.=&Apache::loncommon::plainname($uname,$udom);
+	    }
+	    $number++;
+	}
+        $result.="</p>\n";
+	if ($number==0) {
+	    $result.='<span class="LC_error">'.&mt('No IDs found to determine correct answer').'</span>';
+	    return $result.&show_grading_menu_form($symb);
+	}
+    }
+    if (length($env{'form.upfile'}) < 2) {
+        $result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.',
+		     '<span class="LC_error">',
+		     '</span>',
+		     '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>');
+        return $result.&show_grading_menu_form($symb);
+    }
+
+# Were able to get all the info needed, now analyze the file
+
+    $result.=&Apache::loncommon::studentbrowser_javascript();
+    my $heading=&mt('Scanning clicker file');
+    $result.=(<<ENDHEADER);
+<br /><table width="100%" border="0"><tr><td bgcolor="#777777">
+<table width="100%" border="0"><tr bgcolor="#e6ffff"><td>
+<b>$heading</b></td></tr><tr bgcolor=#ffffe6><td>
+<form method="post" action="/adm/grades" name="clickeranalysis">
+<input type="hidden" name="symb" value="$symb" />
+<input type="hidden" name="command" value="assignclickergrades" />
+<input type="hidden" name="probTitle" value="$env{'form.probTitle'}" />
+<input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
+<input type="hidden" name="gradingmechanism" value="$env{'form.gradingmechanism'}" />
+<input type="hidden" name="pcorrect" value="$env{'form.pcorrect'}" />
+<input type="hidden" name="pincorrect" value="$env{'form.pincorrect'}" />
+ENDHEADER
+    my %responses;
+    my @questiontitles;
+    my $errormsg='';
+    my $number=0;
+    if ($env{'form.upfiletype'} eq 'iclicker') {
+	($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses);
+    }
+    $result.='<br />'.&mt('Found [_1] question(s)',$number).'<br />'.
+             '<input type="hidden" name="number" value="'.$number.'" />'.
+             &mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
+                 $env{'form.pcorrect'},$env{'form.pincorrect'}).
+             '<br />';
+# Remember Question Titles
+# FIXME: Possibly need delimiter other than ":"
+    for (my $i=0;$i<$number;$i++) {
+        $result.='<input type="hidden" name="question:'.$i.'" value="'.
+                 &HTML::Entities::encode($questiontitles[$i],'"&<>').'" />';
+    }
+    my $correct_count=0;
+    my $student_count=0;
+    my $unknown_count=0;
+# Match answers with usernames
+# FIXME: Possibly need delimiter other than ":"
+    foreach my $id (keys(%responses)) {
+       if ($correct_ids{$id}) {
+          $result.="\n".'<input type="hidden" name="correct:'.$correct_count.':'.$correct_ids{$id}.'" value="'.$responses{$id}.'" />';
+          $correct_count++;
+       } elsif ($clicker_ids{$id}) {
+          $result.="\n".'<input type="hidden" name="student:'.$clicker_ids{$id}.'" value="'.$responses{$id}.'" />';
+          $student_count++;
+       } else {
+          $result.="\n<hr />".&mt('Unregistered Clicker')." <tt>".$id."</tt><br />";
+          $result.="\n".'<input type="hidden" name="unknown:'.$id.'" value="'.$responses{$id}.'" />'.
+                   "\n".&mt("Username").": <input type='text' name='uname".$id."' />&nbsp;".
+                   "\n".&mt("Domain").": ".
+                   &Apache::loncommon::select_dom_form($env{'course.'.$env{'request.course.id'}.'.domain'},'udom'.$id).'&nbsp;'.
+                   &Apache::loncommon::selectstudent_link('clickeranalysis','uname'.$id,'udom'.$id);
+          $unknown_count++;
+       }
+    }
+    $result.='<hr />'.
+             &mt('Found [_1] registered and [_2] unregistered clickers.',$student_count,$unknown_count);
+    if ($env{'form.gradingmechanism'} ne 'attendance') {
+       if ($correct_count==0) {
+          $errormsg.="Found no correct answers answers for grading!";
+       } elsif ($correct_count>1) {
+          $result.='<br /><span class="LC_warning">'.&mt("Found [_1] entries for grading!",$correct_count).'</span>';
+       }
+    }
+    if ($errormsg) {
+       $result.='<br /><span class="LC_error">'.&mt($errormsg).'</span>';
+    } else {
+       $result.='<br /><input type="submit" name="finalize" value="'.&mt('Finalize Grading').'" />';
+    }
+    $result.='</form></td></tr></table>'."\n".
+             '</td></tr></table><br /><br />'."\n";
+    return $result.&show_grading_menu_form($symb);
+}
+
+sub iclicker_eval {
+    my ($questiontitles,$responses)=@_;
+    my $number=0;
+    my $errormsg='';
+    foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
+        my %components=&Apache::loncommon::record_sep($line);
+        my @entries=map {$components{$_}} (sort(keys(%components)));
+	if ($entries[0] eq 'Question') {
+	    for (my $i=3;$i<$#entries;$i+=6) {
+		$$questiontitles[$number]=$entries[$i];
+		$number++;
+	    }
+	}
+	if ($entries[0]=~/^\#/) {
+	    my $id=$entries[0];
+	    my @idresponses;
+	    $id=~s/^[\#0]+//;
+	    for (my $i=0;$i<$number;$i++) {
+		my $idx=3+$i*6;
+		push(@idresponses,$entries[$idx]);
+	    }
+	    $$responses{$id}=join(',',@idresponses);
+	}
+    }
+    return ($errormsg,$number);
+}
+
+sub assign_clicker_grades {
+    my ($r)=@_;
+    my ($symb)=&get_symb($r);
+    if (!$symb) {return '';}
+# See which part we are saving to
+    my ($partlist,$handgrade,$responseType) = &response_type($symb);
+# FIXME: This should probably look for the first handgradeable part
+    my $part=$$partlist[0];
+# Start screen output
+    my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
+
+    my $heading=&mt('Assigning grades based on clicker file');
+    $result.=(<<ENDHEADER);
+<br /><table width="100%" border="0"><tr><td bgcolor="#777777">
+<table width="100%" border="0"><tr bgcolor="#e6ffff"><td>
+<b>$heading</b></td></tr><tr bgcolor=#ffffe6><td>
+ENDHEADER
+# Get correct result
+# FIXME: Possibly need delimiter other than ":"
+    my @correct=();
+    my $gradingmechanism=$env{'form.gradingmechanism'};
+    my $number=$env{'form.number'};
+    if ($gradingmechanism ne 'attendance') {
+       foreach my $key (keys(%env)) {
+          if ($key=~/^form\.correct\:/) {
+             my @input=split(/\,/,$env{$key});
+             for (my $i=0;$i<=$#input;$i++) {
+                 if (($correct[$i]) && ($input[$i]) &&
+                     ($correct[$i] ne $input[$i])) {
+                    $result.='<br /><span class="LC_warning">'.
+                             &mt('More than one correct result given for question "[_1]": [_2] versus [_3].',
+                                 $env{'form.question:'.$i},$correct[$i],$input[$i]).'</span>';
+                 } elsif ($input[$i]) {
+                    $correct[$i]=$input[$i];
+                 }
+             }
+          }
+       }
+       for (my $i=0;$i<$number;$i++) {
+          if (!$correct[$i]) {
+             $result.='<br /><span class="LC_error">'.
+                      &mt('No correct result given for question "[_1]"!',
+                          $env{'form.question:'.$i}).'</span>';
+          }
+       }
+       $result.='<br />'.&mt("Correct answer: [_1]",join(', ',map { ($_?$_:'-') } @correct));
+    }
+# Start grading
+    my $pcorrect=$env{'form.pcorrect'};
+    my $pincorrect=$env{'form.pincorrect'};
+    my $storecount=0;
+    foreach my $key (keys(%env)) {
+       if ($key=~/^form\.student\:(.*)$/) {
+          my $user=$1;
+          my @answer=split(/\,/,$env{$key});
+          my $sum=0;
+          for (my $i=0;$i<$number;$i++) {
+             if ($answer[$i]) {
+                if ($gradingmechanism eq 'attendance') {
+                   $sum+=$pcorrect;
+                } else {
+                   if ($answer[$i] eq $correct[$i]) {
+                      $sum+=$pcorrect;
+                   } else {
+                      $sum+=$pincorrect;
+                   }
+                }
+             }
+          }
+          my $ave=$sum/(100*$number);
+# Store
+          my ($username,$domain)=split(/\:/,$user);
+          my %grades=();
+          $grades{"resource.$part.solved"}='correct_by_override';
+          $grades{"resource.$part.awarded"}=$ave;
+          $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}";
+          my $returncode=&Apache::lonnet::cstore(\%grades,$symb,
+                                                 $env{'request.course.id'},
+                                                 $domain,$username);
+          if ($returncode ne 'ok') {
+             $result.="<br /><span class=\"LC_error\">Failed to save student $username:$domain. Message when trying to save was ($returncode)</span>";
+          } else {
+             $storecount++;
+          }
+       }
+    }
+# We are done
+    $result.='<br />'.&mt('Successfully stored grades for [_1] student(s).',$storecount).
+             '</td></tr></table>'."\n".
+             '</td></tr></table><br /><br />'."\n";
+    return $result.&show_grading_menu_form($symb);
+}
+
 sub handler {
     my $request=$_[0];
 
@@ -6192,6 +6609,12 @@ sub handler {
 	    $request->print(&editgrades($request));
 	} elsif ($command eq 'verify' && $perm{'vgr'}) {
 	    $request->print(&verifyreceipt($request));
+        } elsif ($command eq 'processclicker' && $perm{'mgr'}) {
+            $request->print(&process_clicker($request));
+        } elsif ($command eq 'processclickerfile' && $perm{'mgr'}) {
+            $request->print(&process_clicker_file($request));
+        } elsif ($command eq 'assignclickergrades' && $perm{'mgr'}) {
+            $request->print(&assign_clicker_grades($request));
 	} elsif ($command eq 'csvform' && $perm{'mgr'}) {
 	    $request->print(&upcsvScores_form($request));
 	} elsif ($command eq 'csvupload' && $perm{'mgr'}) {