--- loncom/homework/grades.pm	2007/06/15 22:10:15	1.407
+++ loncom/homework/grades.pm	2007/07/04 18:37:30	1.419
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.407 2007/06/15 22:10:15 albertel Exp $
+# $Id: grades.pm,v 1.419 2007/07/04 18:37:30 www Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -93,6 +93,7 @@ sub get_symb {
 	    return ();
 	}
     }
+    &Apache::lonenc::check_decrypt(\$symb);
     return ($symb);
 }
 
@@ -492,7 +493,7 @@ sub jscriptNform {
 	'    }'."\n".
 	'</script>'."\n";
     $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".
-	'<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
 	'<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n".
 	'<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
@@ -617,7 +618,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) {
@@ -742,7 +743,7 @@ LISTJAVASCRIPT
 	'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" /><br />'."\n".
 	'<input type="hidden" name="saveState"   value="'.$env{'form.saveState'}.'" />'."\n".
 	'<input type="hidden" name="probTitle"   value="'.$env{'form.probTitle'}.'" />'."\n".
-	'<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n";
 
     if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) {
@@ -1751,7 +1752,7 @@ sub submission {
 			'<input type="hidden" name="refresh"    value="off" />'."\n".
 			'<input type="hidden" name="studentNo"  value="" />'."\n".
 			'<input type="hidden" name="gradeOpt"   value="" />'."\n".
-			'<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".
+			'<input type="hidden" name="symb"       value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 			'<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" />'."\n".
 			'<input type="hidden" name="vProb"      value="'.$env{'form.vProb'}.'" />'."\n".
 			'<input type="hidden" name="vAns"       value="'.$env{'form.vAns'}.'" />'."\n".
@@ -1792,10 +1793,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
@@ -1921,7 +1922,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;
@@ -1999,7 +2000,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)) {
@@ -2023,7 +2024,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').
@@ -2075,7 +2076,7 @@ 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>'.
@@ -2084,9 +2085,9 @@ KEYWORDS
 	$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' />";
@@ -2168,18 +2169,10 @@ sub processHandGrade {
 	    }
 	    my $includemsg = $env{'form.includemsg'.$ctr};
 	    my ($subject,$message,$msgstatus) = ('','','');
-            my $restitle = &Apache::lonnet::gettitle($symb);
-            my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl',
-                                                $symb,$udom,$uname);
-            my ($feedurl,$baseurl,$showsymb,$messagetail);
-            $feedurl = &Apache::lonnet::clutter($url);
-            if ($encrypturl =~ /^yes$/i) {
-                $baseurl = &Apache::lonenc::encrypted($feedurl,1);
-                $showsymb = &Apache::lonenc::encrypted($symb,1);
-            } else {
-                $baseurl = $feedurl;
-                $showsymb = $symb;
-            }
+	    my $restitle = &Apache::lonnet::gettitle($symb);
+            my ($feedurl,$showsymb) =
+		&get_feedurl_and_symb($symb,$uname,$udom);
+	    my $messagetail;
 	    if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) {
 		$subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/);
 		unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); }
