Diff for /loncom/homework/grades.pm between versions 1.37 and 1.42

version 1.37, 2002/07/08 21:18:54 version 1.42, 2002/07/26 20:28:42
Line 40  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="submission" />'."\n");
     $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\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("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("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('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");
     $request->print('</form>');   $request->print('</form>');
   }      }
   return '';      return '';
 }  }
   
 sub verifyreceipt {  sub verifyreceipt {
Line 69  sub verifyreceipt { Line 71  sub verifyreceipt {
 #    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 82  sub verifyreceipt { Line 84  sub verifyreceipt {
         foreach my $student ( sort(@{ $$classlist{'all'} }) ) {          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->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');          $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');
Line 94  sub verifyreceipt { Line 96  sub verifyreceipt {
 }  }
   
 sub student_gradeStatus {  sub student_gradeStatus {
   my ($url,$udom,$uname) = @_;      my ($url,$udom,$uname,$partlist) = @_;
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));      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 %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
   foreach my $part (&getpartlist($url)) {      my %partstatus = ();
     my ($temp,$part,$type)=split(/_/,$part);      foreach (@$partlist) {
     if ($type eq 'solved') {   my ($status,$foo)=split(/_/,$record{"resource.$_.solved"},2);
       my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);   $status = 'nothing' if ($status eq '');
       $status = 'partial' if ($foo =~ /^partially/);   $partstatus{$_} = $status;
       $status = 'nothing' if ($status eq '');   $partstatus{"resource.$_.submitted_by"} = $record{"resource.$_.submitted_by"} 
       return $type,$status;   if ($record{"resource.$_.submitted_by"} ne '');
     }      }
   }      return %partstatus;
   return '';  
 }  }
   
 sub get_fullname {  sub get_fullname {
     my ($sname,$sdom) = @_;      my ($uname,$udom) = @_;
     my %name=&Apache::lonnet::get('environment', ['lastname','generation',      my %name=&Apache::lonnet::get('environment', ['lastname','generation',
   'firstname','middlename'],    'firstname','middlename'],$udom,$uname);
   $sdom,$sname);  
     my $fullname;      my $fullname;
     my ($tmp) = keys(%name);      my ($tmp) = keys(%name);
     if ($tmp !~ /^(con_lost|error|no_such_host)/i) {      if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
Line 124  sub get_fullname { Line 124  sub get_fullname {
     return $fullname;      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{1,2}.*/) {
       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 $getsec    =$ENV{'form.section'};      my $getsec    =$ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'};
   my $submitonly=$ENV{'form.submitonly'};      my $submitonly=$ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
   
   $request->print(<<ENDTABLEST);      my $result='<h2><font color="#339933">&nbsp;View Submissions for a Student or a Group of Students</font></h2>';
 <h2><font color="#339933">&nbsp;View Submissions for a Student or a Group of Students</font></h2>      $result.='<table border="0">';
 &nbsp;<font size=+1><b>Resource:</b> $ENV{'form.url'}<br /><br />      $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>';
 <form action="/adm/grades" method="post">&nbsp;<b>View Options</b></font><br />      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>'.$_.'</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">
 &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no   &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no 
 <input type="radio" name="vProb" value="yes"> yes <br />  <input type="radio" name="vProb" value="yes"> yes <br />
 &nbsp;<b>Submissions: </b>  &nbsp;<b>Submissions: </b>
 <input type="radio" name="lastSub" value="lastonly" checked> last sub only  <input type="radio" name="lastSub" value="hdgrade" checked /> handgrade only
 <input type="radio" name="lastSub" value="last"> last sub & parts info  <input type="radio" name="lastSub" value="lastonly" /> last sub only
 <input type="radio" name="lastSub" value="all"> all details  <input type="radio" name="lastSub" value="last" /> last sub & parts info
 <input type="hidden" name="section" value="$getsec">  <input type="radio" name="lastSub" value="all" /> all details
 <input type="hidden" name="submitonly" value="$submitonly">  <input type="hidden" name="section" value="$getsec" />
 <input type="hidden" name="response" value="$ENV{'form.response'}">  <input type="hidden" name="submitonly" value="$submitonly" />
 <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}">  <input type="hidden" name="response" value="$ENV{'form.response'}" />
 <table border="0"><tr><td bgcolor="#777777">  <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" /><br />
 <table border="0"><tr bgcolor="#e6ffff">  <input type="hidden" name="showgrading" value="$ENV{'form.showgrading'}" /><br />
 <td><b>&nbsp;Select&nbsp;</b></td><td><b>&nbsp;Username&nbsp;</b></td>  <input type="submit" name="submit" value="View/Grade" />
 <td><b>&nbsp;Fullname&nbsp;</b></td><td><b>&nbsp;Domain&nbsp;</b></td>  
 <td><b>&nbsp;Grade Status&nbsp;</b></td></tr>  
 ENDTABLEST  ENDTABLEST
   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="processGroup" />'."\n");      $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
       
   my ($classlist) = &getclasslist($getsec,'0');      my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
   foreach my $student ( sort(@{ $$classlist{$getsec} }) ) {      
       my ($sname,$sdom) = split(/:/,$student);      $result='<table border="0"><tr><td bgcolor="#777777">'.
       my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);   '<table border="0"><tr bgcolor="#e6ffff">'.
       next if ($status eq 'nothing' && $submitonly eq 'yes');   '<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>';
       my $fullname = &get_fullname($sname,$sdom);      foreach (sort(@$partlist)) {
       if ( $Apache::grades::viewgrades eq 'F' ) {   $result.='<td><b>&nbsp;Part ID '.$_.' Status&nbsp;</b></td>';
   $request->print("\n".'<tr bgcolor="#ffffe6">'.      }
   '<td align="center"><input type=checkbox name="stuinfo" value="'.      $request->print($result.'</tr>'."\n");
   $student.':'.$fullname.'"></td>'."\n".  
   '<td>&nbsp;'.$sname.'&nbsp;</td>'."\n".      foreach my $student (sort(@{ $$classlist{$getsec} }) ) {
   '<td>&nbsp;'.$fullname.'&nbsp;</td>'."\n".   my ($uname,$udom) = split(/:/,$student);
   '<td align="middle">&nbsp;'.$sdom.'&nbsp;</td>'."\n");   my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist);
   $request->print('<td align="middle">&nbsp;'.$status.'&nbsp;</td>'."\n");   my $statusflg = '';
    foreach (keys(%status)) {
       $statusflg = 1 if ($status{$_} ne 'nothing');
       my ($foo,$partid,$foo) = split(/\./,$_);
       if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
    $statusflg = '';
    $request->print('<input type="hidden" name="'.
    $student.':submitted_by" value="'.
    $status{'resource.'.$partid.'.submitted_by'}.'" />');
       }
    }
    next if ($statusflg eq '' && $submitonly eq 'yes');
   
   $request->print('</tr>');   if ( $Apache::grades::viewgrades eq 'F' ) {
       }      $result='<tr bgcolor="#ffffe6">'.
   }   '<td align="center"><input type=checkbox name="stuinfo" value="'.
   $request->print('</table></td></tr></table>');   $student.':'.$$fullname{$student}.'"></td>'."\n".
   $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');   '<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 {  sub processGroup {
   my ($request)  = shift;      my ($request)  = shift;
   my $ctr        = 0;      my $ctr        = 0;
   my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}      my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
                            : ($ENV{'form.stuinfo'}));        : ($ENV{'form.stuinfo'}));
   my $total      = scalar(@stuchecked)-1;      my $total      = scalar(@stuchecked)-1;
   if ($stuchecked[0] eq '') {      if ($stuchecked[0] eq '') {
       &userError($request,'No student was selected for viewing/grading.');   &userError($request,'No student was selected for viewing/grading.');
       return;   return;
   }      }
   foreach (@stuchecked) {      foreach (@stuchecked) {
       my ($sname,$sdom,$fullname) = split(/:/);   my ($uname,$udom,$fullname) = split(/:/);
       $ENV{'form.student'} = $sname;   $ENV{'form.student'} = $uname;
       $ENV{'form.fullname'} = $fullname;   $ENV{'form.fullname'} = $fullname;
       &submission($request,$ctr,$total);   &submission($request,$ctr,$total);
       $ctr++;   $ctr++;
   }      }
   return 'The End';      return '';
 }  }
   
 sub userError {  sub userError {
Line 213  sub userError { Line 266  sub userError {
   
 #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');   my ($classlist) = &getclasslist('all','0');
     foreach ( sort(@{ $$classlist{'all'} }) ) {   foreach ( sort(@{ $$classlist{'all'} }) ) {
       my ($posname,$posdomain) = split(/:/);      my ($posname,$posdomain) = split(/:/);
       if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }      if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
     }   }
     return ($name,$domain);   return ($name,$domain);
   } else {      } else {
     return ($ENV{'user.name'},$ENV{'user.domain'});   return ($ENV{'user.name'},$ENV{'user.domain'});
   }      }
 }  }
   
 sub getclasslist {  sub getclasslist {
   my ($getsec,$hideexpired) = @_;      my ($getsec,$hideexpired) = @_;
   my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});      my $now = time;
   my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);      my %classlist=&Apache::lonnet::dump('classlist',
   my $now = time;   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
   my (@holdsec,@sections);   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   foreach my $student (keys(%classlist)) {      my (@holdsec,@sections,%allids,%stusec,%fullname);
     my ($end,$start)=split(/:/,$classlist{$student});      foreach (keys(%classlist)) {
     # still a student?   my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
     if (($hideexpired) && ($end) && ($end < $now)) {         # still a student?
       next;   if (($hideexpired) && ($end) && ($end < $now)) {
     }      next;
     my ($unam,$udom) = split(/:/,$student,2);   }
     my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});   $section = ($section ne '' ? $section : 'no');
     $section = ($section ne '-1' ? $section : 'no');   push @holdsec,$section;
     push @holdsec,$section;   if ($getsec eq 'all' || $getsec eq $section) {
     push (@{ $classlist{$getsec} }, $student) if ($getsec eq 'all' || $getsec eq $section);      push (@{ $classlist{$getsec} }, $_);
   }      $allids{$_}=$id;
   my %seen = ();      $stusec{$_}=$section;
   foreach my $item (@holdsec) {      $fullname{$_}=$fullname;
       push (@sections, $item) unless $seen{$item}++;   }
   }      }
   return (\%classlist,\@sections);      my %seen = ();
       foreach my $item (@holdsec) {
    push (@sections, $item) unless $seen{$item}++;
       }
       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 print_hash {
       my ($request, $hash) = @_;
       $request->print('<table border=1><tr><td>Key</td><td>Value</td></tr>');
       for (sort keys (%$hash)) {
    $request->print('<tr><td>'.$_.'</td><td>'.$$hash{$_}.'&nbsp;</td></tr>');
       }
       $request->print('</table>');
       return '';
   }
   #
   # --------------------------- show submissions of a student, option to grade --------
   sub submission {
       my ($request,$counter,$total) = @_;
   
       (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
       if ($ENV{'form.student'} eq '') { &moreinfo($request,'Need student login id'); return ''; }
       my ($uname,$udom) = &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';
   
    }
    $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".
    '<input type="hidden" name="command"    value="handgrade" />'."\n".
    '<input type="hidden" name="refresh"    value="off" />'."\n".
    '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url"        value="'.$url.'" />'."\n".
    '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" />'."\n".
    '<input type="hidden" name="vProb"      value="'.$ENV{'form.vProb'}.'" />'."\n".
    '<input type="hidden" name="lastSub"    value="'.$ENV{'form.lastSub'}.'" />'."\n".
    '<input type="hidden" name="section"    value="'.$ENV{'form.section'}.'">'."\n".
    '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".
    '<input type="hidden" name="response"   value="'.$ENV{'form.response'}.'">'."\n".
    '<input type="hidden" name="handgrade"  value="'.$ENV{'form.handgrade'}.'">'."\n".
    '<input type="hidden" name="keywords"   value="'.$ENV{'form.keywords'}.'" />'."\n".
    '<input type="hidden" name="kwclr"      value="'.$ENV{'form.kwclr'}.'" />'."\n".
    '<input type="hidden" name="kwsize"     value="'.$ENV{'form.kwsize'}.'" />'."\n".
    '<input type="hidden" name="kwstyle"    value="'.$ENV{'form.kwstyle'}.'" />'."\n".
    '<input type="hidden" name="msgsub"     value="'.$ENV{'form.msgsub'}.'" />'."\n".
    '<input type="hidden" name="savemsgN"   value="'.$ENV{'form.savemsgN'}.'" />'."\n".
    '<input type="hidden" name="NCT"'.
    ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");
   
    my ($cts,$prnmsg) = (1,'');
    while ($cts <= $ENV{'form.savemsgN'}) {
       $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.
    ($keyhash{$symb.'_savemsg'.$cts} eq '' ? $ENV{'form.savemsg'.$cts} : $keyhash{$symb.'_savemsg'.$cts}).
    '" />'."\n";
       $cts++;
    }
    $request->print($prnmsg);
   
    if ($ENV{'form.handgrade'} eq 'yes' && $ENV{'form.showgrading'} eq 'yes') {
       $request->print(<<KEYWORDS);
   &nbsp;<b>Keyword Options:</b>&nbsp;
   <a href="javascript:keywords(document.SCORE.keywords)"; TARGET=_self>List</a>&nbsp; &nbsp;
   <a href="#" onMouseDown="javascript:getSel(); return false"
    CLASS="page">Paste Selection to List</a>&nbsp; &nbsp;
   <a href="javascript:kwhighlight()"; TARGET=_self>Highlight Attribute</a><br /><br />
   KEYWORDS
           }
       }
       my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
       my ($partlist,$handgrade) = &response_type($url);
   #    &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>'.$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");
   
       # print student answer
       if ($ENV{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
    if ($ENV{'form.'.$uname.':'.$udom.':submitted_by'}) {
       my $submitby='</td></tr><tr><td bgcolor="#e6ffff">'.
    '<b>Collaborative submission by: </b>'.
    '<a href="javascript:viewSubmitter(\''.$ENV{'form.'.$uname.':'.$udom.':submitted_by'}.
    '\')"; TARGET=_self>'.
    $$fullname{$ENV{'form.'.$uname.':'.$udom.':submitted_by'}}.'</a>';
       $submitby.='</td></tr><tr><td bgcolor="#ffffff">'."\n";
       $request->print($submitby);
    } else {
       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>'.
    ($$timestamp eq '' ? '' : '&nbsp; &nbsp; <b>Date Submitted:</b> '.$$timestamp).'</td></tr>';
       if ($$timestamp eq '') {
    $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>';
       } else {
    for my $part (sort keys(%$handgrade)) {
       foreach (@$string) {
    my ($partid,$respid) = /^resource\.(\d+)\.(\d+)\.submission/;
    if ($part eq ($partid.'_'.$respid)) {
       my ($ressub,$subval) = split(/:/,$_,2);
       $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part ID</b> '.
    $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 {
    $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
    $ENV{'request.course.id'},$last,
    '.submission','Apache::grades::keywords_highlight'));
       }
       
       # view submission with no grading option
       if ($ENV{'form.showgrading'} eq '') {
    $request->print('</td></tr></table></td></tr></table></form>');
    return;
       }
   
       $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.GRADE_BOX'.$counter.'_'.$partid.
    ',this.form.GRADE_SEL'.$counter.'_'.$partid.','.$ctr.
    ',this.form.stores'.$counter.'_'.$partid.')" '.
    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
       $ctr++;
    }
    $result.='</tr></table>';
   
    $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';
    $result.='<td><input type="text" name="GRADE_BOX'.$counter.'_'.$partid.'"'.
       ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
       'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GRADE_BOX'.$counter.'_'.$partid.
       ',this.form.GRADE_SEL'.$counter.'_'.$partid.
       ',this.form.stores'.$counter.'_'.$partid.')" /></td>'."\n";
    $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';
   
    $result.='<select name="GRADE_SEL'.$counter.'_'.$partid.'" '.
       'onChange="javascript:clearRadBox(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GRADE_BOX'.$counter.'_'.$partid.
       ',this.form.GRADE_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 get_last_submission {
       my ($symb,$username,$domain,$course)=@_;
       if ($symb) {
    my (@string,$timestamp);
    my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);
    if ($returnhash{'version'}) {
       my %lasthash=();
       my ($version);
       for ($version=1;$version<=$returnhash{'version'};$version++) {
    foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
       $lasthash{$_}=$returnhash{$version.':'.$_};
    }
       }
       foreach ((keys %lasthash)) {
    if ($_ =~ /\.submission$/) {push @string, (join(':',$_,$lasthash{$_}))}
    if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))};
       }
    }
    @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string;
    return \@string,\$timestamp;
       }
   }
   
   sub keywords_highlight {
       my $string  = shift;
       my $size    = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};
       my $styleon = $ENV{'form.kwstyle'} eq ''  ? '' : $ENV{'form.kwstyle'};
       (my $styleoff = $styleon) =~ s/\</\<\//;
       my @keylist = split(/[,\s+]/,$ENV{'form.keywords'});
       foreach (@keylist) {
    $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,$foo) = 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 saveHandGrade {
       my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_;
   #   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
       my %newrecord;
       foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
    if ($ENV{'form.GRADE_SEL'.$newflg.'_'.$_} eq 'excused') {
       $newrecord{'resource.'.$_.'.solved'} = 'excused';
    } else {
       my $pts    = ($ENV{'form.GRADE_BOX'.$newflg.'_'.$_} ne '' ? 
     $ENV{'form.GRADE_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_});
       if ($pts eq '') {
    &userError($request,'No point was assigned for part id '.$_.' and for username '.$stuname.'.');
    return 'error';
       }
       my $wgt    = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_};
       my $partial= $pts/$wgt;
       $newrecord{'resource.'.$_.'.awarded'}  = $partial;
       if ($partial == 0) {
    $newrecord{'resource.'.$_.'.solved'} = 'incorrect_by_override';
       } else {
    $newrecord{'resource.'.$_.'.solved'} = 'correct_by_override';
       }
       $newrecord{'resource.'.$_.'.submitted_by'} = $submitter if ($submitter);
    }
       }
       
       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 get_symb_and_url {
       my ($request) = @_;
       (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
       my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
       if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
       return ($symb,$url);
   }
   
   sub show_grading_menu_form {
       my ($symb,$url)=@_;
       my $result.='<form action="/adm/grades" method="post">'."\n".
    '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="gradingmenu" />'."\n".
    '<input type="submit" name="submit" value="Grading Menu" />'."\n".
    '</form>'."\n";
       return $result;
   }
   
   sub gradingmenu {
       my ($request) = @_;
       my ($symb,$url)=&get_symb_and_url($request);
       if (!$symb) {return '';}
       my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';
       $result.='<table border="0">';
       $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>';
       my ($partlist,$handgrade) = &response_type($url);
       my ($resptype,$hdgrade)=('','no');
       for (sort keys(%$handgrade)) {
    my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
    $resptype = $responsetype;
    $hdgrade = $handgrade if ($handgrade eq 'yes');
    $result.='<tr><td><b>Part id: </b>'.$_.'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $result.=&view_edit_entire_class_form($symb,$url).'<br />';
       $result.=&upcsvScores_form($symb,$url).'<br />';
       $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).'<br />';
       $result.=&verifyReceipt_form($symb,$url).'<br />';
       $result.=&view_classlist_form($symb,$url);
   
       return $result;
   }
   
   sub view_classlist_form {
       my ($symb,$url)=@_;
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
       $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
       $result.='&nbsp;<b>View Class List</b></td></tr>'."\n";
       $result.='<tr bgcolor=#ffffe6><td>'."\n";
       $result.='<form action="/adm/grades" method="post">'."\n".
    '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="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 '';
   }
   
   sub view_edit_entire_class_form {
       my ($symb,$url)=@_;
       my ($classlist,$sections) = &getclasslist('all','0');
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
       $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
       $result.='&nbsp;<b>View/Grade Entire Section/Class</b></td></tr>'."\n";
       $result.='<tr bgcolor=#ffffe6><td>'."\n";
       $result.='<form action="/adm/grades" method="post">'."\n".
    '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url" value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="viewgrades" />'."\n";
       $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";
       foreach (sort (@$sections)) {
    $result.= '<option>'.$_.'</option>'."\n";
       }
       $result.= '<option selected="on">all</select>'."<br />\n";
   #    $result.='&nbsp;<b>Display students who has: </b>'.
   # '<input type="radio" name="submitonly" value="yes" checked> submitted'.
   # '<input type="radio" name="submitonly" value="all"> everybody <br /><br />';
       $result.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   sub upcsvScores_form {
       my ($symb,$url) = @_;
       if (!$symb) {return '';}
       my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";
       $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
       $result.='&nbsp;<b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";
       $result.='<tr bgcolor=#ffffe6><td>'."\n";
       my $upfile_select=&Apache::loncommon::upfile_select_html();
     $result.=<<ENDUPFORM;
   <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
   <input type="hidden" name="symb" value="$symb" />
   <input type="hidden" name="url" value="$url" />
   <input type="hidden" name="command" value="csvuploadmap" />
   $upfile_select
   <br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />
   </form>
   ENDUPFORM
       $result.='</td></tr></table>'."\n";
       $result.='</td></tr></table>'."\n";
       return $result;
   }
   
   sub viewGradeaStu_form {
       my ($symb,$url,$response,$handgrade) = @_;
       my ($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.counter"+i+".value");
       var scorename = eval("document.classgrade.GRADE_"+user+
    "_"+partid+"_awarded");
       var saveval   = eval("document.classgrade.GRADE_"+user+
    "_"+partid+"_solved_save.value");
       var selname   = eval("document.classgrade.GRADE_"+user+"_"+partid+"_solved");
       if (saveval != "correct") {
    scorename.value = point;
    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);
    if (selval[1].selected) {
       var radioButton = eval("document.classgrade.RADVAL_"+partid);
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
   
       }
       var textbox = eval("document.classgrade.TEXTVAL_"+partid);
       textbox.value = "";
   
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.counter"+i+".value");
    var scorename = eval("document.classgrade.GRADE_"+user+
        "_"+partid+"_awarded");
    var saveval   = eval("document.classgrade.GRADE_"+user+
        "_"+partid+"_solved_save.value");
    var selname   = eval("document.classgrade.GRADE_"+user+
        "_"+partid+"_solved");
    if (saveval != "correct") {
       scorename.value = "";
       selname[1].selected = true;
    }
       }
    }
       }
   
       function changeSelect(partid,user) {
    var selval = eval("document.classgrade.GRADE_"+user+'_'+partid+"_solved");
    selval[0].selected = true;
       }
   
       function changeOneScore(partid,user) {
    var selval = eval("document.classgrade.GRADE_"+user+'_'+partid+"_solved");
    if (selval[1].selected) {
       var boxval = eval("document.classgrade.GRADE_"+user+'_'+partid+"_awarded");
       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.counter"+i+".value");
    var resetscore = eval("document.classgrade.GRADE_"+user+
         "_"+partid+"_awarded");
    resetscore.value = eval("document.classgrade.GRADE_"+user+
    "_"+partid+"_awarded_save.value");
   
    var saveselval   = eval("document.classgrade.GRADE_"+user+
        "_"+partid+"_solved_save.value");
   
    var selname   = eval("document.classgrade.GRADE_"+user+"_"+partid+"_solved");
    if (saveselval == "excused") {
       selname[1].selected = true;
    } else {
       selname[0].selected = true;
    }
       }
    }
       }
   
   
   </script>
   VIEWJAVASCRIPT
   }
   
   sub viewgrades {
       my ($request) = shift;
       &viewgrades_js($request);
   
       my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'}); 
       $request->print ('<h2><font color="#339933">Manual Grading</font></h2>');
   
       my $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="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="counter'.$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 {  sub viewstudentgrade {
   my ($url,$symb,$courseid,$student,@parts) = @_;      my ($url,$symb,$courseid,$student,$fullname,$parts,$weight) = @_;
   my $result ='';      my ($username,$domain) = split(/:/,$student);
   my $cellclr = '"#ffffdd"';      my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
   my ($username,$domain) = split(/:/,$student);      my $result='<tr bgcolor="#ffffdd"><td>'.
    '<a href="javascript:viewOneStudent(\''.$username.'\')"; TARGET=_self>'.$username.'</a>'.
   my $fullname = &get_fullname($username,$domain);   '</td><td>'.$fullname.'</td><td align="middle">'.$domain.'</td>'."\n";
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);      foreach my $part (@$parts) {
    my ($temp,$part,$type)=split(/_/,$part);
   $result.="<tr bgcolor=$cellclr><td>$username</td><td>$fullname</td><td align=\"middle\">$domain</td>\n";   my $score=$record{"resource.$part.$type"};
   foreach my $part (@parts) {   next if $type eq 'tries';
     my ($temp,$part,$type)=split(/_/,$part);   if ($type eq 'awarded') {
     my $score=$record{"resource.$part.$type"};      my $pts = $score eq '' ? '' : $score*$$weight{$part};
     if ($type eq 'awarded' || $type eq 'tries') {      $result.='<input type="hidden" name="'.
       $result.='<td align="middle"><input type="text" name="GRADE.'.$student.'.'.$part.'.'.$type.   'GRADE_'.$username.'_'.$part.'_awarded_save" value="'.$pts.'" />'."\n";
   '" value="'.$score.'" size="4" /></td>'."\n";      $result.='<td align="middle"><input type="text" name="'.
     } elsif ($type eq 'solved') {   'GRADE_'.$username.'_'.$part.'_awarded"'.
       my ($status,$foo)=split(/_/,$score,2);   'onChange="javascript:changeSelect('.$part.',\''.$username.'\')" value="'.
       $result.="<td align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";   $pts.'" size="4" /></td>'."\n";
       my $optsel = '<option>correct</option><option>incorrect</option><option>excused</option>'.   } elsif ($type eq 'solved') {
   '<option>ungraded</option><option>partial</option><option>nothing</option>'."\n";      my ($status,$foo)=split(/_/,$score,2);
       $status = 'nothing' if ($status eq '');      $status = 'nothing' if ($status eq '');
       $optsel =~ s/<option>$status/<option selected="on">$status/;      $result.='<input type="hidden" name="'.
       $result.=$optsel;   'GRADE_'.$username.'_'.$part.'_solved_save" value="'.$status.'" />'."\n";
       $result.="</select></td>\n";      $result.='<td align="middle"><select name="'.
    'GRADE_'.$username.'_'.$part.'_solved" '.
    '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>';
   $result.='<td></td></tr>';      return $result;
   return $result;  }
   
   
   sub editgrades {
       my ($request) = @_;
   
       my $symb=$ENV{'form.symb'};
       if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }
       my $url=$ENV{'form.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="viewgrades" />'."\n".
    '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";
       
       my (@parts) = &getpartlist($url);
       my ($classlist) = &getclasslist($ENV{'form.section'},'0');
       foreach my $student ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
    $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);
       }
   
       $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';
       return $result;
 }  }
   
   
 #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an  #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.  #interface based on that, also do that to above function.
 sub setstudentgrade {  sub setstudentgrade {
   my ($url,$symb,$courseid,$student,@parts) = @_;      my ($url,$symb,$courseid,$student,@parts) = @_;
   print "set student grade parts=@parts<br>";      my $result ='';
   my $result ='';      my ($stuname,$domain) = split(/:/,$student);
   my ($stuname,$domain) = split(/:/,$student);      my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$stuname);      my %newrecord;
   my %newrecord;  
       foreach my $part (@parts) {
   foreach my $part (@parts) {   my ($temp,$part,$type)=split(/_/,$part);
     my ($temp,$part,$type)=split(/_/,$part);   my $oldscore=$record{"resource.$part.$type"};
     my $oldscore=$record{"resource.$part.$type"};   my $newscore=$ENV{"form.GRADE.$student.$part.$type"};
     my $newscore=$ENV{"form.GRADE.$student.$part.$type"};   if ($type eq 'solved') {
     print "old=$oldscore:new=$newscore:<br>";      my $update=0;
     if ($type eq 'solved') {      if ($newscore eq 'nothing' ) {
       my $update=0;   if ($oldscore ne '') {
       if ($newscore eq 'nothing' ) {      $update=1;
  if ($oldscore ne '') {      $newscore = '';
   $update=1;   }
   $newscore = '';      } elsif ($oldscore !~ m/^$newscore/) {
  }   $update=1;
       } elsif ($oldscore !~ m/^$newscore/) {   $result.="Updating $stuname to $newscore<br />\n";
  $update=1;   if ($newscore eq 'correct')   { $newscore = 'correct_by_override'; }
  $result.="Updating $stuname to $newscore<br />\n";   if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }
  if ($newscore eq 'correct')   { $newscore = 'correct_by_override'; }   if ($newscore eq 'excused')   { $newscore = 'excused'; }
  if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }   if ($newscore eq 'ungraded')  { $newscore = 'ungraded_attempted'; }
  if ($newscore eq 'excused')   { $newscore = 'excused'; }      } else {
  if ($newscore eq 'ungraded')  { $newscore = 'ungraded_attempted'; }   #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";
  if ($newscore eq 'partial')   { $newscore = 'correct_partially_by_override'; }      }
       } else {      if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";   } else {
       }      if ($oldscore ne $newscore) {
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }   $newrecord{"resource.$part.$type"}=$newscore;
     } else {   $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";
       if ($oldscore ne $newscore) {      } else {
  $newrecord{"resource.$part.$type"}=$newscore;   #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";
  $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 ) {
   if ( scalar(keys(%newrecord)) > 0 ) {   $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
     $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";  #       &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
 #    &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);  
   
     $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";   $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";
   }      }
   return $result;      return $result;
 }  }
   
 #  
 # --------------------------- show submissions of a student, option to grade --------  
 sub submission {  
   my ($request,$counter,$total) = @_;  
   
   if ($counter == 0) {  sub sub_page_js {
       $request->print(<<SUBJAVASCRIPT);      my $request = shift;
       $request->print(<<SUBJAVASCRIPT);
 <script type="text/javascript" language="javascript">  <script type="text/javascript" language="javascript">
   function updateRadio(radioButton,formtextbox,formsel,wgt) {    function updateRadio(radioButton,formtextbox,formsel,scores) {
      var pts = formtextbox.value;       var pts = formtextbox.value;
      var resetbox =false;       var resetbox =false;
      if (isNaN(pts) || pts < 0) {       if (isNaN(pts) || pts < 0) {
Line 378  sub submission { Line 1394  sub submission {
    radioButton[i].checked=true;     radioButton[i].checked=true;
  }   }
     }      }
     updateSelect(formsel,pts,wgt);      updateSelect(formsel);
       scores.value = "0";
   }    }
   
   function writeBox(formrad,formsel,pts,wgt) {    function writeBox(formrad,formsel,pts,scores) {
     formrad.value = pts;      formrad.value = pts;
     updateSelect(formsel,pts,wgt);      scores.value = "0";
       updateSelect(formsel,pts);
     return;      return;
   }    }
   
   function updateSelect(formsel,pts,wgt) {    function clearRadBox(radioButton,formbox,formsel,scores) {
     if (pts == 0) {      for (var i=0; i<formsel.length; i++) {
       formsel[1].selected = true;   if (formsel[i].selected) {
     }      var selectx=i;
     if (pts > 0 && pts < wgt) {   }
       formsel[4].selected = true;  
     }      }
     if (pts == wgt) {      if (selectx == scores.value) { return };
       formsel[0].selected = true;      formbox.value = "";
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
     }      }
       scores.value = selectx;
     }
   
     function updateSelect(formsel) {
       formsel[0].selected = true;
     return;      return;
   }    }
   
   //===================== Show list of keywords ====================
   function keywords(keyform) {    function keywords(keyform) {
     var keywds = keyform.value;      var keywds = keyform.value;
     var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);      var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);
Line 408  sub submission { Line 1433  sub submission {
     return;      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) ==================  //===================== Script to add keyword(s) ==================
   function getSel() {    function getSel() {
     if (document.getSelection) txt = document.getSelection();      if (document.getSelection) txt = document.getSelection();
Line 418  sub submission { Line 1452  sub submission {
  alert("Select a word or group of words from document and then click this link.");   alert("Select a word or group of words from document and then click this link.");
  return;   return;
     }      }
     var nret = prompt("Add selection to keyword list?",cleantxt);      var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt);
     if (nret==null) return;      if (nret==null) return;
     var curlist = document.SCORE.keywords.value;      var curlist = document.SCORE.keywords.value;
     document.SCORE.keywords.value = curlist+" "+nret;      document.SCORE.keywords.value = curlist+" "+nret;
Line 454  sub submission { Line 1488  sub submission {
     return;      return;
   }    }
   
 function savedMsgHeader(Nmsg,usrctr,fullname) {    function savedMsgHeader(Nmsg,usrctr,fullname) {
     var height = 30*Nmsg+250;      var height = 30*Nmsg+250;
     var scrollbar = "no";      var scrollbar = "no";
     if (height > 600) {      if (height > 600) {
Line 463  function savedMsgHeader(Nmsg,usrctr,full Line 1497  function savedMsgHeader(Nmsg,usrctr,full
     }      }
 /*    if (window.pWin)  /*    if (window.pWin)
  window.pWin.close(); */   window.pWin.close(); */
     pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',width=600,height='+height);      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("<html><head>");
     pWin.document.write("<title>Message Central</title>");      pWin.document.write("<title>Message Central</title>");
   
Line 526  function displaySavedMsg(ctr,msg,shwsel) Line 1560  function displaySavedMsg(ctr,msg,shwsel)
     pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");      pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
 }  }
   
 function newMsg(newmsg,shwsel) {    function newMsg(newmsg,shwsel) {
     pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");      pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
     pWin.document.write("<td align=\\"center\\">New</td>");      pWin.document.write("<td align=\\"center\\">New</td>");
     pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");      pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
     pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");      pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
 }  }
   
 function msgTail() {    function msgTail() {
     pWin.document.write("</table>");      pWin.document.write("</table>");
     pWin.document.write("</td></tr></table>&nbsp;");      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=\\"Save\\" onClick=\\"javascript:checkInput()\\">&nbsp;&nbsp;");
Line 574  function msgTail() { Line 1608  function msgTail() {
   }    }
   
   
 function highlightCentral() {    function highlightCentral() {
     hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300');      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("<html><head>");
     hwdWin.document.write("<title>Highlight Central</title>");      hwdWin.document.write("<title>Highlight Central</title>");
   
     hwdWin.document.write("<script language=javascript>");      hwdWin.document.write("<script language=javascript>");
     hwdWin.document.write("function updateChoice() {");      hwdWin.document.write("function updateChoice(flag) {");
     hwdWin.document.write("  opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");      hwdWin.document.write("  opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");
     hwdWin.document.write("  opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");      hwdWin.document.write("  opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");
     hwdWin.document.write("  opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");      hwdWin.document.write("  opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");
   //    hwdWin.document.write("     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("  self.close()");
     hwdWin.document.write("}");      hwdWin.document.write("}");
   
Line 608  function highlightCentral() { Line 1652  function highlightCentral() {
     hwdWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");      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("<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>");      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) {     function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) { 
     hwdWin.document.write("<tr bgcolor=\\"#ffffdd\\">");      hwdWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
     hwdWin.document.write("<td align=\\"left\\">");      hwdWin.document.write("<td align=\\"left\\">");
     hwdWin.document.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"</td>");      hwdWin.document.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"</td>");
Line 619  function highlightbody(clrval,clrtxt,clr Line 1663  function highlightbody(clrval,clrtxt,clr
     hwdWin.document.write("<td align=\\"left\\">");      hwdWin.document.write("<td align=\\"left\\">");
     hwdWin.document.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"</td>");      hwdWin.document.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"</td>");
     hwdWin.document.write("</tr>");      hwdWin.document.write("</tr>");
  }    }
   
 function highlightend() {     function highlightend() { 
     hwdWin.document.write("</table>");      hwdWin.document.write("</table>");
     hwdWin.document.write("</td></tr></table>&nbsp;");      hwdWin.document.write("</td></tr></table>&nbsp;");
     hwdWin.document.write("<input type=\\"button\\" value=\\"Set Options\\" onClick=\\"javascript:updateChoice()\\">&nbsp;&nbsp;");      hwdWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(0)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save & Refresh\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");
     hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");      hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
     hwdWin.document.write("</form>");      hwdWin.document.write("</form>");
     hwdWin.document.write("</body></html>");      hwdWin.document.write("</body></html>");
 }    }
   
 </script>  </script>
 SUBJAVASCRIPT  SUBJAVASCRIPT
 }  }
   (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' : '');  
   
   # header info  
   if ($counter == 0) {  
       $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' && $counter == 0) {  
       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);  
   }  
   
   # beginning of form  
   if ($counter == 0) {  
       my %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'};  
       # if the handgrade db has never being initialized then set some default values  
       if ($keyhash{$symb.'_handgrade'} eq '') {  
   $keyhash{$symb.'_keywords'}     = '';  
   $keyhash{$symb.'_subject'}      = &Apache::lonnet::metadata($url,'title');  
   $keyhash{$loginuser.'_kwclr'}   = $keyhash{$loginuser.'_kwclr'}   eq '' ? 'red' : $keyhash{$loginuser.'_kwclr'};  
   $keyhash{$loginuser.'_kwsize'}  = $keyhash{$loginuser.'_kwsize'}  eq '' ? '0' : $keyhash{$loginuser.'_kwsize'};  
   $keyhash{$loginuser.'_kwstyle'} = $keyhash{$loginuser.'_kwstyle'} eq '' ? ''  : $keyhash{$loginuser.'_kwstyle'};  
    $keyhash{$symb.'_savemsgN'}     = '0';  
       }  
       $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".  
       '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url"        value="'.$url.'" />'."\n".  
       '<input type="hidden" name="vProb"      value="'.$ENV{'form.vProb'}.'" />'."\n".  
       '<input type="hidden" name="lastSub"    value="'.$ENV{'form.lastSub'}.'" />'."\n".  
       '<input type="hidden" name="section"    value="'.$ENV{'form.section'}.'">'."\n".  
       '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".  
       '<input type="hidden" name="response"   value="'.$ENV{'form.response'}.'">'."\n".  
       '<input type="hidden" name="handgrade"  value="'.$ENV{'form.handgrade'}.'">'."\n".  
       '<input type="hidden" name="command"    value="handgrade" />'."\n".  
       '<input type="hidden" name="keywords"   value="'.$keyhash{$symb.'_keywords'}.'" />'."\n".  
       '<input type="hidden" name="kwclr"      value="'.$keyhash{$loginuser.'_kwclr'}.'" />'."\n".  
       '<input type="hidden" name="kwsize"     value="'.$keyhash{$loginuser.'_kwsize'}.'" />'."\n".  
       '<input type="hidden" name="kwstyle"    value="'.$keyhash{$loginuser.'_kwstyle'}.'" />'."\n".  
       '<input type="hidden" name="msgsub"     value="'.$keyhash{$symb.'_subject'}.'" />'."\n".  
       '<input type="hidden" name="savemsgN"   value="'.$keyhash{$symb.'_savemsgN'}.'" />'."\n".  
       '<input type="hidden" name="NCT"'.  
       ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");  
   
       my ($cts,$prnmsg) = (1,'');  
       while ($cts <= $keyhash{$symb.'_savemsgN'}) {  
   $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.$keyhash{$symb.'_savemsg'.$cts}.'" />'."\n";  
   $cts++;  
       }  
       $request->print($prnmsg);  
   
       if ($ENV{'form.handgrade'} eq 'yes') {  
   $request->print(<<KEYWORDS);  
 &nbsp;<b>Keyword Options</b>&nbsp;  
 <a href="javascript:keywords(document.SCORE.keywords)"; TARGET=_self>Keyword List</a>&nbsp; &nbsp;  
 <a href="#" onMouseDown="javascript:getSel(); return false"  
  CLASS="page">Paste Selection to Keyword list</a>&nbsp; &nbsp;  
 <a href="javascript:kwhighlight()"; TARGET=_self>Keyword Highlight Attribute</a><br /><br />  
 KEYWORDS  
       }  
   }  
   
   # Student info  
   $request->print(($counter == 0 ? '' : '<br /><hr><br />'));  
   my $fullname = ($ENV{'form.fullname'} ne '' ? $ENV{'form.fullname'} : &get_fullname($uname,$udom));  
   my $result.='<table border="0"><tr><td><b>Username: </b>'.$uname.  
       '</td><td><b>Fullname: </b>'.$fullname.  
       '</td><td><b>Domain: </b>'.$udom.'</td></tr>';  
   if ($ENV{'form.handgrade'} eq 'yes') {  
 #      my $subonly = &get_last_submission($symb,$uname,$udom,$ENV{'request.course.id'});  
       my ($classlist) = &getclasslist('all','0');  
       my @collaborators;  
 #      foreach ( sort(@{ $$classlist{'all'} }) ) {  
 #  my ($sname,$sdom) = split(/:/);  
 #  push @collaborators,$sname if (grep /\b$sname(\b|\.)/i,$subonly);  
 #      }  
 #      push @collaborators,'leede','carlandmm','freyniks'; # as a test to display collaborators.  
       if (scalar(@collaborators) != 0) {  
   $result.='<tr><td colspan=3><b>Collaborators: </b>';  
   foreach (@collaborators) {  
       $result.=$_.' ('.&get_fullname($_,$udom).') &nbsp; &nbsp;';  
   }  
   $result.='</td></tr>'."\n";  
   $result.='<input type="hidden" name="collaborator'.$counter.  
       '" value="'.(join ':',@collaborators).'" />'."\n";  
       }  
   }  
   $result.='</table>'."\n";  
   $request->print($result);  
   
   # print student answer  
   if ($ENV{'form.lastSub'} eq 'lastonly') {  
       my ($string,$timestamp)=&get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'});  
       $string=&keywords_highlight($string);  
       my $lastsubonly='<table border="0" width=100%><tr><td bgcolor="#777777">';  
       $lastsubonly.='<table border="0" width=100%><tr bgcolor="#e6ffff">';  
       $lastsubonly.='<td><b>Last Submission Only</b>'.  
   ($timestamp eq '' ? '' : '&nbsp; &nbsp; <b>Date Submitted:</b> '.$timestamp).'</td></tr>';  
       $lastsubonly.='<tr><td bgcolor="#ffffe6">';  
       $lastsubonly.=$string;  
       $lastsubonly.='</td></tr></table></td></tr></table>'."\n";  
       $request->print($lastsubonly);  
   } else {  
       $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,  
        $ENV{'request.course.id'},$last,  
        '.submission','Apache::grades::keywords_highlight'));  
   }  
   
   my $wgt    = &Apache::lonnet::EXT('resource.partid.weight',$symb,$udom,$uname);  
   my $wgtmsg = ($wgt > 0 ? '(problem weight)' : '<font color="red">problem weight assigned by computer</font>');  
   $wgt       = ($wgt > 0 ? $wgt : '1');  
   my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);  
   my $score  = ($record{'resource.0.awarded'} eq '' ? '' : $record{'resource.0.awarded'}*$wgt);  
   
   # display grading options  
   $result='<input type="hidden" name="WGT'.$counter.'" value="'.$wgt.'" />'.  
       '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";  
   $result.='<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";  
   $result.='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n";  
   $result.='<table border="0"><tr><td><b>Points</b></td><td>';  
   
   my $ctr = 0;  
   $result.='<table border="0"><tr>';  # display radio buttons in a nice table with 10 across  
   while ($ctr<=$wgt) {  
       $result.= '<td><input type="radio" name="RADVAL'.$counter.'" '.  
   'onclick="javascript:writeBox(this.form.GRADE_BOX'.$counter.  
     ',this.form.GRADE_SEL'.$counter.','.$ctr.','.$wgt.')" '.  
  ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";  
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');  
       $ctr++;  
   }  
   $result.='</tr></table>';  
   
   $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';  
   $result.='<td><input type="text" name="GRADE_BOX'.$counter.'"'.  
       ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.  
        'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.  
         ',this.form.GRADE_BOX'.$counter.  
    ',this.form.GRADE_SEL'.$counter.',\''.$wgt.'\')" /></td>'."\n";  
   $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';  
   
   foreach my $part (&getpartlist($url)) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     if ($type eq 'solved') {  
       my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);  
       $status = 'partial' if ($foo =~ /partially/);  
       $status = 'nothing' if ($status eq '');  
       $result.='<select name="GRADE_SEL'.$counter.'">'."\n";  
       my $optsel = '<option>correct</option><option>incorrect</option>'.  
   '<option>excused</option><option>ungraded</option>'.  
       '<option>partial</option><option>nothing</option>'."\n";  
       $optsel =~ s/<option>$status/<option selected="on">$status/;  
       $result.=$optsel;  
       $result.="</select>&nbsp&nbsp\n";  
       $result.='<a href="javascript:msgCenter(document.SCORE,'.$counter.  
   ',\''.$fullname.'\')"; TARGET=_self>Compose Message</a></td></tr>'."\n";  
     }  
   }  
   $result.='</table>';  
   $request->print($result);  
   
   # print end of form  
   if ($counter == $total) {  
       my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';  
       my $ntstu ='<select name="NTSTU">'.  
   '<option>1</option><option>2</option>'.  
       '<option>3</option><option>5</option>'.  
   '<option>7</option><option>10</option></select>'."\n";  
       my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');  
       $ntstu =~ s/<option>$nsel/<option selected="on">$nsel/;  
       $endform.=$ntstu.'student(s) &nbsp;&nbsp;';  
       $endform.='<input type="submit" name="gradeOpt" value="Next" />&nbsp';  
       $endform.='<input type="submit" name="gradeOpt" value="Previous" />&nbsp';  
       $endform.='(Next and Previous do not save the scores.)';  
       $endform.='</td><tr></table></form>';  
       $request->print($endform);  
   }  
   return '';  
 }  
   
 sub get_last_submission {  
   my ($symb,$username,$domain,$course)=@_;  
   if ($symb) {  
       my ($string,$timestamp);  
      my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username);  
      if ($returnhash{'version'}) {  
  my %lasthash=();  
  my ($version);  
  for ($version=1;$version<=$returnhash{'version'};$version++) {  
   foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {  
       $lasthash{$_}=$returnhash{$version.':'.$_};  
   }  
         }  
  foreach ((keys %lasthash)) {  
     if ($_ =~ /\.submission$/) {$string = $lasthash{$_}}  
     if ($_ =~ /timestamp/) {$timestamp=scalar(localtime($lasthash{$_}))};  
  }  
     }  
      $string = $string eq '' ? 'Nothing submitted - no attempts.' : $string;  
      return $string,$timestamp;  
   }  
 }  
   
 sub keywords_highlight {  
   my $string  = shift;  
   (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)));  
   my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};  
   
   my @kwkeys = ($symb.'_keywords',  
  $loginuser.'_kwclr',  
  $loginuser.'_kwsize',  
  $loginuser.'_kwstyle'  
  );  
   
   my %keyhash = &Apache::lonnet::get  
       ('nohist_handgrade',\@kwkeys,  
        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
   my @keylist = split(/[,\s+]/,$keyhash{$symb.'_keywords'});  
   my $size    = $keyhash{$kwkeys[2]} eq '0' ? '' : 'size='.$keyhash{$kwkeys[2]};  
   my $styleon = $keyhash{$kwkeys[3]} eq ''  ? '' : $keyhash{$kwkeys[3]};  
   (my $styleoff = $styleon) =~ s/\</\<\//;  
   foreach my $word (@keylist) {  
       next if ($word eq '');  
       $string =~ s/\b$word(\b|\.)/\<font color\=$keyhash{$kwkeys[1]} $size\>$styleon$word$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 = ();  
   $keyhash{$symb.'_handgrade'} = 'activated';  
   $keyhash{$symb.'_keywords'} = $ENV{'form.keywords'};  
   $keyhash{$symb.'_subject'} = $ENV{'form.msgsub'};  
   $keyhash{$loginuser.'_kwclr'} = $ENV{'form.kwclr'};  
   $keyhash{$loginuser.'_kwsize'} = $ENV{'form.kwsize'};  
   $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};  
   
   my ($ctr,$idx) = (1,1);  
   while ($ctr <= $ENV{'form.savemsgN'}) {  
       if ($ENV{'form.savemsg'.$ctr} ne '') {  
   $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};  
   $idx++;  
       }  
       $ctr++;  
   }  
   $ctr = 0;  
   while ($ctr < $ngrade) {  
       if ($ENV{'form.newmsg'.$ctr} ne '') {  
   $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};  
   $idx++;  
       }  
       $ctr++;  
   }  
   
   $keyhash{$symb.'_savemsgN'} = --$idx;  
   my $putresult = &Apache::lonnet::put  
       ('nohist_handgrade',\%keyhash,  
        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
   
   my (@parts) = sort(&getpartlist($url));  
   
   if ($button eq 'Save & Next') {  
       my $ctr = 0;  
       while ($ctr < $ngrade) {  
   my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});  
   &saveHandGrade($url,$symb,$uname,$udom,$ctr,@parts);  
   if ($ENV{'form.collaborator'.$ctr}) {  
       my (@collaborators) = split(/:/,$ENV{'form.collaborator'.$ctr});  
       foreach (@collaborators) {  
   &saveHandGrade($url,$symb,$_,$udom,$ctr,@parts);  
       }  
   }  
   $ctr++;  
       }  
   }  
   my $firststu = $ENV{'form.unamedom0'};  
   my $laststu  = $ENV{'form.unamedom'.($ngrade-1)};  
   
   my ($classlist) = &getclasslist($ENV{'form.section'},'0');  
 #  print "first=$firststu,last=$laststu<br>";  
   my (@nextlist,@prevlist);  
   my ($nextflg,$prevflg,$ctr,$ctprev) = (0,0,0,0);  
   foreach my $student ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {  
       my ($uname,$udom) = split(/:/,$student);  
       my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname);  
       next if ($status eq 'nothing' && $ENV{'form.submitonly'} eq 'yes');  
   
       if ($nextflg == 1 && $button =~ /Next$/) {  
   push @nextlist,$uname if ($ctr < $ntstu);  
   $ctr++;  
       }  
       $nextflg = 1 if ($student eq $laststu);  
       $prevflg = 1 if ($student eq $firststu);  
       if ($prevflg == 0 && $button eq 'Previous') {  
   push @prevlist,$uname;  
   $ctprev++;  
       }  
   }  
 #  print "next student=@nextlist<br>";  
   if ($button eq 'Previous') {  
       if ($ctprev <= $ntstu) {  
   @nextlist = @prevlist;  
       } else {  
   my $idx = 0;  
   my $start = $ctprev - $ntstu;  
   while ($idx < $ntstu) {  
       $nextlist[$idx] = $prevlist[$start+$idx];  
       $idx++;  
   }  
       }  
   }  
   $ctr = 0;  
   my $total = scalar(@nextlist)-1;  
   foreach my $student (@nextlist) {  
       $ENV{'form.student'} = $student;  
       &submission($request,$ctr,$total);  
       $ctr++;  
   }  
   
   return 'The End';  
 }  
   
 sub saveHandGrade {  
   my ($url,$symb,$stuname,$domain,$newflg,@parts) = @_;  
   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);  
   my %newrecord;  
   
   foreach my $part (@parts) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     my $oldscore=$record{"resource.$part.$type"};  
     my $newscore;  
     if ($type eq 'awarded' && $newflg >= 0) {  
  my $pts    = ($ENV{'form.GRADE_BOX'.$newflg} ne '' ?   
       $ENV{'form.GRADE_BOX'.$newflg} : $ENV{'form.RADVAL'.$newflg});  
  my $wgt    = $ENV{'form.WGT'.$newflg};  
 # my $sel    = $ENV{'form.GRADE_SEL'.$newflg};  
  $newscore  = $pts/$wgt if ($wgt != 0);  
     }  
     if ($type eq 'solved') {  
       $newscore = $ENV{'form.GRADE_SEL'.$newflg} if ($newflg >= 0);  
       my $update=0;  
       if ($newscore eq 'nothing' ) {  
  if ($oldscore ne '') {  
   $update=1;  
   $newscore = '';  
  }  
       } elsif ($oldscore !~ m/^$newscore/) {  
  $update=1;  
  if ($newscore eq 'correct')   { $newscore = 'correct_by_override'; }  
  if ($newscore eq 'incorrect') { $newscore = 'incorrect_by_override'; }  
  if ($newscore eq 'excused')   { $newscore = 'excused'; }  
  if ($newscore eq 'ungraded')  { $newscore = 'ungraded_attempted'; }  
  if ($newscore eq 'partial')   { $newscore = 'correct_partially_by_override'; }  
       }  
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }  
     } else {  
       if ($oldscore ne $newscore) {  
  $newrecord{"resource.$part.$type"}=$newscore;  
       }  
     }  
   }  
   if ( scalar(keys(%newrecord)) > 0 ) {  
       $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";  
 #      while (my ($k,$v) = each %newrecord) {  
 # print "k=$k:v=$v:<br>\n";  
 #      }  
 #      print "symb=$symb,courseid=$ENV{'request.course.id'},dom=$domain,name=$stuname<br>";  
 #     &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},$domain,$stuname);  
   }  
   return '';  
 }  
   
 sub get_symb_and_url {  
   my ($request) = @_;  
   (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;  
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));  
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }  
   return ($symb,$url);  
 }  
   
 sub show_grading_menu_form {  
   my ($symb,$url)=@_;  
   my $result.='<form action="/adm/grades" method="post">'."\n".  
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
  '<input type="hidden" name="command" value="gradingmenu" />'."\n".  
   '<input type="submit" name="submit" value="Grading Menu" />'."\n".  
     '</form>'."\n";  
   return $result;  
 }  
   
 sub gradingmenu {  
   my ($request) = @_;  
   my ($symb,$url)=&get_symb_and_url($request);  
   if (!$symb) {return '';}  
   my $allkeys = &Apache::lonnet::metadata($url,'keys');  
   my $handgrade = ($allkeys =~ /parameter_.*?_handgrade/ ? 'yes' : 'no');  
   my ($responsetype,$foo) = split(/_/,&Apache::lonnet::metadata($url,'packages'));  
   
   my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';  
   $result.='<table border="0">';  
   $result.='<tr><td><font size=+1><b>Resource: </b></font></td>'.  
       '<td><font size=+1>'.$url.'</font></td></tr>';  
   $result.='<tr><td><font size=+1><b>Type: </b></font></td>'.  
       '<td><font size=+1>'.$responsetype.'&nbsp;&nbsp;<b>Handgrade: </b>'.$handgrade.'</font></td></tr>';  
   $result.='</table>';  
   
   $result.=&view_edit_entire_class_form($symb,$url).'<br />';  
   $result.=&upcsvScores_form($symb,$url).'<br />';  
   $result.=&viewGradeaStu_form($symb,$url,$responsetype,$handgrade).'<br />';  
   $result.=&verifyReceipt_form($symb,$url);  
   return $result;  
 }  
   
 sub view_edit_entire_class_form {  
   my ($symb,$url)=@_;  
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";  
   $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";  
   $result.='&nbsp;<b>View/Grade Entire Class</b></td></tr>'."\n";  
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  
   $result.='<form action="/adm/grades" method="post">'."\n".  
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
   '<input type="hidden" name="command" value="viewgrades" />'."\n";  
   $result.='&nbsp;<b>Display students who has: </b>'.  
       '<input type="radio" name="submitonly" value="yes" checked> submitted'.  
   '<input type="radio" name="submitonly" value="all"> everybody <br /><br />';  
   $result.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";  
   $result.='</td></tr></table>'."\n";  
   $result.='</td></tr></table>'."\n";  
   return $result;  
 }  
   
 sub upcsvScores_form {  
   my ($symb,$url) = @_;  
   if (!$symb) {return '';}  
   my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n";  
   $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";  
   $result.='&nbsp;<b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";  
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  
   my $upfile_select=&Apache::loncommon::upfile_select_html();  
   $result.=<<ENDUPFORM;  
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  
 <input type="hidden" name="symb" value="$symb" />  
 <input type="hidden" name="url" value="$url" />  
 <input type="hidden" name="command" value="csvuploadmap" />  
 $upfile_select  
 <br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />  
 </form>  
 ENDUPFORM  
   $result.='</td></tr></table>'."\n";  
   $result.='</td></tr></table>'."\n";  
   return $result;  
 }  
   
 sub viewGradeaStu_form {  
   my ($symb,$url,$response,$handgrade) = @_;  
   my ($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="command" value="submission" />'."\n";  
   
   $result.='&nbsp;<b>Select section:</b> <select name="section">'."\n";  
   foreach my $section (sort (@$sections)) {  
       $result.= '<option>'.$section.'</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 {  
   my ($request) = @_;  
   my $result='';  
   
   #get resource reference  
   my ($symb,$url)=&get_symb_and_url($request);  
   if (!$symb) {return '';}  
   #get classlist  
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});  
   #print "Found $cdom:$cnum<br />";  
   my ($classlist) = &getclasslist('all','0');  
   my $headerclr = '"#ccffff"';  
   my $cellclr = '"#ffffcc"';  
   
   #get list of parts for this problem  
   my (@parts) = sort(&getpartlist($url));  
   
   $request->print ("<h2><font color=\"#339933\">Manual Grading</font></h2>");  
   
   #start the form  
   $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="editgrades" />'."\n".  
   '<input type="submit" name="submit" value="Submit Changes" />'."\n".  
     '<table border=0><tr><td bgcolor="#777777">'."\n".  
      '<table border=0>'."\n".  
       '<tr bgcolor='.$headerclr.'><td><b>Username</b></td><td><b>Name</b></td><td><b>Domain</b></td>'."\n";  
   foreach my $part (@parts) {  
      my $display=&Apache::lonnet::metadata($url,$part.'.display');  
      if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }  
      $result.='<td><b>'.$display.'</b></td>'."\n";  
   }  
   $result.='</tr>';  
   #get info for each student  
   foreach my $student ( sort(@{ $$classlist{'all'} }) ) {  
     my $display=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
 #      print "ID=$ENV{'request.course.id'}:STU=$student:DIS=$display:<br>\n";  
     $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
   }  
   $result.='</table></td></tr></table>';  
   $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';  
   $result.=&show_grading_menu_form($symb,$url);  
   return $result;  
 }  
   
 sub editgrades {  
   my ($request) = @_;  
   my $result='';  
   
   my $symb=$ENV{'form.symb'};  
   if ($symb eq '') { $request->print("Unable to handle ambiguous references:$symb:$ENV{'form.url'}"); return ''; }  
   my $url=$ENV{'form.url'};  
   #get classlist  
 #  my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});  
   #print "Found $cdom:$cnum<br />";  
   my ($classlist) = &getclasslist('all','0');  
   
   #get list of parts for this problem  
   my (@parts) = &getpartlist($url);  
   
   $result.='<form action="/adm/grades" method="post">'."\n".  
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".  
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".  
  '<input type="hidden" name="command" value="viewgrades" />'."\n".  
   '<input type="submit" name="submit" value="See Grades" /> <br />'."\n";  
   
   foreach my $student ( sort(@{ $$classlist{'all'} }) ) {  
     $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);  
   }  
   
   $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';  
   return $result;  
 }  
   
 sub csvupload_javascript_reverse_associate {  sub csvupload_javascript_reverse_associate {
   return(<<ENDPICK);    return(<<ENDPICK);
Line 1327  ENDPICK Line 1753  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 1359  to this page if the data selected is ins Line 1785  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 1390  ENDPICK Line 1816  ENDPICK
 }  }
   
 sub csvuploadmap {  sub csvuploadmap {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   my $datatoken;      my $datatoken;
   if (!$ENV{'form.datatoken'}) {      if (!$ENV{'form.datatoken'}) {
     $datatoken=&Apache::loncommon::upfile_store($request);   $datatoken=&Apache::loncommon::upfile_store($request);
   } else {  
     $datatoken=$ENV{'form.datatoken'};  
     &Apache::loncommon::load_tmp_file($request);  
   }  
   my @records=&Apache::loncommon::upfile_record_sep();  
   &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);  
   my $i;  
   my $keyfields;  
   if (@records) {  
     my @fields=&csvupload_fields($url);  
     if ($ENV{'form.upfile_associate'} eq 'reverse') {  
       &Apache::loncommon::csv_print_samples($request,\@records);  
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,  
     \@fields);  
       foreach (@fields) { $keyfields.=$_->[0].','; }  
       chop($keyfields);  
     } else {      } else {
       unshift(@fields,['none','']);   $datatoken=$ENV{'form.datatoken'};
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,   &Apache::loncommon::load_tmp_file($request);
       \@fields);  
       my %sone=&Apache::loncommon::record_sep($records[0]);  
       $keyfields=join(',',sort(keys(%sone)));  
     }      }
   }      my @records=&Apache::loncommon::upfile_record_sep();
   &csvuploadmap_footer($request,$i,$keyfields);      &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
   return '';      my ($i,$keyfields);
       if (@records) {
    my @fields=&csvupload_fields($url);
    if ($ENV{'form.upfile_associate'} eq 'reverse') {
       &Apache::loncommon::csv_print_samples($request,\@records);
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,
     \@fields);
       foreach (@fields) { $keyfields.=$_->[0].','; }
       chop($keyfields);
    } else {
       unshift(@fields,['none','']);
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
       \@fields);
       my %sone=&Apache::loncommon::record_sep($records[0]);
       $keyfields=join(',',sort(keys(%sone)));
    }
       }
       &csvuploadmap_footer($request,$i,$keyfields);
       return '';
 }  }
   
 sub csvuploadassign {  sub csvuploadassign {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   &Apache::loncommon::load_tmp_file($request);      &Apache::loncommon::load_tmp_file($request);
   my @gradedata=&Apache::loncommon::upfile_record_sep();      my @gradedata=&Apache::loncommon::upfile_record_sep();
   my @keyfields = split(/\,/,$ENV{'form.keyfields'});      my @keyfields = split(/\,/,$ENV{'form.keyfields'});
   my %fields=();      my %fields=();
   for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {      for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
     if ($ENV{'form.upfile_associate'} eq 'reverse') {   if ($ENV{'form.upfile_associate'} eq 'reverse') {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$keyfields[$i]}=$ENV{'form.f'.$i};   $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
       }      }
     } else {   } else {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$ENV{'form.f'.$i}}=$keyfields[$i];   $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
       }      }
    }
     }      }
   }      $request->print('<h3>Assigning Grades</h3>');
   $request->print('<h3>Assigning Grades</h3>');      my $courseid=$ENV{'request.course.id'};
   my $courseid=$ENV{'request.course.id'};  
 #  my $cdom=$ENV{"course.$courseid.domain"};  #  my $cdom=$ENV{"course.$courseid.domain"};
 #  my $cnum=$ENV{"course.$courseid.num"};  #  my $cnum=$ENV{"course.$courseid.num"};
   my ($classlist) = &getclasslist('all','1');      my ($classlist) = &getclasslist('all','1');
   my @skipped;      my @skipped;
   my $countdone=0;      my $countdone=0;
   foreach my $grade (@gradedata) {      foreach my $grade (@gradedata) {
     my %entries=&Apache::loncommon::record_sep($grade);   my %entries=&Apache::loncommon::record_sep($grade);
     my $username=$entries{$fields{'username'}};   my $username=$entries{$fields{'username'}};
     my $domain=$entries{$fields{'domain'}};   my $domain=$entries{$fields{'domain'}};
     if (!exists($$classlist{"$username:$domain"})) {   if (!exists($$classlist{"$username:$domain"})) {
       push(@skipped,"$username:$domain");      push(@skipped,"$username:$domain");
       next;      next;
     }   }
     my %grades;   my %grades;
     foreach my $dest (keys(%fields)) {   foreach my $dest (keys(%fields)) {
       if ($dest eq 'username' || $dest eq 'domain') { next; }      if ($dest eq 'username' || $dest eq 'domain') { next; }
       if ($entries{$fields{$dest}} eq '') { next; }      if ($entries{$fields{$dest}} eq '') { next; }
       my $store_key=$dest;      my $store_key=$dest;
       $store_key=~s/^stores/resource/;      $store_key=~s/^stores/resource/;
       $store_key=~s/_/\./g;      $store_key=~s/_/\./g;
       $grades{$store_key}=$entries{$fields{$dest}};      $grades{$store_key}=$entries{$fields{$dest}};
     }   }
     $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";   $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";
     &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},   &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},
     $domain,$username);   $domain,$username);
     $request->print('.');   $request->print('.');
     $request->rflush();   $request->rflush();
     $countdone++;   $countdone++;
   }      }
   $request->print("<br />Stored $countdone students\n");      $request->print("<br />Stored $countdone students\n");
   if (@skipped) {      if (@skipped) {
     $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');   $request->print('<br /><font size="+1"><b>Skipped Students</b></font><br />');
     foreach my $student (@skipped) { $request->print("<br />$student"); }   foreach my $student (@skipped) { $request->print("<br />$student"); }
   }      }
   $request->print(&view_edit_entire_class_form($symb,$url));      $request->print(&view_edit_entire_class_form($symb,$url));
   $request->print(&show_grading_menu_form($symb,$url));      $request->print(&show_grading_menu_form($symb,$url));
   return '';      return '';
 }  }
   
 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{'browser.mathml'}) {      if ($ENV{'browser.mathml'}) {
     $request->content_type('text/xml');   $request->content_type('text/xml');
   } else {      } else {
     $request->content_type('text/html');   $request->content_type('text/html');
   }      }
   $request->send_http_header;      $request->send_http_header;
   return OK if $request->header_only;      return OK if $request->header_only;
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
   my $url=$ENV{'form.url'};      my $url=$ENV{'form.url'};
   my $symb=$ENV{'form.symb'};      my $symb=$ENV{'form.symb'};
   my $command=$ENV{'form.command'};      my $command=$ENV{'form.command'};
   if (!$url) {      if (!$url) {
     my ($temp1,$temp2);   my ($temp1,$temp2);
     ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);   ($temp1,$temp2,$ENV{'form.url'})=split(/___/,$symb);
     $url = $ENV{'form.url'};   $url = $ENV{'form.url'};
   }      }
   &send_header($request);      &send_header($request);
   if ($url eq '' && $symb eq '') {      if ($url eq '' && $symb eq '') {
      if ($ENV{'user.adv'}) {   if ($ENV{'user.adv'}) {
          if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&      if (($ENV{'form.codeone'}) && ($ENV{'form.codetwo'}) &&
              ($ENV{'form.codethree'})) {   ($ENV{'form.codethree'})) {
              my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.   my $token=$ENV{'form.codeone'}.'*'.$ENV{'form.codetwo'}.'*'.
         $ENV{'form.codethree'};      $ENV{'form.codethree'};
              my ($tsymb,$tuname,$tudom,$tcrsid)=   my ($tsymb,$tuname,$tudom,$tcrsid)=
  &Apache::lonnet::checkin($token);      &Apache::lonnet::checkin($token);
              if ($tsymb) {   if ($tsymb) {
                 my ($map,$id,$url)=split(/\_\_\_/,$tsymb);      my ($map,$id,$url)=split(/\_\_\_/,$tsymb);
                 if (&Apache::lonnet::allowed('mgr',$tcrsid)) {      if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
                    $request->print(   $request->print(
                      &Apache::lonnet::ssi('/res/'.$url,   &Apache::lonnet::ssi('/res/'.$url,
                         ('grade_username' => $tuname,       ('grade_username' => $tuname,
                          'grade_domain' => $tudom,        'grade_domain' => $tudom,
                          'grade_courseid' => $tcrsid,        'grade_courseid' => $tcrsid,
                          'grade_symb' => $tsymb)));        'grade_symb' => $tsymb)));
                 } else {      } else {
                    $request->print('<h1>Not authorized: '.$token.'</h1>');   $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'});
   } else {   if ($command eq 'submission') {
     #&Apache::lonhomework::showhashsubset(\%ENV,'^form');      &listStudents($request) if ($ENV{'form.student'} eq '');
     $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});      &submission($request,0,0) if ($ENV{'form.student'} ne '');
     if ($command eq 'submission') {   } elsif ($command eq 'processGroup') {
       &listStudents($request) if ($ENV{'form.student'} eq '');      &processGroup($request);
       &submission($request,0,0) if ($ENV{'form.student'} ne '');   } elsif ($command eq 'gradingmenu') {
     } elsif ($command eq 'processGroup') {      $request->print(&gradingmenu($request));
       &processGroup($request);   } elsif ($command eq 'viewgrades') {
     } elsif ($command eq 'gradingmenu') {      $request->print(&viewgrades($request));
       $request->print(&gradingmenu($request));   } elsif ($command eq 'handgrade') {
     } elsif ($command eq 'viewgrades') {      $request->print(&processHandGrade($request));
       $request->print(&viewgrades($request));   } elsif ($command eq 'editgrades') {
     } elsif ($command eq 'handgrade') {      $request->print(&editgrades($request));
       $request->print(&processHandGrade($request));   } elsif ($command eq 'verify') {
     } elsif ($command eq 'editgrades') {      $request->print(&verifyreceipt($request));
       $request->print(&editgrades($request));   } elsif ($command eq 'csvupload') {
     } elsif ($command eq 'verify') {      $request->print(&csvupload($request));
       $request->print(&verifyreceipt($request));   } elsif ($command eq 'viewclasslist') {
     } elsif ($command eq 'csvupload') {      $request->print(&viewclasslist($request));
       $request->print(&csvupload($request));   } elsif ($command eq 'csvuploadmap') {
     } elsif ($command eq 'csvuploadmap') {      $request->print(&csvuploadmap($request));
       $request->print(&csvuploadmap($request));  
 #    } elsif ($command eq 'receiptInput') {  #    } elsif ($command eq 'receiptInput') {
 #      &receiptInput($request);  #      &receiptInput($request);
     } elsif ($command eq 'csvuploadassign') {   } elsif ($command eq 'csvuploadassign') {
       if ($ENV{'form.associate'} ne 'Reverse Association') {      if ($ENV{'form.associate'} ne 'Reverse Association') {
  $request->print(&csvuploadassign($request));   $request->print(&csvuploadassign($request));
       } else {      } else {
  if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {   if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
   $ENV{'form.upfile_associate'} = 'reverse';      $ENV{'form.upfile_associate'} = 'reverse';
    } else {
       $ENV{'form.upfile_associate'} = 'forward';
    }
    $request->print(&csvuploadmap($request));
       }
  } else {   } else {
   $ENV{'form.upfile_associate'} = 'forward';      $request->print("Unknown action: $command:");
  }   }
  $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.37  
changed lines
  Added in v.1.42


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