Diff for /loncom/homework/grades.pm between versions 1.27 and 1.43

version 1.27, 2002/05/24 21:45:22 version 1.43, 2002/07/30 19:59:58
Line 29 Line 29
 # 6/8 Gerd Kortemeyer  # 6/8 Gerd Kortemeyer
 # 7/26 H.K. Ng  # 7/26 H.K. Ng
 # 8/20 Gerd Kortemeyer  # 8/20 Gerd Kortemeyer
   # Year 2002
   # June, July 2002 H.K. Ng
   #
   
 package Apache::grades;  package Apache::grades;
 use strict;  use strict;
Line 37  use Apache::lonxml; Line 40  use Apache::lonxml;
 use Apache::lonnet;  use Apache::lonnet;
 use Apache::loncommon;  use Apache::loncommon;
 use Apache::lonhomework;  use Apache::lonhomework;
   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 {  sub moreinfo {
   my ($request,$reason) = @_;      my ($request,$reason) = @_;
   $request->print("Unable to process request: $reason");      $request->print("Unable to process request: $reason");
   if ( $Apache::grades::viewgrades eq 'F' ) {      if ( $Apache::grades::viewgrades eq 'F' ) {
     $request->print('<form action="/adm/grades" method="post">'."\n");   $request->print('<form action="/adm/grades" method="post">'."\n");
     if ($ENV{'form.url'}) {   if ($ENV{'form.url'}) {
       $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");      $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
     }   }
     if ($ENV{'form.symb'}) {   if ($ENV{'form.symb'}) {
       $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");      $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
    }
   #    $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>');
     }      }
     $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");      return '';
     $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 {  sub verifyreceipt {
     my $request=shift;      my $request=shift;
     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 $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.      my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
                 $ENV{'form.receipt'};   $ENV{'form.receipt'};
     $receipt=~s/[^\-\d]//g;      $receipt=~s/[^\-\d]//g;
     my $symb=$ENV{'form.symb'};      my $symb=$ENV{'form.symb'};
     unless ($symb) {      unless ($symb) {
Line 74  sub verifyreceipt { Line 80  sub verifyreceipt {
     if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {      if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
         $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');          $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');
         my $matches=0;          my $matches=0;
         my (%classlist) = &getclasslist($cdom,$cnum,'0');          my ($classlist) = &getclasslist('all','0');
         foreach my $student ( sort(@{ $classlist{'allids'} }) ) {          foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
             my ($uname,$udom)=split(/\:/,$student);              my ($uname,$udom)=split(/\:/,$student);
             if ($receipt eq               if ($receipt eq 
              &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {   &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
                $request->print('Matching '.$student.'<br>');   $request->print('Matching '.$student.'<br>');
                $matches++;   $matches++;
    }     }
         }          }
         $request->print('<p>'.$matches.' match(es)</p>');          $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');
   # needs to print who is matched
     }      }
     return '';      return '';
 }  }
   
   sub student_gradeStatus {
       my ($url,$udom,$uname,$partlist) = @_;
       my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
       my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
       my %partstatus = ();
       foreach (@$partlist) {
    my ($status,$foo)=split(/_/,$record{"resource.$_.solved"},2);
    $status = 'nothing' if ($status eq '');
    $partstatus{$_} = $status;
    $partstatus{"resource.$_.submitted_by"} = $record{"resource.$_.submitted_by"} 
    if ($record{"resource.$_.submitted_by"} ne '');
       }
       return %partstatus;
   }
   
   sub get_fullname {
       my ($uname,$udom) = @_;
       my %name=&Apache::lonnet::get('environment', ['lastname','generation',
     'firstname','middlename'],$udom,$uname);
       my $fullname;
       my ($tmp) = keys(%name);
       if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
    $fullname=$name{'lastname'}.$name{'generation'};
    if ($fullname =~ /[^\s]+/) { $fullname.=', '; }
    $fullname.=$name{'firstname'}.' '.$name{'middlename'};
       }
       return $fullname;
   }
   
   sub response_type {
       my ($url) = shift;
       my $allkeys = &Apache::lonnet::metadata($url,'keys');
   #    print "allkeys=>$allkeys<br>";
       my %seen = ();
       my (@partlist,%handgrade);
       foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
    if (/^\w+response_\d+.*/) {
       my ($responsetype,$part) = split(/_/,$_,2);
       my ($partid,$respid) = split(/_/,$part);
       $handgrade{$part} = $responsetype.':'.($allkeys =~ /parameter_$part\_handgrade/ ? 'yes' : 'no');
       next if ($seen{$partid} > 0);
       $seen{$partid}++;
       push @partlist,$partid;
    }
       }
       return \@partlist,\%handgrade;
   }
   
   
 sub listStudents {  sub listStudents {
   my ($request) = shift;      my ($request) = shift;
   my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};      my $cdom      =$ENV{"course.$ENV{'request.course.id'}.domain"};
   my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};      my $cnum      =$ENV{"course.$ENV{'request.course.id'}.num"};
   my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});      my $getsec    =$ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'};
   $request->print(<<ENDHEADER);      my $submitonly=$ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
 <h1>Verify a Submission Receipt Issued by this Server</h1>  
       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 id: </b>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $request->print($result);
   
       $request->print(<<ENDTABLEST);
 <form action="/adm/grades" method="post">  <form action="/adm/grades" method="post">
 <tt>$hostver-<input type="text" name="receipt" size="4"></tt>  &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no 
 <input type="submit" name="submit" value="Verify">  <input type="radio" name="vProb" value="yes"> yes <br />
 <input type="hidden" name="command" value="verify">  &nbsp;<b>Submissions: </b>
 ENDHEADER  <input type="radio" name="lastSub" value="hdgrade" checked /> handgrade only
   if ($ENV{'form.url'}) {  <input type="radio" name="lastSub" value="lastonly" /> last sub only
     $request->print(  <input type="radio" name="lastSub" value="last" /> last sub & parts info
     '<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />');  <input type="radio" name="lastSub" value="all" /> all details
   }  <input type="hidden" name="section" value="$getsec" />
   if ($ENV{'form.symb'}) {  <input type="hidden" name="submitonly" value="$submitonly" />
     $request->print(  <input type="hidden" name="response" value="$ENV{'form.response'}" />
     '<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />');  <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" /><br />
   }  <input type="hidden" name="showgrading" value="$ENV{'form.showgrading'}" /><br />
   $request->print(<<ENDTABLEST);  <input type="submit" name="submit" value="View/Grade" />
 </form>  
 <h1>Show Student Submissions on Assessment</h1>  
 <table border="1">  
 <tr><th>Username</th><th>Domain</th><th>Name</th><th>&nbsp;</th></tr>  
 ENDTABLEST  ENDTABLEST
   my (%classlist) = &getclasslist($cdom,$cnum,'0');      if ($ENV{'form.url'}) {
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {   $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
       my ($sname,$sdom) = split(/:/,$student);      }
       if ($ENV{'form.symb'}) {
       my %name=&Apache::lonnet::get('environment', ['lastname','generation',   $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
     'firstname','middlename'],      }
     $sdom,$sname);      $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
       my $fullname;      
       my ($tmp) = keys(%name);      my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
       if ($tmp !~ /^(con_lost|error|no_such_host)/i) {      
  $fullname=$name{'lastname'}.$name{'generation'};      $result='<table border="0"><tr><td bgcolor="#777777">'.
  if ($fullname =~ /[^\s]+/) { $fullname.=','; }   '<table border="0"><tr bgcolor="#e6ffff">'.
  $fullname.=$name{'firstname'}.' '.$name{'middlename'};   '<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>';
       if ( $Apache::grades::viewgrades eq 'F' ) {      foreach (sort(@$partlist)) {
   $request->print("\n".'<tr>'."<td>$sname</td><td>$sdom</td><td>$fullname</td><td>".   $result.='<td><b>&nbsp;Part ID '.(split(/_/))[0].' Status&nbsp;</b></td>';
   '<form action="/adm/grades" method="post">');      }
   if ($ENV{'form.url'}) {      $request->print($result.'</tr>'."\n");
     $request->print(  
     '<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />');      foreach my $student (sort(@{ $$classlist{$getsec} }) ) {
   }   my ($uname,$udom) = split(/:/,$student);
   if ($ENV{'form.symb'}) {   my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist);
     $request->print(   my $statusflg = '';
     '<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />');   foreach (keys(%status)) {
   }      $statusflg = 1 if ($status{$_} ne 'nothing');
   $request->print(      my ($foo,$partid,$foo1) = split(/\./,$_);
     '<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />');      if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
   $request->print(   $statusflg = '';
              '<input type="hidden" name="student" value="'.$sname.'" />');   $request->print('<input type="hidden" name="'.
   $request->print(   $student.':submitted_by" value="'.
              '<input type="hidden" name="domain" value="'.$sdom.'" />');   $status{'resource.'.$partid.'.submitted_by'}.'" />');
   $request->print(      }
                          '<input type="submit" name="submit" value="View" />');   }
   $request->print('</form></td></tr>');   next if ($statusflg eq '' && $submitonly eq 'yes');
       }  
   }   if ( $Apache::grades::viewgrades eq 'F' ) {
   $request->print('</table>');      $result='<tr bgcolor="#ffffe6">'.
    '<td align="center"><input type=checkbox name="stuinfo" value="'.
    $student.':'.$$fullname{$student}.'"></td>'."\n".
    '<td>&nbsp;'.$uname.'&nbsp;</td>'."\n".
    '<td>&nbsp;'.$$fullname{$student}.'&nbsp;</td>'."\n".
    '<td align="middle">&nbsp;'.$udom.'&nbsp;</td>'."\n";
       
       foreach (sort keys(%status)) {
    next if (/^resource.*?submitted_by$/);
    $result.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";
       }
       $request->print($result.'</tr>'."\n");
    }
       }
       $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 ($uname,$udom,$fullname) = split(/:/);
    $ENV{'form.student'} = $uname;
    $ENV{'form.fullname'} = $fullname;
    &submission($request,$ctr,$total);
    $ctr++;
       }
       return '';
   }
   
   sub userError {
       my ($request, $reason, $step) = @_;
       $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n");
       $request->print('<b>Reason: </b>'.$reason.'<br /><br />'."\n");
       $request->print('<b>Step: </b>'.($step ne '' ? $step : 'Use your browser back button to correct')
       .'<br /><br />'."\n");
       return '';
   }
   
 #FIXME - needs to handle multiple matches  #FIXME - needs to handle multiple matches
 sub finduser {  sub finduser {
   my ($name) = @_;      my ($name) = @_;
   my $domain = '';      my $domain = '';
       if ( $Apache::grades::viewgrades eq 'F' ) {
   if ( $Apache::grades::viewgrades eq 'F' ) {   my ($classlist) = &getclasslist('all','0');
     #get classlist   foreach ( sort(@{ $$classlist{'all'} }) ) {
     my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});      my ($posname,$posdomain) = split(/:/);
     #print "Found $cdom:$cnum<br />";      if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
     my (%classlist) = &getclasslist($cdom,$cnum,'0');   }
     foreach my $student ( sort(@{ $classlist{'allids'} }) ) {   return ($name,$domain);
       my ($posname,$posdomain) = split(/:/,$student);      } else {
       if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }   return ($ENV{'user.name'},$ENV{'user.domain'});
     }      }
     return ($name,$domain);  
   } else {  
     return ($ENV{'user.name'},$ENV{'user.domain'});  
   }  
 }  }
   
 sub getclasslist {  sub getclasslist {
   my ($coursedomain,$coursenum,$hideexpired) = @_;      my ($getsec,$hideexpired) = @_;
   my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);      my $now = time;
   my $now = time;      my %classlist=&Apache::lonnet::dump('classlist',
   foreach my $student (keys(%classlist)) {   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
     my ($end,$start)=split(/:/,$classlist{$student});   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
     # still a student?      my (@holdsec,@sections,%allids,%stusec,%fullname);
     if (($hideexpired) && ($end) && ($end < $now)) {      foreach (keys(%classlist)) {
       #print "Skipping:$name:$end:$now<br />\n";   my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
       next;         # still a student?
    if (($hideexpired) && ($end) && ($end < $now)) {
       next;
    }
    $section = ($section ne '' ? $section : 'no');
    push @holdsec,$section;
    if ($getsec eq 'all' || $getsec eq $section) {
       push (@{ $classlist{$getsec} }, $_);
       $allids{$_}=$id;
       $stusec{$_}=$section;
       $fullname{$_}=$fullname;
    }
     }      }
     #print "record=$record<br>";      my %seen = ();
     push( @{ $classlist{'allids'} }, $student);      foreach my $item (@holdsec) {
   }   push (@sections, $item) unless $seen{$item}++;
   return (%classlist);      }
       return (\%classlist,\@sections,\%allids,\%stusec,\%fullname);
 }  }
   
 sub getpartlist {  sub getpartlist {
   my ($url) = @_;      my ($url) = @_;
   my @parts =();      my @parts =();
   my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));      my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
   foreach my $key (@metakeys) {      foreach my $key (@metakeys) {
     if ( $key =~ m/stores_([0-9]+)_.*/ ) {   if ( $key =~ m/stores_([0-9]+)_.*/) {
       push(@parts,$key);      push(@parts,$key);
    }
     }      }
   }      return @parts;
   return @parts;  
 }  }
   
 sub viewstudentgrade {  sub print_hash {
   my ($url,$symb,$courseid,$student,@parts) = @_;      my ($request, $hash) = @_;
   my $result ='';      $request->print('<table border=1><tr><td>Key</td><td>Value</td></tr>');
   my $cellclr = '"#ffffdd"';      for (sort keys (%$hash)) {
   my ($stuname,$domain) = split(/:/,$student);   $request->print('<tr><td>'.$_.'</td><td>'.$$hash{$_}.'&nbsp;</td></tr>');
   
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);  
   
   $result.="<tr><td bgcolor=$cellclr>$stuname</td><td bgcolor=$cellclr align=\"middle\">$domain</td>\n";  
   foreach my $part (@parts) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     #print "resource.$part.$type = ".$record{"resource.$part.$type"}." <br />\n";  
     if ($type eq 'awarded') {  
       my $score=$record{"resource.$part.$type"};  
       $result.="<td bgcolor=$cellclr align=\"middle\"><input type=\"text\" name=\"GRADE.$student.$part.$type\" value=\"$score\" size=\"4\" /></td>\n";  
     } elsif ($type eq 'tries') {  
       my $score=$record{"resource.$part.$type"};  
       $result.="<td bgcolor=$cellclr align=\"middle\"><input type=\"text\" name=\"GRADE.$student.$part.$type\" value=\"$score\" size=\"4\" /></td>\n"  
     } elsif ($type eq 'solved') {  
       my $score=$record{"resource.$part.$type"};  
       $result.="<td bgcolor=$cellclr align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";  
       if ($score =~ /^correct/) {  
  $result.="<option selected=\"on\">correct</option>\n<option>incorrect</option>\n<option>excused</option>\n<option>ungraded</option>\n<option>nothing</option>\n";  
       } elsif ($score =~ /^incorrect/) {  
  $result.="<option>correct</option>\n<option selected=\"on\">incorrect</option>\n<option>excused</option>\n<option>ungraded</option>\n<option>nothing</option>\n";  
       } elsif ($score eq '') {  
  $result.="<option>correct</option>\n<option>incorrect</option>\n<option>excused</option>\n<option>ungraded</option>\n<option selected=\"on\">nothing</option>\n";  
       } elsif ($score =~ /^excused/) {  
  $result.="<option>correct</option>\n<option>incorrect</option>\n<option selected=\"on\">excused</option>\n<option>ungraded</option>\n<option>nothing</option>\n";  
       } elsif ($score =~ /^ungraded/) {  
  $result.="<option>correct</option>\n<option>incorrect</option>\n<option>excused</option>\n<option selected=\"on\">ungraded</option>\n<option>nothing</option>\n";  
       }  
       $result.="</select></td>\n";  
     }      }
   }      $request->print('</table>');
   $result.='</tr>';      return '';
   return $result;  
 }  }
 #FIXME need to look at the meatdata <stores> spec on what type of data to accept and provide an  #
 #interface based on that, also do that to above function.  # --------------------------- show submissions of a student, option to grade --------
 sub setstudentgrade {  sub submission {
   my ($url,$symb,$courseid,$student,@parts) = @_;      my ($request,$counter,$total) = @_;
   
   my $result ='';      (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) = &finduser($ENV{'form.student'});
       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>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 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';
   
   my ($stuname,$domain) = split(/:/,$student);   }
    $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);
   
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);   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);
   #    &print_hash($request,\%record);
   
       # 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>Fullname: </b>'.$ENV{'form.fullname'}.
   #    $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Fullname: </b>'.$fullname.
    '</td><td>&nbsp; &nbsp;<b>Username: </b>'.$uname.
    '</td><td>&nbsp; &nbsp;<b>Domain: </b>'.$udom.'</td></tr>';
       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.='<tr bgcolor="#ffffff"><td colspan=3><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;
       }
       push @col_list, $collaborator;
       $result.=$$fullname{$collaborator.':'.$udom}.' ('.$collaborator.') &nbsp; &nbsp;';
    }
    $result.='</td></tr>'."\n";
    $result.='<tr bgcolor="#ffbbbb"><td colspan=2>'.
       'This student has submitted '.(scalar (@badcollaborators) > 1 ? '' : 'an').
       ' invalid collaborator'.(scalar (@badcollaborators) > 1 ? 's. ' : '. ').
       (join ', ',@badcollaborators).'</td></tr>' 
       if (scalar(@badcollaborators) > 0);
   
    $result.='<tr bgcolor="#ffbbbb"><td colspan=2>'.
       'This student has submitted too many collaborators. Maximum is '.
       $ncol.'.</td></tr>' if (scalar(@collaborators) > $ncol);
    $result.='<input type="hidden" name="collaborator'.$counter.
       '" value="'.(join ':',@col_list).'" />'."\n";
       }
    }
       }
    }
       }
       $request->print($result.'</table>'."\n");
   
   my %newrecord;      # print student answer
       if ($ENV{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
   foreach my $part (@parts) {   if ($ENV{'form.'.$uname.':'.$udom.':submitted_by'}) {
     my ($temp,$part,$type)=split(/_/,$part);      my $submitby='</td></tr><tr><td bgcolor="#e6ffff">'.
     my $oldscore=$record{"resource.$part.$type"};   '<b>Collaborative submission by: </b>'.
     my $newscore=$ENV{"form.GRADE.$student.$part.$type"};   '<a href="javascript:viewSubmitter(\''.$ENV{'form.'.$uname.':'.$udom.':submitted_by'}.
     if ($type eq 'solved') {   '\')"; TARGET=_self>'.
       my $update=0;   $$fullname{$ENV{'form.'.$uname.':'.$udom.':submitted_by'}}.'</a>';
       if ($newscore eq 'nothing' ) {      $submitby.='</td></tr><tr><td bgcolor="#ffffff">'."\n";
  if ($oldscore ne '') {      $request->print($submitby);
   $update=1;   } else {
   $newscore = '';      my ($string,$timestamp)=&get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'});
  }      my $lastsubonly.='</td></tr><tr><td bgcolor="#e6ffff"><b>Last Submission Only</b>'.
       } elsif ($oldscore !~ m/^$newscore/) {   ($$timestamp eq '' ? '' : '&nbsp; &nbsp; <b>Date Submitted:</b> '.$$timestamp).'</td></tr>';
  $update=1;      if ($$timestamp eq '') {
  $result.="Updating $stuname to $newscore<br />\n";   $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>';
  if ($newscore eq 'correct') { $newscore = 'correct_by_override'; }      } else {
  if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }   for my $part (sort keys(%$handgrade)) {
  if ($newscore eq 'excused') { $newscore = 'excused'; }      foreach (@$string) {
  if ($newscore eq 'ungraded') { $newscore = 'ungraded_attempted'; }   my ($partid,$respid) = /^resource\.(\d+)\.(\d+)\.submission/;
       } else {   if ($part eq ($partid.'_'.$respid)) {
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";      my ($ressub,$subval) = split(/:/,$_,2);
       }      $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part ID</b> '.
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }   $partid.' <b>Response ID</b> '.$respid.
    ' <b>Submission</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 {      } else {
       if ($oldscore ne $newscore) {   $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
  $newrecord{"resource.$part.$type"}=$newscore;   $ENV{'request.course.id'},$last,
  $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";   '.submission','Apache::grades::keywords_highlight'));
       } else {      }
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";      
       }      # view submission with no grading option
     }      if ($ENV{'form.showgrading'} eq '') {
   }   $request->print('</td></tr></table></td></tr></table></form>');
   if ( scalar(keys(%newrecord)) > 0 ) {   return;
     $newrecord{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";      }
     &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);  
       $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.
    ',\''.$fullname.'\')"; TARGET=_self>Compose Message</a><br />'."\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);
   
    # display grading options
    $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.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";   $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';
   }   $result.='<td><input type="text" name="GD_BOX'.$counter.'_'.$partid.'"'.
   return $result;      ($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.')" /></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 '';
 }  }
   
 sub submission {  sub get_last_submission {
   my ($request) = @_;      my ($symb,$username,$domain,$course)=@_;
   my $url=$ENV{'form.url'};      if ($symb) {
   $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;   my (@string,$timestamp);
   if ($ENV{'form.student'} eq '') { &moreinfo($request,"Need student login id"); return ''; }   my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);
 #  if ($ENV{'form.student'} eq '') { &listStudents($request); return ''; }   if ($returnhash{'version'}) {
   my ($uname,$udom) = &finduser($ENV{'form.student'});      my %lasthash=();
   if ($uname eq '') { &moreinfo($request,"Unable to find student"); return ''; }      my ($version);
   my $symb;      for ($version=1;$version<=$returnhash{'version'};$version++) {
   if ($ENV{'form.symb'}) {   foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
     $symb=$ENV{'form.symb'};      $lasthash{$_}=$returnhash{$version.':'.$_};
   } else {   }
     $symb=&Apache::lonnet::symbread($url);      }
   }      foreach ((keys %lasthash)) {
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }   if ($_ =~ /\.submission$/) {push @string, (join(':',$_,$lasthash{$_}))}
   my $answer=&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,   if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))};
       $ENV{'request.course.id'});      }
   my $result="<h2> Submission Record </h2>  $uname:$udom for $url <br />".$answer;   }
   my $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,   @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
    $ENV{'request.course.id'});   return \@string,\$timestamp;
   $result.="Student's view of the problem:<br /> $rendered <br /> Correct answer:<br />";      }
   
   $answer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,  
   $ENV{'request.course.id'});  
   $result.=$answer;  
   return $result;  
 }  }
   
 sub get_symb_and_url {  sub keywords_highlight {
  my ($request) = @_;      my $string  = shift;
   my $url=$ENV{'form.url'};      my $size    = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};
   $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;      my $styleon = $ENV{'form.kwstyle'} eq ''  ? '' : $ENV{'form.kwstyle'};
   my $symb=$ENV{'form.symb'};      (my $styleoff = $styleon) =~ s/\</\<\//;
   if (!$symb) { $symb=&Apache::lonnet::symbread($url); }      my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }      foreach (@keylist) {
  return ($symb,$url);   $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;
       $ENV{'form.keywords'}           =~ s/^\s+|\s+$//;
       $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'});
   
       if ($ENV{'form.refresh'} eq 'on') {
    my $ctr = 0;
    $ENV{'form.NTSTU'}=$ngrade;
    while ($ctr < $ngrade) {
       ($ENV{'form.student'},my $udom) = split(/:/,$ENV{'form.unamedom'.$ctr});
       &submission($request,$ctr,$ngrade-1);
       $ctr++;
    }
    return '';
       }
   
       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++;
    }
       }
       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(@{ $$classlist{$ENV{'form.section'}} }) ) {
    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'},$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.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 '';
 }  }
   
 sub gradingmenu {  sub saveHandGrade {
   my ($request) = @_;      my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_;
   my ($symb,$url)=&get_symb_and_url($request);  #   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
   if (!$symb) {return '';}      my %newrecord;
   my $result='<h2>Select a grading method</h2><br />';      foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
   $result.='<form action="/adm/grades" method="post">'."\n".   if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') {
      '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      $newrecord{'resource.'.$_.'.solved'} = 'excused';
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".   } else {
  '<input type="hidden" name="command" value="viewgrades" />'."\n".      my $pts    = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? 
   '<input type="submit" name="submit" value="View/Edit Entire Class" />'."\n".    $ENV{'form.GD_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_});
     '</form>';      if ($pts eq '') {
   $result.='<form action="/adm/grades" method="post">'."\n".   &userError($request,'No point was assigned for part id '.$_.' and for username '.$stuname.'.');
      '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".   return 'error';
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      }
  '<input type="hidden" name="command" value="csvupload" />'."\n".      my $wgt    = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_};
   '<input type="submit" name="submit" value="Upload Scores" />'."\n".      my $partial= $pts/$wgt;
     '</form>';      $newrecord{'resource.'.$_.'.awarded'}  = $partial;
   $result.='<form action="/adm/grades" method="post">'."\n".      if ($partial == 0) {
      '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".   $newrecord{'resource.'.$_.'.solved'} = 'incorrect_by_override';
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      } else {
  '<input type="hidden" name="command" value="submission" />'."\n".   $newrecord{'resource.'.$_.'.solved'} = 'correct_by_override';
   '<input type="submit" name="submit" value="View/Edit Student" />'."\n".      }
     '</form>';      $newrecord{'resource.'.$_.'.submitted_by'} = $submitter if ($submitter);
   return $result;   }
       }
       
       if ( scalar(keys(%newrecord)) > 0 ) {
    $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
   # &print_hash($request,\%newrecord);
    &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);
       }
       return '';
 }  }
   
 sub viewgrades {  sub get_symb_and_url {
   my ($request) = @_;      my ($request) = @_;
   my $result='';      (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;
   }
   
   #get resource reference  sub gradingmenu {
   my ($symb,$url)=&get_symb_and_url($request);      my ($request) = @_;
   if (!$symb) {return '';}      my ($symb,$url)=&get_symb_and_url($request);
   #get classlist      if (!$symb) {return '';}
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});      my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';
   #print "Found $cdom:$cnum<br />";      $result.='<table border="0">';
   my (%classlist) = &getclasslist($cdom,$cnum,'0');      $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>';
   my $headerclr = '"#ccffff"';      my ($partlist,$handgrade) = &response_type($url);
   my $cellclr = '"#ffffcc"';      my ($resptype,$hdgrade)=('','no');
       for (sort keys(%$handgrade)) {
   #get list of parts for this problem   my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
   my (@parts) = &getpartlist($url);   $resptype = $responsetype;
    $hdgrade = $handgrade if ($handgrade eq 'yes');
   $request->print ("<h2><font color=\"#339966\">Manual Grading</font></h2>");   $result.='<tr><td><b>Part ID: </b>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
   #start the form      '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
   $result = '<form action="/adm/grades" method="post">'."\n".      }
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      $result.='</table>';
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      $result.=&view_edit_entire_class_form($symb,$url).'<br />';
  '<input type="hidden" name="command" value="editgrades" />'."\n".      $result.=&upcsvScores_form($symb,$url).'<br />';
   '<input type="submit" name="submit" value="Submit Changes" />'."\n".      $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).'<br />';
     '<table border=0><tr><td bgcolor="#999999">'."\n".      $result.=&verifyReceipt_form($symb,$url).'<br />';
      '<table border=0>'."\n".      $result.=&view_classlist_form($symb,$url);
       '<tr><td bgcolor='.$headerclr.'>UserId</td><td bgcolor='.$headerclr.'>Domain</td>'."\n";  
   foreach my $part (sort(@parts)) {      return $result;
      my $display=&Apache::lonnet::metadata($url,$part.'.display');  }
      if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }  
      $result.='<td bgcolor='.$headerclr.'>'.$display.'</td>'."\n";  sub view_classlist_form {
    }      my ($symb,$url)=@_;
   $result.="</tr>";      my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
   #get info for each student      $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {      $result.='&nbsp;<b>View Class List</b></td></tr>'."\n";
     $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);      $result.='<tr bgcolor=#ffffe6><td>'."\n";
   }      $result.='<form action="/adm/grades" method="post">'."\n".
   $result.='</table></td></tr></table><input type="submit" name="submit" value="Submit Changes" /></form>';   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="viewclasslist" />'."\n";
       $result.='&nbsp;<input type="submit" name="submit" value="View Class" /></form>'."\n";
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   sub viewclasslist {
       my ($request) = shift;
       my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});
       my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);
       $request->print('<table border=1>');
       foreach (sort keys(%classlist)) {
   #    my ($unam,$udom) = split(/:/,$_,2);
   #    my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
   #    my $fullname = &get_fullname ($unam,$udom);
   #    my @uname;
   #    $uname[0]=$unam;
   #    my %userid=&Apache::lonnet::idrget($udom,@uname);
   #    my $value=$classlist{$_}.':'.$userid{$unam}.':'.$section.':'.$fullname;
   #    $classlist{$_}=$value;
    $request->print('<tr><td>'.$_.' </td><td><pre> '.$classlist{$_}.'</pre></td></tr>');
       }
       $request->print('</table>');
   #  my $putresult = &Apache::lonnet::put
   #      ('classlist',\%classlist,
   #       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
   #       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
   return $result;      return '';
 }  }
   
 sub editgrades {  sub view_edit_entire_class_form {
   my ($request) = @_;      my ($symb,$url)=@_;
   my $result='';      my ($classlist,$sections) = &getclasslist('all','0');
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
   my $symb=$ENV{'form.symb'};      $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }      $result.='&nbsp;<b>View/Grade Entire Section/Class</b></td></tr>'."\n";
   my $url=$ENV{'form.url'};      $result.='<tr bgcolor=#ffffe6><td>'."\n";
   #get classlist      $result.='<form action="/adm/grades" method="post">'."\n".
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
   #print "Found $cdom:$cnum<br />";   '<input type="hidden" name="url" value="'.$url.'" />'."\n".
   my (%classlist) = &getclasslist($cdom,$cnum,'0');   '<input type="hidden" name="command" value="viewgrades" />'."\n";
       $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";
   #get list of parts for this problem      foreach (sort (@$sections)) {
   my (@parts) = &getpartlist($url);   $result.= '<option>'.$_.'</option>'."\n";
       }
   $result.='<form action="/adm/grades" method="post">'."\n".      $result.='<option selected="on">all</select>'."<br />\n";
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      $result.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      $result.='</td></tr></table>'."\n";
  '<input type="hidden" name="command" value="viewgrades" />'."\n".      $result.='</td></tr></table>'."\n";
   '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";      return $result;
   }
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {  
     $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  sub upcsvScores_form {
   }      my ($symb,$url) = @_;
       if (!$symb) {return '';}
   $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';      my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
   return $result;      $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";
 sub csvupload {      my $upfile_select=&Apache::loncommon::upfile_select_html();
   my ($request)= @_;  
   my $result;  
   my ($symb,$url)=&get_symb_and_url($request);  
   if (!$symb) {return '';}  
   my $upfile_select=&Apache::loncommon::upfile_select_html();  
   $result.=<<ENDUPFORM;    $result.=<<ENDUPFORM;
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <input type="hidden" name="symb" value="$symb" />  <input type="hidden" name="symb" value="$symb" />
 <input type="hidden" name="url" value="$url" />  <input type="hidden" name="url" value="$url" />
 <input type="hidden" name="command" value="csvuploadmap" />  <input type="hidden" name="command" value="csvuploadmap" />
 <hr />  
 <h3>Specify a file containing the class grades for resource $url</h3>  
 $upfile_select  $upfile_select
 <p><input type="submit" name="submit" value="Upload Grades" />  <br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />
   </form>
 ENDUPFORM  ENDUPFORM
   return $result;      $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   sub viewGradeaStu_form {
       my ($symb,$url,$response,$handgrade) = @_;
       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 an Individual Student\'s Submission</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="response" value="'.$response.'" />'."\n".
    '<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;
   }
   
   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 viewgrades_js {
       my ($request) = shift;
   
       $request->print(<<VIEWJAVASCRIPT);
   <script type="text/javascript" language="javascript">
       function viewOneStudent(user) {
    document.onestudent.student.value = user;
    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;
       }
       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");
    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};
    }
       }
    }
       }
   
       function submitForm() {
    document.classgrade.submit();
       }
   
   </script>
   VIEWJAVASCRIPT
   }
   
   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".
    '</form>'."\n";
   
       #start the 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 score 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>';
   
       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.='<tr><td><b>Part ID:</b> '.$partid.'&nbsp; &nbsp;</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="document.classgrade.submit();" TARGET=_self />'."\n";
       $result.= '<input type="submit" name="submit"  value="Submit Changes" />'."\n";
   
       $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".
    '<table border=0><tr bgcolor="#deffff">'.
    '<td><b>Username</b></td><td><b>Fullname</b></td><td><b>Domain</b></td>'."\n";
       #get list of parts for this problem
       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
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
       my $ctr = 0;
       foreach ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
    (my $username = $_) = split(/:/);
    $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$username.'" />'."\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;
   }
   
   sub viewstudentgrade {
       my ($url,$symb,$courseid,$student,$fullname,$parts,$weight) = @_;
       my ($username,$domain) = split(/:/,$student);
       my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
       my $result='<tr bgcolor="#ffffdd"><td>'.
    '<a href="javascript:viewOneStudent(\''.$username.'\')"; TARGET=_self>'.$username.'</a>'.
    '</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"};
    next if $type eq 'tries';
    if ($type eq 'awarded') {
       my $pts = $score eq '' ? '' : $score*$$weight{$part};
       $result.='<input type="hidden" name="'.
    'GD_'.$username.'_'.$part.'_aw_s" value="'.$pts.'" />'."\n";
       $result.='<td align="middle"><input type="text" name="'.
    'GD_'.$username.'_'.$part.'_aw"'.
    'onChange="javascript:changeSelect('.$part.',\''.$username.'\')" 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_'.$username.'_'.$part.'_sv_s" value="'.$status.'" />'."\n";
       $result.='<td align="middle"><select name="'.
    'GD_'.$username.'_'.$part.'_sv" '.
    'onChange="javascript:changeOneScore('.$part.',\''.$username.'\')" >'."\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;
   }
   
   
   sub editgrades {
       my ($request) = @_;
   
       my $symb=$ENV{'form.symb'};
       my $url =$ENV{'form.url'};
       my $result='<h2><font color="#339933">Current Grade Status</font></h2>';
       $result.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br />'."\n";
       $result.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n";
       $result.= &show_grading_menu_form ($symb,$url);
       $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) = (0,0);
       while ($ctr < $ENV{'form.totalparts'}) {
    my $partid = $ENV{'form.partid_'.$ctr};
    push @partid,$partid;
    my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
    $weight{$partid} = $wgt eq '' ? '1' : $wgt;
    $ctr++;
    $result .= '<td colspan = 2 align="center"><b>Part ID '.$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;
   
    }
    $result .= '</tr>'."\n";
    if ($updateflag) {
       $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";
       return $result;
   }
   
   
   #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an
   #interface based on that, also do that to above function.
   sub setstudentgrade {
       my ($url,$symb,$courseid,$student,@parts) = @_;
       my $result ='';
       my ($stuname,$domain) = split(/:/,$student);
       my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);
       my %newrecord;
   
       foreach my $part (@parts) {
    my ($temp,$part,$type)=split(/_/,$part);
    my $oldscore=$record{"resource.$part.$type"};
    my $newscore=$ENV{"form.GD.$student.$part.$type"};
    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'; }
       } 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";
       }
    }
       }
       if ( scalar(keys(%newrecord)) > 0 ) {
    $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
   #       &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
   
    $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";
       }
       return $result;
   }
   
   
   sub sub_page_js {
       my $request = shift;
       $request->print(<<SUBJAVASCRIPT);
   <script type="text/javascript" language="javascript">
     function updateRadio(radioButton,formtextbox,formsel,scores) {
        var pts = formtextbox.value;
        var resetbox =false;
        if (isNaN(pts) || pts < 0) {
    alert("A number equal or greater than 0 is expected. Entered value = "+pts);
    for (var i=0; i<radioButton.length; i++) {
      if (radioButton[i].checked) {
         formtextbox.value = i;
         resetbox = true;
      }
    }
    if (!resetbox) {
      formtextbox.value = "";
    }
    return;
       }
   
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
    if (pts == i) {
      radioButton[i].checked=true;
    }
       }
       updateSelect(formsel);
       scores.value = "0";
     }
   
     function writeBox(formrad,formsel,pts,scores) {
       formrad.value = pts;
       scores.value = "0";
       updateSelect(formsel,pts);
       return;
     }
   
     function clearRadBox(radioButton,formbox,formsel,scores) {
       for (var i=0; i<formsel.length; i++) {
    if (formsel[i].selected) {
       var selectx=i;
    }
       }
       if (selectx == scores.value) { return };
       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;
     }
   
   //===================== Show list of keywords ====================
     function keywords(keyform) {
       var keywds = keyform.value;
       var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);
       if (nret==null) return;
       keyform.value = nret;
       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;
     }
   
   //===================== Script to add keyword(s) ==================
     function getSel() {
       if (document.getSelection) txt = document.getSelection();
       else if (document.selection) txt = document.selection.createRange().text;
       else return;
       var cleantxt = txt.replace(new RegExp('([\\f\\n\\r\\t\\v ])+', 'g')," ");
       if (cleantxt=="") {
    alert("Select a word or group of words from document and then click this link.");
    return;
       }
       var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt);
       if (nret==null) return;
       var curlist = document.SCORE.keywords.value;
       document.SCORE.keywords.value = curlist+" "+nret;
       return;
     }
   
   //====================== Script for composing message ==============
     function msgCenter(msgform,usrctr,fullname) {
       var Nmsg  = msgform.savemsgN.value;
       savedMsgHeader(Nmsg,usrctr,fullname);
       var subject = msgform.msgsub.value;
       var rtrchk  = eval("document.SCORE.includemsg"+usrctr);
       var msgchk = rtrchk.value;
   //    alert("checked=>"+msgchk);
       re = /msgsub/;
       var shwsel = "";
       if (re.test(msgchk)) { shwsel = "checked" }
       displaySubject(subject,shwsel);
       for (var i=1; i<=Nmsg; i++) {
    var testpt = "savemsg"+i+",";
    re = /testpt/;
    shwsel = "";
    if (re.test(msgchk)) { shwsel = "checked" }
    var message = eval("document.SCORE.savemsg"+i+".value");
    displaySavedMsg(i,message,shwsel);
       }
       newmsg = eval("document.SCORE.newmsg"+usrctr+".value");
       shwsel = "";
       re = /newmsg/;
       if (re.test(msgchk)) { shwsel = "checked" }
       newMsg(newmsg,shwsel);
       msgTail(); 
       return;
     }
   
     function savedMsgHeader(Nmsg,usrctr,fullname) {
       var height = 30*Nmsg+250;
       var scrollbar = "no";
       if (height > 600) {
    height = 600;
    scrollbar = "yes";
       }
   /*    if (window.pWin)
    window.pWin.close(); */
       pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx=70,screeny=75,width=600,height='+height);
       pWin.document.write("<html><head>");
       pWin.document.write("<title>Message Central</title>");
   
       pWin.document.write("<script language=javascript>");
       pWin.document.write("function checkInput() {");
       pWin.document.write("  opener.document.SCORE.msgsub.value = document.msgcenter.msgsub.value;");
       pWin.document.write("  var nmsg   = opener.document.SCORE.savemsgN.value;");
       pWin.document.write("  var usrctr = document.msgcenter.usrctr.value;");
       pWin.document.write("  var newval = eval(\\"opener.document.SCORE.newmsg\\"+usrctr);");
       pWin.document.write("  newval.value = document.msgcenter.newmsg.value;");
   
       pWin.document.write("  var msgchk = \\"\\";");
       pWin.document.write("  if (document.msgcenter.subchk.checked) {");
       pWin.document.write("     msgchk = \\"msgsub,\\";");
       pWin.document.write("  }");
       pWin.document.write(   "for (var i=1; i<=nmsg; i++) {");
       pWin.document.write("      var opnmsg = eval(\\"opener.document.SCORE.savemsg\\"+i);");
       pWin.document.write("      var frmmsg = eval(\\"document.msgcenter.msg\\"+i);");
       pWin.document.write("      opnmsg.value = frmmsg.value;");
       pWin.document.write("      var chkbox = eval(\\"document.msgcenter.msgn\\"+i);");
       pWin.document.write("      if (chkbox.checked) {");
       pWin.document.write("         msgchk += \\"savemsg\\"+i+\\",\\";");
       pWin.document.write("      }");
       pWin.document.write("  }");
       pWin.document.write("  if (document.msgcenter.newmsgchk.checked) {");
       pWin.document.write("     msgchk += \\"newmsg\\"+usrctr;");
       pWin.document.write("  }");
       pWin.document.write("  var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");
       pWin.document.write("  includemsg.value = msgchk;");
   
   //    pWin.document.write("  alert(\\"slected=\\"+msgchk)");
       pWin.document.write("  self.close()");
   
       pWin.document.write("}");
   
       pWin.document.write("<");
       pWin.document.write("/script>");
   
       pWin.document.write("</head><body bgcolor=white>");
   
       pWin.document.write("<form action=\\"inactive\\" name=\\"msgcenter\\">");
       pWin.document.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">");
       pWin.document.write("<font color=\\"green\\" size=+1>&nbsp;Compose Message for \"+fullname+\"</font><br><br>");
   
       pWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
       pWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
       pWin.document.write("<td><b>Type</b></td><td><b>Include</b></td><td><b>Message</td></tr>");
   }
       function displaySubject(msg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       pWin.document.write("<td>Subject</td>");
       pWin.document.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
       pWin.document.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+" \\"size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
   function displaySavedMsg(ctr,msg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       pWin.document.write("<td align=\\"center\\">"+ctr+"</td>");
       pWin.document.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"></td>");
       pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
     function newMsg(newmsg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       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><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
     function msgTail() {
       pWin.document.write("</table>");
       pWin.document.write("</td></tr></table>&nbsp;");
       pWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\">&nbsp;&nbsp;");
       pWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
       pWin.document.write("</form>");
       pWin.document.write("</body></html>");
   }
   
   //====================== Script for keyword highlight options ==============
     function kwhighlight() {
       var kwclr    = document.SCORE.kwclr.value;
       var kwsize   = document.SCORE.kwsize.value;
       var kwstyle  = document.SCORE.kwstyle.value;
       var redsel = "";
       var grnsel = "";
       var blusel = "";
       if (kwclr=="red")   {var redsel="checked"};
       if (kwclr=="green") {var grnsel="checked"};
       if (kwclr=="blue")  {var blusel="checked"};
       var sznsel = "";
       var sz1sel = "";
       var sz2sel = "";
       if (kwsize=="0")  {var sznsel="checked"};
       if (kwsize=="+1") {var sz1sel="checked"};
       if (kwsize=="+2") {var sz2sel="checked"};
       var synsel = "";
       var syisel = "";
       var sybsel = "";
       if (kwstyle=="")    {var synsel="checked"};
       if (kwstyle=="<i>") {var syisel="checked"};
       if (kwstyle=="<b>") {var sybsel="checked"};
       highlightCentral();
       highlightbody('red','red',redsel,'0','normal',sznsel,'','normal',synsel);
       highlightbody('green','green',grnsel,'+1','+1',sz1sel,'<i>','italic',syisel);
       highlightbody('blue','blue',blusel,'+2','+2',sz2sel,'<b>','bold',sybsel);
       highlightend();
       return;
     }
   
   
     function highlightCentral() {
       hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx=100,screeny=75');
       hwdWin.document.write("<html><head>");
       hwdWin.document.write("<title>Highlight Central</title>");
   
       hwdWin.document.write("<script language=javascript>");
       hwdWin.document.write("function updateChoice(flag) {");
       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.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");
   //    hwdWin.document.write("     var kwords=opener.document.SCORE.keywords.value;");
   //    hwdWin.document.write("     alert(\\"keywords=\\"+opener.document.SCORE.keywords.value);");
   //    hwdWin.document.write("     return;");
   
       hwdWin.document.write("  if (flag==1){");
       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("   }");
       hwdWin.document.write("  self.close()");
       hwdWin.document.write("}");
   
       hwdWin.document.write("function radioSelection(radioButton) {");
       hwdWin.document.write("    var selection=null;");
       hwdWin.document.write("    for (var i=0; i<radioButton.length; i++) {");
       hwdWin.document.write("        if (radioButton[i].checked) {");
       hwdWin.document.write("            selection=radioButton[i].value;");
       hwdWin.document.write("            return selection;");
       hwdWin.document.write("        }");
       hwdWin.document.write("    }");
       hwdWin.document.write("}");
   
       hwdWin.document.write("<");
       hwdWin.document.write("/script>");
   
       hwdWin.document.write("</head><body bgcolor=white>");
   
       hwdWin.document.write("<form action=\\"inactive\\" name=\\"hlCenter\\">");
       hwdWin.document.write("<font color=\\"green\\" size=+1>&nbsp;Keyword Highlight Options</font><br><br>");
   
       hwdWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
       hwdWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
       hwdWin.document.write("<td><b>Text Color</b></td><td><b>Font Size</b></td><td><b>Font Style</td></tr>");
     }
   
     function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) { 
       hwdWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"</td>");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdsize\\" type=\\"radio\\" value=\\""+szval+"\\" "+szsel+">&nbsp;"+sztxt+"</td>");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"</td>");
       hwdWin.document.write("</tr>");
     }
   
     function highlightend() { 
       hwdWin.document.write("</table>");
       hwdWin.document.write("</td></tr></table>&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(0)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save & Refresh\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
       hwdWin.document.write("</form>");
       hwdWin.document.write("</body></html>");
     }
   
   </script>
   SUBJAVASCRIPT
 }  }
   
 sub csvupload_javascript_reverse_associate {  sub csvupload_javascript_reverse_associate {
Line 523  ENDPICK Line 1840  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 555  to this page if the data selected is ins Line 1872  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 586  ENDPICK Line 1903  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'};
   &Apache::lonhomework::showhash(('1'=>\@keyfields));  #  my $cdom=$ENV{"course.$courseid.domain"};
   &Apache::lonhomework::showhash(%fields);  #  my $cnum=$ENV{"course.$courseid.num"};
   my $courseid=$ENV{'request.course.id'};      my ($classlist) = &getclasslist('all','1');
   my $cdom=$ENV{"course.$courseid.domain"};      my @skipped;
   my $cnum=$ENV{"course.$courseid.num"};      my $countdone=0;
   my (%classlist) = &getclasslist($cdom,$cnum,'1');  
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {  
     my %newhash;  
     foreach my $grade (@gradedata) {      foreach my $grade (@gradedata) {
       my %entries=&Apache::loncommon::record_sep($grade);   my %entries=&Apache::loncommon::record_sep($grade);
       foreach my $dest (keys(%fields)) {   my $username=$entries{$fields{'username'}};
    my $domain=$entries{$fields{'domain'}};
       }   if (!exists($$classlist{"$username:$domain"})) {
       push(@skipped,"$username:$domain");
       next;
    }
    my %grades;
    foreach my $dest (keys(%fields)) {
       if ($dest eq 'username' || $dest eq 'domain') { next; }
       if ($entries{$fields{$dest}} eq '') { next; }
       my $store_key=$dest;
       $store_key=~s/^stores/resource/;
       $store_key=~s/_/\./g;
       $grades{$store_key}=$entries{$fields{$dest}};
    }
    $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
    &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
    $domain,$username);
    $request->print('.');
    $request->rflush();
    $countdone++;
       }
       $request->print("<br />Stored $countdone students\n");
       if (@skipped) {
    $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');
    foreach my $student (@skipped) { $request->print("<br />$student"); }
     }      }
   }      $request->print(&view_edit_entire_class_form($symb,$url));
       $request->print(&show_grading_menu_form($symb,$url));
       return '';
 }  }
   
 sub send_header {  sub send_header {
   my ($request)= @_;      my ($request)= @_;
   $request->print(&Apache::lontexconvert::header());      $request->print(&Apache::lontexconvert::header());
 #  $request->print("  #  $request->print("
 #<script>  #<script>
 #remotewindow=open('','homeworkremote');  #remotewindow=open('','homeworkremote');
 #remotewindow.close();  #remotewindow.close();
 #</script>");   #</script>"); 
   $request->print('<body bgcolor="#FFFFFF">');      $request->print('<body bgcolor="#FFFFFF">');
 }  }
   
 sub send_footer {  sub send_footer {
   my ($request)= @_;      my ($request)= @_;
   $request->print('</body>');      $request->print('</body>');
   $request->print(&Apache::lontexconvert::footer());      $request->print(&Apache::lontexconvert::footer());
 }  }
   
 sub handler {  sub handler {
   my $request=$_[0];      my $request=$_[0];
       
   if ( $ENV{'user.name'} eq 'albertel' ) {$Apache::lonxml::debug=1;} else {$Apache::lonxml::debug=0;}      if ($ENV{'browser.mathml'}) {
      $request->content_type('text/xml');
   if ($ENV{'browser.mathml'}) {      } else {
     $request->content_type('text/xml');   $request->content_type('text/html');
   } else {      }
     $request->content_type('text/html');      $request->send_http_header;
   }      return OK if $request->header_only;
   $request->send_http_header;      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
   return OK if $request->header_only;      my $url=$ENV{'form.url'};
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});      my $symb=$ENV{'form.symb'};
   my $url=$ENV{'form.url'};      my $command=$ENV{'form.command'};
   my $symb=$ENV{'form.symb'};      if (!$url) {
   my $command=$ENV{'form.command'};   my ($temp1,$temp2);
   if (!$url) {   ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);
     my ($temp1,$temp2);   $url = $ENV{'form.url'};
     ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);      }
     $url = $ENV{'form.url'};      &send_header($request);
   }      if ($url eq '' && $symb eq '') {
   &send_header($request);   if ($ENV{'user.adv'}) {
   if ($url eq '' && $symb eq '') {      if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&
      if ($ENV{'user.adv'}) {   ($ENV{'form.codethree'})) {
          if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&   my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.
              ($ENV{'form.codethree'})) {      $ENV{'form.codethree'};
              my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.   my ($tsymb,$tuname,$tudom,$tcrsid)=
         $ENV{'form.codethree'};      &Apache::lonnet::checkin($token);
              my ($tsymb,$tuname,$tudom,$tcrsid)=   if ($tsymb) {
  &Apache::lonnet::checkin($token);      my ($map,$id,$url)=split(/\_\_\_/,$tsymb);
              if ($tsymb) {      if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
                 my ($map,$id,$url)=split(/\_\_\_/,$tsymb);   $request->print(
                 if (&Apache::lonnet::allowed('mgr',$tcrsid)) {   &Apache::lonnet::ssi('/res/'.$url,
                    $request->print(       ('grade_username' => $tuname,
                      &Apache::lonnet::ssi('/res/'.$url,        'grade_domain' => $tudom,
                         ('grade_username' => $tuname,        'grade_courseid' => $tcrsid,
                          'grade_domain' => $tudom,        'grade_symb' => $tsymb)));
                          'grade_courseid' => $tcrsid,      } else {
                          'grade_symb' => $tsymb)));   $request->print('<h1>Not authorized: '.$token.'</h1>');
                 } else {      }           
                    $request->print('<h1>Not authorized: '.$token.'</h1>');   } else {
                 }                 $request->print('<h1>Not a valid DocID: '.$token.'</h1>');
    }
     } 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 '');  
       $request->print(&submission($request)) if ($ENV{'form.student'} ne '');  
     } elsif ($command eq 'gradingmenu') {  
       $request->print(&gradingmenu($request));  
     } elsif ($command eq 'viewgrades') {  
       $request->print(&viewgrades($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 '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 '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 {
       $request->print("Unknown action: $command:");
    }
     }      }
   }      &send_footer($request);
   &send_footer($request);      return OK;
   return OK;  
 }  }
   
 1;  1;

Removed from v.1.27  
changed lines
  Added in v.1.43


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