@@ -2192,12 +2185,12 @@ sub processHandGrade {
 		if ($env{'form.withgrades'.$ctr}) {
 		    $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
 		    $messagetail = " for <a href=\"".
-		                   $baseurl."?symb=$showsymb\">$env{'form.probTitle'}</a>";
+		                   $feedurl."?symb=$showsymb\">$env{'form.probTitle'}</a>";
 		}
 		$msgstatus = 
                     &Apache::lonmsg::user_normal_msg($uname,$udom,$subject,
 						     $message.$messagetail,
-                                                     undef,$baseurl,undef,
+                                                     undef,$feedurl,undef,
                                                      undef,undef,$showsymb,
                                                      $restitle);
 		$request->print('<br />'.&mt('Sending message to [_1]:[_2]',$uname,$udom).': '.
@@ -2214,26 +2207,16 @@ sub processHandGrade {
 			if ($errorflag eq 'not_allowed') {
 			    $request->print("<span class=\"LC_error\">".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")."</span>");
 			    next;
-			} else {
-			    if ($message ne '') {
-                                $encrypturl=
-                                  &Apache::lonnet::EXT('resource.0.encrypturl',
-                                                       $symb,$udom,$collaborator);
-                                if ($encrypturl =~ /^yes$/i) {
-                                    $baseurl = &Apache::lonenc::encrypted($feedurl,1);
-                                    $showsymb = &Apache::lonenc::encrypted($symb,1);
-                                } else {
-                                    $baseurl = $feedurl;
-                                    $showsymb = $symb;
-                                }
-                                if ($env{'form.withgrades'.$ctr}) {
-                                    $messagetail = " for <a href=\"".
+			} elsif ($message ne '') {
+			    my ($baseurl,$showsymb) = 
+				&get_feedurl_and_symb($symb,$collaborator,
+						      $udom);
+			    if ($env{'form.withgrades'.$ctr}) {
+				$messagetail = " for <a href=\"".
                                     $baseurl."?symb=$showsymb\">$env{'form.probTitle'}</a>";
-
-                                }
-				$msgstatus = 
-                                    &Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle);
 			    }
+			    $msgstatus = 
+				&Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle);
 			}
 		    }
 		}
@@ -2587,28 +2570,31 @@ sub handback_files {
 		$message .= "<strong>".&Apache::lonnet::gettitle($symb)."</strong><br />";
 		$message .= ' The returned file(s) are named: '. $file_msg;
 		$message .= " and can be found in your portfolio space.";
-		my $url = (&Apache::lonnet::decode_symb($symb))[2];
-		my $feedurl = &Apache::lonnet::clutter($url);
-                my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl',
-                                                    $symb,$domain,$stuname);
-                my ($baseurl,$showsymb);
-                if ($encrypturl =~ /^yes$/i) {
-                    $baseurl = &Apache::lonenc::encrypted($feedurl,1);
-                    $showsymb = &Apache::lonenc::encrypted($symb,1);
-                } else {
-                    $baseurl = $feedurl;
-                    $showsymb = $symb;
-                }
+		my ($feedurl,$showsymb) = 
+		    &get_feedurl_and_symb($symb,$domain,$stuname);
                 my $restitle = &Apache::lonnet::gettitle($symb);
 		my $msgstatus = 
                    &Apache::lonmsg::user_normal_msg($stuname,$domain,$subject.
 			 ' (File Returned) ['.$restitle.']',$message,undef,
-                         $baseurl,undef,undef,undef,$showsymb,$restitle);
+                         $feedurl,undef,undef,undef,$showsymb,$restitle);
             }
         }
     return;
 }
 
