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

version 1.33, 2002/06/27 21:34:18 version 1.43, 2002/07/30 19:59:58
Line 30 Line 30
 # 7/26 H.K. Ng  # 7/26 H.K. Ng
 # 8/20 Gerd Kortemeyer  # 8/20 Gerd Kortemeyer
 # Year 2002  # Year 2002
 # June 2002 H.K. Ng  # June, July 2002 H.K. Ng
 #  #
   
 package Apache::grades;  package Apache::grades;
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="'.$ENV{'form.command'}.'" />'."\n");
    $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");
    $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");
    $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");
    $request->print('</form>');
     }      }
     $request->print('<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />'."\n");      return '';
     $request->print("Student:".'<input type="text" name="student" value="'.$ENV{'form.student'}.'" />'."<br />\n");  
     $request->print("Domain:".'<input type="text" name="domain" value="'.$ENV{'user.domain'}.'" />'."<br />\n");  
     $request->print('<input type="submit" name="submit" value="ReSubmit" />'."<br />\n");  
     $request->print('</form>');  
   }  
   return '';  
 }  }
   
 sub verifyreceipt {  sub verifyreceipt {
     my $request=shift;      my $request=shift;
     my $courseid=$ENV{'request.course.id'};      my $courseid=$ENV{'request.course.id'};
     my $cdom=$ENV{"course.$courseid.domain"};  #    my $cdom=$ENV{"course.$courseid.domain"};
     my $cnum=$ENV{"course.$courseid.num"};  #    my $cnum=$ENV{"course.$courseid.num"};
     my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.      my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
                 $ENV{'form.receipt'};   $ENV{'form.receipt'};
     $receipt=~s/[^\-\d]//g;      $receipt=~s/[^\-\d]//g;
     my $symb=$ENV{'form.symb'};      my $symb=$ENV{'form.symb'};
     unless ($symb) {      unless ($symb) {
Line 77  sub verifyreceipt { Line 80  sub verifyreceipt {
     if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {      if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
         $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');          $request->print('<h1>Verifying Submission Receipt '.$receipt.'</h1>');
         my $matches=0;          my $matches=0;
         my (%classlist) = &getclasslist($cdom,$cnum,'0');          my ($classlist) = &getclasslist('all','0');
         foreach my $student ( sort(@{ $classlist{'allids'} }) ) {          foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
             my ($uname,$udom)=split(/\:/,$student);              my ($uname,$udom)=split(/\:/,$student);
             if ($receipt eq               if ($receipt eq 
              &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {   &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
                $request->print('Matching '.$student.'<br>');   $request->print('Matching '.$student.'<br>');
                $matches++;   $matches++;
    }     }
         }          }
         $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');          $request->printf('<p>'.$matches." match%s</p>",$matches <= 1 ? '' : 'es');
Line 92  sub verifyreceipt { Line 95  sub verifyreceipt {
     return '';      return '';
 }  }
   
 sub receiptInput {  sub student_gradeStatus {
   my ($request) = shift;      my ($url,$udom,$uname,$partlist) = @_;
   my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"};      my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
   my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"};      my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
   my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'});      my %partstatus = ();
   $request->print(<<ENDHEADER);      foreach (@$partlist) {
 <h2><font color="#339933">Verify a Submission Receipt Issued by this Server</font></h2>   my ($status,$foo)=split(/_/,$record{"resource.$_.solved"},2);
 <form action="/adm/grades" method="post">   $status = 'nothing' if ($status eq '');
 <tt>$hostver-<input type="text" name="receipt" size="4"></tt>   $partstatus{$_} = $status;
 <input type="submit" name="submit" value="Verify">   $partstatus{"resource.$_.submitted_by"} = $record{"resource.$_.submitted_by"} 
 <input type="hidden" name="command" value="verify">   if ($record{"resource.$_.submitted_by"} ne '');
 ENDHEADER      }
   if ($ENV{'form.url'}) {      return %partstatus;
     $request->print(  }
     '<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />');  
   }  sub get_fullname {
   if ($ENV{'form.symb'}) {      my ($uname,$udom) = @_;
     $request->print(      my %name=&Apache::lonnet::get('environment', ['lastname','generation',
     '<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />');    'firstname','middlename'],$udom,$uname);
   }      my $fullname;
 #  $request->print(<<ENDTABLEST);      my ($tmp) = keys(%name);
   $request->print('</form>');      if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
     return '';   $fullname=$name{'lastname'}.$name{'generation'};
    if ($fullname =~ /[^\s]+/) { $fullname.=', '; }
    $fullname.=$name{'firstname'}.' '.$name{'middlename'};
       }
       return $fullname;
 }  }
   
 sub student_gradeStatus {  sub response_type {
   my ($url,$udom,$uname) = @_;      my ($url) = shift;
   my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $allkeys = &Apache::lonnet::metadata($url,'keys');
   my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);  #    print "allkeys=>$allkeys<br>";
   foreach my $part (&getpartlist($url)) {      my %seen = ();
     my ($temp,$part,$type)=split(/_/,$part);      my (@partlist,%handgrade);
     if ($type eq 'solved') {      foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
       my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);   if (/^\w+response_\d+.*/) {
       $status = 'nothing' if ($status eq '');      my ($responsetype,$part) = split(/_/,$_,2);
       return $type,$status;      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;
   return '';  
 }  }
   
   
 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'} eq '' ? 'all' : $ENV{'form.section'};
   $request->print(<<ENDTABLEST);      my $submitonly=$ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};
 <h2><font color="#339933">Show Student Submissions on Assessment</font></h2>  
       my $result='<h2><font color="#339933">&nbsp;View Submissions for a Student or a Group of Students</font></h2>';
 <table border="0"><tr><td bgcolor="#777777">      $result.='<table border="0">';
 <table border="0">      $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>';
 <tr bgcolor="#e6ffff"><td colspan="7"><b>Resource: </b> $ENV{'form.url'}</td></tr>      my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
 <tr bgcolor="#e6ffff"><td><b>Username</b></td><td><b>Name</b></td><td><b>Domain</b></td>      for (sort keys(%$handgrade)) {
 <td><b>View Problem</b></td><td><b>Submissions</b></td>   my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
 <td><b>Grade Status</b></td><td><b>Action</b></td></tr>   $ENV{'form.handgrade'} = 'yes' if ($handgrade eq 'yes');
    $result.='<tr><td><b>Part id: </b>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $request->print($result);
   
       $request->print(<<ENDTABLEST);
   <form action="/adm/grades" method="post">
   &nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no 
   <input type="radio" name="vProb" value="yes"> yes <br />
   &nbsp;<b>Submissions: </b>
   <input type="radio" name="lastSub" value="hdgrade" checked /> handgrade only
   <input type="radio" name="lastSub" value="lastonly" /> last sub only
   <input type="radio" name="lastSub" value="last" /> last sub & parts info
   <input type="radio" name="lastSub" value="all" /> all details
   <input type="hidden" name="section" value="$getsec" />
   <input type="hidden" name="submitonly" value="$submitonly" />
   <input type="hidden" name="response" value="$ENV{'form.response'}" />
   <input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" /><br />
   <input type="hidden" name="showgrading" value="$ENV{'form.showgrading'}" /><br />
   <input type="submit" name="submit" value="View/Grade" />
 ENDTABLEST  ENDTABLEST
   my (%classlist) = &getclasslist($cdom,$cnum,'0');      if ($ENV{'form.url'}) {
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {   $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n");
       my ($sname,$sdom) = split(/:/,$student);      }
       if ($ENV{'form.symb'}) {
       my %name=&Apache::lonnet::get('environment', ['lastname','generation',   $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
     'firstname','middlename'],      }
     $sdom,$sname);      $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
       my $fullname;      
       my ($tmp) = keys(%name);      my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
       if ($tmp !~ /^(con_lost|error|no_such_host)/i) {      
  $fullname=$name{'lastname'}.$name{'generation'};      $result='<table border="0"><tr><td bgcolor="#777777">'.
  if ($fullname =~ /[^\s]+/) { $fullname.=', '; }   '<table border="0"><tr bgcolor="#e6ffff">'.
  $fullname.=$name{'firstname'}.' '.$name{'middlename'};   '<td><b>&nbsp;Select&nbsp;</b></td><td><b>&nbsp;Username&nbsp;</b></td>'.
       }   '<td><b>&nbsp;Fullname&nbsp;</b></td><td><b>&nbsp;Domain&nbsp;</b></td>';
       if ( $Apache::grades::viewgrades eq 'F' ) {      foreach (sort(@$partlist)) {
   $request->print("\n".'<tr bgcolor=#ffffe6>'."<td>$sname</td><td>$fullname</td><td align=\"middle\">$sdom</td>".   $result.='<td><b>&nbsp;Part ID '.(split(/_/))[0].' Status&nbsp;</b></td>';
   '<form action="/adm/grades" method="post">');      }
   if ($ENV{'form.url'}) {      $request->print($result.'</tr>'."\n");
     $request->print(  
     '<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />');      foreach my $student (sort(@{ $$classlist{$getsec} }) ) {
   }   my ($uname,$udom) = split(/:/,$student);
   if ($ENV{'form.symb'}) {   my (%status) = &student_gradeStatus($ENV{'form.url'},$udom,$uname,$partlist);
     $request->print(   my $statusflg = '';
     '<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />');   foreach (keys(%status)) {
   }      $statusflg = 1 if ($status{$_} ne 'nothing');
   $request->print(      my ($foo,$partid,$foo1) = split(/\./,$_);
   '<input type="hidden" name="command" value="'.$ENV{'form.command'}.'" />');      if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
   $request->print(   $statusflg = '';
   '<input type="hidden" name="student" value="'.$sname.'" />');   $request->print('<input type="hidden" name="'.
   $request->print(   $student.':submitted_by" value="'.
   '<input type="hidden" name="fullname" value="'.$fullname.'" />');   $status{'resource.'.$partid.'.submitted_by'}.'" />');
   $request->print(      }
   '<input type="hidden" name="domain" value="'.$sdom.'" />');   }
   $request->print('<td>'.   next if ($statusflg eq '' && $submitonly eq 'yes');
   '<input type="radio" name="vProb" value="no" checked> no '.  
   '<input type="radio" name="vProb" value="yes"> yes </td>');   if ( $Apache::grades::viewgrades eq 'F' ) {
   $request->print('<td>'.      $result='<tr bgcolor="#ffffe6">'.
   '<input type="radio" name="lastSub" value="last" checked> last '.   '<td align="center"><input type=checkbox name="stuinfo" value="'.
   '<input type="radio" name="lastSub" value="all"> all </td>');   $student.':'.$$fullname{$student}.'"></td>'."\n".
   my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);   '<td>&nbsp;'.$uname.'&nbsp;</td>'."\n".
   $request->print(   '<td>&nbsp;'.$$fullname{$student}.'&nbsp;</td>'."\n".
   '<td align="middle">'.$status.'&nbsp;</td>');   '<td align="middle">&nbsp;'.$udom.'&nbsp;</td>'."\n";
   $request->print(      
                          '<td><input type="submit" name="submit" value="View/Grade" />');      foreach (sort keys(%status)) {
   $request->print('</td></tr></form>');   next if (/^resource.*?submitted_by$/);
 #  $request->print('</form></td></tr>');   $result.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";
       }      }
   }      $request->print($result.'</tr>'."\n");
   $request->print('</table></td></tr></table>');   }
       }
       $request->print('</table></td></tr></table>');
       $request->print('<input type="submit" name="submit" value="View/Grade" /><form />');
 }  }
   
   sub processGroup {
       my ($request)  = shift;
       my $ctr        = 0;
       my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
         : ($ENV{'form.stuinfo'}));
       my $total      = scalar(@stuchecked)-1;
       if ($stuchecked[0] eq '') {
    &userError($request,'No student was selected for viewing/grading.');
    return;
       }
       foreach (@stuchecked) {
    my ($uname,$udom,$fullname) = split(/:/);
    $ENV{'form.student'} = $uname;
    $ENV{'form.fullname'} = $fullname;
    &submission($request,$ctr,$total);
    $ctr++;
       }
       return '';
   }
   
   sub userError {
       my ($request, $reason, $step) = @_;
       $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n");
       $request->print('<b>Reason: </b>'.$reason.'<br /><br />'."\n");
       $request->print('<b>Step: </b>'.($step ne '' ? $step : 'Use your browser back button to correct')
       .'<br /><br />'."\n");
       return '';
   }
   
 #FIXME - needs to handle multiple matches  #FIXME - needs to handle multiple matches
 sub finduser {  sub finduser {
   my ($name) = @_;      my ($name) = @_;
   my $domain = '';      my $domain = '';
       if ( $Apache::grades::viewgrades eq 'F' ) {
   if ( $Apache::grades::viewgrades eq 'F' ) {   my ($classlist) = &getclasslist('all','0');
     #get classlist   foreach ( sort(@{ $$classlist{'all'} }) ) {
     my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});      my ($posname,$posdomain) = split(/:/);
     #print "Found $cdom:$cnum<br />";      if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
     my (%classlist) = &getclasslist($cdom,$cnum,'0');   }
     foreach my $student ( sort(@{ $classlist{'allids'} }) ) {   return ($name,$domain);
       my ($posname,$posdomain) = split(/:/,$student);      } else {
       if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }   return ($ENV{'user.name'},$ENV{'user.domain'});
     }      }
     return ($name,$domain);  
   } else {  
     return ($ENV{'user.name'},$ENV{'user.domain'});  
   }  
 }  }
   
 sub getclasslist {  sub getclasslist {
   my ($coursedomain,$coursenum,$hideexpired) = @_;      my ($getsec,$hideexpired) = @_;
   my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);      my $now = time;
   my $now = time;      my %classlist=&Apache::lonnet::dump('classlist',
   foreach my $student (keys(%classlist)) {   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
     my ($end,$start)=split(/:/,$classlist{$student});   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
     # still a student?      my (@holdsec,@sections,%allids,%stusec,%fullname);
     if (($hideexpired) && ($end) && ($end < $now)) {      foreach (keys(%classlist)) {
       #print "Skipping:$name:$end:$now<br />\n";   my ($end,$start,$id,$section,$fullname)=split(/:/,$classlist{$_});
       next;         # still a student?
    if (($hideexpired) && ($end) && ($end < $now)) {
       next;
    }
    $section = ($section ne '' ? $section : 'no');
    push @holdsec,$section;
    if ($getsec eq 'all' || $getsec eq $section) {
       push (@{ $classlist{$getsec} }, $_);
       $allids{$_}=$id;
       $stusec{$_}=$section;
       $fullname{$_}=$fullname;
    }
     }      }
     #print "record=$record<br>";      my %seen = ();
     push( @{ $classlist{'allids'} }, $student);      foreach my $item (@holdsec) {
   }   push (@sections, $item) unless $seen{$item}++;
   return (%classlist);      }
       return (\%classlist,\@sections,\%allids,\%stusec,\%fullname);
 }  }
   
 sub getpartlist {  sub getpartlist {
   my ($url) = @_;      my ($url) = @_;
   my @parts =();      my @parts =();
   my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));      my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
   foreach my $key (@metakeys) {      foreach my $key (@metakeys) {
     if ( $key =~ m/stores_([0-9]+)_.*/) {   if ( $key =~ m/stores_([0-9]+)_.*/) {
       push(@parts,$key);      push(@parts,$key);
    }
     }      }
   }      return @parts;
   return @parts;  }
   
   sub 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>'.$ENV{'form.fullname'}.
   #    $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Fullname: </b>'.$fullname.
    '</td><td>&nbsp; &nbsp;<b>Username: </b>'.$uname.
    '</td><td>&nbsp; &nbsp;<b>Domain: </b>'.$udom.'</td></tr>';
       if ($ENV{'form.handgrade'} eq 'yes') {
    my @col_list;
    ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0');
    for (keys (%$handgrade)) {
       my $ncol = &Apache::lonnet::EXT('resource.'.$_.'.maxcollaborators',$symb,$udom,$uname);
       if ($ncol > 0) {
    s/\_/\./g;
    if ($record{'resource.'.$_.'.collaborators'} ne '') {
       my (@collaborators) = split(/,?\s+/,$record{'resource.'.$_.'.collaborators'});
       my (@badcollaborators);
       if (scalar(@collaborators) != 0) {
    $result.='<tr bgcolor="#ffffff"><td colspan=3><b>Collaborators: </b>';
    foreach my $collaborator (@collaborators) {
       $collaborator = $collaborator =~ /\@|:/ ? 
    (split(/@|:/,$collaborator))[0] : $collaborator;
       next if ($collaborator eq $uname);
       if (!grep /^$collaborator:/i,keys %$classlist) {
    push @badcollaborators,$collaborator;
    next;
       }
       push @col_list, $collaborator;
       $result.=$$fullname{$collaborator.':'.$udom}.' ('.$collaborator.') &nbsp; &nbsp;';
    }
    $result.='</td></tr>'."\n";
    $result.='<tr bgcolor="#ffbbbb"><td colspan=2>'.
       'This student has submitted '.(scalar (@badcollaborators) > 1 ? '' : 'an').
       ' invalid collaborator'.(scalar (@badcollaborators) > 1 ? 's. ' : '. ').
       (join ', ',@badcollaborators).'</td></tr>' 
       if (scalar(@badcollaborators) > 0);
   
    $result.='<tr bgcolor="#ffbbbb"><td colspan=2>'.
       'This student has submitted too many collaborators. Maximum is '.
       $ncol.'.</td></tr>' if (scalar(@collaborators) > $ncol);
    $result.='<input type="hidden" name="collaborator'.$counter.
       '" value="'.(join ':',@col_list).'" />'."\n";
       }
    }
       }
    }
       }
       $request->print($result.'</table>'."\n");
   
       # 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.GD_BOX'.$counter.'_'.$partid.
    ',this.form.GD_SEL'.$counter.'_'.$partid.','.$ctr.
    ',this.form.stores'.$counter.'_'.$partid.')" '.
    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</td>\n";
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
       $ctr++;
    }
    $result.='</tr></table>';
   
    $result.='</td><td>&nbsp;<b>or</b>&nbsp;</td>';
    $result.='<td><input type="text" name="GD_BOX'.$counter.'_'.$partid.'"'.
       ($score ne ''? ' value = "'.$score.'"':'').' size="4" '.
       'onChange="javascript:updateRadio(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GD_BOX'.$counter.'_'.$partid.
       ',this.form.GD_SEL'.$counter.'_'.$partid.
       ',this.form.stores'.$counter.'_'.$partid.')" /></td>'."\n";
    $result.='<td>/'.$wgt.' '.$wgtmsg.' </td><td>';
   
    $result.='<select name="GD_SEL'.$counter.'_'.$partid.'" '.
       'onChange="javascript:clearRadBox(this.form.RADVAL'.$counter.'_'.$partid.
       ',this.form.GD_BOX'.$counter.'_'.$partid.
       ',this.form.GD_SEL'.$counter.'_'.$partid.
       ',this.form.stores'.$counter.'_'.$partid.')" />'."\n".
       '<option selected="on"> </option>'.
       '<option>excused</option></select>'."&nbsp&nbsp\n";
    $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="0" />';
    $result.='</td></tr></table>';
    $request->print($result);
       }
       $request->print('<input type="hidden" name="partlist'.$counter.'" value="'.(join ":",@partlist).'" />'."\n");
       $request->print('</td></tr></table></td></tr></table>'."\n");
   
       # print end of form
       if ($counter == $total) {
    my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />';
    my $ntstu ='<select name="NTSTU">'.
       '<option>1</option><option>2</option>'.
       '<option>3</option><option>5</option>'.
       '<option>7</option><option>10</option></select>'."\n";
    my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');
    $ntstu =~ s/<option>$nsel</<option selected="on">$nsel</;
    $endform.=$ntstu.'student(s) &nbsp;&nbsp;'.
       '<input type="submit" name="gradeOpt" value="Next" />&nbsp'.
       '<input type="submit" name="gradeOpt" value="Previous" />&nbsp'.
       '(Next and Previous do not save the scores.)'.
       '</td><tr></table></form>';
    $request->print($endform);
       }
       return '';
   }
   
   sub 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,$foo1) = split(/\./,$_);
    $statusflg = '' if ($status{'resource.'.$partid.'.submitted_by'} ne '');
       }
       next if ($statusflg eq '');
    }
    push @nextlist,$student if ($ctr < $ntstu);
    $ctr++;
       }
   
       $ctr = 0;
       my $total = scalar(@nextlist)-1;
   
       foreach (sort @nextlist) {
    my ($uname,$udom,$submitter) = split(/:/);
    $ENV{'form.student'} = $uname;
    $ENV{'form.fullname'} = $$fullname{$_};
   # $ENV{'form.'.$_.':submitted_by'} = $submitter;
   # print "submitter=$ENV{'form.'.$_.':submitted_by'}= $submitter:<br>";
    &submission($request,$ctr,$total);
    $ctr++;
       }
       if ($total < 0) {
    my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";
    $the_end.='<b>Message: </b> No more students for this section or class.<br /><br />'."\n";
    $the_end.='Click on the button below to return to the grading menu.<br /><br />'."\n";
    $the_end.=&show_grading_menu_form ($symb,$url);
    $request->print($the_end);
       }
       return '';
   }
   
   sub saveHandGrade {
       my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter) = @_;
   #   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);
       my %newrecord;
       foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {
    if ($ENV{'form.GD_SEL'.$newflg.'_'.$_} eq 'excused') {
       $newrecord{'resource.'.$_.'.solved'} = 'excused';
    } else {
       my $pts    = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? 
     $ENV{'form.GD_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_});
       if ($pts eq '') {
    &userError($request,'No point was assigned for part 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>'.(split(/_/))[0].'</td>'.
       '<td><b>Type: </b>'.$responsetype.'</td>'.
       '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>';
       }
       $result.='</table>';
       $result.=&view_edit_entire_class_form($symb,$url).'<br />';
       $result.=&upcsvScores_form($symb,$url).'<br />';
       $result.=&viewGradeaStu_form($symb,$url,$resptype,$hdgrade).'<br />';
       $result.=&verifyReceipt_form($symb,$url).'<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;<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.ctr"+i+".value");
       var scorename = eval("document.classgrade.GD_"+user+
    "_"+partid+"_aw");
       var saveval   = eval("document.classgrade.GD_"+user+
    "_"+partid+"_sv_s.value");
       var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
       if (saveval != "correct") {
    scorename.value = point;
    if (selname[0].selected != true) {
       selname[0].selected = true;
    }
       }
    }
    var selval   = eval("document.classgrade.SELVAL_"+partid);
    selval[0].selected = true;
       }
   
       function writeRadText(partid,weight) {
    var selval   = eval("document.classgrade.SELVAL_"+partid);
    var radioButton = eval("document.classgrade.RADVAL_"+partid);
    var textbox = eval("document.classgrade.TEXTVAL_"+partid);
    if (selval[1].selected) {
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
   
       }
       textbox.value = "";
   
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var scorename = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw");
    var saveval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
    var selname   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv");
    if (saveval != "correct") {
       scorename.value = "";
       selname[1].selected = true;
    }
       }
    } else {
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var scorename = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw");
    var saveval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
    var selname   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv");
    if (saveval != "correct") {
       scorename.value = eval("document.classgrade.GD_"+user+
        "_"+partid+"_aw_s.value");;
       selname[0].selected = true;
    }
       }
    }    
       }
   
       function changeSelect(partid,user) {
    var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
    selval[0].selected = true;
       }
   
       function changeOneScore(partid,user) {
    var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
    if (selval[1].selected) {
       var boxval = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
       boxval.value = "";
    }
       }
   
       function resetEntry(numpart) {
    for (ctpart=0;ctpart<numpart;ctpart++) {
       var partid = eval("document.classgrade.partid_"+ctpart+".value");
       var radioButton = eval("document.classgrade.RADVAL_"+partid);
       var textbox = eval("document.classgrade.TEXTVAL_"+partid);
       var selval  = eval("document.classgrade.SELVAL_"+partid);
       for (var i=0; i<radioButton.length; i++) {
    radioButton[i].checked=false;
   
       }
       textbox.value = "";
       selval[0].selected = true;
   
       for (i=0;i<document.classgrade.total.value;i++) {
    var user = eval("document.classgrade.ctr"+i+".value");
    var resetscore = eval("document.classgrade.GD_"+user+
         "_"+partid+"_aw");
    resetscore.value = eval("document.classgrade.GD_"+user+
    "_"+partid+"_aw_s.value");
   
    var saveselval   = eval("document.classgrade.GD_"+user+
        "_"+partid+"_sv_s.value");
   
    var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
    if (saveselval == "excused") {
       if (selname[1].selected == false) { selname[1].selected = true;}
    } else {
       if (selname[0].selected == false) {selname[0].selected = true};
    }
       }
    }
       }
   
       function submitForm() {
    document.classgrade.submit();
       }
   
   </script>
   VIEWJAVASCRIPT
   }
   
   sub viewgrades {
       my ($request) = shift;
       &viewgrades_js($request);
   
       my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'}); 
       my $result='<h2><font color="#339933">Manual Grading</font></h2>';
   
       $result.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font>'."\n";
   
       #view individual student submission form - called using Javascript viewOneStudent
       $result.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".
    '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="submission" />'."\n".
    '<input type="hidden" name="student" value="" />'."\n".
    '</form>'."\n";
   
       #start the form
       $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n".
    '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
    '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
    '<input type="hidden" name="command" value="editgrades" />'."\n".
    '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'" />'."\n";
   
       $result.='To assign the same score for all the students use the radio buttons or '.
    'text box below. To assign scores individually fill in the score boxes for '.
    'each student in the table below. <font color="red">A score that has already '.
    'been graded does not get changed using the radio buttons or text box. '.
    'If needed, it has to be changed individually.</font>';
   
       my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
       my %weight = ();
       my $ctsparts = 0;
       $result.='<table border="0">';
       for (sort keys(%$handgrade)) {
    my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
    my ($partid,$respid) = split (/_/);
    my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
    $weight{$partid} = $wgt eq '' ? '1' : $wgt;
   
    $result.='<input type="hidden" name="partid_'.$ctsparts.'" value="'.$partid.'" />'."\n";
    $result.='<tr><td><b>Part ID:</b> '.$partid.'&nbsp; &nbsp;</td><td>';
    $result.='<table border="0"><tr>';  
    my $ctr = 0;
    while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
       $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.
    'onclick="javascript:writePoint('.$partid.','.$weight{$partid}.
    ','.$ctr.')" />'.$ctr."</td>\n";
       $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
       $ctr++;
    }
    $result.='</tr></table>';
    $result.= '</td><td><b> or </b><input type="text" name="TEXTVAL_'.$partid.'" size="4" '.
       'onChange="javascript:writePoint('.$partid.','.$weight{$partid}.',\'textval\')" /> /'.
       $weight{$partid}.' (problem weight)</td>'."\n";
    $result.= '</td><td><select name="SELVAL_'.$partid.'"'.
       'onChange="javascript:writeRadText('.$partid.','.$weight{$partid}.')" /> '.
       '<option selected="on"> </option>'.
       '<option>excused</option></select></td></tr>'."\n";
    $ctsparts++;
       }
       $result.='</table><input type="hidden" name="totalparts" value="'.$ctsparts.'" />';
       $result.='<input type="button" value="Reset" '.
    'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> &nbsp; &nbsp;';
   #    $result.='<input type="button" value="Submit Changes" '.
   # 'onClick="document.classgrade.submit();" TARGET=_self />'."\n";
       $result.= '<input type="submit" name="submit"  value="Submit Changes" />'."\n";
   
       $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".
    '<table border=0><tr bgcolor="#deffff">'.
    '<td><b>Username</b></td><td><b>Fullname</b></td><td><b>Domain</b></td>'."\n";
       #get list of parts for this problem
       my (@parts) = sort(&getpartlist($url));
       foreach my $part (@parts) {
    my $display=&Apache::lonnet::metadata($url,$part.'.display');
    next if ($display =~ /^Number of Attempts/);
    if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
    if ($display =~ /^Partial Credit Factor/) {
       $_ = $display;
       my ($partid) = /.*?(\d+).*/;
       $result.='<td><b>Score Part '.$partid.'<br>(weight = '.
    $weight{$partid}.')</b></td>'."\n";
       next;
    }
    $display =~ s/Problem Status/Grade Status<br>/;
    $result.='<td><b>'.$display.'</b></td>'."\n";
       }
       $result.='</tr>';
       #get info for each student
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
       my $ctr = 0;
       foreach ( sort(@{ $$classlist{$ENV{'form.section'}} }) ) {
    (my $username = $_) = split(/:/);
    $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$username.'" />'."\n";
    $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},
      $_,$$fullname{$_},\@parts,\%weight);
    $ctr++;
       }
       $result.='</table></td></tr></table>';
       $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";
       $result.='<input type="submit" name="submit" value="Submit Changes" /></form>';
       $result.=&show_grading_menu_form($symb,$url);
       return $result;
 }  }
   
 sub viewstudentgrade {  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 (@requests) = ('lastname','firstname','middlename','generation');   '</td><td>'.$fullname.'</td><td align="middle">'.$domain.'</td>'."\n";
   my (%name) = &Apache::lonnet::get('environment',\@requests,$domain,$username);      foreach my $part (@$parts) {
   my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);   my ($temp,$part,$type)=split(/_/,$part);
    my $score=$record{"resource.$part.$type"};
   my $fullname=$name{'lastname'}.$name{'generation'};   next if $type eq 'tries';
   if ($fullname =~ /[^\s]+/) { $fullname.=', '; }   if ($type eq 'awarded') {
   $fullname.=$name{'firstname'}.' '.$name{'middlename'};      my $pts = $score eq '' ? '' : $score*$$weight{$part};
       $result.='<input type="hidden" name="'.
   $result.="<tr bgcolor=$cellclr><td>$username</td><td>$fullname</td><td align=\"middle\">$domain</td>\n";   'GD_'.$username.'_'.$part.'_aw_s" value="'.$pts.'" />'."\n";
   foreach my $part (@parts) {      $result.='<td align="middle"><input type="text" name="'.
     my ($temp,$part,$type)=split(/_/,$part);   'GD_'.$username.'_'.$part.'_aw"'.
     my $score=$record{"resource.$part.$type"};   'onChange="javascript:changeSelect('.$part.',\''.$username.'\')" value="'.
     if ($type eq 'awarded' || $type eq 'tries') {   $pts.'" size="4" /></td>'."\n";
       $result.='<td align="middle"><input type="text" name="GRADE.'.$student.'.'.$part.'.'.$type.   } elsif ($type eq 'solved') {
   '" value="'.$score.'" size="4" /></td>'."\n";      my ($status,$foo)=split(/_/,$score,2);
     } elsif ($type eq 'solved') {      $status = 'nothing' if ($status eq '');
       my ($status,$foo)=split(/_/,$score,2);      $result.='<input type="hidden" name="'.
       $result.="<td align=\"middle\"><select name=\"GRADE.$student.$part.$type\">\n";   'GD_'.$username.'_'.$part.'_sv_s" value="'.$status.'" />'."\n";
       my $optsel = '<option>correct</option><option>incorrect</option><option>excused</option>'.      $result.='<td align="middle"><select name="'.
   '<option>ungraded</option><option>partial</option><option>nothing</option>'."\n";   'GD_'.$username.'_'.$part.'_sv" '.
       $status = 'nothing' if ($status eq '');   'onChange="javascript:changeOneScore('.$part.',\''.$username.'\')" >'."\n";
       $optsel =~ s/<option>$status/<option selected="on">$status/;      my $optsel = '<option selected="on"> </option><option>excused</option>'."\n";
       $result.=$optsel;      $optsel = '<option> </option><option selected="on">excused</option>'."\n"
       $result.="</select></td>\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'};
       my $url =$ENV{'form.url'};
       my $result='<h2><font color="#339933">Current Grade Status</font></h2>';
       $result.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br />'."\n";
       $result.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n";
       $result.= &show_grading_menu_form ($symb,$url);
       $result.= '<table border="0"><tr><td bgcolor="#777777">'."\n";
       $result.= '<table border="0"><tr bgcolor="#deffff">'.
    '<td rowspan=2><b>Username</b></td><td rowspan=2><b>Fullname</b></td>'."\n";
   
       my %scoreptr = (
       'correct'  =>'correct_by_override',
       'incorrect'=>'incorrect_by_override',
       'excused'  =>'excused',
       'ungraded' =>'ungraded_attempted',
       'nothing'  => '',
       );
       my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0');
   
       my (@partid);
       my %weight = ();
       my ($i,$ctr) = (0,0);
       while ($ctr < $ENV{'form.totalparts'}) {
    my $partid = $ENV{'form.partid_'.$ctr};
    push @partid,$partid;
    my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
    $weight{$partid} = $wgt eq '' ? '1' : $wgt;
    $ctr++;
    $result .= '<td colspan = 2 align="center"><b>Part ID '.$partid.
       '</b> (Weight = '.$weight{$partid}.')</td>';
       }
       $result .= '</tr><tr bgcolor="#deffff">';
       foreach (@partid) {
    $result .= '<td align="center">&nbsp;<b>Old Score</b>&nbsp;</td>'.
       '<td align="center">&nbsp;<b>New Score</b>&nbsp;</td>';
       }
       $result .= '</tr>'."\n";
   
       for ($i=0; $i<$ENV{'form.total'}; $i++) {
    my $user = $ENV{'form.ctr'.$i};
    my %newrecord;
    my $updateflag = 0;
    my @userdom = grep /^$user:/,keys %$classlist;
    my ($foo,$udom) = split(/:/,$userdom[0]);
   
    $result .= '<tr bgcolor="#ffffde"><td>'.$user.'&nbsp;</td><td>'.
       $$fullname{$userdom[0]}.'&nbsp;</td>';
   
    foreach (@partid) {
       my $old_aw    = $ENV{'form.GD_'.$user.'_'.$_.'_aw_s'};
       my $old_part  = $old_aw eq '' ? '' : $old_aw/$weight{$_};
       my $old_score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
   
       my $awarded   = $ENV{'form.GD_'.$user.'_'.$_.'_aw'};
       my $partial   = $awarded eq '' ? '' : $awarded/$weight{$_};
       my $score;
       if ($partial eq '') {
    $score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
       } elsif ($partial > 0) {
    $score = 'correct_by_override';
       } elsif ($partial == 0) {
    $score = 'incorrect_by_override';
       }
       $score = 'excused' if (($ENV{'form.GD_'.$user.'_'.$_.'_sv'} eq 'excused') &&
      ($score ne 'excused'));
       $result .= '<td align="center">'.$old_aw.'&nbsp;</td>'.
    '<td align="center">'.$awarded.
    ($score eq 'excused' ? $score : '').'&nbsp;</td>';
   
       next if ($old_part eq $partial && $old_score eq $score);
   
       $updateflag = 1;
       $newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';
       $newrecord{'resource.'.$_.'.solved'} = $score;
   
    }
    $result .= '</tr>'."\n";
    if ($updateflag) {
       $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
       &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},
       $udom,$user);
    }
       }
       $result .= '</table></td></tr></table>'."\n";
       return $result;
 }  }
   
   
 #FIXME need to look at the metadata <stores> spec on what type of data to accept and provide an  #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) = @_;
       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.GD.$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";
       } else {      }
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";      if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }
       }   } else {
       if ($update) { $newrecord{"resource.$part.$type"}=$newscore; }      if ($oldscore ne $newscore) {
     } else {   $newrecord{"resource.$part.$type"}=$newscore;
       if ($oldscore ne $newscore) {   $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";
  $newrecord{"resource.$part.$type"}=$newscore;      } else {
  $result.="Updating $student"."'s status for $part.$type to $newscore<br />\n";   #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";
       } else {      }
  #$result.="$stuname:$part:$type:unchanged  $oldscore to $newscore:<br />\n";   }
       }  
     }  
   }  
   if ( scalar(keys(%newrecord)) > 0 ) {  
     $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";  
     print "grader=$newrecord{'resource.regrader'}:<br>records<br>";  
     while (my ($k,$v) = each %newrecord) {  
  print "k=$k:v=$v:<br>\n";  
     }      }
     &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);      if ( scalar(keys(%newrecord)) > 0 ) {
    $newrecord{'resource.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";
   #       &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);
   
     $result.="Stored away ".scalar(keys(%newrecord))." elements.<br />\n";   $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) = @_;  
   
   $request->print(<<JAVASCRIPT);  sub sub_page_js {
       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 369  sub submission { Line 1481  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) {  
       formsel[0].selected = true;  
     }      }
     return;      if (selectx == scores.value) { return };
   }      formbox.value = "";
       for (var i=0; i<radioButton.length; i++) {
 </script>   radioButton[i].checked=false;
 JAVASCRIPT  
   (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 ''; }  
   print "formstu=$ENV{'form.student'}:<br>";  
   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 ''; }  
 #  
 # header info  
   my $result='<h2><font color="#339933">Submission Record</font></h2>';  
   $result.='<table border="0"><tr><td><b>Username: </b>'.$uname.  
       '</td><td><b>Fullname: </b>'.$ENV{'form.fullname'}.'</td><td><b>Domain: </b>'.$udom.'</td></tr>';  
   $result.='<tr><td colspan=3><b>Resource: </b>'.$url.'</td></tr></table>';  
 #  
 # option to display problem  
   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'});  
       $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 />';  
   }  
   my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');  
   my $answer=&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,  
       $ENV{'request.course.id'},$last);  
   $result.=$answer;  
   
   my $wgt   = &Apache::lonnet::EXT('resource.partid.weight',$symb,$udom,$uname);  
   my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);  
   my $score = $record{'resource.0.awarded'}*$wgt;  
   
   $result.= '<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="'.$last.'" />'."\n".  
     '<input type="hidden" name="command" value="handgrade" />'."\n".  
       '<input type="hidden" name="NCT"'.  
         ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1').'" />'."\n";  
   
   my $counter = 0;  
   $result.='<input type="hidden" name="WGT'.$counter.'" value="'.$wgt.'" />'.  
       '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n";  
   $result.='<table border="0"><tr><td><b>Points</b></td><td>';  
   my $ctr = 0;  
   while ($ctr<=$wgt) {  
       $result.= '<input type="radio" name="RADVAL'.$counter.'" '.  
   'onclick="javascript:writeBox(this.form.GRADE_BOX'.$counter.  
     ',this.form.GRADE_SEL'.$counter.',\''.$ctr.'\',\''.$wgt.'\')" '.  
  ($score == $ctr? 'checked':'').' /> '.$ctr."\n";  
       $ctr++;  
   }  
   $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 > 0 ? $wgt.' (problem weight)' : '<font color="red">invalid problem weight</font>' ).  
       ' </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);  
       $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";  
       $status = 'nothing' if ($status eq '');  
       $optsel =~ s/<option>$status/<option selected="on">$status/;  
       $result.=$optsel;  
       $result.="</select></td></tr>\n";  
     }      }
       scores.value = selectx;
   }    }
   
   $result.='<tr><td colspan="6"><input type="submit" name="gradeOpt" value="Save & Next" />';    function updateSelect(formsel) {
   my $ntstu ='<select name="NTSTU">'.      formsel[0].selected = true;
       '<option>1</option><option>2</option>'.      return;
   '<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/;  
   $result.=$ntstu.'student(s) &nbsp;'."\n <br />";  
   $result.='<input type="submit" name="gradeOpt" value="Next" />&nbsp';  
   $result.='<input type="submit" name="gradeOpt" value="Previous" />&nbsp';  
   $result.='(Next and Previous do not save the scores.)';  
   $result.='</td><tr></table></form>';  
   return $result;  
 }  
   
 sub processHandGrade {  
   my ($request) = @_;  
   my $result='';  
   
   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 $vProb  = $ENV{'form.vProb'};  
   my $lastSub= $ENV{'form.lastSub'};  
   
   my (@parts) = sort(&getpartlist($url));  
   if ($button eq 'Save & Next') {  
       my $ctr = 0;  
       while ($ctr < $ENV{'form.NCT'}) {  
   my $pts    = ($ENV{'form.GRADE_BOX'.$ctr} ne '' ? $ENV{'form.GRADE_BOX'.$ctr} : $ENV{'form.RADVAL'.$ctr});  
   my $wgt    = $ENV{'form.WGT'.$ctr};  
   my $sel    = $ENV{'form.GRADE_SEL'.$ctr};  
   my $score  = $pts/$wgt if ($wgt != 0);  
   my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});  
   &saveHandGrade($url,$symb,$uname,$udom,$score,@parts);  
   $ctr++;  
       }  
   }    }
   my $firststu = $ENV{'form.unamedom0'};  
   my $laststu  = $ENV{'form.unamedom'.($ngrade-1)};  
   
   #get classlist  //===================== Show list of keywords ====================
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});    function keywords(keyform) {
   my (%classlist) = &getclasslist($cdom,$cnum,'0');      var keywds = keyform.value;
       var nret = prompt("Keywords list, separated by a space. Add/delete to list if desired.",keywds);
   my (@nextlist,@prevlist);      if (nret==null) return;
   my ($nextflg,$prevflg,$ctr) = (0,0,0);      keyform.value = nret;
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {      return;
       my ($uname,$udom) = split(/:/,$student);  
       if ($nextflg == 1 && $button =~ /Next$/) {  
   push @nextlist,$uname if ($ctr < $ENV{'form.NTSTU'});  
   $ctr++;  
       }  
       $nextflg = 1 if ($student eq $laststu);  
       $prevflg = 1 if ($student eq $firststu);  
   }  
   foreach my $student (@nextlist) {  
       $ENV{'form.student'} = $student;  
       $request->print(&submission($request));  
   }    }
   $request->print ("<h2><font color=\"#339933\">Grading</font></h2>");  
   
   #get info for each student  //===================== Script to view submitted by ==================
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {    function viewSubmitter(submitter) {
     my $display=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);      document.SCORE.refresh.value = "on";
       print "ID=$ENV{'request.course.id'}:STU=$student:DIS=$display:<br>\n";      document.SCORE.NCT.value = "1";
 #    $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);      document.SCORE.unamedom0.value = submitter;
       document.SCORE.submit();
       return;
   }    }
   
   return 'The End';  //===================== Script to add keyword(s) ==================
 #  return $result;    function getSel() {
 }      if (document.getSelection) txt = document.getSelection();
       else if (document.selection) txt = document.selection.createRange().text;
 sub saveHandGrade {      else return;
   my ($url,$symb,$stuname,$domain,$newscore,@parts) = @_;      var cleantxt = txt.replace(new RegExp('([\\f\\n\\r\\t\\v ])+', 'g')," ");
       if (cleantxt=="") {
 #  my ($stuname,$domain) = split(/:/,$student);   alert("Select a word or group of words from document and then click this link.");
   my %record=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);   return;
   my %newrecord;  
   
   foreach my $part (@parts) {  
     my ($temp,$part,$type)=split(/_/,$part);  
     my $oldscore=$record{"resource.$part.$type"};  
     if ($type eq 'solved') {  
       my $update=0;  
       if ($newscore eq 'nothing' ) {  
  if ($oldscore ne '') {  
   $update=1;  
   $newscore = '';  
  }  
       } elsif ($oldscore !~ m/^$newscore/) {  
  $update=1;  
  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 = 'partial_correct'; }  
       }  
       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'}";  
 #      print "grader=$newrecord{'resource.regrader'}:<br>records<br>";  
 #      while (my ($k,$v) = each %newrecord) {  
 # print "k=$k:v=$v:<br>\n";  
 #      }  
 #     &Apache::lonnet::cstore(\%newrecord,$symb,$courseid,$domain,$stuname);  
     }      }
     return '';      var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt);
       if (nret==null) return;
       var curlist = document.SCORE.keywords.value;
       document.SCORE.keywords.value = curlist+" "+nret;
       return;
   }    }
 }  
   
 sub get_symb_and_url {  
  my ($request) = @_;  
   my $url=$ENV{'form.url'};  
   $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;  
 #  my $symb=$ENV{'form.symb'};  
 #  if (!$symb) { $symb=&Apache::lonnet::symbread($url); }  
   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 view_edit_entire_class_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="viewgrades" />'."\n".  
   '<input type="submit" name="submit" value="View/Grade Entire Class" />'."\n".  
     '</form>'."\n";  
   return $result;  
 }  
   
 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><br />';  
   $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>Resource :</b> '.$url.'</td></tr>'."\n";  
   $result.='<tr bgcolor=#ffffe6><td>'."\n";  
   $result.=&view_edit_entire_class_form($symb,$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="csvupload" />'."\n".  
   '<input type="submit" name="submit" value="Upload Scores" />'."\n".  
     '</form>'."\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="submission" />'."\n".  
   '<input type="submit" name="submit" value="View/Grade A Student" />'."\n".  
     '</form>'."\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="receiptInput" />'."\n".  
   '<input type="submit" name="submit" value="Verify Receipt" />'."\n".  
     '</form>'."\n";  
   $result.='</td></tr></table>'."\n";  
   $result.='</td></tr></table>'."\n";  
   return $result;  
 }  
   
 sub viewgrades {  //====================== Script for composing message ==============
   my ($request) = @_;    function msgCenter(msgform,usrctr,fullname) {
   my $result='';      var Nmsg  = msgform.savemsgN.value;
       savedMsgHeader(Nmsg,usrctr,fullname);
   #get resource reference      var subject = msgform.msgsub.value;
   my ($symb,$url)=&get_symb_and_url($request);      var rtrchk  = eval("document.SCORE.includemsg"+usrctr);
   if (!$symb) {return '';}      var msgchk = rtrchk.value;
   #get classlist  //    alert("checked=>"+msgchk);
   my ($cdom,$cnum) = split(/_/,$ENV{'request.course.id'});      re = /msgsub/;
   #print "Found $cdom:$cnum<br />";      var shwsel = "";
   my (%classlist) = &getclasslist($cdom,$cnum,'0');      if (re.test(msgchk)) { shwsel = "checked" }
   my $headerclr = '"#ccffff"';      displaySubject(subject,shwsel);
   my $cellclr = '"#ffffcc"';      for (var i=1; i<=Nmsg; i++) {
    var testpt = "savemsg"+i+",";
   #get list of parts for this problem   re = /testpt/;
   my (@parts) = sort(&getpartlist($url));   shwsel = "";
    if (re.test(msgchk)) { shwsel = "checked" }
   $request->print ("<h2><font color=\"#339933\">Manual Grading</font></h2>");   var message = eval("document.SCORE.savemsg"+i+".value");
    displaySavedMsg(i,message,shwsel);
   #start the form      }
   $result = '<form action="/adm/grades" method="post">'."\n".      newmsg = eval("document.SCORE.newmsg"+usrctr+".value");
     '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".      shwsel = "";
       '<input type="hidden" name="url" value="'.$url.'" />'."\n".      re = /newmsg/;
  '<input type="hidden" name="command" value="editgrades" />'."\n".      if (re.test(msgchk)) { shwsel = "checked" }
   '<input type="submit" name="submit" value="Submit Changes" />'."\n".      newMsg(newmsg,shwsel);
     '<table border=0><tr><td bgcolor="#777777">'."\n".      msgTail(); 
      '<table border=0>'."\n".      return;
       '<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'); }  
       print "Manual grading:$url:$part:$display:<br>";  
      $result.='<td><b>'.$display.'</b></td>'."\n";  
   }  
   $result.='</tr>';  
   #get info for each student  
   foreach my $student ( sort(@{ $classlist{'allids'} }) ) {  
     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 {    function savedMsgHeader(Nmsg,usrctr,fullname) {
   my ($request) = @_;      var height = 30*Nmsg+250;
   my $result='';      var scrollbar = "no";
       if (height > 600) {
    height = 600;
    scrollbar = "yes";
       }
   /*    if (window.pWin)
    window.pWin.close(); */
       pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx=70,screeny=75,width=600,height='+height);
       pWin.document.write("<html><head>");
       pWin.document.write("<title>Message Central</title>");
   
       pWin.document.write("<script language=javascript>");
       pWin.document.write("function checkInput() {");
       pWin.document.write("  opener.document.SCORE.msgsub.value = document.msgcenter.msgsub.value;");
       pWin.document.write("  var nmsg   = opener.document.SCORE.savemsgN.value;");
       pWin.document.write("  var usrctr = document.msgcenter.usrctr.value;");
       pWin.document.write("  var newval = eval(\\"opener.document.SCORE.newmsg\\"+usrctr);");
       pWin.document.write("  newval.value = document.msgcenter.newmsg.value;");
   
       pWin.document.write("  var msgchk = \\"\\";");
       pWin.document.write("  if (document.msgcenter.subchk.checked) {");
       pWin.document.write("     msgchk = \\"msgsub,\\";");
       pWin.document.write("  }");
       pWin.document.write(   "for (var i=1; i<=nmsg; i++) {");
       pWin.document.write("      var opnmsg = eval(\\"opener.document.SCORE.savemsg\\"+i);");
       pWin.document.write("      var frmmsg = eval(\\"document.msgcenter.msg\\"+i);");
       pWin.document.write("      opnmsg.value = frmmsg.value;");
       pWin.document.write("      var chkbox = eval(\\"document.msgcenter.msgn\\"+i);");
       pWin.document.write("      if (chkbox.checked) {");
       pWin.document.write("         msgchk += \\"savemsg\\"+i+\\",\\";");
       pWin.document.write("      }");
       pWin.document.write("  }");
       pWin.document.write("  if (document.msgcenter.newmsgchk.checked) {");
       pWin.document.write("     msgchk += \\"newmsg\\"+usrctr;");
       pWin.document.write("  }");
       pWin.document.write("  var includemsg = eval(\\"opener.document.SCORE.includemsg\\"+usrctr);");
       pWin.document.write("  includemsg.value = msgchk;");
   
   //    pWin.document.write("  alert(\\"slected=\\"+msgchk)");
       pWin.document.write("  self.close()");
   
       pWin.document.write("}");
   
       pWin.document.write("<");
       pWin.document.write("/script>");
   
       pWin.document.write("</head><body bgcolor=white>");
   
       pWin.document.write("<form action=\\"inactive\\" name=\\"msgcenter\\">");
       pWin.document.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">");
       pWin.document.write("<font color=\\"green\\" size=+1>&nbsp;Compose Message for \"+fullname+\"</font><br><br>");
   
       pWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
       pWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
       pWin.document.write("<td><b>Type</b></td><td><b>Include</b></td><td><b>Message</td></tr>");
   }
       function displaySubject(msg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       pWin.document.write("<td>Subject</td>");
       pWin.document.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
       pWin.document.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+" \\"size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
   function displaySavedMsg(ctr,msg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       pWin.document.write("<td align=\\"center\\">"+ctr+"</td>");
       pWin.document.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"></td>");
       pWin.document.write("<td><input name=\\"msg"+ctr+"\\" type=\\"text\\" value=\\""+msg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
     function newMsg(newmsg,shwsel) {
       pWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       pWin.document.write("<td align=\\"center\\">New</td>");
       pWin.document.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");
       pWin.document.write("<td><input name=\\"newmsg\\" type=\\"text\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" value=\\""+newmsg+" \\" size=\\"60\\" maxlength=\\"80\\"></td></tr>");
   }
   
     function msgTail() {
       pWin.document.write("</table>");
       pWin.document.write("</td></tr></table>&nbsp;");
       pWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\">&nbsp;&nbsp;");
       pWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
       pWin.document.write("</form>");
       pWin.document.write("</body></html>");
   }
   
   //====================== Script for keyword highlight options ==============
     function kwhighlight() {
       var kwclr    = document.SCORE.kwclr.value;
       var kwsize   = document.SCORE.kwsize.value;
       var kwstyle  = document.SCORE.kwstyle.value;
       var redsel = "";
       var grnsel = "";
       var blusel = "";
       if (kwclr=="red")   {var redsel="checked"};
       if (kwclr=="green") {var grnsel="checked"};
       if (kwclr=="blue")  {var blusel="checked"};
       var sznsel = "";
       var sz1sel = "";
       var sz2sel = "";
       if (kwsize=="0")  {var sznsel="checked"};
       if (kwsize=="+1") {var sz1sel="checked"};
       if (kwsize=="+2") {var sz2sel="checked"};
       var synsel = "";
       var syisel = "";
       var sybsel = "";
       if (kwstyle=="")    {var synsel="checked"};
       if (kwstyle=="<i>") {var syisel="checked"};
       if (kwstyle=="<b>") {var sybsel="checked"};
       highlightCentral();
       highlightbody('red','red',redsel,'0','normal',sznsel,'','normal',synsel);
       highlightbody('green','green',grnsel,'+1','+1',sz1sel,'<i>','italic',syisel);
       highlightbody('blue','blue',blusel,'+2','+2',sz2sel,'<b>','bold',sybsel);
       highlightend();
       return;
     }
   
   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($cdom,$cnum,'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{'allids'} }) ) {    function highlightCentral() {
     $result.=&setstudentgrade($url,$symb,$ENV{'request.course.id'},$student,@parts);      hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx=100,screeny=75');
       hwdWin.document.write("<html><head>");
       hwdWin.document.write("<title>Highlight Central</title>");
   
       hwdWin.document.write("<script language=javascript>");
       hwdWin.document.write("function updateChoice(flag) {");
       hwdWin.document.write("  opener.document.SCORE.kwclr.value = radioSelection(document.hlCenter.kwdclr);");
       hwdWin.document.write("  opener.document.SCORE.kwsize.value = radioSelection(document.hlCenter.kwdsize);");
       hwdWin.document.write("  opener.document.SCORE.kwstyle.value = radioSelection(document.hlCenter.kwdstyle);");
   //    hwdWin.document.write("     var kwords=opener.document.SCORE.keywords.value;");
   //    hwdWin.document.write("     alert(\\"keywords=\\"+opener.document.SCORE.keywords.value);");
   //    hwdWin.document.write("     return;");
   
       hwdWin.document.write("  if (flag==1){");
       hwdWin.document.write("     opener.document.SCORE.refresh.value = \\"on\\";");
       hwdWin.document.write("     if (opener.document.SCORE.keywords.value!=\\"\\"){");
       hwdWin.document.write("        opener.document.SCORE.submit();");
       hwdWin.document.write("     }");
       hwdWin.document.write("   }");
       hwdWin.document.write("  self.close()");
       hwdWin.document.write("}");
   
       hwdWin.document.write("function radioSelection(radioButton) {");
       hwdWin.document.write("    var selection=null;");
       hwdWin.document.write("    for (var i=0; i<radioButton.length; i++) {");
       hwdWin.document.write("        if (radioButton[i].checked) {");
       hwdWin.document.write("            selection=radioButton[i].value;");
       hwdWin.document.write("            return selection;");
       hwdWin.document.write("        }");
       hwdWin.document.write("    }");
       hwdWin.document.write("}");
   
       hwdWin.document.write("<");
       hwdWin.document.write("/script>");
   
       hwdWin.document.write("</head><body bgcolor=white>");
   
       hwdWin.document.write("<form action=\\"inactive\\" name=\\"hlCenter\\">");
       hwdWin.document.write("<font color=\\"green\\" size=+1>&nbsp;Keyword Highlight Options</font><br><br>");
   
       hwdWin.document.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
       hwdWin.document.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
       hwdWin.document.write("<td><b>Text Color</b></td><td><b>Font Size</b></td><td><b>Font Style</td></tr>");
     }
   
     function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) { 
       hwdWin.document.write("<tr bgcolor=\\"#ffffdd\\">");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"</td>");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdsize\\" type=\\"radio\\" value=\\""+szval+"\\" "+szsel+">&nbsp;"+sztxt+"</td>");
       hwdWin.document.write("<td align=\\"left\\">");
       hwdWin.document.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"</td>");
       hwdWin.document.write("</tr>");
     }
   
     function highlightend() { 
       hwdWin.document.write("</table>");
       hwdWin.document.write("</td></tr></table>&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(0)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Save & Refresh\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");
       hwdWin.document.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br><br>");
       hwdWin.document.write("</form>");
       hwdWin.document.write("</body></html>");
   }    }
   
   $result.='<input type="submit" name="submit" value="See Grades" /></table></form>';  </script>
   return $result;  SUBJAVASCRIPT
 }  
   
 sub csvupload {  
   my ($request)= @_;  
   my $result;  
   my ($symb,$url)=&get_symb_and_url($request);  
   if (!$symb) {return '';}  
   my $upfile_select=&Apache::loncommon::upfile_select_html();  
   $result.=<<ENDUPFORM;  
 <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" />  
 <hr />  
 <h3>Specify a file containing the class grades for resource $url</h3>  
 $upfile_select  
 <p><input type="submit" name="submit" value="Upload Grades" />  
 ENDUPFORM  
   return $result;  
 }  }
   
 sub csvupload_javascript_reverse_associate {  sub csvupload_javascript_reverse_associate {
Line 829  ENDPICK Line 1840  ENDPICK
 }  }
   
 sub csvuploadmap_header {  sub csvuploadmap_header {
   my ($request,$symb,$url,$datatoken,$distotal)= @_;      my ($request,$symb,$url,$datatoken,$distotal)= @_;
   my $result;      my $result;
   my $javascript;      my $javascript;
   if ($ENV{'form.upfile_associate'} eq 'reverse') {      if ($ENV{'form.upfile_associate'} eq 'reverse') {
     $javascript=&csvupload_javascript_reverse_associate();   $javascript=&csvupload_javascript_reverse_associate();
   } else {      } else {
     $javascript=&csvupload_javascript_forward_associate();   $javascript=&csvupload_javascript_forward_associate();
   }      }
   $request->print(<<ENDPICK);      $request->print(<<ENDPICK);
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <h3>Uploading Class Grades for resource $url</h3>  <h3>Uploading Class Grades for resource $url</h3>
 <hr>  <hr>
Line 861  to this page if the data selected is ins Line 1872  to this page if the data selected is ins
 $javascript  $javascript
 </script>  </script>
 ENDPICK  ENDPICK
   return '';  return '';
   
 }  }
   
 sub csvupload_fields {  sub csvupload_fields {
   my ($url) = @_;      my ($url) = @_;
   my (@parts) = &getpartlist($url);      my (@parts) = &getpartlist($url);
   my @fields=(['username','Student Username'],['domain','Student Domain']);      my @fields=(['username','Student Username'],['domain','Student Domain']);
   foreach my $part (sort(@parts)) {      foreach my $part (sort(@parts)) {
     my @datum;   my @datum;
     my $display=&Apache::lonnet::metadata($url,$part.'.display');   my $display=&Apache::lonnet::metadata($url,$part.'.display');
     my $name=$part;   my $name=$part;
     if  (!$display) { $display = $name; }   if  (!$display) { $display = $name; }
     @datum=($name,$display);   @datum=($name,$display);
     push(@fields,\@datum);   push(@fields,\@datum);
   }      }
   return (@fields);      return (@fields);
 }  }
   
 sub csvuploadmap_footer {  sub csvuploadmap_footer {
   my ($request,$i,$keyfields) =@_;      my ($request,$i,$keyfields) =@_;
   $request->print(<<ENDPICK);      $request->print(<<ENDPICK);
 </table>  </table>
 <input type="hidden" name="nfields" value="$i" />  <input type="hidden" name="nfields" value="$i" />
 <input type="hidden" name="keyfields" value="$keyfields" />  <input type="hidden" name="keyfields" value="$keyfields" />
Line 892  ENDPICK Line 1903  ENDPICK
 }  }
   
 sub csvuploadmap {  sub csvuploadmap {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   my $datatoken;      my $datatoken;
   if (!$ENV{'form.datatoken'}) {      if (!$ENV{'form.datatoken'}) {
     $datatoken=&Apache::loncommon::upfile_store($request);   $datatoken=&Apache::loncommon::upfile_store($request);
   } else {  
     $datatoken=$ENV{'form.datatoken'};  
     &Apache::loncommon::load_tmp_file($request);  
   }  
   my @records=&Apache::loncommon::upfile_record_sep();  
   &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);  
   my $i;  
   my $keyfields;  
   if (@records) {  
     my @fields=&csvupload_fields($url);  
     if ($ENV{'form.upfile_associate'} eq 'reverse') {  
       &Apache::loncommon::csv_print_samples($request,\@records);  
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,  
     \@fields);  
       foreach (@fields) { $keyfields.=$_->[0].','; }  
       chop($keyfields);  
     } else {      } else {
       unshift(@fields,['none','']);   $datatoken=$ENV{'form.datatoken'};
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,   &Apache::loncommon::load_tmp_file($request);
       \@fields);  
       my %sone=&Apache::loncommon::record_sep($records[0]);  
       $keyfields=join(',',sort(keys(%sone)));  
     }      }
   }      my @records=&Apache::loncommon::upfile_record_sep();
   &csvuploadmap_footer($request,$i,$keyfields);      &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
   return '';      my ($i,$keyfields);
       if (@records) {
    my @fields=&csvupload_fields($url);
    if ($ENV{'form.upfile_associate'} eq 'reverse') {
       &Apache::loncommon::csv_print_samples($request,\@records);
       $i=&Apache::loncommon::csv_print_select_table($request,\@records,
     \@fields);
       foreach (@fields) { $keyfields.=$_->[0].','; }
       chop($keyfields);
    } else {
       unshift(@fields,['none','']);
       $i=&Apache::loncommon::csv_samples_select_table($request,\@records,
       \@fields);
       my %sone=&Apache::loncommon::record_sep($records[0]);
       $keyfields=join(',',sort(keys(%sone)));
    }
       }
       &csvuploadmap_footer($request,$i,$keyfields);
       return '';
 }  }
   
 sub csvuploadassign {  sub csvuploadassign {
   my ($request)= @_;      my ($request)= @_;
   my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
   if (!$symb) {return '';}      if (!$symb) {return '';}
   &Apache::loncommon::load_tmp_file($request);      &Apache::loncommon::load_tmp_file($request);
   my @gradedata=&Apache::loncommon::upfile_record_sep();      my @gradedata=&Apache::loncommon::upfile_record_sep();
   my @keyfields = split(/\,/,$ENV{'form.keyfields'});      my @keyfields = split(/\,/,$ENV{'form.keyfields'});
   my %fields=();      my %fields=();
   for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {      for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {
     if ($ENV{'form.upfile_associate'} eq 'reverse') {   if ($ENV{'form.upfile_associate'} eq 'reverse') {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$keyfields[$i]}=$ENV{'form.f'.$i};   $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
       }      }
     } else {   } else {
       if ($ENV{'form.f'.$i} ne 'none') {      if ($ENV{'form.f'.$i} ne 'none') {
  $fields{$ENV{'form.f'.$i}}=$keyfields[$i];   $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
       }      }
    }
     }      }
   }      $request->print('<h3>Assigning Grades</h3>');
   $request->print('<h3>Assigning Grades</h3>');      my $courseid=$ENV{'request.course.id'};
   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($cdom,$cnum,'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'});  
     if ($command eq 'submission') {  
       &listStudents($request) if ($ENV{'form.student'} eq '');  
       $request->print(&submission($request)) if ($ENV{'form.student'} ne '');  
     } elsif ($command eq 'gradingmenu') {  
       $request->print(&gradingmenu($request));  
     } elsif ($command eq 'viewgrades') {  
       $request->print(&viewgrades($request));  
     } elsif ($command eq 'handgrade') {  
       $request->print(&processHandGrade($request));  
     } elsif ($command eq 'editgrades') {  
       $request->print(&editgrades($request));  
     } elsif ($command eq 'verify') {  
       $request->print(&verifyreceipt($request));  
     } elsif ($command eq 'csvupload') {  
       $request->print(&csvupload($request));  
     } elsif ($command eq 'csvuploadmap') {  
       $request->print(&csvuploadmap($request));  
     } elsif ($command eq 'receiptInput') {  
       &receiptInput($request);  
     } elsif ($command eq 'csvuploadassign') {  
       if ($ENV{'form.associate'} ne 'Reverse Association') {  
  $request->print(&csvuploadassign($request));  
       } else {  
  if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {  
   $ENV{'form.upfile_associate'} = 'reverse';  
  } else {  
   $ENV{'form.upfile_associate'} = 'forward';  
  }   }
  $request->print(&csvuploadmap($request));  
       }  
     } else {      } else {
       $request->print("Unknown action: $command:");   #&Apache::lonhomework::showhashsubset(\%ENV,'^form');
    $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
    if ($command eq 'submission') {
       &listStudents($request) if ($ENV{'form.student'} eq '');
       &submission($request,0,0) if ($ENV{'form.student'} ne '');
    } elsif ($command eq 'processGroup') {
       &processGroup($request);
    } elsif ($command eq 'gradingmenu') {
       $request->print(&gradingmenu($request));
    } elsif ($command eq 'viewgrades') {
       $request->print(&viewgrades($request));
    } elsif ($command eq 'handgrade') {
       $request->print(&processHandGrade($request));
    } elsif ($command eq 'editgrades') {
       $request->print(&editgrades($request));
    } elsif ($command eq 'verify') {
       $request->print(&verifyreceipt($request));
    } elsif ($command eq 'csvupload') {
       $request->print(&csvupload($request));
    } elsif ($command eq 'viewclasslist') {
       $request->print(&viewclasslist($request));
    } elsif ($command eq 'csvuploadmap') {
       $request->print(&csvuploadmap($request));
   #    } elsif ($command eq 'receiptInput') {
   #      &receiptInput($request);
    } elsif ($command eq 'csvuploadassign') {
       if ($ENV{'form.associate'} ne 'Reverse Association') {
    $request->print(&csvuploadassign($request));
       } else {
    if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
       $ENV{'form.upfile_associate'} = 'reverse';
    } else {
       $ENV{'form.upfile_associate'} = 'forward';
    }
    $request->print(&csvuploadmap($request));
       }
    } else {
       $request->print("Unknown action: $command:");
    }
     }      }
   }      &send_footer($request);
   &send_footer($request);      return OK;
   return OK;  
 }  }
   
 1;  1;

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


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