Diff for /loncom/homework/grades.pm between versions 1.38 and 1.44

version 1.38, 2002/07/10 21:08:38 version 1.44, 2002/08/02 21:10:03
Line 30 Line 30
 # 7/26 H.K. Ng  # 7/26 H.K. Ng
 # 8/20 Gerd Kortemeyer  # 8/20 Gerd Kortemeyer
 # Year 2002  # Year 2002
 # June, July 2002 H.K. Ng  # June-August H.K. Ng
 #  #
   
 package Apache::grades;  package Apache::grades;
Line 42  use Apache::loncommon; Line 42  use Apache::loncommon;
 use Apache::lonhomework;  use Apache::lonhomework;
 use Apache::lonmsg qw(:user_normal_msg);  use Apache::lonmsg qw(:user_normal_msg);
 use Apache::Constants qw(:common);  use Apache::Constants qw(:common);
 use Time::HiRes qw( gettimeofday tv_interval );  
   
 sub moreinfo {  # ----- These first few routines are general use routines.-----
   my ($request,$reason) = @_;  #
   $request->print("Unable to process request: $reason");  # --- Retrieve the parts that matches stores_\d+ from the metadata file.---
   if ( $Apache::grades::viewgrades eq 'F' ) {  sub getpartlist {
     $request->print('<form action="/adm/grades" method="post">'."\n");      my ($url) = @_;
     if ($ENV{'form.url'}) {      my @parts =();
       $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");      my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
     }      foreach my $key (@metakeys) {
     if ($ENV{'form.symb'}) {   if ( $key =~ m/stores_([0-9]+)_.*/) {
       $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");      push(@parts,$key);
     }   }
 #    $request->print('<input type="hidden" name="command" value="submission" />'."\n");  
     $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");  
     $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");  
     $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");  
     $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");  
     $request->print('</form>');  
   }  
   return '';  
 }  
   
 sub verifyreceipt {  
     my $request=shift;  
     my $courseid=$ENV{'request.course.id'};  
 #    my $cdom=$ENV{"course.$courseid.domain"};  
 #    my $cnum=$ENV{"course.$courseid.num"};  
     my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.  
                 $ENV{'form.receipt'};  
     $receipt=~s/[^\-\d]//g;  
     my $symb=$ENV{'form.symb'};  
     unless ($symb) {  
  $symb=&Apache::lonnet::symbread($ENV{'form.url'});  
     }  
     if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {  
         $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');  
         my $matches=0;  
         my ($classlist) = &getclasslist('all','0');  
         foreach my $student ( sort(@{ $$classlist{'all'} }) ) {  
             my ($uname,$udom)=split(/\:/,$student);  
             if ($receipt eq   
              &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {  
                $request->print('Matching '.$student.'<br>');  
                $matches++;  
    }  
         }  
         $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');  
 # needs to print who is matched  
     }      }
     return '';      return @parts;
 }  }
   
 sub student_gradeStatus {  # --- Get the symbolic name of a problem and the url
   my ($url,$udom,$uname) = @_;  sub get_symb_and_url {
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));      my ($request) = @_;
   my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);      (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
   foreach my $part (&getpartlist($url)) {      my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
     my ($temp,$part,$type)=split(/_/,$part);      if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
     if ($type eq 'solved') {      return ($symb,$url);
       my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);  
       $status = 'partial' if ($foo =~ /^partially/);  
       $status = 'nothing' if ($status eq '');  
       return $type,$status;  
     }  
   }  
   return '';  
 }  }
   
   # --- Retrieve the fullname for a user. Return lastname, first middle ---
   # --- Generation is attached next to the lastname if it exists. ---
 sub get_fullname {  sub get_fullname {
     my ($sname,$sdom) = @_;      my ($uname,$udom) = @_;
     my %name=&Apache::lonnet::get('environment', ['lastname','generation',      my %name=&Apache::lonnet::get('environment', ['lastname','generation',
   'firstname','middlename'],    'firstname','middlename'],$udom,$uname);
   $sdom,$sname);  
     my $fullname;      my $fullname;
     my ($tmp) = keys(%name);      my ($tmp) = keys(%name);
     if ($tmp !~ /^(con_lost|error|no_such_host)/i) {      if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
Line 126  sub get_fullname { Line 83  sub get_fullname {
     return $fullname;      return $fullname;
 }  }
   
 sub listStudents {  #--- Get the partlist and the response type for a given problem. ---
   my ($request) = shift;  #--- Indicate if a response type is coded handgraded or not. ---
   my $cdom      =$ENV{"course.$ENV{'request.course.id'}.domain"};  sub response_type {
   my $cnum      =$ENV{"course.$ENV{'request.course.id'}.num"};      my ($url) = shift;
   my $getsec    =$ENV{'form.section'};      my $allkeys = &Apache::lonnet::metadata($url,'keys');
   my $submitonly=$ENV{'form.submitonly'};      my %seen = ();
       my (@partlist,%handgrade);
   $request->print(<<ENDTABLEST);      foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
 <h2><font color="#339933">&nbsp;View Submissions for a Student or a Group of Students</font></h2>   if (/^\w+response_\d+.*/) {
 &nbsp;<font size=+1><b>Resource:</b> $ENV{'form.url'}<br /><br />      my ($responsetype,$part) = split(/_/,$_,2);
 <form action="/adm/grades" method="post">&nbsp;<b>View Options</b></font><br />      my ($partid,$respid) = split(/_/,$part);
 &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no       $handgrade{$part} = $responsetype.':'.($allkeys =~ /parameter_$part\_handgrade/ ? 'yes' : 'no');
 <input type="radio" name="vProb" value="yes"> yes <br />      next if ($seen{$partid} > 0);
 &nbsp;<b>Submissions: </b>      $seen{$partid}++;
 <input type="radio" name="lastSub" value="lastonly" checked> last sub only      push @partlist,$partid;
 <input type="radio" name="lastSub" value="last"> last sub & parts info   }
 <input type="radio" name="lastSub" value="all"> all details      }
 <input type="hidden" name="section" value="$getsec">      return \@partlist,\%handgrade;
 <input type="hidden" name="submitonly" value="$submitonly">  
 <input type="hidden" name="response" value="$ENV{'form.response'}">  
 <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}">  
 <table border="0"><tr><td bgcolor="#777777">  
 <table border="0"><tr bgcolor="#e6ffff">  
 <td><b>&nbsp;Select&nbsp;</b></td><td><b>&nbsp;Username&nbsp;</b></td>  
 <td><b>&nbsp;Fullname&nbsp;</b></td><td><b>&nbsp;Domain&nbsp;</b></td>  
 <td><b>&nbsp;Grade Status&nbsp;</b></td></tr>  
 ENDTABLEST  
   if ($ENV{'form.url'}) {  
       $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");  
   }  
   if ($ENV{'form.symb'}) {  
       $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");  
   }  
   $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");  
   
   my $t0=&Time::HiRes::time();  
   
   my ($classlist) = &getclasslist($getsec,'0');  
   my $t1=&Time::HiRes::time();  
   print "getclasslist=",$t1-$t0,"<br />";  
   
   foreach my $student ( sort(@{ $$classlist{$getsec} }) ) {  
       my ($sname,$sdom) = split(/:/,$student);  
       my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);  
       next if ($status eq 'nothing' && $submitonly eq 'yes');  
   
       my $fullname = &get_fullname($sname,$sdom);  
       if ( $Apache::grades::viewgrades eq 'F' ) {  
   $request->print("\n".'<tr bgcolor="#ffffe6">'.  
   '<td align="center"><input type=checkbox name="stuinfo" value="'.  
   $student.':'.$fullname.'"></td>'."\n".  
   '<td>&nbsp;'.$sname.'&nbsp;</td>'."\n".  
   '<td>&nbsp;'.$fullname.'&nbsp;</td>'."\n".  
   '<td align="middle">&nbsp;'.$sdom.'&nbsp;</td>'."\n");  
   $request->print('<td align="middle">&nbsp;'.$status.'&nbsp;</td>'."\n");  
   
   $request->print('</tr>');  
       }  
   }  
   my $t2=&Time::HiRes::time();  
   print "processclasslist=",$t2-$t1,"<br />";  
   $request->print('</table></td></tr></table>');  
   $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');  
 }  
   
 sub processGroup {  
   my ($request)  = shift;  
   my $ctr        = 0;  
   my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}  
                            : ($ENV{'form.stuinfo'}));  
   my $total      = scalar(@stuchecked)-1;  
   if ($stuchecked[0] eq '') {  
       &userError($request,'No student was selected for viewing/grading.');  
       return;  
   }  
   foreach (@stuchecked) {  
       my ($sname,$sdom,$fullname) = split(/:/);  
       $ENV{'form.student'} = $sname;  
       $ENV{'form.fullname'} = $fullname;  
       &submission($request,$ctr,$total);  
       $ctr++;  
   }  
   return 'The End';  
 }  }
   
   #--- Prints a message on screen if a user did something wrong
   #--- Operator error ---
 sub userError {  sub userError {
     my ($request, $reason, $step) = @_;      my ($request, $reason, $step) = @_;
     $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n");      $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n");
Line 220  sub userError { Line 114  sub userError {
     return '';      return '';
 }  }
   
 #FIXME - needs to handle multiple matches  #--- Dumps the class list with usernames,list of sections,
 sub finduser {  #--- section, ids and fullnames for each user.
   my ($name) = @_;  
   my $domain = '';  
   if ( $Apache::grades::viewgrades eq 'F' ) {  
     my ($classlist) = &getclasslist('all','0');  
     foreach ( sort(@{ $$classlist{'all'} }) ) {  
       my ($posname,$posdomain) = split(/:/);  
       if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }  
     }  
     return ($name,$domain);  
   } else {  
     return ($ENV{'user.name'},$ENV{'user.domain'});  
   }  
 }  
   
 sub getclasslist {  sub getclasslist {
   my ($getsec,$hideexpired) = @_;      my ($getsec,$hideexpired) = @_;
   my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});      my $now = time;
   my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);      my %classlist=&Apache::lonnet::dump('classlist',
   my $now = time;   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
   my (@holdsec,@sections);   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   foreach my $student (keys(%classlist)) {      # codes to check for fields in the classlist
     my ($end,$start)=split(/:/,$classlist{$student});      # should contain end:start:id:section:fullname
     # still a student?      for (keys %classlist) {
     if (($hideexpired) && ($end) && ($end < $now)) {   my (@fields) = split(/:/,$classlist{$_});
       next;   %classlist   = &reformat_classlist(\%classlist) if (scalar(@fields) <= 2);
     }   last;
     my ($unam,$udom) = split(/:/,$student,2);      }
     my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});  
     $section = ($section ne '-1' ? $section : 'no');      my (@holdsec,@sections,%allids,%stusec,%fullname);
     push @holdsec,$section;      foreach (keys(%classlist)) {
     push (@{ $classlist{$getsec} }, $student) if ($getsec eq 'all' || $getsec eq $section);   my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
   }   # still a student?
   my %seen = ();   if (($hideexpired) && ($end) && ($end < $now)) {
   foreach my $item (@holdsec) {      next;
       push (@sections, $item) unless $seen{$item}++;   }
   }   $section = ($section ne '' ? $section : 'no');
   return (\%classlist,\@sections);   push @holdsec,$section;
 }   if ($getsec eq 'all' || $getsec eq $section) {
       push (@{ $classlist{$getsec} }, $_);
 sub getpartlist {      $allids{$_}  =$id;
   my ($url) = @_;      $stusec{$_}  =$section;
   my @parts =();      $fullname{$_}=$fullname;
   my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));   }
   foreach my $key (@metakeys) {  
     if ( $key =~ m/stores_([0-9]+)_.*/) {  
       push(@parts,$key);  
     }      }
   }      my %seen = ();
   return @parts;      foreach my $item (@holdsec) {
 }   push (@sections, $item) unless $seen{$item}++;
   
 sub viewstudentgrade {  
   my ($url,$symb,$courseid,$student,@parts) = @_;  
   my $result ='';  
   my $cellclr = '"#ffffdd"';  
   my ($username,$domain) = split(/:/,$student);  
   
   my $fullname = &get_fullname($username,$domain);  
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);  
   
   $result.="<tr bgcolor=$cellclr><td>$username</td><td>$fullname</td><td align=\"middle\">$domain</td>\n";  
   foreach my $part (@parts) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     my $score=$record{"resource.$part.$type"};  
     if ($type eq 'awarded' || $type eq 'tries') {  
       $result.='<td align="middle"><input type="text" name="GRADE.'.$student.'.'.$part.'.'.$type.  
   '" value="'.$score.'" size="4" /></td>'."\n";  
     } elsif ($type eq 'solved') {  
       my ($status,$foo)=split(/_/,$score,2);  
       $result.="<td align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";  
       my $optsel = '<option>correct</option><option>incorrect</option><option>excused</option>'.  
   '<option>ungraded</option><option>partial</option><option>nothing</option>'."\n";  
       $status = 'nothing' if ($status eq '');  
       $optsel =~ s/<option>$status/<option selected="on">$status/;  
       $result.=$optsel;  
       $result.="</select></td>\n";  
     }      }
   }      return (\%classlist,\@sections,\%allids,\%stusec,\%fullname);
   $result.='</td></tr>';  
   return $result;  
 }  }
   
 #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an  # add id, section and fullname to the classlist.db
 #interface based on that, also do that to above function.  # done to maintain backward compatibility with older versions
 sub setstudentgrade {  sub reformat_classlist {
   my ($url,$symb,$courseid,$student,@parts) = @_;      my ($classlist) = shift;
   print "set student grade parts=@parts<br>";      foreach (sort keys(%$classlist)) {
   my $result ='';   my ($unam,$udom) = split(/:/);
   my ($stuname,$domain) = split(/:/,$student);   my $section      = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);   my $fullname     = &get_fullname ($unam,$udom);
   my %newrecord;   my %userid       = &Apache::lonnet::idrget($udom,($unam));
    $$classlist{$_}  = $$classlist{$_}.':'.$userid{$unam}.':'.$section.':'.$fullname;
   foreach my $part (@parts) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     my $oldscore=$record{"resource.$part.$type"};  
     my $newscore=$ENV{"form.GRADE.$student.$part.$type"};  
     print "old=$oldscore:new=$newscore:<br>";  
     if ($type eq 'solved') {  
       my $update=0;  
       if ($newscore eq 'nothing' ) {  
  if ($oldscore ne '') {  
   $update=1;  
   $newscore = '';  
  }  
       } elsif ($oldscore !~ m/^$newscore/) {  
  $update=1;  
  $result.="Updating $stuname to $newscore<br />\n";  
  if ($newscore eq 'correct')   { $newscore = 'correct_by_override'; }  
  if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }  
  if ($newscore eq 'excused')   { $newscore = 'excused'; }  
  if ($newscore eq 'ungraded')  { $newscore = 'ungraded_attempted'; }  
  if ($newscore eq 'partial')   { $newscore = 'correct_partially_by_override'; }  
       } else {  
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";  
       }  
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }  
     } else {  
       if ($oldscore ne $newscore) {  
  $newrecord{"resource.$part.$type"}=$newscore;  
  $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";  
       } else {  
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";  
       }  
     }      }
   }      my $putresult = &Apache::lonnet::put
   if ( scalar(keys(%newrecord)) > 0 ) {   ('classlist',\%$classlist,
     $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
 #    &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
     $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";      return %$classlist;
   }  
   return $result;  
 }  }
   
 #  #find user domain
 # --------------------------- show submissions of a student, option to grade --------  sub finduser {
 sub submission {      my ($name) = @_;
   my ($request,$counter,$total) = @_;      my $domain = '';
       if ( $Apache::grades::viewgrades eq 'F' ) {
   (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;   my %classlist=&Apache::lonnet::dump('classlist',
   if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
   my ($uname,$udom) = &finduser($ENV{'form.student'});      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   if ($uname eq '') { &moreinfo($request,'Unable to find student'); return ''; }   my (@fields) = grep /^$name:/, keys %classlist;
    ($name, $domain) = split(/:/,$fields[0]);
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));   return ($name,$domain);
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }      } else {
   my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');   return ($ENV{'user.name'},$ENV{'user.domain'});
   
   # header info  
   if ($counter == 0) {  
       &sub_page_js($request);  
       $request->print('<h2>&nbsp;<font color="#339933">Submission Record</font></h2>'.  
       '<font size=+1>&nbsp;<b>Resource: </b>'.$url.'</font>');  
   
       # option to display problem, only once else it cause problems with the form later   
       # since the problem has a form.  
       if ($ENV{'form.vProb'} eq 'yes') {  
   my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,  
     $ENV{'request.course.id'});  
   my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,  
  $ENV{'request.course.id'});  
   my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">';  
   $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">';  
   $result.='<b>Student\'s view of the problem</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />';  
   $result.='<b>Correct answer:</b><br />'.$companswer;  
   $result.='</td></tr></table>';  
   $result.='</td></tr></table><br />';  
   $request->print($result);  
       }  
   
       # kwclr is the only variable that is non blank if this has been used once.  
       my %keyhash = ();  
       if ($ENV{'form.kwclr'} eq '') {  
   %keyhash = &Apache::lonnet::dump('nohist_handgrade',  
       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
   
   my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};  
   $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';  
   $ENV{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';  
   $ENV{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';  
   $ENV{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';  
   $ENV{'form.msgsub'}   = $keyhash{$symb.'_subject'} ne '' ?   
       $keyhash{$symb.'_subject'} : &Apache::lonnet::metadata($url,'title');  
   $ENV{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';  
   
       }  
       $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".  
       '<input type="hidden" name="command"    value="handgrade" />'."\n".  
       '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url"        value="'.$url.'" />'."\n".  
       '<input type="hidden" name="vProb"      value="'.$ENV{'form.vProb'}.'" />'."\n".  
       '<input type="hidden" name="lastSub"    value="'.$ENV{'form.lastSub'}.'" />'."\n".  
       '<input type="hidden" name="section"    value="'.$ENV{'form.section'}.'">'."\n".  
       '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".  
       '<input type="hidden" name="response"   value="'.$ENV{'form.response'}.'">'."\n".  
       '<input type="hidden" name="handgrade"  value="'.$ENV{'form.handgrade'}.'">'."\n".  
       '<input type="hidden" name="keywords"   value="'.$ENV{'form.keywords'}.'" />'."\n".  
       '<input type="hidden" name="kwclr"      value="'.$ENV{'form.kwclr'}.'" />'."\n".  
       '<input type="hidden" name="kwsize"     value="'.$ENV{'form.kwsize'}.'" />'."\n".  
       '<input type="hidden" name="kwstyle"    value="'.$ENV{'form.kwstyle'}.'" />'."\n".  
       '<input type="hidden" name="msgsub"     value="'.$ENV{'form.msgsub'}.'" />'."\n".  
       '<input type="hidden" name="savemsgN"   value="'.$ENV{'form.savemsgN'}.'" />'."\n".  
       '<input type="hidden" name="NCT"'.  
       ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");  
   
       my ($cts,$prnmsg) = (1,'');  
       while ($cts <= $ENV{'form.savemsgN'}) {  
   $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.  
       ($keyhash{$symb.'_savemsg'.$cts} eq '' ? $ENV{'form.savemsg'.$cts} : $keyhash{$symb.'_savemsg'.$cts}).  
       '" />'."\n";  
   $cts++;  
       }  
       $request->print($prnmsg);  
   
       if ($ENV{'form.handgrade'} eq 'yes') {  
   $request->print(<<KEYWORDS);  
 &nbsp;<b>Keyword Options:</b>&nbsp;  
 <a href="javascript:keywords(document.SCORE.keywords)"; 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 />  
 KEYWORDS  
       }  
   }  
   
   # Student info  
   $request->print(($counter == 0 ? '' : '<br />'));  
   my $fullname = ($ENV{'form.fullname'} ne '' ? $ENV{'form.fullname'} : &get_fullname($uname,$udom));  
   my $result.='<table border="0" width=100%><tr><td bgcolor="#777777">'.  
       '<table border="0" width=100%><tr bgcolor="#ffffff"><td>';  
   $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Username: </b>'.$uname.  
       '</td><td><b>Fullname: </b>'.$fullname.  
       '</td><td><b>Domain: </b>'.$udom.'</td></tr>';  
   if ($ENV{'form.handgrade'} eq 'yes') {  
 #      my $subonly = &get_last_submission($symb,$uname,$udom,$ENV{'request.course.id'});  
       my ($classlist) = &getclasslist('all','0');  
       my @collaborators;  
 #      foreach ( sort(@{ $$classlist{'all'} }) ) {  
 #  my ($sname,$sdom) = split(/:/);  
 #  push @collaborators,$sname if (grep /\b$sname(\b|\.)/i,$subonly);  
 #      }  
 #      push @collaborators,'leede','carlandmm','freyniks'; # as a test to display collaborators.  
       if (scalar(@collaborators) != 0) {  
   $result.='<tr bgcolor="#ffffff"><td colspan=3><b>Collaborators: </b>';  
   foreach (@collaborators) {  
       $result.=$_.' ('.&get_fullname($_,$udom).') &nbsp; &nbsp;';  
   }  
   $result.='</td></tr>'."\n";  
   $result.='<input type="hidden" name="collaborator'.$counter.  
       '" value="'.(join ':',@collaborators).'" />'."\n";  
       }  
   }  
   $result.='</table>'."\n";  
   $request->print($result);  
   
  # print student answer  
   if ($ENV{'form.lastSub'} eq 'lastonly') {  
       my ($string,$timestamp)=&get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'});  
       $string=&keywords_highlight(join('::::',@$string));  
       my $lastsubonly='<table border="0" width=100%><tr><td bgcolor="#777777">';  
       $lastsubonly.='<table border="0" width=100%><tr bgcolor="#ddffff">';  
       $lastsubonly.='<td><b>Last Submission Only</b>'.  
   ($timestamp eq '' ? '' : '&nbsp; &nbsp; <b>Date Submitted:</b> '.@$timestamp).'</td></tr>';  
       $lastsubonly.='<tr><td bgcolor="#ffffe6">';  
       $lastsubonly.=$string;  
       $lastsubonly.='</td></tr></table></td></tr></table>'."\n";  
       $request->print($lastsubonly);  
   } else {  
       $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,  
        $ENV{'request.course.id'},$last,  
        '.submission','Apache::grades::keywords_highlight'));  
   }  
   
   my $wgt    = &Apache::lonnet::EXT('resource.partid.weight',$symb,$udom,$uname);  
   my $wgtmsg = ($wgt > 0 ? '(problem weight)' : '<font color="red">problem weight assigned by computer</font>');  
   $wgt       = ($wgt > 0 ? $wgt : '1');  
   my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);  
   my $score  = ($record{'resource.0.awarded'} eq '' ? '' : $record{'resource.0.awarded'}*$wgt);  
   
   # display grading options  
   $result='<input type="hidden" name="WGT'.$counter.'" value="'.$wgt.'" />'.  
       '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";  
   $result.='<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";  
   $result.='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n";  
   $result.='<table border="0"><tr><td><b>Points</b></td><td>';  
   
   my $ctr = 0;  
   $result.='<table border="0"><tr>';  # display radio buttons in a nice table with 10 across  
   while ($ctr<=$wgt) {  
       $result.= '<td><input type="radio" name="RADVAL'.$counter.'" '.  
   'onclick="javascript:writeBox(this.form.GRADE_BOX'.$counter.  
     ',this.form.GRADE_SEL'.$counter.','.$ctr.','.$wgt.')" '.  
  ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";  
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');  
       $ctr++;  
   }  
   $result.='</tr></table>';  
   
   $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';  
   $result.='<td><input type="text" name="GRADE_BOX'.$counter.'"'.  
       ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.  
        'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.  
         ',this.form.GRADE_BOX'.$counter.  
    ',this.form.GRADE_SEL'.$counter.',\''.$wgt.'\')" /></td>'."\n";  
   $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';  
   
   foreach my $part (&getpartlist($url)) {  
       print "parts=$part<br>";  
     my ($temp,$part,$type)=split(/_/,$part);  
     if ($type eq 'solved') {  
       my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);  
       $status = 'partial' if ($foo =~ /partially/);  
       $status = 'nothing' if ($status eq '');  
       $result.='<select name="GRADE_SEL'.$counter.'">'."\n";  
       my $optsel = '<option>correct</option><option>incorrect</option>'.  
   '<option>excused</option><option>ungraded</option>'.  
       '<option>partial</option><option>nothing</option>'."\n";  
       $optsel =~ s/<option>$status/<option selected="on">$status/;  
       $result.=$optsel;  
       $result.="</select>&nbsp&nbsp\n";  
     }      }
   }  
   $result.='<a href="javascript:msgCenter(document.SCORE,'.$counter.  
       ',\''.$fullname.'\')"; TARGET=_self>Compose Message</a></td></tr></table>'."\n";  
 #  $result.='</table>';  
   $result.='</td></tr></table></td></tr></table>';  
   $request->print($result);  
   
   # print end of form  
   if ($counter == $total) {  
       my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';  
       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/;  
       $endform.=$ntstu.'student(s) &nbsp;&nbsp;';  
       $endform.='<input type="submit" name="gradeOpt" value="Next" />&nbsp';  
       $endform.='<input type="submit" name="gradeOpt" value="Previous" />&nbsp';  
       $endform.='(Next and Previous do not save the scores.)';  
       $endform.='</td><tr></table></form>';  
       $request->print($endform);  
   }  
   
   return '';  
 }  }
   
 sub get_last_submission {  #--- Prompts a user to enter a username.
   my ($symb,$username,$domain,$course)=@_;  sub moreinfo {
   if ($symb) {      my ($request,$reason) = @_;
       my (@string,@timestamp);      $request->print("Unable to process request: $reason");
      my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);      if ( $Apache::grades::viewgrades eq 'F' ) {
      if ($returnhash{'version'}) {   $request->print('<form action="/adm/grades" method="post">'."\n");
  my %lasthash=();   if ($ENV{'form.url'}) {
  my ($version);      $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
  for ($version=1;$version<=$returnhash{'version'};$version++) {  
   foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {  
       $lasthash{$_}=$returnhash{$version.':'.$_};  
   }  
         }  
  foreach ((keys %lasthash)) {  
     print "lasthash key=$_<br>";  
     if ($_ =~ /\.submission$/) {push @string, $_,$lasthash{$_}}  
     if ($_ =~ /timestamp/) {push @timestamp, scalar(localtime($lasthash{$_}))};  
 #    if ($_ =~ /\.submission$/) {$string = $lasthash{$_}}  
 #    if ($_ =~ /timestamp/) {$timestamp=scalar(localtime($lasthash{$_}))};  
  }   }
    if ($ENV{'form.symb'}) {
       $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
    }
    $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");
    $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");
    $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");
    $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");
    $request->print('</form>');
     }      }
      @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;      return '';
      return \@string,\@timestamp;  
   }  
 }  
   
 sub keywords_highlight {  
   my $string  = shift;  
   my $size    = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};  
   my $styleon = $ENV{'form.kwstyle'} eq ''  ? '' : $ENV{'form.kwstyle'};  
   (my $styleoff = $styleon) =~ s/\</\<\//;  
   my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});  
   foreach (@keylist) {  
  #     next if ($_ eq '');  
       $string =~ s/\b$_(\b|\.)/\<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff\<\/font\>/gi;  
   }  
   return $string;  
 }  
   
 sub processHandGrade {  
   my ($request) = shift;  
   my $url    = $ENV{'form.url'};  
   my $symb   = $ENV{'form.symb'};  
   my $button = $ENV{'form.gradeOpt'};  
   my $ngrade = $ENV{'form.NCT'};  
   my $ntstu  = $ENV{'form.NTSTU'};  
   
   my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};  
   my %keyhash = ();  
   $ENV{'form.keywords'} =~ s/,\s{0,}|\s+/ /g;  
   $keyhash{$symb.'_handgrade'} = 'activated';  
   $keyhash{$symb.'_keywords'} = $ENV{'form.keywords'};  
   $keyhash{$symb.'_subject'} = $ENV{'form.msgsub'};  
   $keyhash{$loginuser.'_kwclr'} = $ENV{'form.kwclr'};  
   $keyhash{$loginuser.'_kwsize'} = $ENV{'form.kwsize'};  
   $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};  
   
   my ($ctr,$idx) = (1,1);  
   while ($ctr <= $ENV{'form.savemsgN'}) {  
       if ($ENV{'form.savemsg'.$ctr} ne '') {  
   $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};  
   $idx++;  
       }  
       $ctr++;  
   }  
   $ctr = 0;  
   while ($ctr < $ngrade) {  
       if ($ENV{'form.newmsg'.$ctr} ne '') {  
   $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};  
   $ENV{'form.savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};  
   $idx++;  
       }  
       $ctr++;  
   }  
   $ENV{'form.savemsgN'} = --$idx;  
   $keyhash{$symb.'_savemsgN'} = $ENV{'form.savemsgN'};  
   my $putresult = &Apache::lonnet::put  
       ('nohist_handgrade',\%keyhash,  
        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
   
   my (@parts) = sort(&getpartlist($url));  
   
   if ($button eq 'Save & Next') {  
       my $ctr = 0;  
       while ($ctr < $ngrade) {  
   my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});  
   &saveHandGrade($url,$symb,$uname,$udom,$ctr,@parts);  
   
   my $includemsg = $ENV{'form.includemsg'.$ctr};  
   my ($subject,$message,$msgstatus) = ('','','');  
   if ($includemsg =~ /savemsg|new$ctr/) {  
       $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/);  
       my (@msgnum) = split(/,/,$includemsg);  
       foreach (@msgnum) {  
   $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');  
       }  
       $message =~ s/\s+/ /g;  
       $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);  
   }  
   if ($ENV{'form.collaborator'.$ctr}) {  
       my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr});  
       foreach (@collaborators) {  
   &saveHandGrade($url,$symb,$_,$udom,$ctr,@parts);  
   if ($message ne '') {  
       $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,$ENV{'form.msgsub'},$message);  
   }  
       }  
   }  
   $ctr++;  
       }  
   }  
   my $firststu = $ENV{'form.unamedom0'};  
   my $laststu  = $ENV{'form.unamedom'.($ngrade-1)};  
   
   my ($classlist) = &getclasslist($ENV{'form.section'},'0');  
   my (@nextlist,@prevlist);  
   my ($nextflg,$prevflg,$ctr,$ctprev) = (0,0,0,0);  
   foreach my $student ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {  
       my ($uname,$udom) = split(/:/,$student);  
       my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname);  
       next if ($status eq 'nothing' && $ENV{'form.submitonly'} eq 'yes');  
   
       if ($nextflg == 1 && $button =~ /Next$/) {  
   push @nextlist,$uname if ($ctr < $ntstu);  
   $ctr++;  
       }  
       $nextflg = 1 if ($student eq $laststu);  
       $prevflg = 1 if ($student eq $firststu);  
       if ($prevflg == 0 && $button eq 'Previous') {  
   push @prevlist,$uname;  
   $ctprev++;  
       }  
   }  
   if ($button eq 'Previous') {  
       if ($ctprev <= $ntstu) {  
   @nextlist = @prevlist;  
       } else {  
   my $idx = 0;  
   my $start = $ctprev - $ntstu;  
   while ($idx < $ntstu) {  
       $nextlist[$idx] = $prevlist[$start+$idx];  
       $idx++;  
   }  
       }  
   }  
   $ctr = 0;  
   my $total = scalar(@nextlist)-1;  
   foreach my $student (@nextlist) {  
       $ENV{'form.student'} = $student;  
       &submission($request,$ctr,$total);  
       $ctr++;  
   }  
   if ($total < 0) {  
       my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";  
       $the_end.='<b>Message: </b> No more students for this section or class.<br /><br />'."\n";  
       $the_end.='Click on the button below to return to the grading menu.<br /><br />'."\n";  
       $the_end.=&show_grading_menu_form ($symb,$url);  
       $request->print($the_end);  
   }  
   return '';  
 }  }
   
 sub saveHandGrade {  #--- Retrieve the grade status of a student for all the parts
   my ($url,$symb,$stuname,$domain,$newflg,@parts) = @_;  sub student_gradeStatus {
   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);      my ($url,$symb,$udom,$uname,$partlist) = @_;
   my %newrecord;      my %record     = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
       my %partstatus = ();
   foreach my $part (@parts) {      foreach (@$partlist) {
     my ($temp,$part,$type)=split(/_/,$part);   my ($status,$foo)    = split(/_/,$record{"resource.$_.solved"},2);
     my $oldscore=$record{"resource.$part.$type"};   $status              = 'nothing' if ($status eq '');
     my $newscore;   $partstatus{$_}      = $status;
     if ($type eq 'awarded' && $newflg >= 0) {   my $subkey           = "resource.$_.submitted_by";
  my $pts    = ($ENV{'form.GRADE_BOX'.$newflg} ne '' ?    $partstatus{$subkey} = $record{$subkey} if ($record{$subkey} ne '');
       $ENV{'form.GRADE_BOX'.$newflg} : $ENV{'form.RADVAL'.$newflg});  
  my $wgt    = $ENV{'form.WGT'.$newflg};  
 # my $sel    = $ENV{'form.GRADE_SEL'.$newflg};  
  $newscore  = $pts/$wgt if ($wgt != 0);  
     }  
     if ($type eq 'solved') {  
       $newscore = $ENV{'form.GRADE_SEL'.$newflg} if ($newflg >= 0);  
       my $update=0;  
       if ($newscore eq 'nothing' ) {  
  if ($oldscore ne '') {  
   $update=1;  
   $newscore = '';  
  }  
       } elsif ($oldscore !~ m/^$newscore/) {  
  $update=1;  
  if ($newscore eq 'correct')   { $newscore = 'correct_by_override'; }  
  if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }  
  if ($newscore eq 'excused')   { $newscore = 'excused'; }  
  if ($newscore eq 'ungraded')  { $newscore = 'ungraded_attempted'; }  
  if ($newscore eq 'partial')   { $newscore = 'correct_partially_by_override'; }  
       }  
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }  
     } else {  
       if ($oldscore ne $newscore) {  
  $newrecord{"resource.$part.$type"}=$newscore;  
       }  
     }      }
   }      return %partstatus;
   if ( scalar(keys(%newrecord)) > 0 ) {  
       $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";  
 #      while (my ($k,$v) = each %newrecord) {  
 # print "k=$k:v=$v:<br>\n";  
 #      }  
 #      print "symb=$symb,courseid=$ENV{'request.course.id'},dom=$domain,name=$stuname<br>";  
 #     &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);  
   }  
   return '';  
 }  
   
 sub get_symb_and_url {  
   my ($request) = @_;  
   (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;  
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));  
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }  
   return ($symb,$url);  
 }  
   
 sub show_grading_menu_form {  
   my ($symb,$url)=@_;  
   my $result.='<form action="/adm/grades" method="post">'."\n".  
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
  '<input type="hidden" name="command" value="gradingmenu" />'."\n".  
   '<input type="submit" name="submit" value="Grading Menu" />'."\n".  
     '</form>'."\n";  
   return $result;  
 }  }
   
 sub gradingmenu {  
   my ($request) = @_;  
   my ($symb,$url)=&get_symb_and_url($request);  
   if (!$symb) {return '';}  
   my $allkeys = &Apache::lonnet::metadata($url,'keys');  
   my $handgrade = ($allkeys =~ /parameter_.*?_handgrade/ ? 'yes' : 'no');  
   my ($responsetype,$foo) = split(/_/,&Apache::lonnet::metadata($url,'packages'));  
   $allkeys=~s/,/\<br\>/g;  
 #  print "allkeys=$allkeys<br><br>";  
   $Apache::lonxml::debug=1;  
   &Apache::lonxml::debug(join(':',&Apache::lonnet::metadata($url,'packages')));  
   $Apache::lonxml::debug=0;  
   
   my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';  
   $result.='<table border="0">';  
   $result.='<tr><td><font size=+1><b>Resource: </b></font></td>'.  
       '<td><font size=+1>'.$url.'</font></td></tr>';  
   $result.='<tr><td><font size=+1><b>Type: </b></font></td>'.  
       '<td><font size=+1>'.$responsetype.'&nbsp;&nbsp;<b>Handgrade: </b>'.$handgrade.'</font></td></tr>';  
   $result.='</table>';  
   my $t0=&Time::HiRes::time();  
   $result.=&view_edit_entire_class_form($symb,$url).'<br />';  
   my $t1=&Time::HiRes::time();  
   print "elapsed10=",$t1-$t0,"<br />";  
   $result.=&upcsvScores_form($symb,$url).'<br />';  
   my $t2=&Time::HiRes::time();  
   print "elapsed21=",$t2-$t1,"<br />";  
   $result.=&viewGradeaStu_form($symb,$url,$responsetype,$handgrade).'<br />';  
   my $t3=&Time::HiRes::time();  
   print "elapsed32=",$t3-$t2,"<br />";  
   $result.=&verifyReceipt_form($symb,$url);  
   my $t4=&Time::HiRes::time();  
   print "elapsed43=",$t4-$t3,"<br />";  
   print "Total elapsed time=",$t4-$t0,"<br />";  
   return $result;  
 }  
   
 sub view_edit_entire_class_form {  #------------------ End of general use routines --------------------
   my ($symb,$url)=@_;  #-------------------------------------------------------------------
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";  
   $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";  
   $result.='&nbsp;<b>View/Grade Entire Class</b></td></tr>'."\n";  
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  
   $result.='<form action="/adm/grades" method="post">'."\n".  
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
   '<input type="hidden" name="command" value="viewgrades" />'."\n";  
   $result.='&nbsp;<b>Display students who has: </b>'.  
       '<input type="radio" name="submitonly" value="yes" checked> submitted'.  
   '<input type="radio" name="submitonly" value="all"> everybody <br /><br />';  
   $result.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";  
   $result.='</td></tr></table>'."\n";  
   $result.='</td></tr></table>'."\n";  
   return $result;  
 }  
   
 sub upcsvScores_form {  
   my ($symb,$url) = @_;  
   if (!$symb) {return '';}  
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";  
   $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";  
   $result.='&nbsp;<b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";  
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  
   my $upfile_select=&Apache::loncommon::upfile_select_html();  
   $result.=<<ENDUPFORM;  
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  
 <input type="hidden" name="symb" value="$symb" />  
 <input type="hidden" name="url" value="$url" />  
 <input type="hidden" name="command" value="csvuploadmap" />  
 $upfile_select  
 <br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />  
 </form>  
 ENDUPFORM  
   $result.='</td></tr></table>'."\n";  
   $result.='</td></tr></table>'."\n";  
   return $result;  
 }  
   
 sub viewGradeaStu_form {  
   my ($symb,$url,$response,$handgrade) = @_;  
   
   
   my $t3=&Time::HiRes::time();  
   
   my ($classlist,$sections) = &getclasslist('all','0');  
   
   my $t4=&Time::HiRes::time();  
   print "elapsed_getclasslist=",$t4-$t3,"<br />";  
   
   #------------------------------------ Receipt Verification Routines
   #--- Check whether a receipt number is valid.---
   sub verifyreceipt {
       my $request  = shift;
   
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";      my $courseid = $ENV{'request.course.id'};
   $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";      my $receipt  = unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
   $result.='&nbsp;<b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n";   $ENV{'form.receipt'};
   $result.='<tr bgcolor=#ffffe6><td>'."\n";      $receipt     =~ s/[^\-\d]//g;
   $result.='<form action="/adm/grades" method="post">'."\n".      my $url      = $ENV{'form.url'};
      '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      my $symb     = $ENV{'form.symb'};
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      unless ($symb) {
        '<input type="hidden" name="response" value="'.$response.'" />'."\n".   $symb    = &Apache::lonnet::symbread($url);
         '<input type="hidden" name="handgrade" value="'.$handgrade.'" />'."\n".      }
  '<input type="hidden" name="command" value="submission" />'."\n";  
   
   $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";      my $jscript='<script type="text/javascript" language="javascript">'."\n".
   foreach my $section (sort (@$sections)) {   '    function viewOneStudent(user,domain) {'."\n".
       $result.= '<option>'.$section.'</option>'."\n";   ' document.onestudent.student.value = user;'."\n".
   }   ' document.onestudent.userdom.value = domain;'."\n".
   $result.= '<option selected="on">all</select>'."\n";   ' document.onestudent.submit();'."\n".
   $result.='&nbsp;&nbsp;<b>Display students who has: </b>'.   '    }'."\n".
       '<input type="radio" name="submitonly" value="yes" checked> submitted'.   '</script>'."\n";
   '<input type="radio" name="submitonly" value="all"> everybody <br />';      $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".
   $result.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />'    '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
       if (grep /no/,@$sections);   '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="submission" />'."\n".
   $result.='<br />&nbsp;<input type="submit" name="submit" value="View/Grade" />'."\n".   '<input type="hidden" name="student" value="" />'."\n".
       '</form>'."\n";   '<input type="hidden" name="userdom" value="" />'."\n".
   $result.='</td></tr></table>'."\n";   '</form>'."\n";
   $result.='</td></tr></table>'."\n";  
   return $result;      my $title.='<h2><font color="#339933">Verifying Submission Receipt '.
 }   $receipt.'</h2></font>'."\n".
    '<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br><br>'."\n";
   
       my ($string,$contents,$matches) = ('','',0);
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0');
       
       foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
    my ($uname,$udom)=split(/\:/);
    if ($receipt eq 
       &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
       $contents.='<tr bgcolor="#ffffe6"><td>&nbsp;'."\n".
    '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
    '\')"; TARGET=_self>'.$$fullname{$_}.'</a>&nbsp;</td>'."\n".
    '<td>&nbsp;'.$uname.'&nbsp;</td>'.
    '<td>&nbsp;'.$udom.'&nbsp;</td></tr>'."\n";
       
       $matches++;
    }
       }
       if ($matches == 0) {
    $string = $title.'No match found for the above receipt.';
       } else {
    $string = $jscript.$title.
       'The above receipt matches the following student'.
       ($matches <= 1 ? '.' : 's.')."\n".
       '<table border="0"><tr><td bgcolor="#777777">'."\n".
       '<table border="0"><tr bgcolor="#e6ffff">'."\n".
       '<td><b>&nbsp;Fullname&nbsp;</b></td>'."\n".
       '<td><b>&nbsp;Username&nbsp;</b></td>'."\n".
       '<td><b>&nbsp;Domain&nbsp;</b></td></tr>'."\n".
       $contents.
       '</table></td></tr></table>'."\n";
       }
       return $string.&show_grading_menu_form ($symb,$url);
   }
   
   #--- This is called by a number of programs.
   #--- Called from the Grading Menu - View/Grade an individual student
   #--- Also called directly when one clicks on the subm button 
   #    on the problem page.
   sub listStudents {
       my ($request) = shift;
       my $cdom      = $ENV{"course.$ENV{'request.course.id'}.domain"};
       my $cnum      = $ENV{"course.$ENV{'request.course.id'}.num"};
       my $getsec    = $ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'};
       my $submitonly= $ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
   
       my $result='<h2><font color="#339933">&nbsp;'.
    'View Submissions for a Student or a Group of Students</font></h2>';
       $result.='<table border="0">';
       $result.='<tr><td colspan=3><font size=+1>'.
    '<b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>';
       my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
       for (sort keys(%$handgrade)) {
    my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
    $ENV{'form.handgrade'} = 'yes' if ($handgrade eq 'yes');
    $result.='<tr><td><b>Part </b>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $request->print($result);
   
 sub verifyReceipt_form {      $request->print(<<ENDTABLEST);
   my ($symb,$url) = @_;  <form action="/adm/grades" method="post">
   my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};  &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no 
   my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};  <input type="radio" name="vProb" value="yes"> yes <br />
   my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});  &nbsp;<b>Submissions: </b>
   <input type="radio" name="lastSub" value="hdgrade" checked /> handgrade only
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";  <input type="radio" name="lastSub" value="lastonly" /> last sub only
   $result.='<table width=100% border=0><tr><td bgcolor=#e6ffff>'."\n";  <input type="radio" name="lastSub" value="last" /> last sub & parts info
   $result.='&nbsp;<b>Verify a Submission Receipt Issued by this Server</td></tr>'."\n";  <input type="radio" name="lastSub" value="all" /> all details
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  <input type="hidden" name="section" value="$getsec" />
   $result.='<form action="/adm/grades" method="post">'."\n";  <input type="hidden" name="submitonly" value="$submitonly" />
   $result.='&nbsp;<tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n";  <input type="hidden" name="response" value="$ENV{'form.response'}" />
   $result.='&nbsp;<input type="submit" name="submit" value="Verify Receipt">'."\n";  <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" /><br />
   $result.='<input type="hidden" name="command" value="verify">'."\n";  <input type="hidden" name="showgrading" value="$ENV{'form.showgrading'}" /><br />
   if ($ENV{'form.url'}) {  <input type="submit" name="submit" value="View/Grade" />
       $result.='<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />';  ENDTABLEST
   }      if ($ENV{'form.url'}) {
   if ($ENV{'form.symb'}) {   $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
       $result.='<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />';      }
   }      if ($ENV{'form.symb'}) {
   $result.='</form>';   $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
   $result.='</td></tr></table>'."\n";      }
   $result.='</td></tr></table>'."\n";      $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
   return $result;  
 }  
   
 sub viewgrades {      my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
   my ($request) = @_;      
   my $result='';      $result='<table border="0"><tr><td bgcolor="#777777">'.
    '<table border="0"><tr bgcolor="#e6ffff">'.
    '<td><b>&nbsp;Select&nbsp;</b></td><td><b>&nbsp;Fullname&nbsp;</b></td>'.
    '<td><b>&nbsp;Username&nbsp;</b></td><td><b>&nbsp;Domain&nbsp;</b></td>';
       foreach (sort(@$partlist)) {
    $result.='<td><b>&nbsp;Part '.(split(/_/))[0].' Status&nbsp;</b></td>';
       }
       $request->print($result.'</tr>'."\n");
   
       foreach my $student (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
    my ($uname,$udom) = split(/:/,$student);
    my (%status) = &student_gradeStatus($ENV{'form.url'},
       $ENV{'form.symb'},$udom,$uname,$partlist);
    my $statusflg = '';
    foreach (keys(%status)) {
       $statusflg = 1 if ($status{$_} ne 'nothing');
       my ($foo,$partid,$foo1) = split(/\./,$_);
       if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
    $statusflg = '';
    $request->print('<input type="hidden" name="'.
    $student.':submitted_by" value="'.
    $status{'resource.'.$partid.'.submitted_by'}.'" />');
       }
    }
    next if ($statusflg eq '' && $submitonly eq 'yes');
   
   #get resource reference   if ( $Apache::grades::viewgrades eq 'F' ) {
   my ($symb,$url)=&get_symb_and_url($request);      $result='<tr bgcolor="#ffffe6">'.
   if (!$symb) {return '';}   '<td align="center"><input type=checkbox name="stuinfo" value="'.
   #get classlist   $student.':'.$$fullname{$student}.'"></td>'."\n".
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});   '<td>&nbsp;'.$$fullname{$student}.'&nbsp;</td>'."\n".
   #print "Found $cdom:$cnum<br />";   '<td>&nbsp;'.$uname.'&nbsp;</td>'."\n".
   my ($classlist) = &getclasslist('all','0');   '<td align="middle">&nbsp;'.$udom.'&nbsp;</td>'."\n";
   my $headerclr = '"#ddffff"';      
   my $cellclr = '"#ffffdd"';      foreach (sort keys(%status)) {
    next if (/^resource.*?submitted_by$/);
   #get list of parts for this problem   $result.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";
   my (@parts) = sort(&getpartlist($url));      }
       $request->print($result.'</tr>'."\n");
   $request->print ("<h2><font color=\"#339933\">Manual Grading</font></h2>");   }
       }
   #start the form      $request->print('</table></td></tr></table>');
   $result = '<form action="/adm/grades" method="post">'."\n".      $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      return '';
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
  '<input type="hidden" name="command" value="editgrades" />'."\n".  
   '<input type="submit" name="submit" value="Submit Changes" />'."\n".  
     '<table border=0><tr><td bgcolor="#777777">'."\n".  
      '<table border=0>'."\n".  
       '<tr bgcolor='.$headerclr.'><td><b>Username</b></td><td><b>Fullname</b></td><td><b>Domain</b></td>'."\n";  
   foreach my $part (@parts) {  
      my $display=&Apache::lonnet::metadata($url,$part.'.display');  
      if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }  
      $result.='<td><b>'.$display.'</b></td>'."\n";  
   }  
   $result.='</tr>';  
   #get info for each student  
   foreach my $student ( sort(@{ $$classlist{'all'} }) ) {  
 #    my $display=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
 #      print "ID=$ENV{'request.course.id'}:STU=$student:DIS=$display:<br>\n";  
     $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
   }  
   $result.='</table></td></tr></table>';  
   $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';  
   $result.=&show_grading_menu_form($symb,$url);  
   return $result;  
 }  }
   
 sub editgrades {  #---- Called from the listStudents routine
   my ($request) = @_;  #     Displays the submissions for one student or a group of students
   my $result='';  sub processGroup {
       my ($request)  = shift;
   my $symb=$ENV{'form.symb'};      my $ctr        = 0;
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }      my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
   my $url=$ENV{'form.url'};        : ($ENV{'form.stuinfo'}));
   #get classlist      my $total      = scalar(@stuchecked)-1;
 #  my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});      if ($stuchecked[0] eq '') {
   #print "Found $cdom:$cnum<br />";   &userError($request,'No student was selected for viewing/grading.');
   my ($classlist) = &getclasslist('all','0');   return;
       }
   #get list of parts for this problem      foreach (@stuchecked) {
   my (@parts) = &getpartlist($url);   my ($uname,$udom,$fullname) = split(/:/);
    $ENV{'form.student'}        = $uname;
   $result.='<form action="/adm/grades" method="post">'."\n".   $ENV{'form.userdom'}        = $udom;
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".   $ENV{'form.fullname'}       = $fullname;
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".   &submission($request,$ctr,$total);
  '<input type="hidden" name="command" value="viewgrades" />'."\n".   $ctr++;
   '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";      }
       return '';
   foreach my $student ( sort(@{ $$classlist{'all'} }) ) {  
     $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
   }  
   
   $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';  
   return $result;  
 }  }
   
   #------------------------------------------------------------------------------------
   #
   #-------------------------- Next few routines handles grading by student, essentially
   #                           handles essay response type problem/part
   #
   #--- Javascript to handle the submission page functionality ---
 sub sub_page_js {  sub sub_page_js {
   my $request = shift;      my $request = shift;
   $request->print(<<SUBJAVASCRIPT);      $request->print(<<SUBJAVASCRIPT);
 <script type="text/javascript" language="javascript">  <script type="text/javascript" language="javascript">
   function updateRadio(radioButton,formtextbox,formsel,wgt) {    function updateRadio(radioButton,formtextbox,formsel,scores,weight) {
      var pts = formtextbox.value;       var pts = formtextbox.value;
      var resetbox =false;       var resetbox =false;
      if (isNaN(pts) || pts < 0) {       if (isNaN(pts) || pts < 0) {
  alert("A number equal or greater than 0 is expected. Entered value = "+pts);          alert("A number equal or greater than 0 is expected. Entered value = "+pts);
  for (var i=0; i<radioButton.length; i++) {          for (var i=0; i<radioButton.length; i++) {
    if (radioButton[i].checked) {             if (radioButton[i].checked) {
       formtextbox.value = i;        formtextbox.value = i;
       resetbox = true;        resetbox = true;
    }     }
Line 1042  sub sub_page_js { Line 442  sub sub_page_js {
    formtextbox.value = "";     formtextbox.value = "";
  }   }
  return;   return;
        }
   
        if (pts > weight) {
           var resp = confirm("You entered a value ("+pts+
             ") greater than the weight for the part. Accept?");
           if (resp == false) {
              formtextbox.value = "";
              return;
          }
     }      }
   
     for (var i=0; i<radioButton.length; i++) {      for (var i=0; i<radioButton.length; i++) {
Line 1050  sub sub_page_js { Line 459  sub sub_page_js {
    radioButton[i].checked=true;     radioButton[i].checked=true;
  }   }
     }      }
     updateSelect(formsel,pts,wgt);      updateSelect(formsel);
       scores.value = "0";
   }    }
   
   function writeBox(formrad,formsel,pts,wgt) {    function writeBox(formrad,formsel,pts,scores) {
     formrad.value = pts;      formrad.value = pts;
     updateSelect(formsel,pts,wgt);      scores.value = "0";
       updateSelect(formsel,pts);
     return;      return;
   }    }
   
   function updateSelect(formsel,pts,wgt) {    function clearRadBox(radioButton,formbox,formsel,scores) {
     if (pts == 0) {      for (var i=0; i<formsel.length; i++) {
       formsel[1].selected = true;   if (formsel[i].selected) {
     }      var selectx=i;
     if (pts > 0 && pts < wgt) {   }
       formsel[4].selected = true;  
     }      }
     if (pts == wgt) {      if (selectx == scores.value) { return };
       formsel[0].selected = true;      formbox.value = "";
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
     }      }
       scores.value = selectx;
     }
   
     function updateSelect(formsel) {
       formsel[0].selected = true;
     return;      return;
   }    }
   
   //===================== Show list of keywords ====================
   function keywords(keyform) {    function keywords(keyform) {
     var keywds = keyform.value;      var keywds = keyform.value;
     var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);      var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);
     if (nret==null) return;      if (nret==null) return;
     keyform.value = nret;      keyform.value = nret;
   
       document.SCORE.refresh.value = "on";
       if (document.SCORE.keywords.value != "") {
    document.SCORE.submit();
       }
       return;
     }
   
   //===================== Script to view submitted by ==================
     function viewSubmitter(submitter) {
       document.SCORE.refresh.value = "on";
       document.SCORE.NCT.value = "1";
       document.SCORE.unamedom0.value = submitter;
       document.SCORE.submit();
     return;      return;
   }    }
   
Line 1094  sub sub_page_js { Line 526  sub sub_page_js {
     if (nret==null) return;      if (nret==null) return;
     var curlist = document.SCORE.keywords.value;      var curlist = document.SCORE.keywords.value;
     document.SCORE.keywords.value = curlist+" "+nret;      document.SCORE.keywords.value = curlist+" "+nret;
       document.SCORE.refresh.value = "on";
       if (document.SCORE.keywords.value != "") {
    document.SCORE.submit();
       }
     return;      return;
   }    }
   
Line 1104  sub sub_page_js { Line 540  sub sub_page_js {
     var subject = msgform.msgsub.value;      var subject = msgform.msgsub.value;
     var rtrchk  = eval("document.SCORE.includemsg"+usrctr);      var rtrchk  = eval("document.SCORE.includemsg"+usrctr);
     var msgchk = rtrchk.value;      var msgchk = rtrchk.value;
 //    alert("checked=>"+msgchk);  
     re = /msgsub/;      re = /msgsub/;
     var shwsel = "";      var shwsel = "";
     if (re.test(msgchk)) { shwsel = "checked" }      if (re.test(msgchk)) { shwsel = "checked" }
Line 1166  sub sub_page_js { Line 601  sub sub_page_js {
     pWin.document.write("  var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");      pWin.document.write("  var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");
     pWin.document.write("  includemsg.value = msgchk;");      pWin.document.write("  includemsg.value = msgchk;");
   
 //    pWin.document.write("  alert(\\"slected=\\"+msgchk)");  
     pWin.document.write("  self.close()");      pWin.document.write("  self.close()");
   
     pWin.document.write("}");      pWin.document.write("}");
Line 1202  function displaySavedMsg(ctr,msg,shwsel) Line 636  function displaySavedMsg(ctr,msg,shwsel)
     pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");      pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
     pWin.document.write("<td align=\\"center\\">New</td>");      pWin.document.write("<td align=\\"center\\">New</td>");
     pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");      pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
     pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");      pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
 }  }
   
   function msgTail() {    function msgTail() {
Line 1252  function displaySavedMsg(ctr,msg,shwsel) Line 686  function displaySavedMsg(ctr,msg,shwsel)
     hwdWin.document.write("<title>Highlight Central</title>");      hwdWin.document.write("<title>Highlight Central</title>");
   
     hwdWin.document.write("<script language=javascript>");      hwdWin.document.write("<script language=javascript>");
     hwdWin.document.write("function updateChoice() {");      hwdWin.document.write("function updateChoice(flag) {");
     hwdWin.document.write("  opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");      hwdWin.document.write("  opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");
     hwdWin.document.write("  opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");      hwdWin.document.write("  opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");
     hwdWin.document.write("  opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");      hwdWin.document.write("  opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");
       hwdWin.document.write("  opener.document.SCORE.refresh.value = \\"on\\";");
       hwdWin.document.write("  if (opener.document.SCORE.keywords.value!=\\"\\"){");
       hwdWin.document.write("     opener.document.SCORE.submit();");
       hwdWin.document.write("  }");
     hwdWin.document.write("  self.close()");      hwdWin.document.write("  self.close()");
     hwdWin.document.write("}");      hwdWin.document.write("}");
   
Line 1296  function displaySavedMsg(ctr,msg,shwsel) Line 734  function displaySavedMsg(ctr,msg,shwsel)
   function highlightend() {     function highlightend() { 
     hwdWin.document.write("</table>");      hwdWin.document.write("</table>");
     hwdWin.document.write("</td></tr></table>&nbsp;");      hwdWin.document.write("</td></tr></table>&nbsp;");
     hwdWin.document.write("<input type=\\"button\\" value=\\"Set Options\\" onClick=\\"javascript:updateChoice()\\">&nbsp;&nbsp;");  //    hwdWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(0)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");
     hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");      hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
     hwdWin.document.write("</form>");      hwdWin.document.write("</form>");
     hwdWin.document.write("</body></html>");      hwdWin.document.write("</body></html>");
Line 1306  function displaySavedMsg(ctr,msg,shwsel) Line 745  function displaySavedMsg(ctr,msg,shwsel)
 SUBJAVASCRIPT  SUBJAVASCRIPT
 }  }
   
   
   # --------------------------- show submissions of a student, option to grade 
   sub submission {
       my ($request,$counter,$total) = @_;
   
       (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
   #    if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }
       my ($uname,$udom)     = ($ENV{'form.student'},$ENV{'form.userdom'});
       ($uname,$udom)        = &finduser($uname) if $udom eq '';
       $ENV{'form.fullname'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq '';
   #    if ($uname eq '') { &moreinfo($request,'Unable to find student'); return ''; }
   
       my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
       if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
       my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');
       $ENV{'form.vProb'} = $ENV{'form.vProb'} ne '' ? $ENV{'form.vProb'} : 'yes';
       my ($classlist,$seclist,$ids,$stusec,$fullname);
   
       # header info
       if ($counter == 0) {
    &sub_page_js($request);
    $request->print('<h2>&nbsp;<font color="#339933">Submission Record</font></h2>'.
    '<font size=+1>&nbsp;<b>Resource: </b>'.$url.'</font>');
   
    # option to display problem, only once else it cause problems 
           # with the form later since the problem has a form.
    if ($ENV{'form.vProb'} eq 'yes') {
       my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,
         $ENV{'request.course.id'});
       my $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,
      $ENV{'request.course.id'});
       my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">';
       $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">';
       $result.='<b> View of the problem for '.$ENV{'form.fullname'}.
    '</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />';
       $result.='<b>Correct answer:</b><br />'.$companswer;
       $result.='</td></tr></table>';
       $result.='</td></tr></table><br />';
       $request->print($result);
    }
   
    # kwclr is the only variable that is guaranteed to be non blank 
           # if this subroutine has been called once.
    my %keyhash = ();
    if ($ENV{'form.kwclr'} eq '') {
       %keyhash = &Apache::lonnet::dump('nohist_handgrade',
        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
       my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
       $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';
       $ENV{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';
       $ENV{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';
       $ENV{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
       $ENV{'form.msgsub'}   = $keyhash{$symb.'_subject'} ne '' ? 
    $keyhash{$symb.'_subject'} : &Apache::lonnet::metadata($url,'title');
       $ENV{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
   
    }
   
    $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".
    '<input type="hidden" name="command"    value="handgrade" />'."\n".
    '<input type="hidden" name="refresh"    value="off" />'."\n".
    '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url"        value="'.$url.'" />'."\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="lastSub"    value="'.$ENV{'form.lastSub'}.'" />'."\n".
    '<input type="hidden" name="section"    value="'.$ENV{'form.section'}.'">'."\n".
    '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".
    '<input type="hidden" name="response"   value="'.$ENV{'form.response'}.'">'."\n".
    '<input type="hidden" name="handgrade"  value="'.$ENV{'form.handgrade'}.'">'."\n".
    '<input type="hidden" name="keywords"   value="'.$ENV{'form.keywords'}.'" />'."\n".
    '<input type="hidden" name="kwclr"      value="'.$ENV{'form.kwclr'}.'" />'."\n".
    '<input type="hidden" name="kwsize"     value="'.$ENV{'form.kwsize'}.'" />'."\n".
    '<input type="hidden" name="kwstyle"    value="'.$ENV{'form.kwstyle'}.'" />'."\n".
    '<input type="hidden" name="msgsub"     value="'.$ENV{'form.msgsub'}.'" />'."\n".
    '<input type="hidden" name="savemsgN"   value="'.$ENV{'form.savemsgN'}.'" />'."\n".
    '<input type="hidden" name="NCT"'.
    ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");
   
    my ($cts,$prnmsg) = (1,'');
    while ($cts <= $ENV{'form.savemsgN'}) {
       $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.
    ($keyhash{$symb.'_savemsg'.$cts} eq '' ? $ENV{'form.savemsg'.$cts} : $keyhash{$symb.'_savemsg'.$cts}).
    '" />'."\n";
       $cts++;
    }
    $request->print($prnmsg);
   
    if ($ENV{'form.handgrade'} eq 'yes' && $ENV{'form.showgrading'} eq 'yes') {
       $request->print(<<KEYWORDS);
   &nbsp;<b>Keyword Options:</b>&nbsp;
   <a href="javascript:keywords(document.SCORE.keywords)"; 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 />
   KEYWORDS
           }
       }
   
       my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
       my ($partlist,$handgrade) = &response_type($url);
   
       # Display student info
       $request->print(($counter == 0 ? '' : '<br />'));
       my $result='<table border="0" width=100%><tr><td bgcolor="#777777">'.
    '<table border="0" width=100%><tr bgcolor="#edffff"><td>';
   
   #    $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Fullname: </b>'.$ENV{'form.fullname'}.
       $result.='<b>Fullname: </b>'.$ENV{'form.fullname'}.
    '<font color="#999999">&nbsp; &nbsp;Username: '.$uname.'</font>'.
    '<font color="#999999">&nbsp; &nbsp;Domain: '.$udom.'</font><br />';
   
       # If this is handgraded, then check for collaborators
       my $col_flag = 0;
       if ($ENV{'form.handgrade'} eq 'yes') {
    my @col_list;
    ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0');
    for (keys (%$handgrade)) {
       my $ncol = &Apache::lonnet::EXT('resource.'.$_.
       '.maxcollaborators',$symb,$udom,$uname);
       if ($ncol > 0) {
    s/\_/\./g;
    if ($record{'resource.'.$_.'.collaborators'} ne '') {
       my (@collaborators) = split(/,?\s+/,
    $record{'resource.'.$_.'.collaborators'});
       my (@badcollaborators);
       if (scalar(@collaborators) != 0) {
    $result.='<b>Collaborators: </b>';
    foreach my $collaborator (@collaborators) {
       $collaborator = $collaborator =~ /\@|:/ ? 
    (split(/@|:/,$collaborator))[0] : $collaborator;
       next if ($collaborator eq $uname);
       if (!grep /^$collaborator:/i,keys %$classlist) {
    push @badcollaborators,$collaborator;
    next;
       }
       $col_flag++;
       push @col_list, $collaborator;
       $result.=$$fullname{$collaborator.':'.$udom}.'&nbsp; &nbsp; &nbsp;';
    }
    $result.='<br />'."\n";
    $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'.
       'This student has submitted '.
       (scalar (@badcollaborators) > 1 ? '' : 'an').
       ' invalid collaborator'.(scalar (@badcollaborators) > 1 ? 's. ' : '. ').
       (join ', ',@badcollaborators).'</td></tr></table>' 
       if (scalar(@badcollaborators) > 0);
   
    $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>'.
       'This student has submitted too many collaborators. Maximum is '.
       $ncol.'.</td></tr></table>' if (scalar(@collaborators) > $ncol);
    $result.='<input type="hidden" name="collaborator'.$counter.
       '" value="'.(join ':',@col_list).'" />'."\n";
       }
    }
       }
    }
       }
       $request->print($result."\n");
   
       # print student answer/submission
       # Options are (1) Handgaded submission only
       #             (2) Last submission, includes submission that is not handgraded 
       #                  (for multi-response type part)
       #             (3) Last submission plus the parts info
       #             (4) The whole record for this student
       if ($ENV{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
    if ($ENV{'form.'.$uname.':'.$udom.':submitted_by'}) {
       my $submitby=''.
    '<b>Collaborative submission by: </b>'.
    '<a href="javascript:viewSubmitter(\''.
    $ENV{'form.'.$uname.':'.$udom.':submitted_by'}.
    '\')"; TARGET=_self>'.
    $$fullname{$ENV{'form.'.$uname.':'.$udom.':submitted_by'}}.'</a>';
       $request->print($submitby);
    } else {
       my ($string,$timestamp)=
    &get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'});
       my $lastsubonly.=''.
    ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '.
    $$timestamp).'';
       if ($$timestamp eq '') {
    $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>';
       } else {
    for my $part (sort keys(%$handgrade)) {
       foreach (@$string) {
    my ($partid,$respid) = /^resource\.(\d+)\.(\d+)\.submission/;
    if ($part eq ($partid.'_'.$respid)) {
       my ($ressub,$subval) = split(/:/,$_,2);
       $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '.
    $partid.'</b> <font color="#999999">( ID '.$respid.
    ' )</font>&nbsp; &nbsp;<b>Answer: </b>'.
    &keywords_highlight($subval).'</td></tr>'
    if ($ENV{'form.lastSub'} eq 'lastonly' || 
       ($ENV{'form.lastSub'} eq 'hdgrade' && 
        $$handgrade{$part} =~ /:yes$/));
    }
       }
    }
       }
       $lastsubonly.='</td></tr><tr><td bgcolor="#ffffff">'."\n";
       $request->print($lastsubonly);
    }
       } else {
    $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
    $ENV{'request.course.id'},
    $last,'.submission',
    'Apache::grades::keywords_highlight'));
       }
       
       # return if view submission with no grading option
       if ($ENV{'form.showgrading'} eq '') {
    $request->print('</td></tr></table></td></tr></table></form>');
    return;
       }
   
       # Grading options
       $result='<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n".
    '<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n".
    '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";
       $result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
    ',\''.$ENV{'form.fullname'}.'\')"; TARGET=_self>'.
    'Compose Message to student'.($col_flag > 1 ? 's' : '').'</a>'.
    '<br />&nbsp;(Message will be sent when you click on Save & Next below.)'."\n" 
    if ($ENV{'form.handgrade'} eq 'yes');
       $request->print($result);
   
       my %seen = ();
       my @partlist;
       for (sort keys(%$handgrade)) {
    my ($partid,$respid) = split(/_/);
    next if ($seen{$partid} > 0);
    $seen{$partid}++;
    next if ($$handgrade{$_} =~ /:no$/);
    push @partlist,$partid;
    my $wgt    = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
    my $wgtmsg = ($wgt > 0 ? '(problem weight)' : 
         '<font color="red">problem weight assigned by computer</font>');
    $wgt       = ($wgt > 0 ? $wgt : '1');
    my $score  = ($record{'resource.'.$partid.'.awarded'} eq '' ?
         '' : $record{'resource.'.$partid.'.awarded'}*$wgt);
    $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />';
    $result.='<table border="0"><tr><td><b>Part </b>'.$partid.' <b>Points: </b></td><td>';
   
    my $ctr = 0;
    $result.='<table border="0"><tr>';  # display radio buttons in a nice table 10 across
    while ($ctr<=$wgt) {
       $result.= '<td><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
    'onclick="javascript:writeBox(this.form.GD_BOX'.$counter.'_'.$partid.
    ',this.form.GD_SEL'.$counter.'_'.$partid.','.$ctr.
    ',this.form.stores'.$counter.'_'.$partid.')" '.
    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
       $ctr++;
    }
    $result.='</tr></table>';
   
    $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';
    $result.='<td><input type="text" name="GD_BOX'.$counter.'_'.$partid.'"'.
       ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
       'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GD_BOX'.$counter.'_'.$partid.
       ',this.form.GD_SEL'.$counter.'_'.$partid.
       ',this.form.stores'.$counter.'_'.$partid.
       ','.$wgt.')" /></td>'."\n";
    $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';
   
    $result.='<select name="GD_SEL'.$counter.'_'.$partid.'" '.
       'onChange="javascript:clearRadBox(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GD_BOX'.$counter.'_'.$partid.
       ',this.form.GD_SEL'.$counter.'_'.$partid.
       ',this.form.stores'.$counter.'_'.$partid.')" />'."\n".
       '<option selected="on"> </option>'.
       '<option>excused</option></select>'."&nbsp&nbsp\n";
    $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="0" />';
    $result.='</td></tr></table>';
    $request->print($result);
       }
       $request->print('<input type="hidden" name="partlist'.$counter.'" value="'.(join ":",@partlist).'" />'."\n");
       $request->print('</td></tr></table></td></tr></table>'."\n");
   
       # print end of form
       if ($counter == $total) {
    my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';
    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</;
    $endform.=$ntstu.'student(s) &nbsp;&nbsp;'.
       '<input type="submit" name="gradeOpt" value="Next" />&nbsp'.
       '<input type="submit" name="gradeOpt" value="Previous" />&nbsp'.
       '(Next and Previous do not save the scores.)'.
       '</td><tr></table></form>';
    $request->print($endform);
       }
       return '';
   }
   
   #--- Retrieve the last submission for all the parts
   sub get_last_submission {
       my ($symb,$username,$domain,$course)=@_;
       if ($symb) {
    my (@string,$timestamp);
    my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);
    if ($returnhash{'version'}) {
       my %lasthash=();
       my ($version);
       for ($version=1;$version<=$returnhash{'version'};$version++) {
    foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
       $lasthash{$_}=$returnhash{$version.':'.$_};
    }
       }
       foreach ((keys %lasthash)) {
    if ($_ =~ /\.submission$/) {
       my ($partid,$foo) = split(/submission$/,$_);
       my $draft  = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ?
    '<font color="red">Draft Copy</font> ' : '';
       push @string, (join(':',$_,$draft.$lasthash{$_}));
    }
    if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))};
       }
    }
    @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
    return \@string,\$timestamp;
       }
   }
   
   #--- High light keywords, with style choosen by user.
   sub keywords_highlight {
       my $string    = shift;
       my $size      = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};
       my $styleon   = $ENV{'form.kwstyle'} eq ''  ? '' : $ENV{'form.kwstyle'};
       (my $styleoff = $styleon) =~ s/\</\<\//;
       my @keylist   = split(/[,\s+]/,$ENV{'form.keywords'});
       foreach (@keylist) {
    $string =~ s/\b$_(\b|\.)/\<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff\<\/font\>/gi;
       }
       return $string;
   }
   
   #--- Called from submission routine
   sub processHandGrade {
       my ($request) = shift;
       my $url    = $ENV{'form.url'};
       my $symb   = $ENV{'form.symb'};
       my $button = $ENV{'form.gradeOpt'};
       my $ngrade = $ENV{'form.NCT'};
       my $ntstu  = $ENV{'form.NTSTU'};
   
       if ($button eq 'Save & Next') {
    my $ctr = 0;
    while ($ctr < $ngrade) {
       my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
       my ($errorflg) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);
       return '' if ($errorflg eq 'error');
   
       my $includemsg = $ENV{'form.includemsg'.$ctr};
       my ($subject,$message,$msgstatus) = ('','','');
       if ($includemsg =~ /savemsg|new$ctr/) {
    $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/);
    my (@msgnum) = split(/,/,$includemsg);
    foreach (@msgnum) {
       $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');
    }
    $message =~ s/\s+/ /g;
    $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,
          $ENV{'form.msgsub'},$message);
       }
       if ($ENV{'form.collaborator'.$ctr}) {
    my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr});
    foreach (@collaborators) {
       &saveHandGrade($request,$url,$symb,$_,$udom,$ctr,
      $ENV{'form.unamedom'.$ctr});
       if ($message ne '') {
    $msgstatus = &Apache::lonmsg::user_normal_msg ($_,$udom,
          $ENV{'form.msgsub'},
          $message);
       }
    }
       }
       $ctr++;
    }
       }
   
       # Keywords sorted in alphabatical order
       my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
       my %keyhash = ();
       $ENV{'form.keywords'}           =~ s/,\s{0,}|\s+/ /g;
       $ENV{'form.keywords'}           =~ s/^\s+|\s+$//;
       my (@keywords) = sort(split(/\s+/,$ENV{'form.keywords'}));
       $ENV{'form.keywords'} = join(' ',@keywords);
       $keyhash{$symb.'_keywords'}     = $ENV{'form.keywords'};
       $keyhash{$symb.'_subject'}      = $ENV{'form.msgsub'};
       $keyhash{$loginuser.'_kwclr'}   = $ENV{'form.kwclr'};
       $keyhash{$loginuser.'_kwsize'}  = $ENV{'form.kwsize'};
       $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};
   
       # message center - Order of message gets changed. Blank line is eliminated.
       # New messages are saved in ENV for the next student.
       # All messages are saved in nohist_handgrade.db
       my ($ctr,$idx) = (1,1);
       while ($ctr <= $ENV{'form.savemsgN'}) {
    if ($ENV{'form.savemsg'.$ctr} ne '') {
       $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};
       $idx++;
    }
    $ctr++;
       }
       $ctr = 0;
       while ($ctr < $ngrade) {
    if ($ENV{'form.newmsg'.$ctr} ne '') {
       $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
       $ENV{'form.savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};
       $idx++;
    }
    $ctr++;
       }
       $ENV{'form.savemsgN'} = --$idx;
       $keyhash{$symb.'_savemsgN'} = $ENV{'form.savemsgN'};
       my $putresult = &Apache::lonnet::put
    ('nohist_handgrade',\%keyhash,
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
       # Called by Save & Refresh from Highlight Attribute Window
       if ($ENV{'form.refresh'} eq 'on') {
    my $ctr = 0;
    $ENV{'form.NTSTU'}=$ngrade;
    while ($ctr < $ngrade) {
       ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$ENV{'form.unamedom'.$ctr});
       &submission($request,$ctr,$ngrade-1);
       $ctr++;
    }
    return '';
       }
   
       # Get the next/previous one or group of students
       my $firststu = $ENV{'form.unamedom0'};
       my $laststu = $ENV{'form.unamedom'.($ngrade-1)};
       $ctr = 2;
       while ($laststu eq '') {
    $laststu  = $ENV{'form.unamedom'.($ngrade-$ctr)};
    $ctr++;
    $laststu = $firststu if ($ctr > $ngrade);
       }
   
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
       my (@parsedlist,@nextlist);
       my ($nextflg) = 0;
       foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
    if ($nextflg == 1 && $button =~ /Next$/) {
       push @parsedlist,$_;
    }
    $nextflg = 1 if ($_ eq $laststu);
    if ($button eq 'Previous') {
       last if ($_ eq $firststu);
       push @parsedlist,$_;
    }
       }
       $ctr = 0;
       my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
       @parsedlist = reverse @parsedlist if ($button eq 'Previous');
       foreach my $student (@parsedlist) {
    my ($uname,$udom) = split(/:/,$student);
    if ($ENV{'form.submitonly'} eq 'yes') {
       my (%status) = &student_gradeStatus($ENV{'form.url'},$symb,$udom,$uname,$partlist) ;
       my $statusflg = '';
       foreach (keys(%status)) {
    $statusflg = 1 if ($status{$_} ne 'nothing');
    my ($foo,$partid,$foo1) = split(/\./);
    $statusflg = '' if ($status{'resource.'.$partid.'.submitted_by'} ne '');
       }
       next if ($statusflg eq '');
    }
    push @nextlist,$student if ($ctr < $ntstu);
    $ctr++;
       }
   
       $ctr = 0;
       my $total = scalar(@nextlist)-1;
   
       foreach (sort @nextlist) {
    my ($uname,$udom,$submitter) = split(/:/);
    $ENV{'form.student'}  = $uname;
    $ENV{'form.userdom'}  = $udom;
    $ENV{'form.fullname'} = $$fullname{$_};
   # $ENV{'form.'.$_.':submitted_by'} = $submitter;
   # print "submitter=$ENV{'form.'.$_.':submitted_by'}= $submitter:<br>";
    &submission($request,$ctr,$total);
    $ctr++;
       }
       if ($total < 0) {
    my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";
    $the_end.='<b>Message: </b> No more students for this section or class.<br /><br />'."\n";
    $the_end.='Click on the button below to return to the grading menu.<br /><br />'."\n";
    $the_end.=&show_grading_menu_form ($symb,$url);
    $request->print($the_end);
       }
       return '';
   }
   
   #---- Save the score and award for each student, if changed
   sub saveHandGrade {
       my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_;
       my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
       my %newrecord;
       foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
    if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') {
       $newrecord{'resource.'.$_.'.solved'} = 'excused' 
    if ($record{'resource.'.$_.'.solved'} ne 'excused');
    } else {
       my $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? 
          $ENV{'form.GD_BOX'.$newflg.'_'.$_} : 
          $ENV{'form.RADVAL'.$newflg.'_'.$_});
       if ($pts eq '') {
    &userError($request,'No point was assigned for part '.$_.
      ' and for username '.$stuname.'.');
    return 'error';
       }
       my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : 
    $ENV{'form.WGT'.$newflg.'_'.$_};
       my $partial= $pts/$wgt;
       $newrecord{'resource.'.$_.'.awarded'}  = $partial 
    if ($record{'resource.'.$_.'.awarded'} ne $partial);
       my $reckey = 'resource.'.$_.'.solved';
       if ($partial == 0) {
    $newrecord{$reckey} = 'incorrect_by_override' 
       if ($record{$reckey} ne 'incorrect_by_override');
       } else {
    $newrecord{$reckey} = 'correct_by_override' 
       if ($record{$reckey} ne 'correct_by_override');
       }
       $newrecord{'resource.'.$_.'.submitted_by'} = $submitter 
    if ($submitter && ($record{'resource.'.$_.'.submitted_by'} ne $submitter));
    }
       }
   
       if (scalar(keys(%newrecord)) > 0) {
    $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
    &Apache::lonnet::cstore(\%newrecord,$symb,
    $ENV{'request.course.id'},$domain,$stuname);
       }
       return '';
   }
   
   #--------------------------------------------------------------------------------------
   #
   #-------------------------- Next few routines handles grading by section or whole class
   #
   #--- Javascript to handle grading by section or whole class
   sub viewgrades_js {
       my ($request) = shift;
   
       $request->print(<<VIEWJAVASCRIPT);
   <script type="text/javascript" language="javascript">
       function viewOneStudent(user,domain) {
    document.onestudent.student.value = user;
    document.onestudent.userdom.value = domain;
    document.onestudent.submit();
       }
   
       function writePoint(partid,weight,point) {
    var radioButton = eval("document.classgrade.RADVAL_"+partid);
    var textbox = eval("document.classgrade.TEXTVAL_"+partid);
    if (point == "textval") {
       var point = eval("document.classgrade.TEXTVAL_"+partid+".value");
       if (isNaN(point) || point < 0) {
    alert("A number equal or greater than 0 is expected. Entered value = "+point);
    var resetbox = false;
    for (var i=0; i<radioButton.length; i++) {
       if (radioButton[i].checked) {
    textbox.value = i;
    resetbox = true;
       }
    }
    if (!resetbox) {
       textbox.value = "";
    }
    return;
       }
       if (point > weight) {
    var resp = confirm("You entered a value ("+point+
      ") greater than the weight for the part. Accept?");
    if (resp == false) {
       textbox.value = "";
       return;
    }
       }
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
    if (point == i) {
       radioButton[i].checked=true;
    }
       }
   
    } else {
       textbox.value = point;
    }
    for (i=0;i<document.classgrade.total.value;i++) {
       var user = eval("document.classgrade.ctr"+i+".value");
       var scorename = eval("document.classgrade.GD_"+user+
    "_"+partid+"_aw");
       var saveval   = eval("document.classgrade.GD_"+user+
    "_"+partid+"_sv_s.value");
       var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
       if (saveval != "correct") {
    scorename.value = point;
    if (selname[0].selected != true) {
       selname[0].selected = true;
    }
       }
    }
    var selval   = eval("document.classgrade.SELVAL_"+partid);
    selval[0].selected = true;
       }
   
       function writeRadText(partid,weight) {
    var selval   = eval("document.classgrade.SELVAL_"+partid);
    var radioButton = eval("document.classgrade.RADVAL_"+partid);
    var textbox = eval("document.classgrade.TEXTVAL_"+partid);
    if (selval[1].selected) {
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
   
       }
       textbox.value = "";
   
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var scorename = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw");
    var saveval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
    var selname   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv");
    if (saveval != "correct") {
       scorename.value = "";
       selname[1].selected = true;
    }
       }
    } else {
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var scorename = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw");
    var saveval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
    var selname   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv");
    if (saveval != "correct") {
       scorename.value = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw_s.value");;
       selname[0].selected = true;
    }
       }
    }    
       }
   
       function changeSelect(partid,user) {
    var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
    var textbox = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
    var point  = textbox.value;
    var weight = eval("document.classgrade.weight_"+partid+".value");
   
    if (isNaN(point) || point < 0) {
       alert("A number equal or greater than 0 is expected. Entered value = "+point);
       textbox.value = "";
       return;
    }
    if (point > weight) {
       var resp = confirm("You entered a value ("+point+
          ") greater than the weight of the part. Accept?");
       if (resp == false) {
    textbox.value = "";
    return;
       }
    }
    selval[0].selected = true;
       }
   
       function changeOneScore(partid,user) {
    var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
    if (selval[1].selected) {
       var boxval = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
       boxval.value = "";
    }
       }
   
       function resetEntry(numpart) {
    for (ctpart=0;ctpart<numpart;ctpart++) {
       var partid = eval("document.classgrade.partid_"+ctpart+".value");
       var radioButton = eval("document.classgrade.RADVAL_"+partid);
       var textbox = eval("document.classgrade.TEXTVAL_"+partid);
       var selval  = eval("document.classgrade.SELVAL_"+partid);
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
   
       }
       textbox.value = "";
       selval[0].selected = true;
   
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var resetscore = eval("document.classgrade.GD_"+user+
         "_"+partid+"_aw");
    resetscore.value = eval("document.classgrade.GD_"+user+
    "_"+partid+"_aw_s.value");
   
    var saveselval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
   
    var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
    if (saveselval == "excused") {
       if (selname[1].selected == false) { selname[1].selected = true;}
    } else {
       if (selname[0].selected == false) {selname[0].selected = true};
    }
       }
    }
       }
   
   </script>
   VIEWJAVASCRIPT
   }
   
   #--- show scores for a section or whole class w/ option to change/update a score
   sub viewgrades {
       my ($request) = shift;
       &viewgrades_js($request);
   
       my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'}); 
       my $result='<h2><font color="#339933">Manual Grading</font></h2>';
   
       $result.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font>'."\n";
   
       #view individual student submission form - called using Javascript viewOneStudent
       $result.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".
    '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="submission" />'."\n".
    '<input type="hidden" name="student" value="" />'."\n".
    '<input type="hidden" name="userdom" value="" />'."\n".
    '</form>'."\n";
   
       #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="url"     value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="editgrades" />'."\n".
    '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'" />'."\n";
   
       $result.='To assign the same score for all the students use the radio buttons or '.
    'text box below. To assign scores individually fill in the score boxes for '.
    'each student in the table below. <font color="red">A part that has already '.
    'been graded does not get changed using the radio buttons or text box. '.
    'If needed, it has to be changed individually.</font>';
   
       #radio buttons/text box for assigning points for a section or class.
       #handles different parts of a problem
       my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
       my %weight = ();
       my $ctsparts = 0;
       $result.='<table border="0">';
       for (sort keys(%$handgrade)) {
    my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
    my ($partid,$respid) = split (/_/);
    my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
    $weight{$partid} = $wgt eq '' ? '1' : $wgt;
   
    $result.='<input type="hidden" name="partid_'.
       $ctsparts.'" value="'.$partid.'" />'."\n";
    $result.='<input type="hidden" name="weight_'.
       $partid.'" value="'.$weight{$partid}.'" />'."\n";
    $result.='<tr><td><b>Part  '.$partid.'&nbsp; &nbsp;Point:</b> </td><td>';
    $result.='<table border="0"><tr>';  
    my $ctr = 0;
    while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
       $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.
    'onclick="javascript:writePoint('.$partid.','.$weight{$partid}.
    ','.$ctr.')" />'.$ctr."</td>\n";
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
       $ctr++;
    }
    $result.='</tr></table>';
    $result.= '</td><td><b> or </b><input type="text" name="TEXTVAL_'.
       $partid.'" size="4" '.
       'onChange="javascript:writePoint('.$partid.','.$weight{$partid}.
       ',\'textval\')" /> /'.
       $weight{$partid}.' (problem weight)</td>'."\n";
    $result.= '</td><td><select name="SELVAL_'.$partid.'"'.
       'onChange="javascript:writeRadText('.$partid.','.$weight{$partid}.')" /> '.
       '<option selected="on"> </option>'.
       '<option>excused</option></select></td></tr>'."\n";
    $ctsparts++;
       }
       $result.='</table><input type="hidden" name="totalparts" value="'.$ctsparts.'" />';
       $result.='<input type="button" value="Reset" '.
    'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> &nbsp; &nbsp;';
   #    $result.='<input type="button" value="Submit Changes" '.
   # 'onClick="submit();" TARGET=_self />'."\n";
       $result.= '<input type="submit" name="submit"  value="Submit Changes" />'."\n";
   
       #table listing all the students in a section/class
       #header of table
       $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".
    '<table border=0><tr bgcolor="#deffff">'.
    '<td><b>Fullname</b></td><td><b>Username</b></td><td><b>Domain</b></td>'."\n";
       my (@parts) = sort(&getpartlist($url));
       foreach my $part (@parts) {
    my $display=&Apache::lonnet::metadata($url,$part.'.display');
    next if ($display =~ /^Number of Attempts/);
    if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
    if ($display =~ /^Partial Credit Factor/) {
       $_ = $display;
       my ($partid) = /.*?(\d+).*/;
       $result.='<td><b>Score Part '.$partid.'<br>(weight = '.
    $weight{$partid}.')</b></td>'."\n";
       next;
    }
    $display =~ s/Problem Status/Grade Status<br>/;
    $result.='<td><b>'.$display.'</b></td>'."\n";
       }
       $result.='</tr>';
   
       #get info for each student
       #list all the students - with points and grade status
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
       my $ctr = 0;
       foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
    my ($uname,$udom) = split(/:/);
    $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$uname.'" />'."\n";
    $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},
      $_,$$fullname{$_},\@parts,\%weight);
    $ctr++;
       }
       $result.='</table></td></tr></table>';
       $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";
       $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';
       $result.=&show_grading_menu_form($symb,$url);
       return $result;
   }
   
   #--- call by previous routine to display each student
   sub viewstudentgrade {
       my ($url,$symb,$courseid,$student,$fullname,$parts,$weight) = @_;
       my ($uname,$udom) = split(/:/,$student);
       my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
       my $result='<tr bgcolor="#ffffdd"><td>'.
    '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
    '\')"; TARGET=_self>'.$fullname.'</a>'.
    '</td><td>'.$uname.'</td><td align="middle">'.$udom.'</td>'."\n";
       foreach my $part (@$parts) {
    my ($temp,$part,$type)=split(/_/,$part);
    my $score=$record{"resource.$part.$type"};
    next if $type eq 'tries';
    if ($type eq 'awarded') {
       my $pts = $score eq '' ? '' : $score*$$weight{$part};
       $result.='<input type="hidden" name="'.
    'GD_'.$uname.'_'.$part.'_aw_s" value="'.$pts.'" />'."\n";
       $result.='<td align="middle"><input type="text" name="'.
    'GD_'.$uname.'_'.$part.'_aw" '.
    'onChange="javascript:changeSelect('.$part.',\''.$uname.
    '\')" value="'.$pts.'" size="4" /></td>'."\n";
    } elsif ($type eq 'solved') {
       my ($status,$foo)=split(/_/,$score,2);
       $status = 'nothing' if ($status eq '');
       $result.='<input type="hidden" name="'.
    'GD_'.$uname.'_'.$part.'_sv_s" value="'.$status.'" />'."\n";
       $result.='<td align="middle"><select name="'.
    'GD_'.$uname.'_'.$part.'_sv" '.
    'onChange="javascript:changeOneScore('.$part.',\''.$uname.'\')" >'."\n";
       my $optsel = '<option selected="on"> </option><option>excused</option>'."\n";
       $optsel = '<option> </option><option selected="on">excused</option>'."\n"
    if ($status eq 'excused');
       $result.=$optsel;
       $result.="</select></td>\n";
    }
       }
       $result.='</tr>';
       return $result;
   }
   
   #--- change scores for all the students in a section/class
   #    record does not get update if unchanged
   sub editgrades {
       my ($request) = @_;
   
       my $symb=$ENV{'form.symb'};
       my $url =$ENV{'form.url'};
       my $title='<h2><font color="#339933">Current Grade Status</font></h2>';
       $title.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br />'."\n";
       $title.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n";
       $title.= &show_grading_menu_form ($symb,$url);
       my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n";
       $result.= '<table border="0"><tr bgcolor="#deffff">'.
    '<td rowspan=2><b>Username</b></td><td rowspan=2><b>Fullname</b></td>'."\n";
   
       my %scoreptr = (
       'correct'  =>'correct_by_override',
       'incorrect'=>'incorrect_by_override',
       'excused'  =>'excused',
       'ungraded' =>'ungraded_attempted',
       'nothing'  => '',
       );
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
   
       my (@partid);
       my %weight = ();
       my ($i,$ctr,$count,$rec_update) = (0,0,0,0);
       while ($ctr < $ENV{'form.totalparts'}) {
    my $partid = $ENV{'form.partid_'.$ctr};
    push @partid,$partid;
    $weight{$partid} = $ENV{'form.weight_'.$partid};
    $ctr++;
    $result .= '<td colspan = 2 align="center"><b>Part '.$partid.
       '</b> (Weight = '.$weight{$partid}.')</td>';
       }
       $result .= '</tr><tr bgcolor="#deffff">';
       foreach (@partid) {
    $result .= '<td align="center">&nbsp;<b>Old Score</b>&nbsp;</td>'.
       '<td align="center">&nbsp;<b>New Score</b>&nbsp;</td>';
       }
       $result .= '</tr>'."\n";
   
       for ($i=0; $i<$ENV{'form.total'}; $i++) {
    my $user = $ENV{'form.ctr'.$i};
    my %newrecord;
    my $updateflag = 0;
    my @userdom = grep /^$user:/,keys %$classlist;
    my ($foo,$udom) = split(/:/,$userdom[0]);
   
    $result .= '<tr bgcolor="#ffffde"><td>'.$user.'&nbsp;</td><td>'.
       $$fullname{$userdom[0]}.'&nbsp;</td>';
   
    foreach (@partid) {
       my $old_aw    = $ENV{'form.GD_'.$user.'_'.$_.'_aw_s'};
       my $old_part  = $old_aw eq '' ? '' : $old_aw/$weight{$_};
       my $old_score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
   
       my $awarded   = $ENV{'form.GD_'.$user.'_'.$_.'_aw'};
       my $partial   = $awarded eq '' ? '' : $awarded/$weight{$_};
       my $score;
       if ($partial eq '') {
    $score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
       } elsif ($partial > 0) {
    $score = 'correct_by_override';
       } elsif ($partial == 0) {
    $score = 'incorrect_by_override';
       }
       $score = 'excused' if (($ENV{'form.GD_'.$user.'_'.$_.'_sv'} eq 'excused') &&
      ($score ne 'excused'));
       $result .= '<td align="center">'.$old_aw.'&nbsp;</td>'.
    '<td align="center">'.$awarded.
    ($score eq 'excused' ? $score : '').'&nbsp;</td>';
   
       next if ($old_part eq $partial && $old_score eq $score);
   
       $updateflag = 1;
       $newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';
       $newrecord{'resource.'.$_.'.solved'}   = $score;
       $rec_update++;
    }
    $result .= '</tr>'."\n";
    if ($updateflag) {
       $count++;
       $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
       &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},
       $udom,$user);
    }
       }
       $result .= '</table></td></tr></table>'."\n";
       my $msg = '<b>Number of records updated = '.$rec_update.
    ' for '.$count.' student'.($count <= 1 ? '' : 's').'.</b><br />'.
    '<b>Total number of students = '.$ENV{'form.total'}.'</b><br />';
       return $title.$msg.$result;
   }
   #------------- end of section for handling grading by section/class ---------
   #
   #----------------------------------------------------------------------------
   
   
   #----------------------------------------------------------------------------
   #
   #-------------------------- Next few routines handles grading by csv upload
   #
   #--- Javascript to handle csv upload
 sub csvupload_javascript_reverse_associate {  sub csvupload_javascript_reverse_associate {
   return(<<ENDPICK);    return(<<ENDPICK);
   function verify(vf) {    function verify(vf) {
Line 1380  ENDPICK Line 1809  ENDPICK
 }  }
   
 sub csvuploadmap_header {  sub csvuploadmap_header {
   my ($request,$symb,$url,$datatoken,$distotal)= @_;      my ($request,$symb,$url,$datatoken,$distotal)= @_;
   my $result;      my $result;
   my $javascript;      my $javascript;
   if ($ENV{'form.upfile_associate'} eq 'reverse') {      if ($ENV{'form.upfile_associate'} eq 'reverse') {
     $javascript=&csvupload_javascript_reverse_associate();   $javascript=&csvupload_javascript_reverse_associate();
   } else {      } else {
     $javascript=&csvupload_javascript_forward_associate();   $javascript=&csvupload_javascript_forward_associate();
   }      }
   $request->print(<<ENDPICK);      $request->print(<<ENDPICK);
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <h3>Uploading Class Grades for resource $url</h3>  <h3>Uploading Class Grades for resource $url</h3>
 <hr>  <hr>
Line 1412  to this page if the data selected is ins Line 1841  to this page if the data selected is ins
 $javascript  $javascript
 </script>  </script>
 ENDPICK  ENDPICK
   return '';  return '';
   
 }  }
   
 sub csvupload_fields {  sub csvupload_fields {
   my ($url) = @_;      my ($url) = @_;
   my (@parts) = &getpartlist($url);      my (@parts) = &getpartlist($url);
   my @fields=(['username','Student Username'],['domain','Student Domain']);      my @fields=(['username','Student Username'],['domain','Student Domain']);
   foreach my $part (sort(@parts)) {      foreach my $part (sort(@parts)) {
     my @datum;   my @datum;
     my $display=&Apache::lonnet::metadata($url,$part.'.display');   my $display=&Apache::lonnet::metadata($url,$part.'.display');
     my $name=$part;   my $name=$part;
     if  (!$display) { $display = $name; }   if  (!$display) { $display = $name; }
     @datum=($name,$display);   @datum=($name,$display);
     push(@fields,\@datum);   push(@fields,\@datum);
   }      }
   return (@fields);      return (@fields);
 }  }
   
 sub csvuploadmap_footer {  sub csvuploadmap_footer {
   my ($request,$i,$keyfields) =@_;      my ($request,$i,$keyfields) =@_;
   $request->print(<<ENDPICK);      $request->print(<<ENDPICK);
 </table>  </table>
 <input type="hidden" name="nfields" value="$i" />  <input type="hidden" name="nfields" value="$i" />
 <input type="hidden" name="keyfields" value="$keyfields" />  <input type="hidden" name="keyfields" value="$keyfields" />
Line 1443  ENDPICK Line 1872  ENDPICK
 }  }
   
 sub csvuploadmap {  sub csvuploadmap {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   my $datatoken;      my $datatoken;
   if (!$ENV{'form.datatoken'}) {      if (!$ENV{'form.datatoken'}) {
     $datatoken=&Apache::loncommon::upfile_store($request);   $datatoken=&Apache::loncommon::upfile_store($request);
   } else {  
     $datatoken=$ENV{'form.datatoken'};  
     &Apache::loncommon::load_tmp_file($request);  
   }  
   my @records=&Apache::loncommon::upfile_record_sep();  
   &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);  
   my $i;  
   my $keyfields;  
   if (@records) {  
     my @fields=&csvupload_fields($url);  
     if ($ENV{'form.upfile_associate'} eq 'reverse') {  
       &Apache::loncommon::csv_print_samples($request,\@records);  
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,  
     \@fields);  
       foreach (@fields) { $keyfields.=$_->[0].','; }  
       chop($keyfields);  
     } else {      } else {
       unshift(@fields,['none','']);   $datatoken=$ENV{'form.datatoken'};
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,   &Apache::loncommon::load_tmp_file($request);
       \@fields);  
       my %sone=&Apache::loncommon::record_sep($records[0]);  
       $keyfields=join(',',sort(keys(%sone)));  
     }      }
   }      my @records=&Apache::loncommon::upfile_record_sep();
   &csvuploadmap_footer($request,$i,$keyfields);      &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
   return '';      my ($i,$keyfields);
       if (@records) {
    my @fields=&csvupload_fields($url);
    if ($ENV{'form.upfile_associate'} eq 'reverse') {
       &Apache::loncommon::csv_print_samples($request,\@records);
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,
     \@fields);
       foreach (@fields) { $keyfields.=$_->[0].','; }
       chop($keyfields);
    } else {
       unshift(@fields,['none','']);
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
       \@fields);
       my %sone=&Apache::loncommon::record_sep($records[0]);
       $keyfields=join(',',sort(keys(%sone)));
    }
       }
       &csvuploadmap_footer($request,$i,$keyfields);
       return '';
 }  }
   
 sub csvuploadassign {  sub csvuploadassign {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   &Apache::loncommon::load_tmp_file($request);      &Apache::loncommon::load_tmp_file($request);
   my @gradedata=&Apache::loncommon::upfile_record_sep();      my @gradedata = &Apache::loncommon::upfile_record_sep();
   my @keyfields = split(/\,/,$ENV{'form.keyfields'});      my @keyfields = split(/\,/,$ENV{'form.keyfields'});
   my %fields=();      my %fields=();
   for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {      for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
     if ($ENV{'form.upfile_associate'} eq 'reverse') {   if ($ENV{'form.upfile_associate'} eq 'reverse') {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$keyfields[$i]}=$ENV{'form.f'.$i};   $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
       }      }
     } else {   } else {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$ENV{'form.f'.$i}}=$keyfields[$i];   $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
       }      }
    }
     }      }
   }      $request->print('<h3>Assigning Grades</h3>');
   $request->print('<h3>Assigning Grades</h3>');      my $courseid=$ENV{'request.course.id'};
   my $courseid=$ENV{'request.course.id'};  
 #  my $cdom=$ENV{"course.$courseid.domain"};  #  my $cdom=$ENV{"course.$courseid.domain"};
 #  my $cnum=$ENV{"course.$courseid.num"};  #  my $cnum=$ENV{"course.$courseid.num"};
   my ($classlist) = &getclasslist('all','1');      my ($classlist) = &getclasslist('all','1');
   my @skipped;      my @skipped;
   my $countdone=0;      my $countdone=0;
   foreach my $grade (@gradedata) {      foreach my $grade (@gradedata) {
     my %entries=&Apache::loncommon::record_sep($grade);   my %entries=&Apache::loncommon::record_sep($grade);
     my $username=$entries{$fields{'username'}};   my $username=$entries{$fields{'username'}};
     my $domain=$entries{$fields{'domain'}};   my $domain=$entries{$fields{'domain'}};
     if (!exists($$classlist{"$username:$domain"})) {   if (!exists($$classlist{"$username:$domain"})) {
       push(@skipped,"$username:$domain");      push(@skipped,"$username:$domain");
       next;      next;
     }   }
     my %grades;   my %grades;
     foreach my $dest (keys(%fields)) {   foreach my $dest (keys(%fields)) {
       if ($dest eq 'username' || $dest eq 'domain') { next; }      if ($dest eq 'username' || $dest eq 'domain') { next; }
       if ($entries{$fields{$dest}} eq '') { next; }      if ($entries{$fields{$dest}} eq '') { next; }
       my $store_key=$dest;      my $store_key=$dest;
       $store_key=~s/^stores/resource/;      $store_key=~s/^stores/resource/;
       $store_key=~s/_/\./g;      $store_key=~s/_/\./g;
       $grades{$store_key}=$entries{$fields{$dest}};      $grades{$store_key}=$entries{$fields{$dest}};
     }   }
     $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";   $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
     &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},   &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
     $domain,$username);   $domain,$username);
     $request->print('.');   $request->print('.');
     $request->rflush();   $request->rflush();
     $countdone++;   $countdone++;
   }      }
   $request->print("<br />Stored $countdone students\n");      $request->print("<br />Stored $countdone students\n");
   if (@skipped) {      if (@skipped) {
     $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');   $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');
     foreach my $student (@skipped) { $request->print("<br />$student"); }   foreach my $student (@skipped) { $request->print("<br />$student"); }
   }      }
   $request->print(&view_edit_entire_class_form($symb,$url));      $request->print(&view_edit_entire_class_form($symb,$url));
   $request->print(&show_grading_menu_form($symb,$url));      $request->print(&show_grading_menu_form($symb,$url));
   return '';      return '';
 }  }
   #------------- end of section for handling csv file upload ---------
   #
   #-------------------------------------------------------------------
   
 sub send_header {  #-------------------------- Menu interface -------------------------
   my ($request)= @_;  #
   $request->print(&Apache::lontexconvert::header());  #--- Show a Grading Menu button - Calls the next routine ---
 #  $request->print("  sub show_grading_menu_form {
 #<script>      my ($symb,$url)=@_;
 #remotewindow=open('','homeworkremote');      my $result.='<form action="/adm/grades" method="post">'."\n".
 #remotewindow.close();   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
 #</script>");    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
   $request->print('<body bgcolor="#FFFFFF">');   '<input type="hidden" name="command" value="gradingmenu" />'."\n".
    '<input type="submit" name="submit" value="Grading Menu" />'."\n".
    '</form>'."\n";
       return $result;
 }  }
   
 sub send_footer {  #--- Displays the main menu page -------
   my ($request)= @_;  sub gradingmenu {
   $request->print('</body>');      my ($request) = @_;
   $request->print(&Apache::lontexconvert::footer());      my ($symb,$url)=&get_symb_and_url($request);
       if (!$symb) {return '';}
       my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';
       $result.='<table border="0">';
       $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>';
       my ($partlist,$handgrade) = &response_type($url);
       my ($resptype,$hdgrade)=('','no');
       for (sort keys(%$handgrade)) {
    my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
    $resptype = $responsetype;
    $hdgrade = $handgrade if ($handgrade eq 'yes');
    $result.='<tr><td><b>Part </b>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $result.=&view_edit_entire_class_form($symb,$url).'<br />';
       $result.=&upcsvScores_form($symb,$url).'<br />';
       $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).'<br />';
       $result.=&verifyReceipt_form($symb,$url) 
    if ((&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) && ($symb));
    
       return $result;
 }  }
   
 sub handler {  #--- Menu for grading a section or the whole class ---
   my $request=$_[0];  sub view_edit_entire_class_form {
       my ($symb,$url)=@_;
       my ($classlist,$sections) = &getclasslist('all','0');
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
       $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
       $result.='&nbsp;<b>View/Grade Entire Section/Class</b></td></tr>'."\n";
       $result.='<tr bgcolor=#ffffe6><td>'."\n";
       $result.='<form action="/adm/grades" method="post">'."\n".
    '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="viewgrades" />'."\n";
       $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";
       foreach (sort (@$sections)) {
    $result.= '<option>'.$_.'</option>'."\n";
       }
       $result.='<option selected="on">all</select>'."<br />\n";
       $result.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   if ($ENV{'browser.mathml'}) {  #--- Menu to upload a csv scores ---
     $request->content_type('text/xml');  sub upcsvScores_form {
   } else {      my ($symb,$url) = @_;
     $request->content_type('text/html');      if (!$symb) {return '';}
   }      my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
   $request->send_http_header;      $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
   return OK if $request->header_only;      $result.='&nbsp;<b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});      $result.='<tr bgcolor=#ffffe6><td>'."\n";
   my $url=$ENV{'form.url'};      my $upfile_select=&Apache::loncommon::upfile_select_html();
   my $symb=$ENV{'form.symb'};    $result.=<<ENDUPFORM;
   my $command=$ENV{'form.command'};  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
   if (!$url) {  <input type="hidden" name="symb" value="$symb" />
     my ($temp1,$temp2);  <input type="hidden" name="url" value="$url" />
     ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);  <input type="hidden" name="command" value="csvuploadmap" />
     $url = $ENV{'form.url'};  $upfile_select
   }  <br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />
   &send_header($request);  </form>
   if ($url eq '' && $symb eq '') {  ENDUPFORM
      if ($ENV{'user.adv'}) {      $result.='</td></tr></table>'."\n";
          if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&      $result.='</td></tr></table>'."\n";
              ($ENV{'form.codethree'})) {      return $result;
              my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.  }
         $ENV{'form.codethree'};  
              my ($tsymb,$tuname,$tudom,$tcrsid)=  #--- Handgrading problems ---
  &Apache::lonnet::checkin($token);  sub viewGradeaStu_form {
              if ($tsymb) {      my ($symb,$url,$response,$handgrade) = @_;
                 my ($map,$id,$url)=split(/\_\_\_/,$tsymb);      my ($classlist,$sections) = &getclasslist('all','0');
                 if (&Apache::lonnet::allowed('mgr',$tcrsid)) {      my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
                    $request->print(      $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
                      &Apache::lonnet::ssi('/res/'.$url,      $result.='&nbsp;<b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n";
                         ('grade_username' => $tuname,      $result.='<tr bgcolor=#ffffe6><td>'."\n";
                          'grade_domain' => $tudom,      $result.='<form action="/adm/grades" method="post">'."\n".
                          'grade_courseid' => $tcrsid,   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
                          'grade_symb' => $tsymb)));   '<input type="hidden" name="url" value="'.$url.'" />'."\n".
                 } else {   '<input type="hidden" name="response" value="'.$response.'" />'."\n".
                    $request->print('<h1>Not authorized: '.$token.'</h1>');   '<input type="hidden" name="handgrade" value="'.$handgrade.'" />'."\n".
                 }              '<input type="hidden" name="showgrading" value="yes" />'."\n".
    '<input type="hidden" name="command" value="submission" />'."\n";
   
       $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";
       foreach (sort (@$sections)) {
    $result.= '<option>'.$_.'</option>'."\n";
       }
       $result.= '<option selected="on">all</select>'."\n";
       $result.='&nbsp;&nbsp;<b>Display students who has: </b>'.
    '<input type="radio" name="submitonly" value="yes" checked> submitted'.
    '<input type="radio" name="submitonly" value="all"> everybody <br />';
       $result.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />' 
    if (grep /no/,@$sections);
       
       $result.='<br />&nbsp;<input type="submit" name="submit" value="View/Grade" />'."\n".
    '</form>'."\n";
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   #--- Form to input a receipt number ---
   sub verifyReceipt_form {
       my ($symb,$url) = @_;
       my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};
       my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};
       my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});
   
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
       $result.='<table width=100% border=0><tr><td bgcolor=#e6ffff>'."\n";
       $result.='&nbsp;<b>Verify a Submission Receipt Issued by this Server</td></tr>'."\n";
       $result.='<tr bgcolor=#ffffe6><td>'."\n";
       $result.='<form action="/adm/grades" method="post">'."\n";
       $result.='&nbsp;<tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n";
       $result.='&nbsp;<input type="submit" name="submit" value="Verify Receipt">'."\n";
       $result.='<input type="hidden" name="command" value="verify">'."\n";
       if ($ENV{'form.url'}) {
    $result.='<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />';
       }
       if ($ENV{'form.symb'}) {
    $result.='<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />';
       }
       $result.='</form>';
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   sub handler {
       my $request=$_[0];
       
       if ($ENV{'browser.mathml'}) {
    $request->content_type('text/xml');
       } else {
    $request->content_type('text/html');
       }
       $request->send_http_header;
       return '' if $request->header_only;
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
       my $url=$ENV{'form.url'};
       my $symb=$ENV{'form.symb'};
       my $command=$ENV{'form.command'};
       if (!$url) {
    my ($temp1,$temp2);
    ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);
    $url = $ENV{'form.url'};
       }
       &send_header($request);
       if ($url eq '' && $symb eq '') {
    if ($ENV{'user.adv'}) {
       if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&
    ($ENV{'form.codethree'})) {
    my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.
       $ENV{'form.codethree'};
    my ($tsymb,$tuname,$tudom,$tcrsid)=
       &Apache::lonnet::checkin($token);
    if ($tsymb) {
       my ($map,$id,$url)=split(/\_\_\_/,$tsymb);
       if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
    $request->print(
    &Apache::lonnet::ssi('/res/'.$url,
        ('grade_username' => $tuname,
         'grade_domain' => $tudom,
         'grade_courseid' => $tcrsid,
         'grade_symb' => $tsymb)));
       } else {
    $request->print('<h2>Not authorized: '.$token.'</h2>');
       }           
    } else {
       $request->print('<h2>Not a valid DocID: '.$token.'</h2>');
    }
     } else {      } else {
                 $request->print('<h1>Not a valid DocID: '.$token.'</h1>');   $request->print(&Apache::lonxml::tokeninputfield());
             }      }
  } else {  
              $request->print(&Apache::lonxml::tokeninputfield());  
          }  
      }  
   } else {  
     #&Apache::lonhomework::showhashsubset(\%ENV,'^form');  
     $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});  
     if ($command eq 'submission') {  
       &listStudents($request) if ($ENV{'form.student'} eq '');  
       &submission($request,0,0) if ($ENV{'form.student'} ne '');  
     } elsif ($command eq 'processGroup') {  
       &processGroup($request);  
     } elsif ($command eq 'gradingmenu') {  
       $request->print(&gradingmenu($request));  
     } elsif ($command eq 'viewgrades') {  
       $request->print(&viewgrades($request));  
     } elsif ($command eq 'handgrade') {  
       $request->print(&processHandGrade($request));  
     } elsif ($command eq 'editgrades') {  
       $request->print(&editgrades($request));  
     } elsif ($command eq 'verify') {  
       $request->print(&verifyreceipt($request));  
     } elsif ($command eq 'csvupload') {  
       $request->print(&csvupload($request));  
     } elsif ($command eq 'csvuploadmap') {  
       $request->print(&csvuploadmap($request));  
 #    } elsif ($command eq 'receiptInput') {  
 #      &receiptInput($request);  
     } elsif ($command eq 'csvuploadassign') {  
       if ($ENV{'form.associate'} ne 'Reverse Association') {  
  $request->print(&csvuploadassign($request));  
       } else {  
  if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {  
   $ENV{'form.upfile_associate'} = 'reverse';  
  } else {  
   $ENV{'form.upfile_associate'} = 'forward';  
  }   }
  $request->print(&csvuploadmap($request));  
       }  
     } else {      } else {
       $request->print("Unknown action: $command:");   #&Apache::lonhomework::showhashsubset(\%ENV,'^form');
    $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
    if ($command eq 'submission') {
       &listStudents($request) if ($ENV{'form.student'} eq '');
       &submission($request,0,0) if ($ENV{'form.student'} ne '');
    } elsif ($command eq 'processGroup') {
       &processGroup($request);
    } elsif ($command eq 'gradingmenu') {
       $request->print(&gradingmenu($request));
    } elsif ($command eq 'viewgrades') {
       $request->print(&viewgrades($request));
    } elsif ($command eq 'handgrade') {
       $request->print(&processHandGrade($request));
    } elsif ($command eq 'editgrades') {
       $request->print(&editgrades($request));
    } elsif ($command eq 'verify') {
       $request->print(&verifyreceipt($request));
    } elsif ($command eq 'csvupload') {
       $request->print(&csvupload($request));
    } elsif ($command eq 'viewclasslist') {
       $request->print(&viewclasslist($request));
    } elsif ($command eq 'csvuploadmap') {
       $request->print(&csvuploadmap($request));
    } elsif ($command eq 'csvuploadassign') {
       if ($ENV{'form.associate'} ne 'Reverse Association') {
    $request->print(&csvuploadassign($request));
       } else {
    if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
       $ENV{'form.upfile_associate'} = 'reverse';
    } else {
       $ENV{'form.upfile_associate'} = 'forward';
    }
    $request->print(&csvuploadmap($request));
       }
    } else {
       $request->print("Unknown action: $command:");
    }
     }      }
   }      &send_footer($request);
   &send_footer($request);      return '';
   return OK;  }
   
   sub send_header {
       my ($request)= @_;
       $request->print(&Apache::lontexconvert::header());
   #  $request->print("
   #<script>
   #remotewindow=open('','homeworkremote');
   #remotewindow.close();
   #</script>"); 
       $request->print('<body bgcolor="#FFFFFF">');
   }
   
   sub send_footer {
       my ($request)= @_;
       $request->print('</body>');
       $request->print(&Apache::lontexconvert::footer());
 }  }
   
 1;  1;

Removed from v.1.38  
changed lines
  Added in v.1.44


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>