+sub get_feedurl_and_symb {
+    my ($symb,$uname,$udom) = @_;
+    my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);
+    $url = &Apache::lonnet::clutter($url);
+    my $encrypturl=&Apache::lonnet::EXT('resource.0.encrypturl',
+					$symb,$udom,$uname);
+    if ($encrypturl =~ /^yes$/i) {
+	&Apache::lonenc::encrypted(\$url,1);
+	&Apache::lonenc::encrypted(\$symb,1);
+    }
+    return ($url,$symb);
+}
+
 sub get_submitted_files {
     my ($udom,$uname,$partid,$respid,$record) = @_;
     my @files;
@@ -2969,7 +2955,7 @@ sub viewgrades {
 
     #beginning of class grading form
     $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n".
-	'<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="command" value="editgrades" />'."\n".
 	'<input type="hidden" name="section" value="'.$env{'form.section'}.'" />'."\n".
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
@@ -3036,7 +3022,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
@@ -3087,7 +3073,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'}.
@@ -3107,7 +3093,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) {
@@ -3471,6 +3457,7 @@ sub csvuploadmap_header {
     my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
     my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
     my $ignore=&mt('Ignore First Line');
+    $symb = &Apache::lonenc::check_encrypt($symb);
     $request->print(<<ENDPICK);
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <h3><span class="LC_info">Uploading Class Grades</span></h3>
@@ -3565,6 +3552,7 @@ sub upcsvScores_form {
     my $upload=&mt("Upload Scores");
     my $upfile_select=&Apache::loncommon::upfile_select_html();
     my $ignore=&mt('Ignore First Line');
+    $symb = &Apache::lonenc::check_encrypt($symb);
     $result.=<<ENDUPFORM;
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <input type="hidden" name="symb" value="$symb" />
@@ -3873,7 +3861,7 @@ LISTJAVASCRIPT
     $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
 	'<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
 	'<input type="hidden" name="command" value="displayPage" />'."\n".
-	'<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n";
 
     $result.='&nbsp;<b>'.&mt('Use CODE:').' </b>'.
@@ -3997,7 +3985,7 @@ sub displayPage {
 	'<input type="hidden" name="student" value="'.$env{'form.student'}.'" />'."\n".
 	'<input type="hidden" name="page"    value="'.$pageTitle.'" />'."\n".
 	'<input type="hidden" name="title"   value="'.$env{'form.title'}.'" />'."\n".
-	'<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="overRideScore" value="no" />'."\n".
 	'<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n";
 
@@ -4369,7 +4357,7 @@ sub updateGradeByPage {
 sub defaultFormData {
     my ($symb)=@_;
     return '
-      <input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
+      <input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
      '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
      '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
 }
@@ -5938,7 +5926,7 @@ DOWNLOAD
 sub show_grading_menu_form {
     my ($symb)=@_;
     my $result.='<br /><form action="/adm/grades" method="post">'."\n".
-	'<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
 	'<input type="hidden" name="command" value="gradingmenu" />'."\n".
 	'<input type="submit" name="submit" value="Grading Menu" />'."\n".
@@ -6013,7 +6001,7 @@ GRADINGMENUJS
     my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'});
 
     $result.='<form action="/adm/grades" method="post" name="gradingMenu">'."\n".
-	'<input type="hidden" name="symb"        value="'.$symb.'" />'."\n".
+	'<input type="hidden" name="symb"        value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
 	'<input type="hidden" name="handgrade"   value="'.$hdgrade.'" />'."\n".
 	'<input type="hidden" name="probTitle"   value="'.$probTitle.'" />'."\n".
 	'<input type="hidden" name="command"     value="" />'."\n".
@@ -6129,7 +6117,7 @@ sub init_perm {
 }
 
 sub gather_clicker_ids {
-    my %clicker_ids=();
+    my %clicker_ids;
 
     my $classlist = &Apache::loncoursedata::get_classlist();
 
@@ -6142,13 +6130,13 @@ sub gather_clicker_ids {
         my $username = $classlist->{$student}->[$username_idx];
         my $domain   = $classlist->{$student}->[$domain_idx];
         my $clickers =
-	   (&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1];
+	    (&Apache::lonnet::userenvironment($domain,$username,'clickers'))[1];
         foreach my $id (split(/\,/,$clickers)) {
-            $id=~s/^0+//;
+            $id=~s/^[\#0]+//;
             if (exists($clicker_ids{$id})) {
-               $clicker_ids{$id}.=','.$username.':'.$domain;
+		$clicker_ids{$id}.=','.$username.':'.$domain;
             } else {
-               $clicker_ids{$id}=$username.':'.$domain;
+		$clicker_ids{$id}=$username.':'.$domain;
             }
         }
     }
@@ -6156,28 +6144,36 @@ sub gather_clicker_ids {
 }
 
 sub gather_adv_clicker_ids {
-    my %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 $element (sort(keys(%coursepersonnel))) {
         foreach my $person (split(/\,/,$coursepersonnel{$element})) {
             my ($puname,$pudom)=split(/\:/,$person);
             my $clickers =
-               (&Apache::lonnet::userenvironment($pudom,$puname,'clickers'))[1];
+		(&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;
-               }
+		$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);
@@ -6191,16 +6187,33 @@ sub process_clicker {
     $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"); 
+    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('iclicker','upfiletype',
-                                  ('iclicker' => 'i>clicker'));
-
+    my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
+						   ('iclicker' => 'i>clicker',
+                                                    'interwrite' => 'interwrite PRS'));
+    $symb = &Apache::lonenc::check_encrypt($symb);
     $result.=<<ENDUPFORM;
 <script type="text/javascript">
 function sanitycheck() {
@@ -6248,13 +6261,13 @@ function sanitycheck() {
 <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="checked" onClick="sanitycheck()" /></label>
-<br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" onClick="sanitycheck()" /></label>
-<br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" onClick="sanitycheck()" /></label>
-<input type="text" name="specificid" size="15" />
-<input type="hidden" name="waschecked" value="attendance" />
-<br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="100" onChange="sanitycheck()" /></label>
-<br /><label>$pincorrect: <input type="text" name="pincorrect" size="4" value="100" onChange="sanitycheck()" /></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
@@ -6268,43 +6281,51 @@ 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);
+	$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=();
+    my %correct_ids;
     if ($env{'form.gradingmechanism'} eq 'personnel') {
-       %correct_ids=&gather_adv_clicker_ids();
+	%correct_ids=&gather_adv_clicker_ids();
     }
     if ($env{'form.gradingmechanism'} eq 'specific') {
-       my $correct_id=$env{'form.specificid'};
-       $correct_id=~tr/a-z/A-Z/;
-       $correct_id=~s/\s//gs;
-       $correct_id=~s/^0+//;
-       $correct_ids{$correct_id}='specified';
+	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');
+	$result.=&mt('Score based on attendance only');
     } else {
-       my $number=0;
-       $result.='<h3>'.&mt('Correctness determined by the following IDs').'</h3>';
-       foreach my $id (sort(keys(%correct_ids))) {
-          $result.='<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);
-          }
-          $result.='<br />';
-          $number++;
-       }
-       if ($number==0) {
-          $result.='<span class="LC_error">'.&mt('No IDs found to determine correct answer').'</span>';
-          return $result.&show_grading_menu_form($symb);
-       }
+	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.',
@@ -6313,17 +6334,84 @@ sub process_clicker_file {
 		     '<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>');
         return $result.&show_grading_menu_form($symb);
     }
-    my %responses=();
-    my @questiontitles=();
+
+# Were able to get all the info needed, now analyze the file
+
+    $result.=&Apache::loncommon::studentbrowser_javascript();
+    $symb = &Apache::lonenc::check_encrypt($symb);
+    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);
+	($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses);
     }
-    $result.='<br />'.&mt('Found [_1] questions',$number).'<br />';
-    foreach my $id (keys %responses) {
-       $result.='<br />'.$id.' - '.$responses{$id};
+    if ($env{'form.upfiletype'} eq 'interwrite') {
+        ($errormsg,$number)=&interwrite_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);
 }
 
@@ -6332,32 +6420,146 @@ sub iclicker_eval {
     my $number=0;
     my $errormsg='';
     foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
-       chomp($line);
-       foreach my $quoted ($line=~/\,\s*\"([^\"]*)\"\s*\,/g) {
-          my $replace=$quoted;
-          $replace=~s/\,//g;
-          &Apache::lonnet::logthis($quoted.' - '.$replace.'<br />');
-          $line=~s/\,\s*\"\Q$quoted\E\"\s*\,/,$replace,/gs;
+        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 interwrite_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];
+                 }
+             }
+          }
        }
-       my @entries=split(/\,/,$line);
-       if ($entries[0] eq 'Question') {
-          for (my $i=3;$i<$#entries;$i+=6) {
-              $$questiontitles[$number]=$entries[$i];
-              $number++;
+       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>';
           }
        }
-       if ($entries[0]=~/^\#/) {
-          my $id=$entries[0];
-          my @idresponses=();
-          $id=~s/^[\#0]+//;
+       $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++) {
-             my $idx=3+$i*6;
-             push(@idresponses,$entries[$idx]);
+             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++;
           }
-          $$responses{$id}=join(',',@idresponses);
        }
     }
-    return ($errormsg,$number);
+# 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 {
@@ -6431,6 +6633,8 @@ sub handler {
             $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'}) {