Diff for /loncom/homework/grades.pm between versions 1.201 and 1.305

version 1.201, 2004/05/14 20:26:22 version 1.305, 2006/01/27 00:26:18
Line 25 Line 25
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 # 2/9,2/13 Guy Albertelli  
 # 6/8 Gerd Kortemeyer  
 # 7/26 H.K. Ng  
 # 8/20 Gerd Kortemeyer  
 # Year 2002  
 # June-August H.K. Ng  
 # Year 2003  
 # February, March H.K. Ng  
 # July, H. K. Ng  
 #  
   
 package Apache::grades;  package Apache::grades;
 use strict;  use strict;
Line 90  sub getpartlist { Line 80  sub getpartlist {
 # --- Get the symbolic name of a problem and the url  # --- Get the symbolic name of a problem and the url
 sub get_symb_and_url {  sub get_symb_and_url {
     my ($request,$silent) = @_;      my ($request,$silent) = @_;
     (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;      (my $url=$env{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
     my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
     if ($symb eq '') {       if ($symb eq '') { 
  if (!$silent) {   if (!$silent) {
     $request->print("Unable to handle ambiguous references:$url:.");      $request->print("Unable to handle ambiguous references:$url:.");
Line 101  sub get_symb_and_url { Line 91  sub get_symb_and_url {
     return ($symb,$url);      return ($symb,$url);
 }  }
   
 # --- Retrieve the fullname for a user. Return lastname, first middle ---  
 # --- Generation is attached next to the lastname if it exists. ---  
 sub get_fullname {  
     my ($uname,$udom) = @_;  
     my %name=&Apache::lonnet::get('environment', ['lastname','generation',  
   'firstname','middlename'],  
                                   $udom,$uname);  
     my $fullname;  
     my ($tmp) = keys(%name);  
     if ($tmp !~ /^(con_lost|error|no_such_host)/i) {  
         $fullname = &Apache::loncoursedata::ProcessFullName  
             (@name{qw/lastname generation firstname middlename/});  
     } else {  
         &Apache::lonnet::logthis('grades.pm: no name data for '.$uname.  
                                  '@'.$udom.':'.$tmp);  
     }  
     return $fullname;  
 }  
   
 #--- Format fullname, username:domain if different for display  #--- Format fullname, username:domain if different for display
 #--- Use anywhere where the student names are listed  #--- Use anywhere where the student names are listed
 sub nameUserString {  sub nameUserString {
     my ($type,$fullname,$uname,$udom) = @_;      my ($type,$fullname,$uname,$udom) = @_;
     if ($type eq 'header') {      if ($type eq 'header') {
  return '<b>&nbsp;Fullname&nbsp;</b><font color="#999999">(Username)</font>&nbsp;';   return '<b>&nbsp;Fullname&nbsp;</b><font color="#999999">(Username)</font>';
     } else {      } else {
  return '&nbsp;'.$fullname.'<font color="#999999">&nbsp;('.$uname.   return '&nbsp;'.$fullname.'<font color="#999999">&nbsp;('.$uname.
     ($ENV{'user.domain'} eq $udom ? '' : ' ('.$udom.')').')</font>';      ($env{'user.domain'} eq $udom ? '' : ' ('.$udom.')').')</font>';
     }      }
 }  }
   
Line 136  sub nameUserString { Line 107  sub nameUserString {
 #--- Indicate if a response type is coded handgraded or not. ---  #--- Indicate if a response type is coded handgraded or not. ---
 sub response_type {  sub response_type {
     my ($url,$symb) = shift;      my ($url,$symb) = shift;
     $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url))) if ($symb eq '');      $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url))) if ($symb eq '');
     my $allkeys = &Apache::lonnet::metadata($url,'keys');      my $allkeys = &Apache::lonnet::metadata($url,'keys');
     my %vPart;      my %vPart;
     foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) {      foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) {
Line 167  sub response_type { Line 138  sub response_type {
     return \@partlist,\%handgrade,\%responseType;      return \@partlist,\%handgrade,\%responseType;
 }  }
   
   sub get_display_part {
       my ($partID,$url,$symb)=@_;
       if (!defined($symb) || $symb eq '') {
    $symb=$env{'form.symb'};
    if ($symb eq '') { $symb=&Apache::lonnet::symbread($url) }
       }
       my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display',$symb);
       if (defined($display) and $display ne '') {
    $display.= " (<font color=\"#999900\">id $partID</font>)";
       } else {
    $display=$partID;
       }
       return $display;
   }
   
 #--- Show resource title  #--- Show resource title
 #--- and parts and response type  #--- and parts and response type
 sub showResourceInfo {  sub showResourceInfo {
Line 194  sub showResourceInfo { Line 180  sub showResourceInfo {
     }      }
     $partsseen{$partID}=1;      $partsseen{$partID}=1;
  }   }
  $result.='<td><b>Part </b>'.$partID.' <font color="#999999">'.   my $display_part=&get_display_part($partID,$url);
    $result.='<td><b>Part: </b>'.$display_part.' <font color="#999999">'.
     $resID.'</font></td>'.      $resID.'</font></td>'.
     '<td><b>Type: </b>'.$responsetype.'</td></tr>';      '<td><b>Type: </b>'.$responsetype.'</td></tr>';
 #    '<td><b>Handgrade: </b>'.$handgrade.'</td></tr>';  #    '<td><b>Handgrade: </b>'.$handgrade.'</td></tr>';
Line 213  sub get_order { Line 200  sub get_order {
        ('grade_domain' => $udom),         ('grade_domain' => $udom),
        ('grade_symb' => $symb),         ('grade_symb' => $symb),
        ('grade_courseid' =>          ('grade_courseid' => 
         $ENV{'request.course.id'}),          $env{'request.course.id'}),
        ('grade_username' => $uname));         ('grade_username' => $uname));
     (undef,$subresult)=split(/_HASH_REF__/,$subresult,2);      (undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
     my %analyze=&Apache::lonnet::str2hash($subresult);      my %analyze=&Apache::lonnet::str2hash($subresult);
Line 284  sub cleanRecord { Line 271  sub cleanRecord {
     '<tr valign="top"><td>'.$grayFont.'Option ID</font></td>'.      '<tr valign="top"><td>'.$grayFont.'Option ID</font></td>'.
     $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';      $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';
     } elsif ($response eq 'essay') {      } elsif ($response eq 'essay') {
  if (! exists ($ENV{'form.'.$symb})) {   if (! exists ($env{'form.'.$symb})) {
     my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade',      my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade',
   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},    $env{'course.'.$env{'request.course.id'}.'.domain'},
   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});    $env{'course.'.$env{'request.course.id'}.'.num'});
   
     my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};      my $loginuser = $env{'user.name'}.':'.$env{'user.domain'};
     $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';      $env{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';
     $ENV{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';      $env{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';
     $ENV{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';      $env{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';
     $ENV{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';      $env{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
     $ENV{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob.      $env{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob.
  }   }
  $answer =~ s-\n-<br />-g;   $answer =~ s-\n-<br />-g;
  return '<br /><br /><blockquote><tt>'.&keywords_highlight($answer).'</tt></blockquote>';   return '<br /><br /><blockquote><tt>'.&keywords_highlight($answer).'</tt></blockquote>';
       } elsif ( $response eq 'organic') {
    my $result='Smile representation: "<tt>'.$answer.'</tt>"';
    my $jme=$record->{$version."resource.$partid.$respid.molecule"};
    $result.=&Apache::chemresponse::jme_img($jme,$answer,400);
    return $result;
     }      }
     return $answer;      return $answer;
 }  }
Line 342  COMMONJSFUNCTIONS Line 334  COMMONJSFUNCTIONS
 #--- section, ids and fullnames for each user.  #--- section, ids and fullnames for each user.
 sub getclasslist {  sub getclasslist {
     my ($getsec,$filterlist) = @_;      my ($getsec,$filterlist) = @_;
     $getsec = $getsec eq '' ? 'all' : $getsec;      my @getsec;
       if (!ref($getsec)) {
    if ($getsec ne '' && $getsec ne 'all') {
       @getsec=($getsec);
    }
       } else {
    @getsec=@{$getsec};
       }
       if (grep(/^all$/,@getsec)) { undef(@getsec); }
   
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
     # Bail out if we were unable to get the classlist      # Bail out if we were unable to get the classlist
     return if (! defined($classlist));      return if (! defined($classlist));
     #      #
     my %sections;      my %sections;
     my %fullnames;      my %fullnames;
     foreach (keys(%$classlist)) {      foreach my $student (keys(%$classlist)) {
         # the following undefs are for 'domain', and 'username' respectively.          my $end      = 
  my (undef,undef,$end,$start,$id,$section,$fullname,$status)=              $classlist->{$student}->[&Apache::loncoursedata::CL_END()];
             @{$classlist->{$_}};          my $start    = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_START()];
           my $id       = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_ID()];
           my $section  = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];
           my $fullname = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_FULLNAME()];
           my $status   = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_STATUS()];
  # filter students according to status selected   # filter students according to status selected
  if ($filterlist && $ENV{'form.Status'} ne 'Any') {   if ($filterlist && $env{'form.Status'} ne 'Any') {
     if ($ENV{'form.Status'} ne $status) {      if ($env{'form.Status'} ne $status) {
  delete ($classlist->{$_});   delete ($classlist->{$student});
  next;   next;
     }      }
  }   }
  $section = ($section ne '' ? $section : 'no');   $section = ($section ne '' ? $section : 'none');
  if (&canview($section)) {   if (&canview($section)) {
     if ($getsec eq 'all' || $getsec eq $section) {      if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {
  $sections{$section}++;   $sections{$section}++;
  $fullnames{$_}=$fullname;   $fullnames{$student}=$fullname;
     } else {      } else {
  delete($classlist->{$_});   delete($classlist->{$student});
     }      }
  } else {   } else {
     delete($classlist->{$_});      delete($classlist->{$student});
  }   }
     }      }
     my %seen = ();      my %seen = ();
Line 420  sub canview { Line 430  sub canview {
 #--- Retrieve the grade status of a student for all the parts  #--- Retrieve the grade status of a student for all the parts
 sub student_gradeStatus {  sub student_gradeStatus {
     my ($url,$symb,$udom,$uname,$partlist) = @_;      my ($url,$symb,$udom,$uname,$partlist) = @_;
     my %record     = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);      my %record     = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname);
     my %partstatus = ();      my %partstatus = ();
     foreach (@$partlist) {      foreach (@$partlist) {
  my ($status,undef)   = split(/_/,$record{"resource.$_.solved"},2);   my ($status,undef)   = split(/_/,$record{"resource.$_.solved"},2);
Line 447  sub jscriptNform { Line 457  sub jscriptNform {
     $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".      $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n".
  '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
  '<input type="hidden" name="url"     value="'.$url.'" />'."\n".   '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
  '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n".   '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n".
  '<input type="hidden" name="Status"  value="'.$ENV{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
  '<input type="hidden" name="command" value="submission" />'."\n".   '<input type="hidden" name="command" value="submission" />'."\n".
  '<input type="hidden" name="student" value="" />'."\n".   '<input type="hidden" name="student" value="" />'."\n".
  '<input type="hidden" name="userdom" value="" />'."\n".   '<input type="hidden" name="userdom" value="" />'."\n".
Line 470  sub most_similar { Line 480  sub most_similar {
   
     $uessay=~s/\W+/ /gs;      $uessay=~s/\W+/ /gs;
   
   # ignore empty submissions (occuring when only files are sent)
   
       unless ($uessay=~/\w+/) { return ''; }
   
 # these will be returned. Do not care if not at least 50 percent similar  # these will be returned. Do not care if not at least 50 percent similar
     my $limit=0.6;      my $limit=0.6;
     my $sname='';      my $sname='';
Line 510  sub most_similar { Line 524  sub most_similar {
 sub verifyreceipt {  sub verifyreceipt {
     my $request  = shift;      my $request  = shift;
   
     my $courseid = $ENV{'request.course.id'};      my $courseid = $env{'request.course.id'};
     my $receipt  = &Apache::lonnet::recprefix($courseid).'-'.      my $receipt  = &Apache::lonnet::recprefix($courseid).'-'.
  $ENV{'form.receipt'};   $env{'form.receipt'};
     $receipt     =~ s/[^\-\d]//g;      $receipt     =~ s/[^\-\d]//g;
     my $url      = $ENV{'form.url'};      my $url      = $env{'form.url'};
     my $symb     = $ENV{'form.symb'};      my $symb     = $env{'form.symb'};
     unless ($symb) {      unless ($symb) {
  $symb    = &Apache::lonnet::symbread($url);   $symb    = &Apache::lonnet::symbread($url);
     }      }
   
     my $title.='<h3><font color="#339933">Verifying Submission Receipt '.      my $title.='<h3><font color="#339933">Verifying Submission Receipt '.
  $receipt.'</h3></font>'."\n".   $receipt.'</h3></font>'."\n".
  '<font size=+1><b>Resource: </b>'.$ENV{'form.probTitle'}.'</font><br><br>'."\n";   '<font size=+1><b>Resource: </b>'.$env{'form.probTitle'}.'</font><br><br>'."\n";
   
     my ($string,$contents,$matches) = ('','',0);      my ($string,$contents,$matches) = ('','',0);
     my (undef,undef,$fullname) = &getclasslist('all','0');      my (undef,undef,$fullname) = &getclasslist('all','0');
           
     my $receiptparts=0;      my $receiptparts=0;
     if ($ENV{"course.$courseid.receiptalg"} eq 'receipt2') { $receiptparts=1; }      if ($env{"course.$courseid.receiptalg"} eq 'receipt2') { $receiptparts=1; }
     my $parts=['0'];      my $parts=['0'];
     if ($receiptparts) { ($parts)=&response_type($url,$symb); }      if ($receiptparts) { ($parts)=&response_type($url,$symb); }
     foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {      foreach (sort 
        {
    if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
        return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
    }
    return $a cmp $b;
        } (keys(%$fullname))) {
  my ($uname,$udom)=split(/\:/);   my ($uname,$udom)=split(/\:/);
  foreach my $part (@$parts) {   foreach my $part (@$parts) {
     if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) {      if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) {
Line 577  sub listStudents { Line 597  sub listStudents {
     my ($request) = shift;      my ($request) = shift;
   
     my ($symb,$url) = &get_symb_and_url($request);      my ($symb,$url) = &get_symb_and_url($request);
     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'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
     my $submitonly= $ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'};      my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'};
   
     my $viewgrade = $ENV{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View';      my $viewgrade = $env{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View';
     $ENV{'form.probTitle'} = $ENV{'form.probTitle'} eq '' ?       $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? 
  &Apache::lonnet::gettitle($symb) : $ENV{'form.probTitle'};   &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'};
   
     my $result='<h3><font color="#339933">&nbsp;'.$viewgrade.      my $result='<h3><font color="#339933">&nbsp;'.$viewgrade.
  ' Submissions for a Student or a Group of Students</font></h3>';   ' Submissions for a Student or a Group of Students</font></h3>';
   
     my ($table,undef,$hdgrade,$partlist,$handgrade) = &showResourceInfo($url,$ENV{'form.probTitle'},($ENV{'form.showgrading'} eq 'yes'));      my ($table,undef,$hdgrade,$partlist,$handgrade) = &showResourceInfo($url,$env{'form.probTitle'},($env{'form.showgrading'} eq 'yes'));
   
     $request->print(<<LISTJAVASCRIPT);      $request->print(<<LISTJAVASCRIPT);
 <script type="text/javascript" language="javascript">  <script type="text/javascript" language="javascript">
Line 627  LISTJAVASCRIPT Line 647  LISTJAVASCRIPT
     &commonJSfunctions($request);      &commonJSfunctions($request);
     $request->print($result);      $request->print($result);
   
     my $checkhdgrade = ($ENV{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked' : '';      my $checkhdgrade = ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked' : '';
     my $checklastsub = $checkhdgrade eq '' ? 'checked' : '';      my $checklastsub = $checkhdgrade eq '' ? 'checked' : '';
     my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'.      my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'.
  "\n".$table.   "\n".$table.
  '&nbsp;<b>View Problem Text: </b><input type="radio" name="vProb" value="no" checked="on" /> no '."\n".   '&nbsp;<b>View Problem Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
  '<input type="radio" name="vProb" value="yes" /> one student '."\n".   '<label><input type="radio" name="vProb" value="yes" /> one student </label>'."\n".
  '<input type="radio" name="vProb" value="all" /> all students <br />'."\n".   '<label><input type="radio" name="vProb" value="all" /> all students </label><br />'."\n".
  '&nbsp;<b>View Answer: </b><input type="radio" name="vAns" value="no"  /> no '."\n".   '&nbsp;<b>View Answer: </b><label><input type="radio" name="vAns" value="no"  /> no </label>'."\n".
  '<input type="radio" name="vAns" value="yes" /> one student '."\n".   '<label><input type="radio" name="vAns" value="yes" /> one student </label>'."\n".
  '<input type="radio" name="vAns" value="all" checked="on" /> all students <br />'."\n".   '<label><input type="radio" name="vAns" value="all" checked="on" /> all students </label><br />'."\n".
  '&nbsp;<b>Submissions: </b>'."\n";   '&nbsp;<b>Submissions: </b>'."\n";
     if ($ENV{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) {      if ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) {
  $gradeTable.='<input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> essay part only'."\n";   $gradeTable.='<label><input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> essay part only </label>'."\n";
     }      }
   
     my $saveStatus = $ENV{'form.Status'} eq '' ? 'Active' : $ENV{'form.Status'};      my $saveStatus = $env{'form.Status'} eq '' ? 'Active' : $env{'form.Status'};
     $ENV{'form.Status'} = $saveStatus;      $env{'form.Status'} = $saveStatus;
   
     $gradeTable.='<input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only'."\n".      $gradeTable.='<label><input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only </label>'."\n".
  '<input type="radio" name="lastSub" value="last" /> last submission & parts info'."\n".   '<label><input type="radio" name="lastSub" value="last" /> last submission & parts info </label>'."\n".
  '<input type="radio" name="lastSub" value="datesub" /> by dates and submissions'."\n".   '<label><input type="radio" name="lastSub" value="datesub" /> by dates and submissions </label>'."\n".
  '<input type="radio" name="lastSub" value="all" /> all details'."\n".   '<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n".
  '<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".   '<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
  '<input type="hidden" name="submitonly"  value="'.$submitonly.'" />'."\n".   '<input type="hidden" name="submitonly"  value="'.$submitonly.'" />'."\n".
  '<input type="hidden" name="handgrade"   value="'.$ENV{'form.handgrade'}.'" /><br />'."\n".   '<input type="hidden" name="handgrade"   value="'.$env{'form.handgrade'}.'" /><br />'."\n".
  '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" /><br />'."\n".   '<input type="hidden" name="showgrading" value="'.$env{'form.showgrading'}.'" /><br />'."\n".
  '<input type="hidden" name="saveState"   value="'.$ENV{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState"   value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="probTitle"   value="'.$ENV{'form.probTitle'}.'" />'."\n".   '<input type="hidden" name="probTitle"   value="'.$env{'form.probTitle'}.'" />'."\n".
  '<input type="hidden" name="url"  value="'.$url.'" />'."\n".   '<input type="hidden" name="url"  value="'.$url.'" />'."\n".
  '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
  '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n";   '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n";
   
     if (exists($ENV{'form.gradingMenu'}) && exists($ENV{'form.Status'})) {      if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) {
  $gradeTable.='<input type="hidden" name="Status"   value="'.$ENV{'form.Status'}.'" />'."\n";   $gradeTable.='<input type="hidden" name="Status"   value="'.$env{'form.Status'}.'" />'."\n";
     } else {      } else {
  $gradeTable.='<b>Student Status:</b> '.   $gradeTable.='<b>Student Status:</b> '.
     &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);').'<br />';      &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);').'<br />';
Line 669  LISTJAVASCRIPT Line 689  LISTJAVASCRIPT
     $gradeTable.='To '.lc($viewgrade).' a submission or a group of submissions, click on the check box(es) '.      $gradeTable.='To '.lc($viewgrade).' a submission or a group of submissions, click on the check box(es) '.
  'next to the student\'s name(s). Then click on the Next button.<br />'."\n".   'next to the student\'s name(s). Then click on the Next button.<br />'."\n".
  '<input type="hidden" name="command" value="processGroup" />'."\n";   '<input type="hidden" name="command" value="processGroup" />'."\n";
   
   # checkall buttons
       $gradeTable.=&check_script('gradesub', 'stuinfo');
     $gradeTable.='<input type="button" '."\n".      $gradeTable.='<input type="button" '."\n".
  'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n".   'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n".
  'value="Next->" />'."\n";   'value="Next->" /> <br />'."\n";
     $gradeTable.='<input type="checkbox" name="checkPlag" checked="on">Check For Plagiarism</input>';      $gradeTable.=&check_buttons();
     my (undef, undef, $fullname) = &getclasslist($getsec,'1');        $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="on" />Check For Plagiarism</label>';
       my ($classlist, undef, $fullname) = &getclasslist($getsec,'1');
     $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'.      $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'.
  '<table border="0"><tr bgcolor="#e6ffff">';   '<table border="0"><tr bgcolor="#e6ffff">';
     my $loop = 0;      my $loop = 0;
     while ($loop < 2) {      while ($loop < 2) {
  $gradeTable.='<td><b>&nbsp;No.</b>&nbsp;</td><td><b>&nbsp;Select&nbsp;</b></td>'.   $gradeTable.='<td><b>&nbsp;No.</b>&nbsp;</td><td><b>&nbsp;Select&nbsp;</b></td>'.
     '<td>'.&nameUserString('header').'</td>';      '<td>'.&nameUserString('header').'&nbsp;Section/Group</td>';
  if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {   if ($env{'form.showgrading'} eq 'yes' 
       && $submitonly ne 'queued'
       && $submitonly ne 'all') {
     foreach (sort(@$partlist)) {      foreach (sort(@$partlist)) {
  $gradeTable.='<td><b>&nbsp;Part '.(split(/_/))[0].' Status&nbsp;</b></td>';   my $display_part=&get_display_part((split(/_/))[0],$url,$symb);
    $gradeTable.='<td><b>&nbsp;Part: '.$display_part.
       ' Status&nbsp;</b></td>';
     }      }
    } elsif ($submitonly eq 'queued') {
       $gradeTable.='<td><b>&nbsp;'.&mt('Queue Status').'&nbsp;</b></td>';
  }   }
  $loop++;   $loop++;
 # $gradeTable.='<td></td>' if ($loop%2 ==1);  # $gradeTable.='<td></td>' if ($loop%2 ==1);
Line 691  LISTJAVASCRIPT Line 721  LISTJAVASCRIPT
     $gradeTable.='</tr>'."\n";      $gradeTable.='</tr>'."\n";
   
     my $ctr = 0;      my $ctr = 0;
     foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {      foreach my $student (sort 
    {
        if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
    return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
        }
        return $a cmp $b;
    }
    (keys(%$fullname))) {
  my ($uname,$udom) = split(/:/,$student);   my ($uname,$udom) = split(/:/,$student);
   
  my %status = ();   my %status = ();
  if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {  
    if ($submitonly eq 'queued') {
       my %queue_status = 
    &Apache::bridgetask::get_student_status($symb,$cdom,$cnum,
    $udom,$uname);
       next if (!defined($queue_status{'gradingqueue'}));
       $status{'gradingqueue'} = $queue_status{'gradingqueue'};
    }
   
    if ($env{'form.showgrading'} eq 'yes' 
       && $submitonly ne 'queued'
       && $submitonly ne 'all') {
     (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist);      (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
     my $submitted = 0;      my $submitted = 0;
     my $graded = 0;      my $graded = 0;
       my $incorrect = 0;
     foreach (keys(%status)) {      foreach (keys(%status)) {
  $submitted = 1 if ($status{$_} ne 'nothing');   $submitted = 1 if ($status{$_} ne 'nothing');
  $graded = 1 if ($status{$_} !~ /^correct/);   $graded = 1 if ($status{$_} =~ /^ungraded/);
    $incorrect = 1 if ($status{$_} =~ /^incorrect/);
   
  my ($foo,$partid,$foo1) = split(/\./,$_);   my ($foo,$partid,$foo1) = split(/\./,$_);
  if ($status{'resource.'.$partid.'.submitted_by'} ne '') {   if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
     $submitted = 0;      $submitted = 0;
Line 711  LISTJAVASCRIPT Line 762  LISTJAVASCRIPT
  $status{'resource.'.$partid.'.submitted_by'}.'" />';   $status{'resource.'.$partid.'.submitted_by'}.'" />';
  }   }
     }      }
       
     next if (!$submitted && ($submitonly eq 'yes' ||      next if (!$submitted && ($submitonly eq 'yes' ||
      $submitonly eq 'incorrect' ||       $submitonly eq 'incorrect' ||
      $submitonly eq 'graded'));       $submitonly eq 'graded'));
     next if (!$graded && ($submitonly eq 'graded' ||      next if (!$graded && ($submitonly eq 'graded'));
   $submitonly eq 'incorrect'));      next if (!$incorrect && $submitonly eq 'incorrect');
  }   }
   
  $ctr++;   $ctr++;
    my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];
   
  if ( $perm{'vgr'} eq 'F' ) {   if ( $perm{'vgr'} eq 'F' ) {
     $gradeTable.='<tr bgcolor="#ffffe6">' if ($ctr%2 ==1);      $gradeTable.='<tr bgcolor="#ffffe6">' if ($ctr%2 ==1);
     $gradeTable.='<td align="right">'.$ctr.'&nbsp;</td>'.      $gradeTable.='<td align="right">'.$ctr.'&nbsp;</td>'.
  '<td align="center"><input type=checkbox name="stuinfo" value="'.                 '<td align="center"><label><input type=checkbox name="stuinfo" value="'.
  $student.':'.$$fullname{$student}.'&nbsp;"></td>'."\n".                 $student.':'.$$fullname{$student}.':::SECTION'.$section.
  '<td>'.&nameUserString(undef,$$fullname{$student},$uname,$udom).'</td>'."\n";         ')&nbsp;" />&nbsp;&nbsp;</label></td>'."\n".'<td>'.
          &nameUserString(undef,$$fullname{$student},$uname,$udom).
          '&nbsp;'.$section.'</td>'."\n";
   
     if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {      if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
  foreach (sort keys(%status)) {   foreach (sort keys(%status)) {
     next if (/^resource.*?submitted_by$/);      next if (/^resource.*?submitted_by$/);
     $gradeTable.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";      $gradeTable.='<td align="center">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";
  }   }
     }      }
 #    $gradeTable.='<td></td>' if ($ctr%2 ==1);  #    $gradeTable.='<td></td>' if ($ctr%2 ==1);
Line 738  LISTJAVASCRIPT Line 794  LISTJAVASCRIPT
     }      }
     if ($ctr%2 ==1) {      if ($ctr%2 ==1) {
  $gradeTable.='<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';   $gradeTable.='<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>';
     if ($ENV{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {      if ($env{'form.showgrading'} eq 'yes' 
    && $submitonly ne 'queued'
    && $submitonly ne 'all') {
  foreach (@$partlist) {   foreach (@$partlist) {
     $gradeTable.='<td>&nbsp;</td>';      $gradeTable.='<td>&nbsp;</td>';
  }   }
       } elsif ($submitonly eq 'queued') {
    $gradeTable.='<td>&nbsp;</td>';
     }      }
  $gradeTable.='</tr>';   $gradeTable.='</tr>';
     }      }
   
     $gradeTable.='</table></td></tr></table>'.      $gradeTable.='</table></td></tr></table>'."\n".
  '<input type="button" '.   '<input type="button" '.
  'onClick="javascript:checkSelect(this.form.stuinfo);" '.   'onClick="javascript:checkSelect(this.form.stuinfo);" '.
  'value="Next->" /></form>'."\n";   'value="Next->" /></form>'."\n";
Line 758  LISTJAVASCRIPT Line 818  LISTJAVASCRIPT
     my $submissions='submissions';      my $submissions='submissions';
     if ($submitonly eq 'incorrect') { $submissions = 'incorrect submissions'; }      if ($submitonly eq 'incorrect') { $submissions = 'incorrect submissions'; }
     if ($submitonly eq 'graded'   ) { $submissions = 'ungraded submissions'; }      if ($submitonly eq 'graded'   ) { $submissions = 'ungraded submissions'; }
       if ($submitonly eq 'queued'   ) { $submissions = 'queued submissions'; }
     $gradeTable='<br />&nbsp;<font color="red">'.      $gradeTable='<br />&nbsp;<font color="red">'.
  'No '.$submissions.' found for this resource for any students. ('.$num_students.   'No '.$submissions.' found for this resource for any students. ('.$num_students.
  ' students checked for '.$submissions.')</font><br />';   ' students checked for '.$submissions.')</font><br />';
Line 771  LISTJAVASCRIPT Line 832  LISTJAVASCRIPT
 }  }
   
 #---- Called from the listStudents routine  #---- Called from the listStudents routine
   
   sub check_script {
       my ($form, $type)=@_;
       my $chkallscript='<script type="text/javascript">
       function checkall() {
           for (i=0; i<document.forms.'.$form.'.elements.length; i++) {
               ele = document.forms.'.$form.'.elements[i];
               if (ele.name == "'.$type.'") {
               document.forms.'.$form.'.elements[i].checked=true;
                                          }
           }
       }
   
       function checksec() {
           for (i=0; i<document.forms.'.$form.'.elements.length; i++) {
               ele = document.forms.'.$form.'.elements[i];
              string = document.forms.'.$form.'.chksec.value;
              if
             (ele.value.indexOf(":::SECTION"+string)>0) {
                 document.forms.'.$form.'.elements[i].checked=true;
               }
           }
       }
   
   
       function uncheckall() {
           for (i=0; i<document.forms.'.$form.'.elements.length; i++) {
               ele = document.forms.'.$form.'.elements[i];
               if (ele.name == "'.$type.'") {
               document.forms.'.$form.'.elements[i].checked=false;
                                          }
           }
       }
   
   </script>'."\n";
       return $chkallscript;
   }
   
   sub check_buttons {
       my $buttons.='<input type="button" onclick="checkall()" value="Check All" />';
       $buttons.='<input type="button" onclick="uncheckall()" value="Uncheck All" />&nbsp;';
       $buttons.='<input type="button" onclick="checksec()" value="Check Section/Group" />';
       $buttons.='<input type="text" size="5" name="chksec" />&nbsp;';
       return $buttons;
   }
   
 #     Displays the submissions for one student or a group of students  #     Displays the submissions for one student or a group of students
 sub processGroup {  sub processGroup {
     my ($request)  = shift;      my ($request)  = shift;
Line 780  sub processGroup { Line 887  sub processGroup {
   
     foreach (@stuchecked) {      foreach (@stuchecked) {
  my ($uname,$udom,$fullname) = split(/:/);   my ($uname,$udom,$fullname) = split(/:/);
  $ENV{'form.student'}        = $uname;   $env{'form.student'}        = $uname;
  $ENV{'form.userdom'}        = $udom;   $env{'form.userdom'}        = $udom;
  $ENV{'form.fullname'}       = $fullname;   $env{'form.fullname'}       = $fullname;
  &submission($request,$ctr,$total);   &submission($request,$ctr,$total);
  $ctr++;   $ctr++;
     }      }
Line 975  sub sub_page_kw_js { Line 1082  sub sub_page_kw_js {
     my $request = shift;      my $request = shift;
     my $iconpath = $request->dir_config('lonIconsURL');      my $iconpath = $request->dir_config('lonIconsURL');
     &commonJSfunctions($request);      &commonJSfunctions($request);
       my $docopen=&Apache::lonhtmlcommon::javascript_docopen();
       $docopen=~s/^document\.//;
     $request->print(<<SUBJAVASCRIPT);      $request->print(<<SUBJAVASCRIPT);
 <script type="text/javascript" language="javascript">  <script type="text/javascript" language="javascript">
   
Line 1084  sub sub_page_kw_js { Line 1193  sub sub_page_kw_js {
     var ypos = (screen.height-height)/2-30;      var ypos = (screen.height-height)/2-30;
     ypos = (ypos < 0) ? '0' : ypos;      ypos = (ypos < 0) ? '0' : ypos;
   
     pWin = window.open('', 'MessageCenter', 'toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=600,height='+height);      pWin = window.open('', 'MessageCenter', 'resizable=yes,toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=600,height='+height);
     pWin.focus();      pWin.focus();
     pDoc = pWin.document;      pDoc = pWin.document;
     pDoc.open('text/html','replace');      pDoc.$docopen;
     pDoc.write("<html><head>");      pDoc.write("<html><head>");
     pDoc.write("<title>Message Central</title>");      pDoc.write("<title>Message Central</title>");
   
Line 1215  sub sub_page_kw_js { Line 1324  sub sub_page_kw_js {
     var ypos = (screen.height-330)/2-30;      var ypos = (screen.height-330)/2-30;
     ypos = (ypos < 0) ? '0' : ypos;      ypos = (ypos < 0) ? '0' : ypos;
   
     hwdWin = window.open('', 'KeywordHighlightCentral', 'toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx='+xpos+',screeny='+ypos);      hwdWin = window.open('', 'KeywordHighlightCentral', 'resizeable=yes,toolbar=no,location=no,scrollbars=no,width=400,height=300,screenx='+xpos+',screeny='+ypos);
     hwdWin.focus();      hwdWin.focus();
     var hDoc = hwdWin.document;      var hDoc = hwdWin.document;
     hDoc.open('text/html','replace');      hDoc.$docopen;
     hDoc.write("<html><head>");      hDoc.write("<html><head>");
     hDoc.write("<title>Highlight Central</title>");      hDoc.write("<title>Highlight Central</title>");
   
Line 1289  sub gradeBox { Line 1398  sub gradeBox {
   '' : $$record{'resource.'.$partid.'.awarded'}*$wgt);    '' : $$record{'resource.'.$partid.'.awarded'}*$wgt);
     my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";      my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";
   
       my $display_part=&get_display_part($partid,undef,$symb);
   
       my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
          [$partid]);
       my $aggtries = $$record{'resource.'.$partid.'.tries'};
       if ($last_resets{$partid}) {
           $aggtries = &get_num_tries($record,$last_resets{$partid},$partid);
       }
   
     $result.='<table border="0"><tr><td>'.      $result.='<table border="0"><tr><td>'.
  '<b>Part </b>'.$partid.' <b>Points: </b></td><td>'."\n";   '<b>Part: </b>'.$display_part.' <b>Points: </b></td><td>'."\n";
   
     my $ctr = 0;      my $ctr = 0;
     $result.='<table border="0"><tr>'."\n";  # display radio buttons in a nice table 10 across      $result.='<table border="0"><tr>'."\n";  # display radio buttons in a nice table 10 across
     while ($ctr<=$wgt) {      while ($ctr<=$wgt) {
  $result.= '<td><nobr><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.   $result.= '<td><nobr><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
     'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','.      'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','.
     $ctr.')" value="'.$ctr.'" '.      $ctr.')" value="'.$ctr.'" '.
     ($score eq $ctr ? 'checked':'').' /> '.$ctr."</nobr></td>\n";      ($score eq $ctr ? 'checked':'').' /> '.$ctr."</label></nobr></td>\n";
  $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');   $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
  $ctr++;   $ctr++;
     }      }
Line 1327  sub gradeBox { Line 1445  sub gradeBox {
     $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="" />'."\n".      $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="" />'."\n".
  '<input type="hidden" name="oldpts'.$counter.'_'.$partid.'" value="'.$score.'" />'."\n".   '<input type="hidden" name="oldpts'.$counter.'_'.$partid.'" value="'.$score.'" />'."\n".
  '<input type="hidden" name="solved'.$counter.'_'.$partid.'" value="'.   '<input type="hidden" name="solved'.$counter.'_'.$partid.'" value="'.
  $$record{'resource.'.$partid.'.solved'}.'" />'."\n";   $$record{'resource.'.$partid.'.solved'}.'" />'."\n".
           '<input type="hidden" name="totaltries'.$counter.'_'.$partid.'" value="'.
           $$record{'resource.'.$partid.'.tries'}.'" />'."\n".
           '<input type="hidden" name="aggtries'.$counter.'_'.$partid.'" value="'.
           $aggtries.'" />'."\n";
     $result.='</td></tr></table>'."\n";      $result.='</td></tr></table>'."\n";
     return $result;      return $result;
 }  }
Line 1337  sub show_problem { Line 1459  sub show_problem {
     my $rendered;      my $rendered;
     if ($mode eq 'both' or $mode eq 'text') {      if ($mode eq 'both' or $mode eq 'text') {
  $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,   $rendered=&Apache::loncommon::get_student_view($symb,$uname,$udom,
      $ENV{'request.course.id'});       $env{'request.course.id'});
     }      }
     if ($removeform) {      if ($removeform) {
  $rendered=~s|<form(.*?)>||g;   $rendered=~s|<form(.*?)>||g;
Line 1347  sub show_problem { Line 1469  sub show_problem {
     my $companswer;      my $companswer;
     if ($mode eq 'both' or $mode eq 'answer') {      if ($mode eq 'both' or $mode eq 'answer') {
  $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,   $companswer=&Apache::loncommon::get_student_answers($symb,$uname,$udom,
     $ENV{'request.course.id'});      $env{'request.course.id'});
     }      }
     if ($removeform) {      if ($removeform) {
  $companswer=~s|<form(.*?)>||g;   $companswer=~s|<form(.*?)>||g;
Line 1363  sub show_problem { Line 1485  sub show_problem {
  } else {   } else {
     $result.='Correct answer: ';      $result.='Correct answer: ';
  }   }
  $result.=$ENV{'form.fullname'}.'</b></td></tr>';   $result.=$env{'form.fullname'}.'</b></td></tr>';
     }      }
     if ($mode eq 'both') {      if ($mode eq 'both') {
  $result.='<tr><td bgcolor="#ffffff">'.$rendered.'<br />';   $result.='<tr><td bgcolor="#ffffff">'.$rendered.'<br />';
Line 1382  sub show_problem { Line 1504  sub show_problem {
 sub submission {  sub submission {
     my ($request,$counter,$total) = @_;      my ($request,$counter,$total) = @_;
   
     (my $url=$ENV{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;      (my $url=$env{'form.url'})=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
     my ($uname,$udom)     = ($ENV{'form.student'},$ENV{'form.userdom'});      my ($uname,$udom)     = ($env{'form.student'},$env{'form.userdom'});
     $udom = ($udom eq '' ? $ENV{'user.domain'} : $udom); #has form.userdom changed for a student?      $udom = ($udom eq '' ? $env{'user.domain'} : $udom); #has form.userdom changed for a student?
     my $usec = &Apache::lonnet::getsection($udom,$uname,$ENV{'request.course.id'});      my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'});
     $ENV{'form.fullname'} = &get_fullname ($uname,$udom) if $ENV{'form.fullname'} eq '';      $env{'form.fullname'} = &Apache::loncommon::plainname($uname,$udom,'lastname') if $env{'form.fullname'} eq '';
   
     my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
     if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }      if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
   
     if (!&canview($usec)) {      if (!&canview($usec)) {
  $request->print('<font color="red">Unable to view requested student.('.   $request->print('<font color="red">Unable to view requested student.('.
  $uname.$udom.$usec.$ENV{'request.course.id'}.')</font>');   $uname.'@'.$udom.' in section '.$usec.' in course id '.
    $env{'request.course.id'}.')</font>');
  $request->print(&show_grading_menu_form($symb,$url));   $request->print(&show_grading_menu_form($symb,$url));
  return;   return;
     }      }
   
     if (!$ENV{'form.lastSub'}) { $ENV{'form.lastSub'} = 'datesub'; }      if (!$env{'form.lastSub'}) { $env{'form.lastSub'} = 'datesub'; }
     if (!$ENV{'form.vProb'}) { $ENV{'form.vProb'} = 'yes'; }      if (!$env{'form.vProb'}) { $env{'form.vProb'} = 'yes'; }
     if (!$ENV{'form.vAns'}) { $ENV{'form.vAns'} = 'yes'; }      if (!$env{'form.vAns'}) { $env{'form.vAns'} = 'yes'; }
     my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');      my $last = ($env{'form.lastSub'} eq 'last' ? 'last' : '');
     my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').      my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').
  '/check.gif" height="16" border="0" />';   '/check.gif" height="16" border="0" />';
   
     # header info      # header info
     if ($counter == 0) {      if ($counter == 0) {
  &sub_page_js($request);   &sub_page_js($request);
  &sub_page_kw_js($request) if ($ENV{'form.handgrade'} eq 'yes');   &sub_page_kw_js($request) if ($env{'form.handgrade'} eq 'yes');
  $ENV{'form.probTitle'} = $ENV{'form.probTitle'} eq '' ?    $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? 
     &Apache::lonnet::gettitle($symb) : $ENV{'form.probTitle'};      &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'};
   
  $request->print('<h3>&nbsp;<font color="#339933">Submission Record</font></h3>'."\n".   $request->print('<h3>&nbsp;<font color="#339933">Submission Record</font></h3>'."\n".
  '<font size=+1>&nbsp;<b>Resource: </b>'.$ENV{'form.probTitle'}.'</font>'."\n");   '<font size=+1>&nbsp;<b>Resource: </b>'.$env{'form.probTitle'}.'</font>'."\n");
   
  if ($ENV{'form.handgrade'} eq 'no') {   if ($env{'form.handgrade'} eq 'no') {
     my $checkMark='<br /><br />&nbsp;<b>Note:</b> Part(s) graded correct by the computer is marked with a '.      my $checkMark='<br /><br />&nbsp;<b>Note:</b> Part(s) graded correct by the computer is marked with a '.
  $checkIcon.' symbol.'."\n";   $checkIcon.' symbol.'."\n";
     $request->print($checkMark);      $request->print($checkMark);
Line 1423  sub submission { Line 1546  sub submission {
   
  # option to display problem, only once else it cause problems    # option to display problem, only once else it cause problems 
         # with the form later since the problem has a form.          # with the form later since the problem has a form.
  if ($ENV{'form.vProb'} eq 'yes' or $ENV{'form.vAns'} eq 'yes') {   if ($env{'form.vProb'} eq 'yes' or $env{'form.vAns'} eq 'yes') {
     my $mode;      my $mode;
     if ($ENV{'form.vProb'} eq 'yes' && $ENV{'form.vAns'} eq 'yes') {      if ($env{'form.vProb'} eq 'yes' && $env{'form.vAns'} eq 'yes') {
  $mode='both';   $mode='both';
     } elsif ($ENV{'form.vProb'} eq 'yes') {      } elsif ($env{'form.vProb'} eq 'yes') {
  $mode='text';   $mode='text';
     } elsif ($ENV{'form.vAns'} eq 'yes') {      } elsif ($env{'form.vAns'} eq 'yes') {
  $mode='answer';   $mode='answer';
     }      }
     $request->print(&show_problem($request,$symb,$uname,$udom,0,1,$mode));      $request->print(&show_problem($request,$symb,$uname,$udom,0,1,$mode));
Line 1438  sub submission { Line 1561  sub submission {
  # kwclr is the only variable that is guaranteed to be non blank    # kwclr is the only variable that is guaranteed to be non blank 
         # if this subroutine has been called once.          # if this subroutine has been called once.
  my %keyhash = ();   my %keyhash = ();
  if ($ENV{'form.kwclr'} eq '' && $ENV{'form.handgrade'} eq 'yes') {   if ($env{'form.kwclr'} eq '' && $env{'form.handgrade'} eq 'yes') {
     %keyhash = &Apache::lonnet::dump('nohist_handgrade',      %keyhash = &Apache::lonnet::dump('nohist_handgrade',
      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},       $env{'course.'.$env{'request.course.id'}.'.domain'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});       $env{'course.'.$env{'request.course.id'}.'.num'});
   
     my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};      my $loginuser = $env{'user.name'}.':'.$env{'user.domain'};
     $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';      $env{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';
     $ENV{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';      $env{'form.kwclr'}    = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';
     $ENV{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';      $env{'form.kwsize'}   = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';
     $ENV{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';      $env{'form.kwstyle'}  = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
     $ENV{'form.msgsub'}   = $keyhash{$symb.'_subject'} ne '' ?       $env{'form.msgsub'}   = $keyhash{$symb.'_subject'} ne '' ? 
  $keyhash{$symb.'_subject'} : $ENV{'form.probTitle'};   $keyhash{$symb.'_subject'} : $env{'form.probTitle'};
     $ENV{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';      $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
  }   }
  my $overRideScore = $ENV{'form.overRideScore'} eq '' ? 'no' : $ENV{'form.overRideScore'};   my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};
   
  $request->print('<form action="/adm/grades" method="post" name="SCORE">'."\n".   $request->print('<form action="/adm/grades" method="post" name="SCORE" enctype="multipart/form-data">'."\n".
  '<input type="hidden" name="command"    value="handgrade" />'."\n".   '<input type="hidden" name="command"    value="handgrade" />'."\n".
  '<input type="hidden" name="saveState"  value="'.$ENV{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="Status"     value="'.$ENV{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status"     value="'.$env{'form.Status'}.'" />'."\n".
  '<input type="hidden" name="overRideScore" value="'.$overRideScore.'" />'."\n".   '<input type="hidden" name="overRideScore" value="'.$overRideScore.'" />'."\n".
  '<input type="hidden" name="probTitle"  value="'.$ENV{'form.probTitle'}.'" />'."\n".   '<input type="hidden" name="probTitle"  value="'.$env{'form.probTitle'}.'" />'."\n".
  '<input type="hidden" name="refresh"    value="off" />'."\n".   '<input type="hidden" name="refresh"    value="off" />'."\n".
  '<input type="hidden" name="studentNo"  value="" />'."\n".   '<input type="hidden" name="studentNo"  value="" />'."\n".
  '<input type="hidden" name="gradeOpt"   value="" />'."\n".   '<input type="hidden" name="gradeOpt"   value="" />'."\n".
  '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb"       value="'.$symb.'" />'."\n".
  '<input type="hidden" name="url"        value="'.$url.'" />'."\n".   '<input type="hidden" name="url"        value="'.$url.'" />'."\n".
  '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" />'."\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="vProb"      value="'.$env{'form.vProb'}.'" />'."\n".
  '<input type="hidden" name="vAns"       value="'.$ENV{'form.vAns'}.'" />'."\n".   '<input type="hidden" name="vAns"       value="'.$env{'form.vAns'}.'" />'."\n".
  '<input type="hidden" name="lastSub"    value="'.$ENV{'form.lastSub'}.'" />'."\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="section"    value="'.$env{'form.section'}.'">'."\n".
  '<input type="hidden" name="submitonly" value="'.$ENV{'form.submitonly'}.'">'."\n".   '<input type="hidden" name="submitonly" value="'.$env{'form.submitonly'}.'">'."\n".
  '<input type="hidden" name="handgrade"  value="'.$ENV{'form.handgrade'}.'">'."\n".   '<input type="hidden" name="handgrade"  value="'.$env{'form.handgrade'}.'">'."\n".
  '<input type="hidden" name="NCT"'.   '<input type="hidden" name="NCT"'.
  ' value="'.($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : $total+1).'" />'."\n");   ' value="'.($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : $total+1).'" />'."\n");
  if ($ENV{'form.handgrade'} eq 'yes') {   if ($env{'form.handgrade'} eq 'yes') {
     $request->print('<input type="hidden" name="keywords" value="'.$ENV{'form.keywords'}.'" />'."\n".      $request->print('<input type="hidden" name="keywords" value="'.$env{'form.keywords'}.'" />'."\n".
     '<input type="hidden" name="kwclr"    value="'.$ENV{'form.kwclr'}.'" />'."\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="kwsize"   value="'.$env{'form.kwsize'}.'" />'."\n".
     '<input type="hidden" name="kwstyle"  value="'.$ENV{'form.kwstyle'}.'" />'."\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="msgsub"   value="'.$env{'form.msgsub'}.'" />'."\n".
     '<input type="hidden" name="shownSub" value="0" />'."\n".      '<input type="hidden" name="shownSub" value="0" />'."\n".
     '<input type="hidden" name="savemsgN" value="'.$ENV{'form.savemsgN'}.'" />'."\n");      '<input type="hidden" name="savemsgN" value="'.$env{'form.savemsgN'}.'" />'."\n");
     foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) {      foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) {
  $request->print('<input type="hidden" name="vPart" value="'.$partid.'" />'."\n");   $request->print('<input type="hidden" name="vPart" value="'.$partid.'" />'."\n");
     }      }
  }   }
   
  my ($cts,$prnmsg) = (1,'');   my ($cts,$prnmsg) = (1,'');
  while ($cts <= $ENV{'form.savemsgN'}) {   while ($cts <= $env{'form.savemsgN'}) {
     $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.      $prnmsg.='<input type="hidden" name="savemsg'.$cts.'" value="'.
  (!exists($keyhash{$symb.'_savemsg'.$cts}) ?    (!exists($keyhash{$symb.'_savemsg'.$cts}) ? 
  &Apache::lonfeedback::clear_out_html($ENV{'form.savemsg'.$cts}) :   &Apache::lonfeedback::clear_out_html($env{'form.savemsg'.$cts}) :
  &Apache::lonfeedback::clear_out_html($keyhash{$symb.'_savemsg'.$cts})).   &Apache::lonfeedback::clear_out_html($keyhash{$symb.'_savemsg'.$cts})).
  '" />'."\n".   '" />'."\n".
  '<input type="hidden" name="shownOnce'.$cts.'" value="0" />'."\n";   '<input type="hidden" name="shownOnce'.$cts.'" value="0" />'."\n";
Line 1499  sub submission { Line 1622  sub submission {
  }   }
  $request->print($prnmsg);   $request->print($prnmsg);
   
  if ($ENV{'form.handgrade'} eq 'yes' && $ENV{'form.showgrading'} eq 'yes') {   if ($env{'form.handgrade'} eq 'yes' && $env{'form.showgrading'} eq 'yes') {
 #  #
 # Print out the keyword options line  # Print out the keyword options line
 #  #
Line 1521  KEYWORDS Line 1644  KEYWORDS
         }          }
     }      }
   
     if ($ENV{'form.vProb'} eq 'all' or $ENV{'form.vAns'} eq 'all') {      if ($env{'form.vProb'} eq 'all' or $env{'form.vAns'} eq 'all') {
  $request->print('<br /><br /><br />') if ($counter > 0);   $request->print('<br /><br /><br />') if ($counter > 0);
  my $mode;   my $mode;
  if ($ENV{'form.vProb'} eq 'all' && $ENV{'form.vAns'} eq 'all') {   if ($env{'form.vProb'} eq 'all' && $env{'form.vAns'} eq 'all') {
     $mode='both';      $mode='both';
  } elsif ($ENV{'form.vProb'} eq 'all' ) {   } elsif ($env{'form.vProb'} eq 'all' ) {
     $mode='text';      $mode='text';
  } elsif ($ENV{'form.vAns'} eq 'all') {   } elsif ($env{'form.vAns'} eq 'all') {
     $mode='answer';      $mode='answer';
  }   }
  $request->print(&show_problem($request,$symb,$uname,$udom,1,1,$mode));   $request->print(&show_problem($request,$symb,$uname,$udom,1,1,$mode));
     }      }
   
     my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);      my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname);
   
     my ($partlist,$handgrade,$responseType) = &response_type($url,$symb);      my ($partlist,$handgrade,$responseType) = &response_type($url,$symb);
   
     # Display student info      # Display student info
Line 1543  KEYWORDS Line 1665  KEYWORDS
     my $result='<table border="0" width=100%><tr><td bgcolor="#777777">'."\n".      my $result='<table border="0" width=100%><tr><td bgcolor="#777777">'."\n".
  '<table border="0" width=100%><tr bgcolor="#edffff"><td>'."\n";   '<table border="0" width=100%><tr bgcolor="#edffff"><td>'."\n";
   
     $result.='<b>Fullname: </b>'.&nameUserString(undef,$ENV{'form.fullname'},$uname,$udom).'<br />'."\n";      $result.='<b>Fullname: </b>'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).'<br />'."\n";
     $result.='<input type="hidden" name="name'.$counter.      $result.='<input type="hidden" name="name'.$counter.
  '" value="'.$ENV{'form.fullname'}.'" />'."\n";   '" value="'.$env{'form.fullname'}.'" />'."\n";
   
     # If any part of the problem is an essay-response (handgraded), then check for collaborators      # If any part of the problem is an essay-response (handgraded), then check for collaborators
     my @col_fullnames;      my @col_fullnames;
     my ($classlist,$fullname);      my ($classlist,$fullname);
     if ($ENV{'form.handgrade'} eq 'yes') {      if ($env{'form.handgrade'} eq 'yes') {
  ($classlist,undef,$fullname) = &getclasslist('all','0');   ($classlist,undef,$fullname) = &getclasslist('all','0');
  for (keys (%$handgrade)) {   for (keys (%$handgrade)) {
     my $ncol = &Apache::lonnet::EXT('resource.'.$_.      my $ncol = &Apache::lonnet::EXT('resource.'.$_.
Line 1611  KEYWORDS Line 1733  KEYWORDS
     #                  (for multi-response type part)      #                  (for multi-response type part)
     #             (3) Last submission plus the parts info      #             (3) Last submission plus the parts info
     #             (4) The whole record for this student      #             (4) The whole record for this student
     if ($ENV{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {      if ($env{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
  my ($string,$timestamp)= &get_last_submission(\%record);   my ($string,$timestamp)= &get_last_submission(\%record);
  my $lastsubonly=''.   my $lastsubonly=''.
     ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '.      ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '.
Line 1622  KEYWORDS Line 1744  KEYWORDS
     my %seenparts;      my %seenparts;
     for my $part (sort keys(%$handgrade)) {      for my $part (sort keys(%$handgrade)) {
  my ($partid,$respid) = split(/_/,$part);   my ($partid,$respid) = split(/_/,$part);
  if ($ENV{"form.$uname:$udom:$partid:submitted_by"}) {   my $display_part=&get_display_part($partid,$url,$symb);
    if ($env{"form.$uname:$udom:$partid:submitted_by"}) {
     if (exists($seenparts{$partid})) { next; }      if (exists($seenparts{$partid})) { next; }
     $seenparts{$partid}=1;      $seenparts{$partid}=1;
     my $submitby='<b>Part '.$partid.      my $submitby='<b>Part:</b> '.$display_part.
  ' Collaborative submission by: </b>'.   ' <b>Collaborative submission by:</b> '.
  '<a href="javascript:viewSubmitter(\''.   '<a href="javascript:viewSubmitter(\''.
  $ENV{"form.$uname:$udom:$partid:submitted_by"}.   $env{"form.$uname:$udom:$partid:submitted_by"}.
  '\')"; TARGET=_self>'.   '\')"; TARGET=_self>'.
  $$fullname{$ENV{"form.$uname:$udom:$partid:submitted_by"}}.'</a><br />';   $$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a><br />';
     $request->print($submitby);      $request->print($submitby);
     next;      next;
  }   }
  my $responsetype = $responseType->{$partid}->{$respid};   my $responsetype = $responseType->{$partid}->{$respid};
  if (!exists($record{"resource.$partid.$respid.submission"})) {   if (!exists($record{"resource.$partid.$respid.submission"})) {
     $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '.      $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.
  $partid.'</b> <font color="#999999">( ID '.$respid.   $display_part.' <font color="#999999">( ID '.$respid.
  ' )</font>&nbsp; &nbsp;'.   ' )</font>&nbsp; &nbsp;'.
  '<font color="red">Nothing submitted - no attempts</font><br /><br />';   '<font color="red">Nothing submitted - no attempts</font><br /><br />';
     next;      next;
Line 1648  KEYWORDS Line 1771  KEYWORDS
     my ($ressub,$subval) = split(/:/,$_,2);      my ($ressub,$subval) = split(/:/,$_,2);
     # Similarity check      # Similarity check
     my $similar='';      my $similar='';
     if($ENV{'form.checkPlag'}){      if($env{'form.checkPlag'}){
  my ($oname,$odom,$ocrsid,$oessay,$osim)=   my ($oname,$odom,$ocrsid,$oessay,$osim)=
     &most_similar($uname,$udom,$subval);      &most_similar($uname,$udom,$subval);
  if ($osim) {   if ($osim) {
Line 1662  KEYWORDS Line 1785  KEYWORDS
  }   }
     }      }
     my $order=&get_order($partid,$respid,$symb,$uname,$udom);      my $order=&get_order($partid,$respid,$symb,$uname,$udom);
     if ($ENV{'form.lastSub'} eq 'lastonly' ||       if ($env{'form.lastSub'} eq 'lastonly' || 
  ($ENV{'form.lastSub'} eq 'hdgrade' &&    ($env{'form.lastSub'} eq 'hdgrade' && 
  $$handgrade{$part} eq 'yes')) {   $$handgrade{$part} eq 'yes')) {
  $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '.   my $display_part=&get_display_part($partid,$url,$symb);
     $partid.'</b> <font color="#999999">( ID '.$respid.   $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.
       $display_part.' <font color="#999999">( ID '.$respid.
     ' )</font>&nbsp; &nbsp;';      ' )</font>&nbsp; &nbsp;';
    my @files;
    if ($record{"resource.$partid.$respid.portfiles"}) {
       my $file_url = '/uploaded/'.$udom.'/'.$uname.'/portfolio';
       foreach my $file (split(',',$record{"resource.$partid.$respid.portfiles"})) {
    push(@files,$file_url.$file);
       
    &Apache::lonnet::logthis("found a portfolio file".$record{"resource.$partid.$respid.portfiles"});
    &Apache::lonnet::logthis("uploaded URL file".$record{"resource.$partid.$respid.uploadedurl"});
       }
    }
  if ($record{"resource.$partid.$respid.uploadedurl"}) {   if ($record{"resource.$partid.$respid.uploadedurl"}) {
     &Apache::lonnet::allowuploaded('/adm/grades',      push(@files,$record{"resource.$partid.$respid.uploadedurl"});
       $record{"resource.$partid.$respid.uploadedurl"});   }
     $lastsubonly.='<a href="'.$record{"resource.$partid.$respid.uploadedurl"}.'" target="lonGRDs"><img src="/adm/lonIcons/unknown.gif" border=0"> File uploaded by student</a> <font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';   if (@files) {
       $lastsubonly.='<br /><font color="red" size="1">Like all files provided by users, this file may contain virusses</font><br />';
       my $file_counter = 0;
       foreach my $file (@files) {
           $file_counter ++;
    &Apache::lonnet::allowuploaded('/adm/grades',$file);
    $lastsubonly.='<br /><a href="'.$file.'" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>';
    $lastsubonly.='Return commented document to student. <input type="file" name="returndoc'.$file_counter.'" />'."\n";
    $lastsubonly.='<input type="hidden" name="returndocorig'.$file_counter.'" value="'.$file.'" />';
   
       }
       $lastsubonly.='<br />';
  }   }
  $lastsubonly.='<b>Submitted Answer: </b>'.   $lastsubonly.='<b>Submitted Answer: </b>'.
     &cleanRecord($subval,$responsetype,$symb,$partid,      &cleanRecord($subval,$responsetype,$symb,$partid,
Line 1683  KEYWORDS Line 1828  KEYWORDS
  }   }
  $lastsubonly.='</td></tr><tr bgcolor="#ffffff"><td>'."\n";   $lastsubonly.='</td></tr><tr bgcolor="#ffffff"><td>'."\n";
  $request->print($lastsubonly);   $request->print($lastsubonly);
     } elsif ($ENV{'form.lastSub'} eq 'datesub') {      } elsif ($env{'form.lastSub'} eq 'datesub') {
  my (undef,$responseType,undef,$parts) = &showResourceInfo($url);   my (undef,$responseType,undef,$parts) = &showResourceInfo($url);
  $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));   $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));
     } elsif ($ENV{'form.lastSub'} =~ /^(last|all)$/) {      } elsif ($env{'form.lastSub'} =~ /^(last|all)$/) {
  $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,   $request->print(&Apache::loncommon::get_previous_attempt($symb,$uname,$udom,
  $ENV{'request.course.id'},   $env{'request.course.id'},
  $last,'.submission',   $last,'.submission',
  'Apache::grades::keywords_highlight'));   'Apache::grades::keywords_highlight'));
     }      }
Line 1697  KEYWORDS Line 1842  KEYWORDS
  .$udom.'" />'."\n");   .$udom.'" />'."\n");
           
     # return if view submission with no grading option      # return if view submission with no grading option
     if ($ENV{'form.showgrading'} eq '' || (!&canmodify($usec))) {      if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) {
  my $toGrade.='<input type="button" value="Grade Student" '.   my $toGrade.='<input type="button" value="Grade Student" '.
     'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''      'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''
     .$counter.'\');" TARGET=_self> &nbsp;'."\n" if (&canmodify($usec));      .$counter.'\');" TARGET=_self> &nbsp;'."\n" if (&canmodify($usec));
  $toGrade.='</td></tr></table></td></tr></table>'."\n";   $toGrade.='</td></tr></table></td></tr></table>'."\n";
  if (($ENV{'form.command'} eq 'submission') ||    if (($env{'form.command'} eq 'submission') || 
     ($ENV{'form.command'} eq 'processGroup' && $counter == $total)) {      ($env{'form.command'} eq 'processGroup' && $counter == $total)) {
     $toGrade.='</form>'.&show_grading_menu_form($symb,$url)       $toGrade.='</form>'.&show_grading_menu_form($symb,$url) 
  }   }
  $request->print($toGrade);   $request->print($toGrade);
Line 1713  KEYWORDS Line 1858  KEYWORDS
     }      }
   
     # essay grading message center      # essay grading message center
     if ($ENV{'form.handgrade'} eq 'yes') {      if ($env{'form.handgrade'} eq 'yes') {
  my ($lastname,$givenn) = split(/,/,$ENV{'form.fullname'});   my ($lastname,$givenn) = split(/,/,$env{'form.fullname'});
  my $msgfor = $givenn.' '.$lastname;   my $msgfor = $givenn.' '.$lastname;
  if (scalar(@col_fullnames) > 0) {   if (scalar(@col_fullnames) > 0) {
     my $lastone = pop @col_fullnames;      my $lastone = pop @col_fullnames;
Line 1725  KEYWORDS Line 1870  KEYWORDS
     '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";      '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";
  $result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.   $result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
     ',\''.$msgfor.'\')"; TARGET=_self>'.      ',\''.$msgfor.'\')"; TARGET=_self>'.
     'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> &nbsp;'.      &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> ('.
       &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" />)'.
     '<img src="'.$request->dir_config('lonIconsURL').      '<img src="'.$request->dir_config('lonIconsURL').
     '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".      '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".
     '<br />&nbsp;(Message will be sent when you click on Save & Next below.)'."\n"       '<br />&nbsp;('.
     if ($ENV{'form.handgrade'} eq 'yes');      &mt('Message will be sent when you click on Save & Next below.').")\n";
  $request->print($result);   $request->print($result);
     }      }
       if ($perm{'vgr'}) {
    $request->print('<br />'.
       &Apache::loncommon::track_student_link(&mt('View recent activity'),
      $uname,$udom,'check'));
       }
       if ($perm{'opa'}) {
    $request->print('<br />'.
       &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
    $uname,$udom,$symb,'check'));
       }
   
     my %seen = ();      my %seen = ();
     my @partlist;      my @partlist;
Line 1740  KEYWORDS Line 1896  KEYWORDS
  my ($partid,$respid) = split(/_/);   my ($partid,$respid) = split(/_/);
  next if ($seen{$partid} > 0);   next if ($seen{$partid} > 0);
  $seen{$partid}++;   $seen{$partid}++;
  next if ($$handgrade{$_} =~ /:no$/ && $ENV{'form.lastSub'} =~ /^(hdgrade)$/);   next if ($$handgrade{$_} =~ /:no$/ && $env{'form.lastSub'} =~ /^(hdgrade)$/);
  push @partlist,$partid;   push @partlist,$partid;
  push @gradePartRespid,$partid.'.'.$respid;   push @gradePartRespid,$partid.'.'.$respid;
   
Line 1768  KEYWORDS Line 1924  KEYWORDS
     '<option>1</option><option>2</option>'.      '<option>1</option><option>2</option>'.
     '<option>3</option><option>5</option>'.      '<option>3</option><option>5</option>'.
     '<option>7</option><option>10</option></select>'."\n";      '<option>7</option><option>10</option></select>'."\n";
  my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1');   my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1');
  $ntstu =~ s/<option>$nsel</<option selected="on">$nsel</;   $ntstu =~ s/<option>$nsel</<option selected="on">$nsel</;
  $endform.=$ntstu.'student(s) &nbsp;&nbsp;';   $endform.=$ntstu.'student(s) &nbsp;&nbsp;';
  $endform.='<input type="button" value="Previous" '.   $endform.='<input type="button" value="Previous" '.
Line 1812  sub get_last_submission { Line 1968  sub get_last_submission {
 #--- High light keywords, with style choosen by user.  #--- High light keywords, with style choosen by user.
 sub keywords_highlight {  sub keywords_highlight {
     my $string    = shift;      my $string    = shift;
     my $size      = $ENV{'form.kwsize'} eq '0' ? '' : 'size='.$ENV{'form.kwsize'};      my $size      = $env{'form.kwsize'} eq '0' ? '' : 'size='.$env{'form.kwsize'};
     my $styleon   = $ENV{'form.kwstyle'} eq ''  ? '' : $ENV{'form.kwstyle'};      my $styleon   = $env{'form.kwstyle'} eq ''  ? '' : $env{'form.kwstyle'};
     (my $styleoff = $styleon) =~ s/\</\<\//;      (my $styleoff = $styleon) =~ s/\</\<\//;
     my @keylist   = split(/[,\s+]/,$ENV{'form.keywords'});      my @keylist   = split(/[,\s+]/,$env{'form.keywords'});
     foreach (@keylist) {      foreach (@keylist) {
  $string =~ s/\b\Q$_\E(\b|\.)/<font color\=$ENV{'form.kwclr'} $size\>$styleon$_$styleoff<\/font>/gi;   $string =~ s/\b\Q$_\E(\b|\.)/<font color\=$env{'form.kwclr'} $size\>$styleon$_$styleoff<\/font>/gi;
     }      }
     return $string;      return $string;
 }  }
Line 1825  sub keywords_highlight { Line 1981  sub keywords_highlight {
 #--- Called from submission routine  #--- Called from submission routine
 sub processHandGrade {  sub processHandGrade {
     my ($request) = shift;      my ($request) = shift;
     my $url    = $ENV{'form.url'};      my $url    = $env{'form.url'};
     my $symb   = $ENV{'form.symb'};      my $symb   = $env{'form.symb'};
     my $button = $ENV{'form.gradeOpt'};      my $button = $env{'form.gradeOpt'};
     my $ngrade = $ENV{'form.NCT'};      my $ngrade = $env{'form.NCT'};
     my $ntstu  = $ENV{'form.NTSTU'};      my $ntstu  = $env{'form.NTSTU'};
       my $cdom   = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $cnum   = $env{'course.'.$env{'request.course.id'}.'.num'};
   
     if ($button eq 'Save & Next') {      if ($button eq 'Save & Next') {
  my $ctr = 0;   my $ctr = 0;
  while ($ctr < $ngrade) {   while ($ctr < $ngrade) {
     my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr});      my ($uname,$udom) = split(/:/,$env{'form.unamedom'.$ctr});
     my ($errorflag,$pts,$wgt) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);      my ($errorflag,$pts,$wgt) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr);
     if ($errorflag eq 'no_score') {      if ($errorflag eq 'no_score') {
  $ctr++;   $ctr++;
Line 1844  sub processHandGrade { Line 2003  sub processHandGrade {
  $ctr++;   $ctr++;
  next;   next;
     }      }
     my $includemsg = $ENV{'form.includemsg'.$ctr};      my $includemsg = $env{'form.includemsg'.$ctr};
     my ($subject,$message,$msgstatus) = ('','','');      my ($subject,$message,$msgstatus) = ('','','');
     if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) {      if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) {
  $subject = $ENV{'form.msgsub'} if ($includemsg =~ /^msgsub/);   $subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/);
    unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); }
  my (@msgnum) = split(/,/,$includemsg);   my (@msgnum) = split(/,/,$includemsg);
  foreach (@msgnum) {   foreach (@msgnum) {
     $message.=$ENV{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');      $message.=$env{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');
  }   }
  $message =&Apache::lonfeedback::clear_out_html($message);   $message =&Apache::lonfeedback::clear_out_html($message);
  $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;   if ($env{'form.withgrades'.$ctr}) {
  $message.=" for <a href=\"".      $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
       $message.=" for <a href=\"".
     &Apache::lonnet::clutter($url).      &Apache::lonnet::clutter($url).
     "?symb=$symb\">$ENV{'form.probTitle'}</a>";      "?symb=$symb\">$env{'form.probTitle'}</a>";
    }
  $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,   $msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,
        $ENV{'form.msgsub'},$message);         $subject.' ['.
          &Apache::lonnet::declutter($url).']',$message);
    $request->print('<br />'.&mt('Sending message to [_1]@[_2]',$uname,$udom).': '.
    $msgstatus);
     }      }
     if ($ENV{'form.collaborator'.$ctr}) {      if ($env{'form.collaborator'.$ctr}) {
  my @collabstrs=&Apache::loncommon::get_env_multiple("form.collaborator$ctr");   my @collabstrs=&Apache::loncommon::get_env_multiple("form.collaborator$ctr");
  foreach my $collabstr (@collabstrs) {   foreach my $collabstr (@collabstrs) {
     my ($part,@collaborators) = split(/:/,$collabstr);      my ($part,@collaborators) = split(/:/,$collabstr);
     foreach (@collaborators) {      foreach (@collaborators) {
  my ($errorflag,$pts,$wgt) =    my ($errorflag,$pts,$wgt) = 
     &saveHandGrade($request,$url,$symb,$_,$udom,$ctr,      &saveHandGrade($request,$url,$symb,$_,$udom,$ctr,
    $ENV{'form.unamedom'.$ctr},$part);     $env{'form.unamedom'.$ctr},$part);
  if ($errorflag eq 'not_allowed') {   if ($errorflag eq 'not_allowed') {
     $request->print("<font color=\"red\">Not allowed to modify grades for $_:$udom</font>");      $request->print("<font color=\"red\">Not allowed to modify grades for $_:$udom</font>");
     next;      next;
  } else {   } else {
     if ($message ne '') {      if ($message ne '') {
  $msgstatus = &Apache::lonmsg::user_normal_msg($_,$udom,$ENV{'form.msgsub'},$message);   $msgstatus = &Apache::lonmsg::user_normal_msg($_,$udom,$env{'form.msgsub'},$message);
     }      }
           
  }   }
     }      }
  }   }
     }      }
       if ($env{'form.returndoc1'}) {
           # if multiple files are uploaded names will be 'returndoc2', 'returndoc3'
           my $file_counter = 1;
           while ($env{'form.returndoc'.$file_counter}) {
               my $fname=$env{'form.returndoc'.$file_counter.'.filename'};
               $request->print("<br />".$fname." will be the uploaded file name");
               $request->print("<font color=\"red\">Will upload document</font>".$env{'form.returndocorig'.$file_counter});
               $file_counter ++;
           }
       }
     $ctr++;      $ctr++;
  }   }
     }      }
   
     if ($ENV{'form.handgrade'} eq 'yes') {      if ($env{'form.handgrade'} eq 'yes') {
  # Keywords sorted in alphabatical order   # Keywords sorted in alphabatical order
  my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};   my $loginuser = $env{'user.name'}.':'.$env{'user.domain'};
  my %keyhash = ();   my %keyhash = ();
  $ENV{'form.keywords'}           =~ s/,\s{0,}|\s+/ /g;   $env{'form.keywords'}           =~ s/,\s{0,}|\s+/ /g;
  $ENV{'form.keywords'}           =~ s/^\s+|\s+$//;   $env{'form.keywords'}           =~ s/^\s+|\s+$//;
  my (@keywords) = sort(split(/\s+/,$ENV{'form.keywords'}));   my (@keywords) = sort(split(/\s+/,$env{'form.keywords'}));
  $ENV{'form.keywords'} = join(' ',@keywords);   $env{'form.keywords'} = join(' ',@keywords);
  $keyhash{$symb.'_keywords'}     = $ENV{'form.keywords'};   $keyhash{$symb.'_keywords'}     = $env{'form.keywords'};
  $keyhash{$symb.'_subject'}      = $ENV{'form.msgsub'};   $keyhash{$symb.'_subject'}      = $env{'form.msgsub'};
  $keyhash{$loginuser.'_kwclr'}   = $ENV{'form.kwclr'};   $keyhash{$loginuser.'_kwclr'}   = $env{'form.kwclr'};
  $keyhash{$loginuser.'_kwsize'}  = $ENV{'form.kwsize'};   $keyhash{$loginuser.'_kwsize'}  = $env{'form.kwsize'};
  $keyhash{$loginuser.'_kwstyle'} = $ENV{'form.kwstyle'};   $keyhash{$loginuser.'_kwstyle'} = $env{'form.kwstyle'};
   
  # message center - Order of message gets changed. Blank line is eliminated.   # message center - Order of message gets changed. Blank line is eliminated.
  # New messages are saved in ENV for the next student.   # New messages are saved in env for the next student.
  # All messages are saved in nohist_handgrade.db   # All messages are saved in nohist_handgrade.db
  my ($ctr,$idx) = (1,1);   my ($ctr,$idx) = (1,1);
  while ($ctr <= $ENV{'form.savemsgN'}) {   while ($ctr <= $env{'form.savemsgN'}) {
     if ($ENV{'form.savemsg'.$ctr} ne '') {      if ($env{'form.savemsg'.$ctr} ne '') {
  $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.savemsg'.$ctr};   $keyhash{$symb.'_savemsg'.$idx} = $env{'form.savemsg'.$ctr};
  $idx++;   $idx++;
     }      }
     $ctr++;      $ctr++;
  }   }
  $ctr = 0;   $ctr = 0;
  while ($ctr < $ngrade) {   while ($ctr < $ngrade) {
     if ($ENV{'form.newmsg'.$ctr} ne '') {      if ($env{'form.newmsg'.$ctr} ne '') {
  $keyhash{$symb.'_savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};   $keyhash{$symb.'_savemsg'.$idx} = $env{'form.newmsg'.$ctr};
  $ENV{'form.savemsg'.$idx} = $ENV{'form.newmsg'.$ctr};   $env{'form.savemsg'.$idx} = $env{'form.newmsg'.$ctr};
  $idx++;   $idx++;
     }      }
     $ctr++;      $ctr++;
  }   }
  $ENV{'form.savemsgN'} = --$idx;   $env{'form.savemsgN'} = --$idx;
  $keyhash{$symb.'_savemsgN'} = $ENV{'form.savemsgN'};   $keyhash{$symb.'_savemsgN'} = $env{'form.savemsgN'};
  my $putresult = &Apache::lonnet::put   my $putresult = &Apache::lonnet::put
     ('nohist_handgrade',\%keyhash,      ('nohist_handgrade',\%keyhash,$cdom,$cnum);
      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
     }      }
     # Called by Save & Refresh from Highlight Attribute Window      # Called by Save & Refresh from Highlight Attribute Window
     my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'1');      my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1');
     if ($ENV{'form.refresh'} eq 'on') {      if ($env{'form.refresh'} eq 'on') {
  my ($ctr,$total) = (0,0);   my ($ctr,$total) = (0,0);
  while ($ctr < $ngrade) {   while ($ctr < $ngrade) {
     $total++ if  $ENV{'form.unamedom'.$ctr} ne '';      $total++ if  $env{'form.unamedom'.$ctr} ne '';
     $ctr++;      $ctr++;
  }   }
  $ENV{'form.NTSTU'}=$ngrade;   $env{'form.NTSTU'}=$ngrade;
  $ctr = 0;   $ctr = 0;
  while ($ctr < $total) {   while ($ctr < $total) {
     my $processUser = $ENV{'form.unamedom'.$ctr};      my $processUser = $env{'form.unamedom'.$ctr};
     ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$processUser);      ($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser);
     $ENV{'form.fullname'} = $$fullname{$processUser};      $env{'form.fullname'} = $$fullname{$processUser};
     &submission($request,$ctr,$total-1);      &submission($request,$ctr,$total-1);
     $ctr++;      $ctr++;
  }   }
Line 1947  sub processHandGrade { Line 2120  sub processHandGrade {
   
 # Go directly to grade student - from submission or link from chart page  # Go directly to grade student - from submission or link from chart page
     if ($button eq 'Grade Student') {      if ($button eq 'Grade Student') {
  (undef,undef,$ENV{'form.handgrade'},undef,undef) = &showResourceInfo($url);   (undef,undef,$env{'form.handgrade'},undef,undef) = &showResourceInfo($url);
  my $processUser = $ENV{'form.unamedom'.$ENV{'form.studentNo'}};   my $processUser = $env{'form.unamedom'.$env{'form.studentNo'}};
  ($ENV{'form.student'},$ENV{'form.userdom'}) = split(/:/,$processUser);   ($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser);
  $ENV{'form.fullname'} = $$fullname{$processUser};   $env{'form.fullname'} = $$fullname{$processUser};
  &submission($request,0,0);   &submission($request,0,0);
  return '';   return '';
     }      }
   
     # Get the next/previous one or group of students      # Get the next/previous one or group of students
     my $firststu = $ENV{'form.unamedom0'};      my $firststu = $env{'form.unamedom0'};
     my $laststu = $ENV{'form.unamedom'.($ngrade-1)};      my $laststu = $env{'form.unamedom'.($ngrade-1)};
     my $ctr = 2;      my $ctr = 2;
     while ($laststu eq '') {      while ($laststu eq '') {
  $laststu  = $ENV{'form.unamedom'.($ngrade-$ctr)};   $laststu  = $env{'form.unamedom'.($ngrade-$ctr)};
  $ctr++;   $ctr++;
  $laststu = $firststu if ($ctr > $ngrade);   $laststu = $firststu if ($ctr > $ngrade);
     }      }
   
     my (@parsedlist,@nextlist);      my (@parsedlist,@nextlist);
     my ($nextflg) = 0;      my ($nextflg) = 0;
     foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {      foreach (sort 
        {
    if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
        return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
    }
    return $a cmp $b;
        } (keys(%$fullname))) {
  if ($nextflg == 1 && $button =~ /Next$/) {   if ($nextflg == 1 && $button =~ /Next$/) {
     push @parsedlist,$_;      push @parsedlist,$_;
  }   }
Line 1981  sub processHandGrade { Line 2160  sub processHandGrade {
     @parsedlist = reverse @parsedlist if ($button eq 'Previous');      @parsedlist = reverse @parsedlist if ($button eq 'Previous');
     my ($partlist) = &response_type($url);      my ($partlist) = &response_type($url);
     foreach my $student (@parsedlist) {      foreach my $student (@parsedlist) {
  my $submitonly=$ENV{'form.submitonly'};   my $submitonly=$env{'form.submitonly'};
  my ($uname,$udom) = split(/:/,$student);   my ($uname,$udom) = split(/:/,$student);
   
    if ($submitonly eq 'queued') {
       my %queue_status = 
    &Apache::bridgetask::get_student_status($symb,$cdom,$cnum,
    $udom,$uname);
       next if (!defined($queue_status{'gradingqueue'}));
    }
   
  if ($submitonly =~ /^(yes|graded|incorrect)$/) {   if ($submitonly =~ /^(yes|graded|incorrect)$/) {
 #    my %record = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);  #    my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname);
     my %status=&student_gradeStatus($url,$symb,$udom,$uname,$partlist);      my %status=&student_gradeStatus($url,$symb,$udom,$uname,$partlist);
     my $submitted = 0;      my $submitted = 0;
     my $graded = 1;      my $ungraded = 0;
       my $incorrect = 0;
     foreach (keys(%status)) {      foreach (keys(%status)) {
  $submitted = 1 if ($status{$_} ne 'nothing');   $submitted = 1 if ($status{$_} ne 'nothing');
  $graded = 0 if ($status{$_} =~ /^correct/);   $ungraded = 1 if ($status{$_} =~ /^ungraded/);
    $incorrect = 1 if ($status{$_} =~ /^incorrect/);
  my ($foo,$partid,$foo1) = split(/\./,$_);   my ($foo,$partid,$foo1) = split(/\./,$_);
  if ($status{'resource.'.$partid.'.submitted_by'} ne '') {   if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
     $submitted = 0;      $submitted = 0;
Line 1999  sub processHandGrade { Line 2188  sub processHandGrade {
     next if (!$submitted && ($submitonly eq 'yes' ||      next if (!$submitted && ($submitonly eq 'yes' ||
      $submitonly eq 'incorrect' ||       $submitonly eq 'incorrect' ||
      $submitonly eq 'graded'));       $submitonly eq 'graded'));
     next if (!$graded && ($submitonly eq 'graded' ||      next if (!$ungraded && ($submitonly eq 'graded'));
   $submitonly eq 'incorrect'));      next if (!$incorrect && $submitonly eq 'incorrect');
  }   }
  push @nextlist,$student if ($ctr < $ntstu);   push @nextlist,$student if ($ctr < $ntstu);
  last if ($ctr == $ntstu);   last if ($ctr == $ntstu);
Line 2012  sub processHandGrade { Line 2201  sub processHandGrade {
   
     foreach (sort @nextlist) {      foreach (sort @nextlist) {
  my ($uname,$udom,$submitter) = split(/:/);   my ($uname,$udom,$submitter) = split(/:/);
  $ENV{'form.student'}  = $uname;   $env{'form.student'}  = $uname;
  $ENV{'form.userdom'}  = $udom;   $env{'form.userdom'}  = $udom;
  $ENV{'form.fullname'} = $$fullname{$_};   $env{'form.fullname'} = $$fullname{$_};
  &submission($request,$ctr,$total);   &submission($request,$ctr,$total);
  $ctr++;   $ctr++;
     }      }
Line 2022  sub processHandGrade { Line 2211  sub processHandGrade {
  my $the_end = '<h3><font color="red">LON-CAPA User Message</font></h3><br />'."\n";   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.='<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.='Click on the button below to return to the grading menu.<br /><br />'."\n";
  $the_end.=&show_grading_menu_form ($symb,$url);   $the_end.=&show_grading_menu_form($symb,$url);
  $request->print($the_end);   $request->print($the_end);
     }      }
     return '';      return '';
Line 2031  sub processHandGrade { Line 2220  sub processHandGrade {
 #---- Save the score and award for each student, if changed  #---- Save the score and award for each student, if changed
 sub saveHandGrade {  sub saveHandGrade {
     my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter,$part) = @_;      my ($request,$url,$symb,$stuname,$domain,$newflg,$submitter,$part) = @_;
       my @v_flag;
     my $usec = &Apache::lonnet::getsection($domain,$stuname,      my $usec = &Apache::lonnet::getsection($domain,$stuname,
    $ENV{'request.course.id'});     $env{'request.course.id'});
     if (!&canmodify($usec)) { return('not_allowed'); }      if (!&canmodify($usec)) { return('not_allowed'); }
     my %record     = &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$domain,$stuname);      my %record     = &Apache::lonnet::restore($symb,$env{'request.course.id'},$domain,$stuname);
       my @parts_graded;
     my %newrecord  = ();      my %newrecord  = ();
     my ($pts,$wgt) = ('','');      my ($pts,$wgt) = ('','');
     foreach (split(/:/,$ENV{'form.partlist'.$newflg})) {      my %aggregate = ();
       my $aggregateflag = 0;
   
       my @parts = split(/:/,$env{'form.partlist'.$newflg});
       foreach my $new_part (@parts) {
  #collaborator may vary for different parts   #collaborator may vary for different parts
  if ($submitter && $_ ne $part) { next; }   if ($submitter && $new_part ne $part) { next; }
  my $dropMenu = $ENV{'form.GD_SEL'.$newflg.'_'.$_};   my $dropMenu = $env{'form.GD_SEL'.$newflg.'_'.$new_part};
  if ($dropMenu eq 'excused') {   if ($dropMenu eq 'excused') {
     if ($record{'resource.'.$_.'.solved'} ne 'excused') {      if ($record{'resource.'.$new_part.'.solved'} ne 'excused') {
  $newrecord{'resource.'.$_.'.solved'} = 'excused';   $newrecord{'resource.'.$new_part.'.solved'} = 'excused';
  if (exists($record{'resource.'.$_.'.awarded'})) {   if (exists($record{'resource.'.$new_part.'.awarded'})) {
     $newrecord{'resource.'.$_.'.awarded'} = '';      $newrecord{'resource.'.$new_part.'.awarded'} = '';
  }   }
     $newrecord{'resource.'.$_.'.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";      $newrecord{'resource.'.$new_part.'.regrader'}="$env{'user.name'}:$env{'user.domain'}";
     }      }
  } elsif ($dropMenu eq 'reset status'   } elsif ($dropMenu eq 'reset status'
  && exists($record{'resource.'.$_.'.solved'})) { #don't bother if no old records -> no attempts   && exists($record{'resource.'.$new_part.'.solved'})) { #don't bother if no old records -> no attempts
     foreach my $key (keys (%record)) {      foreach my $key (keys (%record)) {
  if ($key=~/^resource\.\Q$_\E\./) { $newrecord{$key} = ''; }   if ($key=~/^resource\.\Q$new_part\E\./) { $newrecord{$key} = ''; }
     }      }
     $newrecord{'resource.'.$_.'.regrader'}=      $newrecord{'resource.'.$new_part.'.regrader'}=
  "$ENV{'user.name'}:$ENV{'user.domain'}";   "$env{'user.name'}:$env{'user.domain'}";
               my $totaltries = $record{'resource.'.$part.'.tries'};
   
               my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
          [$new_part]);
               my $aggtries =$totaltries;
               if ($last_resets{$new_part}) {
                   $aggtries = &get_num_tries(\%record,$last_resets{$new_part},
      $new_part);
               }
   
               my $solvedstatus = $record{'resource.'.$new_part.'.solved'};
               if ($aggtries > 0) {
                   &decrement($symb,$new_part,\%aggregate,$aggtries,$totaltries,$solvedstatus);
                   $aggregateflag = 1;
               }
  } elsif ($dropMenu eq '') {   } elsif ($dropMenu eq '') {
     $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ?       $pts = ($env{'form.GD_BOX'.$newflg.'_'.$new_part} ne '' ? 
     $ENV{'form.GD_BOX'.$newflg.'_'.$_} :       $env{'form.GD_BOX'.$newflg.'_'.$new_part} : 
     $ENV{'form.RADVAL'.$newflg.'_'.$_});      $env{'form.RADVAL'.$newflg.'_'.$new_part});
     if ($pts eq '' && $ENV{'form.GD_SEL'.$newflg.'_'.$_} eq '') {      if ($pts eq '' && $env{'form.GD_SEL'.$newflg.'_'.$new_part} eq '') {
  next;   next;
     }      }
     $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 :       $wgt = $env{'form.WGT'.$newflg.'_'.$new_part} eq '' ? 1 : 
  $ENV{'form.WGT'.$newflg.'_'.$_};   $env{'form.WGT'.$newflg.'_'.$new_part};
     my $partial= $pts/$wgt;      my $partial= $pts/$wgt;
     if ($partial eq $record{'resource.'.$_.'.awarded'}) {      if ($partial eq $record{'resource.'.$new_part.'.awarded'}) {
  #do not update score for part if not changed.   #do not update score for part if not changed.
  next;   next;
       } else {
           push @parts_graded, $new_part;
     }      }
     if ($record{'resource.'.$_.'.awarded'} ne $partial) {      if ($record{'resource.'.$new_part.'.awarded'} ne $partial) {
  $newrecord{'resource.'.$_.'.awarded'}  = $partial;   $newrecord{'resource.'.$new_part.'.awarded'}  = $partial;
     }      }
     my $reckey = 'resource.'.$_.'.solved';      my $reckey = 'resource.'.$new_part.'.solved';
     if ($partial == 0) {      if ($partial == 0) {
  if ($record{$reckey} ne 'incorrect_by_override') {   if ($record{$reckey} ne 'incorrect_by_override') {
     $newrecord{$reckey} = 'incorrect_by_override';      $newrecord{$reckey} = 'incorrect_by_override';
Line 2084  sub saveHandGrade { Line 2296  sub saveHandGrade {
  }   }
     }          }    
     if ($submitter &&       if ($submitter && 
  ($record{'resource.'.$_.'.submitted_by'} ne $submitter)) {   ($record{'resource.'.$new_part.'.submitted_by'} ne $submitter)) {
  $newrecord{'resource.'.$_.'.submitted_by'} = $submitter;   $newrecord{'resource.'.$new_part.'.submitted_by'} = $submitter;
     }      }
     $newrecord{'resource.'.$_.'.regrader'}=      $newrecord{'resource.'.$new_part.'.regrader'}=
  "$ENV{'user.name'}:$ENV{'user.domain'}";   "$env{'user.name'}:$env{'user.domain'}";
    }
    # unless problem has been graded, set flag to version the submitted files
    unless ($record{'resource.'.$new_part.'.solved'} =~ /^correct_/  || 
           $record{'resource.'.$new_part.'.solved'} eq 'incorrect_by_override' ||
           $dropMenu eq 'reset status')
      {
       push (@v_flag,$new_part);
  }   }
     }      }
       my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
   
     if (scalar(keys(%newrecord)) > 0) {      if (scalar(keys(%newrecord)) > 0) {
           if (scalar(@v_flag)) {
               &version_portfiles(\%record, \@parts_graded, $env{'request.course.id'}, $symb, $domain, $stuname, \@v_flag);
           }
  &Apache::lonnet::cstore(\%newrecord,$symb,   &Apache::lonnet::cstore(\%newrecord,$symb,
  $ENV{'request.course.id'},$domain,$stuname);   $env{'request.course.id'},$domain,$stuname);
   
    my @ungraded_parts;
    foreach my $part (@parts) {
       if ( !defined($record{'resource.'.$part.'.awarded'})
    && !defined($newrecord{'resource.'.$part.'.awarded'}) ) {
    push(@ungraded_parts, $part);
       }
    }
    if ( !@ungraded_parts ) {
       &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,$cdom,
      $cnum,$domain,$stuname);
    }
       }
       if ($aggregateflag) {
           &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
         $cdom,$cnum);
       }
       return ('',$pts,$wgt);
   }
   
   # ----------- Provides number of tries since last reset.
   sub get_num_tries {
       my ($record,$last_reset,$part) = @_;
       my $timestamp = '';
       my $num_tries = 0;
       if ($$record{'version'}) {
           for (my $version=$$record{'version'};$version>=1;$version--) {
               if (exists($$record{$version.':resource.'.$part.'.solved'})) {
                   $timestamp = $$record{$version.':timestamp'};
                   if ($timestamp > $last_reset) {
                       $num_tries ++;
                   } else {
                       last;
                   }
               }
           }
     }      }
     return '',$pts,$wgt;      return $num_tries;
   }
   
   # ----------- Determine decrements required in aggregate totals 
   sub decrement_aggs {
       my ($symb,$part,$aggregate,$aggtries,$totaltries,$solvedstatus) = @_;
       my %decrement = (
                           attempts => 0,
                           users => 0,
                           correct => 0
                       );
       $decrement{'attempts'} = $aggtries;
       if ($solvedstatus =~ /^correct/) {
           $decrement{'correct'} = 1;
       }
       if ($aggtries == $totaltries) {
           $decrement{'users'} = 1;
       }
       foreach my $type (keys (%decrement)) {
           $$aggregate{$symb."\0".$part."\0".$type} = -$decrement{$type};
       }
       return;
   }
   
   # ----------- Determine timestamps for last reset of aggregate totals for parts  
   sub get_last_resets {
       my ($symb,$courseid,$partids) =@_;
       my %last_resets;
       my $cdom = $env{'course.'.$courseid.'.domain'};
       my $cname = $env{'course.'.$courseid.'.num'};
       my @keys;
       foreach my $part (@{$partids}) {
    push(@keys,"$symb\0$part\0resettime");
       }
       my %results=&Apache::lonnet::get('nohist_resourcetracker',\@keys,
        $cdom,$cname);
       foreach my $part (@{$partids}) {
    $last_resets{$part}=$results{"$symb\0$part\0resettime"};
       }
       return %last_resets;
   }
   
   # ----------- Handles creating versions for portfolio files as answers
   sub version_portfiles {
       my ($record, $parts_graded, $courseid, $symb, $domain, $stuname, $v_flag) = @_;
       my $version_parts = join('|',@$v_flag);
       my $parts = join('|', @$parts_graded);
       my $portfolio_root = &Apache::loncommon::propath($domain,
    $stuname).
    '/userfiles/portfolio';
       foreach my $key (keys(%$record)) {
           my $new_portfiles;
   
           if ($key =~ /^resource\.($version_parts)\./ && $key =~ /\.portfiles$/ ) {
               my @v_portfiles;
               my @portfiles = split(/,/,$$record{$key});
               foreach my $file (@portfiles) {
                   &Apache::lonnet::unmark_as_readonly($domain,$stuname,[$symb,$env{'request.course.id'}],$file);
                   my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/);
                   my $version = 0;
    my ($answer_name,$answer_ver,$answer_ext) =
       &file_name_version_ext($answer_file);
                   my @dir_list = &Apache::lonnet::dirlist($directory,$domain,$stuname,$portfolio_root);
                   foreach my $row (@dir_list) {
                       my ($file) = split(/\&/,$row,2);
       my ($file_name,$file_version,$file_ext) =
    &file_name_version_ext($file);
                       if (($file_name eq $answer_name) && 
    ($file_ext eq $answer_ext)) {
                           # gets here if filename and extension match, regardless of version
                           if ($file_version ne '') {
                               # a versioned file is found  so save it for later
                               if ($file_version > $version) {
    $version = $file_version;
       }
                           }
                       }
                   }
                   $version++;
                   $env{'form.copy'} = &Apache::lonnet::getfile("/uploaded/$domain/$stuname/portfolio$directory$answer_file");
                   if($env{'form.copy'} eq '-1') {
                       &Apache::lonnet::logthis('problem getting file '.$directory.$answer_file);
                   } else {
       my $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;
       my $copy_result = &Apache::lonnet::finishuserfileupload(
                                           $stuname,$domain,'copy',
           '/portfolio'.$directory.$new_answer);
                       push(@v_portfiles, $directory.$new_answer);
                       &Apache::lonnet::mark_as_readonly($domain,$stuname,
                                   ['/portfolio'.$directory.$new_answer],
                                   [$symb,$env{'request.course.id'},'graded']);
                   }
               }
               $$record{$key} = join(',',@v_portfiles);
           }
       } 
       return 'ok';   
   }
   
   sub version_selected_portfile {
       my ($file_name,$domain,$stu_name) = @_;
       return 'ok';
   }
   
   sub file_name_version_ext {
       my ($file)=@_;
       my @file_parts = split(/\./, $file);
       my ($name,$version,$ext);
       if (@file_parts > 1) {
    $ext=pop(@file_parts);
    if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) {
       $version=pop(@file_parts);
    }
    $name=join('.',@file_parts);
       } else {
    $name=join('.',@file_parts);
       }
       return($name,$version,$ext);
 }  }
   
 #--------------------------------------------------------------------------------------  #--------------------------------------------------------------------------------------
Line 2147  sub viewgrades_js { Line 2525  sub viewgrades_js {
  }   }
  for (i=0;i<document.classgrade.total.value;i++) {   for (i=0;i<document.classgrade.total.value;i++) {
     var user = document.classgrade["ctr"+i].value;      var user = document.classgrade["ctr"+i].value;
       user = user.replace(new RegExp(':', 'g'),"_");
     var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];      var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
     var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;      var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
     var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];      var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
Line 2163  sub viewgrades_js { Line 2542  sub viewgrades_js {
     function writeRadText(partid,weight) {      function writeRadText(partid,weight) {
  var selval   = document.classgrade["SELVAL_"+partid];   var selval   = document.classgrade["SELVAL_"+partid];
  var radioButton = document.classgrade["RADVAL_"+partid];   var radioButton = document.classgrade["RADVAL_"+partid];
           var override = document.classgrade["FORCE_"+partid].checked;
  var textbox = document.classgrade["TEXTVAL_"+partid];   var textbox = document.classgrade["TEXTVAL_"+partid];
  if (selval[1].selected || selval[2].selected) {   if (selval[1].selected || selval[2].selected) {
     for (var i=0; i<radioButton.length; i++) {      for (var i=0; i<radioButton.length; i++) {
Line 2173  sub viewgrades_js { Line 2553  sub viewgrades_js {
   
     for (i=0;i<document.classgrade.total.value;i++) {      for (i=0;i<document.classgrade.total.value;i++) {
  var user = document.classgrade["ctr"+i].value;   var user = document.classgrade["ctr"+i].value;
    user = user.replace(new RegExp(':', 'g'),"_");
  var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];   var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
  var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;   var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
  var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];   var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
  if (saveval != "correct") {   if ((saveval != "correct") || override) {
     scorename.value = "";      scorename.value = "";
     if (selval[1].selected) {      if (selval[1].selected) {
  selname[1].selected = true;   selname[1].selected = true;
Line 2190  sub viewgrades_js { Line 2571  sub viewgrades_js {
  } else {   } else {
     for (i=0;i<document.classgrade.total.value;i++) {      for (i=0;i<document.classgrade.total.value;i++) {
  var user = document.classgrade["ctr"+i].value;   var user = document.classgrade["ctr"+i].value;
    user = user.replace(new RegExp(':', 'g'),"_");
  var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];   var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
  var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;   var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
  var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];   var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
  if (saveval != "correct") {   if ((saveval != "correct") || override) {
     scorename.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;      scorename.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;
     selname[0].selected = true;      selname[0].selected = true;
  }   }
Line 2230  sub viewgrades_js { Line 2612  sub viewgrades_js {
     if (selval[2].selected) {      if (selval[2].selected) {
  document.classgrade["GD_"+user+'_'+partid+"_tries"].value = "0";   document.classgrade["GD_"+user+'_'+partid+"_tries"].value = "0";
     }      }
  }          }
     }      }
   
     function resetEntry(numpart) {      function resetEntry(numpart) {
Line 2248  sub viewgrades_js { Line 2630  sub viewgrades_js {
   
     for (i=0;i<document.classgrade.total.value;i++) {      for (i=0;i<document.classgrade.total.value;i++) {
  var user = document.classgrade["ctr"+i].value;   var user = document.classgrade["ctr"+i].value;
    user = user.replace(new RegExp(':', 'g'),"_");
  var resetscore = document.classgrade["GD_"+user+"_"+partid+"_awarded"];   var resetscore = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
  resetscore.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;   resetscore.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;
  var resettries = document.classgrade["GD_"+user+"_"+partid+"_tries"];   var resettries = document.classgrade["GD_"+user+"_"+partid+"_tries"];
Line 2272  sub viewgrades { Line 2655  sub viewgrades {
     my ($request) = shift;      my ($request) = shift;
     &viewgrades_js($request);      &viewgrades_js($request);
   
     my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'});       my ($symb,$url) = ($env{'form.symb'},$env{'form.url'}); 
     #need to make sure we have the correct data for later EXT calls,       #need to make sure we have the correct data for later EXT calls, 
     #thus invalidate the cache      #thus invalidate the cache
     &Apache::lonnet::devalidatecourseresdata(      &Apache::lonnet::devalidatecourseresdata(
                  $ENV{'course.'.$ENV{'request.course.id'}.'.num'},                   $env{'course.'.$env{'request.course.id'}.'.num'},
                  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'});                   $env{'course.'.$env{'request.course.id'}.'.domain'});
     &Apache::lonnet::clear_EXT_cache_status();      &Apache::lonnet::clear_EXT_cache_status();
   
     my $result='<h3><font color="#339933">'.&mt('Manual Grading').'</font></h3>';      my $result='<h3><font color="#339933">'.&mt('Manual Grading').'</font></h3>';
     $result.='<font size=+1><b>Current Resource: </b>'.$ENV{'form.probTitle'}.'</font>'."\n";      $result.='<font size=+1><b>Current Resource: </b>'.$env{'form.probTitle'}.'</font>'."\n";
   
     #view individual student submission form - called using Javascript viewOneStudent      #view individual student submission form - called using Javascript viewOneStudent
     $result.=&jscriptNform($url,$symb);      $result.=&jscriptNform($url,$symb);
Line 2291  sub viewgrades { Line 2674  sub viewgrades {
  '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
  '<input type="hidden" name="url"     value="'.$url.'" />'."\n".   '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
  '<input type="hidden" name="command" value="editgrades" />'."\n".   '<input type="hidden" name="command" value="editgrades" />'."\n".
  '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'" />'."\n".   '<input type="hidden" name="section" value="'.$env{'form.section'}.'" />'."\n".
  '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="Status" value="'.$ENV{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n".
  '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n";   '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
   
     my $sectionClass;      my $sectionClass;
     if ($ENV{'form.section'} eq 'all') {      if ($env{'form.section'} eq 'all') {
  $sectionClass='Class </h3>';   $sectionClass='Class </h3>';
     } elsif ($ENV{'form.section'} eq 'no') {      } elsif ($env{'form.section'} eq 'none') {
  $sectionClass='Students in no Section </h3>';   $sectionClass='Students in no Section </h3>';
     } else {      } else {
  $sectionClass='Students in Section '.$ENV{'form.section'}.'</h3>';   $sectionClass='Students in Section '.$env{'form.section'}.'</h3>';
     }      }
     $result.='<h3>Assign Common Grade To '.$sectionClass;      $result.='<h3>Assign Common Grade To '.$sectionClass;
     $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".      $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".
Line 2326  sub viewgrades { Line 2709  sub viewgrades {
     $ctsparts.'" value="'.$partid.'" />'."\n";      $ctsparts.'" value="'.$partid.'" />'."\n";
  $result.='<input type="hidden" name="weight_'.   $result.='<input type="hidden" name="weight_'.
     $partid.'" value="'.$weight{$partid}.'" />'."\n";      $partid.'" value="'.$weight{$partid}.'" />'."\n";
  $result.='<tr><td><b>Part  '.$partid.'&nbsp; &nbsp;Point:</b> </td><td>';   my $display_part=&get_display_part($partid,$url,$symb);
    $result.='<tr><td><b>Part:</b> '.$display_part.'&nbsp; &nbsp;<b>Point:</b> </td><td>';
  $result.='<table border="0"><tr>';     $result.='<table border="0"><tr>';  
  my $ctr = 0;   my $ctr = 0;
  while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across   while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
     $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.      $result.= '<td><label><input type="radio" name="RADVAL_'.$partid.'" '.
  'onclick="javascript:writePoint(\''.$partid.'\','.$weight{$partid}.   'onclick="javascript:writePoint(\''.$partid.'\','.$weight{$partid}.
  ','.$ctr.')" />'.$ctr."</td>\n";   ','.$ctr.')" />'.$ctr."</label></td>\n";
     $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');      $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
     $ctr++;      $ctr++;
  }   }
Line 2346  sub viewgrades { Line 2730  sub viewgrades {
  $weight{$partid}.')"> '.   $weight{$partid}.')"> '.
     '<option selected="on"> </option>'.      '<option selected="on"> </option>'.
     '<option>excused</option>'.      '<option>excused</option>'.
     '<option>reset status</option></select></td></tr>'."\n";      '<option>reset status</option></select></td>'.
               '<td><label><input type="checkbox" name="FORCE_'.$partid.'" /> Override "Correct"</label></td></tr>'."\n";
  $ctsparts++;   $ctsparts++;
     }      }
     $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n".      $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n".
Line 2361  sub viewgrades { Line 2746  sub viewgrades {
  '<table border=0><tr bgcolor="#deffff"><td>&nbsp;<b>No.</b>&nbsp;</td>'.   '<table border=0><tr bgcolor="#deffff"><td>&nbsp;<b>No.</b>&nbsp;</td>'.
  '<td>'.&nameUserString('header')."</td>\n";   '<td>'.&nameUserString('header')."</td>\n";
     my (@parts) = sort(&getpartlist($url,$symb));      my (@parts) = sort(&getpartlist($url,$symb));
       my @partids = ();
     foreach my $part (@parts) {      foreach my $part (@parts) {
  my $display=&Apache::lonnet::metadata($url,$part.'.display');   my $display=&Apache::lonnet::metadata($url,$part.'.display');
  $display =~ s|^Number of Attempts|Tries<br />|; # makes the column narrower   $display =~ s|^Number of Attempts|Tries<br />|; # makes the column narrower
  if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }   if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
    my ($partid) = &split_part_type($part);
           push(@partids, $partid);
    my $display_part=&get_display_part($partid,$url,$symb);
  if ($display =~ /^Partial Credit Factor/) {   if ($display =~ /^Partial Credit Factor/) {
     my ($partid) = &split_part_type($part);      $result.='<td><b>Score Part:</b> '.$display_part.
     $result.='<td><b>Score Part '.$partid.'<br />(weight = '.   ' <br /><b>(weight = '.$weight{$partid}.')</b></td>'."\n";
  $weight{$partid}.')</b></td>'."\n";  
     next;      next;
    } else {
       $display =~s/\[Part: \Q$partid\E\]/Part:<\/b> $display_part/;
  }   }
  $display =~ s|Problem Status|Grade Status<br />|;   $display =~ s|Problem Status|Grade Status<br />|;
  $result.='<td><b>'.$display.'</b></td>'."\n";   $result.='<td><b>'.$display.'</td>'."\n";
     }      }
     $result.='</tr>';      $result.='</tr>';
   
       my %last_resets = 
    &get_last_resets($symb,$env{'request.course.id'},\@partids);
   
     #get info for each student      #get info for each student
     #list all the students - with points and grade status      #list all the students - with points and grade status
     my (undef,undef,$fullname) = &getclasslist($ENV{'form.section'},'1');      my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1');
     my $ctr = 0;      my $ctr = 0;
     foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {      foreach (sort 
  my $uname = $_;       {
  $uname=~s/:/_/;   if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
  $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$uname.'" />'."\n";       return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
    }
    return $a cmp $b;
        } (keys(%$fullname))) {
  $ctr++;   $ctr++;
  $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'},   $result.=&viewstudentgrade($url,$symb,$env{'request.course.id'},
    $_,$$fullname{$_},\@parts,\%weight,$ctr);     $_,$$fullname{$_},\@parts,\%weight,$ctr,\%last_resets);
     }      }
     $result.='</table></td></tr></table>';      $result.='</table></td></tr></table>';
     $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";      $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";
Line 2394  sub viewgrades { Line 2790  sub viewgrades {
  'onClick="javascript:submit();" TARGET=_self /></form>'."\n";   'onClick="javascript:submit();" TARGET=_self /></form>'."\n";
     if (scalar(%$fullname) eq 0) {      if (scalar(%$fullname) eq 0) {
  my $colspan=3+scalar(@parts);   my $colspan=3+scalar(@parts);
  $result='<font color="red">There are no students in section "'.$ENV{'form.section'}.   $result='<font color="red">There are no students in section "'.$env{'form.section'}.
     '" with enrollment status "'.$ENV{'form.Status'}.'" to modify or grade.</font>';      '" with enrollment status "'.$env{'form.Status'}.'" to modify or grade.</font>';
     }      }
     $result.=&show_grading_menu_form($symb,$url);      $result.=&show_grading_menu_form($symb,$url);
     return $result;      return $result;
Line 2403  sub viewgrades { Line 2799  sub viewgrades {
   
 #--- call by previous routine to display each student  #--- call by previous routine to display each student
 sub viewstudentgrade {  sub viewstudentgrade {
     my ($url,$symb,$courseid,$student,$fullname,$parts,$weight,$ctr) = @_;      my ($url,$symb,$courseid,$student,$fullname,$parts,$weight,$ctr,$last_resets) = @_;
     my ($uname,$udom) = split(/:/,$student);      my ($uname,$udom) = split(/:/,$student);
     $student=~s/:/_/;  
     my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);      my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
     my $result='<tr bgcolor="#ffffdd"><td align="right">'.$ctr.'&nbsp;</td><td>&nbsp;'.      my %aggregates = (); 
       my $result='<tr bgcolor="#ffffdd"><td align="right">'.
    '<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'.
    "\n".$ctr.'&nbsp;</td><td>&nbsp;'.
  '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.   '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
  '\')"; TARGET=_self>'.$fullname.'</a> '.   '\')"; TARGET=_self>'.$fullname.'</a> '.
  '<font color="#999999">('.$uname.($ENV{'user.domain'} eq $udom ? '' : ':'.$udom).')</font></td>'."\n";   '<font color="#999999">('.$uname.($env{'user.domain'} eq $udom ? '' : ':'.$udom).')</font></td>'."\n";
       $student=~s/:/_/; # colon doen't work in javascript for names
     foreach my $apart (@$parts) {      foreach my $apart (@$parts) {
  my ($part,$type) = &split_part_type($apart);   my ($part,$type) = &split_part_type($apart);
  my $score=$record{"resource.$part.$type"};   my $score=$record{"resource.$part.$type"};
           $result.='<td align="center">';
           my ($aggtries,$totaltries);
           unless (exists($aggregates{$part})) {
       $totaltries = $record{'resource.'.$part.'.tries'};
   
       $aggtries = $totaltries;
               if ($$last_resets{$part}) {  
                   $aggtries = &get_num_tries(\%record,$$last_resets{$part},
      $part);
               }
               $result.='<input type="hidden" name="'.
                   'GD_'.$student.'_'.$part.'_aggtries" value="'.$aggtries.'" />'."\n";
               $result.='<input type="hidden" name="'.
                   'GD_'.$student.'_'.$part.'_totaltries" value="'.$totaltries.'" />'."\n";
               $aggregates{$part} = 1;
           }
  if ($type eq 'awarded') {   if ($type eq 'awarded') {
     my $pts = $score eq '' ? '' : $score*$$weight{$part};      my $pts = $score eq '' ? '' : $score*$$weight{$part};
     $result.='<input type="hidden" name="'.      $result.='<input type="hidden" name="'.
  'GD_'.$student.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n";   'GD_'.$student.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n";
     $result.='<td align="middle"><input type="text" name="'.      $result.='<input type="text" name="'.
  'GD_'.$student.'_'.$part.'_awarded" '.   'GD_'.$student.'_'.$part.'_awarded" '.
  'onChange="javascript:changeSelect(\''.$part.'\',\''.$student.   'onChange="javascript:changeSelect(\''.$part.'\',\''.$student.
  '\')" value="'.$pts.'" size="4" /></td>'."\n";   '\')" value="'.$pts.'" size="4" /></td>'."\n";
Line 2427  sub viewstudentgrade { Line 2842  sub viewstudentgrade {
     $status = 'nothing' if ($status eq '');      $status = 'nothing' if ($status eq '');
     $result.='<input type="hidden" name="'.'GD_'.$student.'_'.      $result.='<input type="hidden" name="'.'GD_'.$student.'_'.
  $part.'_solved_s" value="'.$status.'" />'."\n";   $part.'_solved_s" value="'.$status.'" />'."\n";
     $result.='<td align="middle">&nbsp;<select name="'.      $result.='&nbsp;<select name="'.
  'GD_'.$student.'_'.$part.'_solved" '.   'GD_'.$student.'_'.$part.'_solved" '.
  'onChange="javascript:changeOneScore(\''.$part.'\',\''.$student.'\')" >'."\n";   'onChange="javascript:changeOneScore(\''.$part.'\',\''.$student.'\')" >'."\n";
     $result.= (($status eq 'excused') ? '<option> </option><option selected="on">excused</option>'       $result.= (($status eq 'excused') ? '<option> </option><option selected="on">excused</option>' 
Line 2438  sub viewstudentgrade { Line 2853  sub viewstudentgrade {
     $result.='<input type="hidden" name="'.      $result.='<input type="hidden" name="'.
  'GD_'.$student.'_'.$part.'_'.$type.'_s" value="'.$score.'" />'.   'GD_'.$student.'_'.$part.'_'.$type.'_s" value="'.$score.'" />'.
     "\n";      "\n";
     $result.='<td align="middle"><input type="text" name="'.      $result.='<input type="text" name="'.
  'GD_'.$student.'_'.$part.'_'.$type.'" '.   'GD_'.$student.'_'.$part.'_'.$type.'" '.
  'value="'.$score.'" size="4" /></td>'."\n";   'value="'.$score.'" size="4" /></td>'."\n";
  }   }
Line 2452  sub viewstudentgrade { Line 2867  sub viewstudentgrade {
 sub editgrades {  sub editgrades {
     my ($request) = @_;      my ($request) = @_;
   
     my $symb=$ENV{'form.symb'};      my $symb=$env{'form.symb'};
     my $url =$ENV{'form.url'};      my $url =$env{'form.url'};
     my $title='<h3><font color="#339933">Current Grade Status</font></h3>';      my $title='<h3><font color="#339933">Current Grade Status</font></h3>';
     $title.='<font size=+1><b>Current Resource: </b>'.$ENV{'form.probTitle'}.'</font><br />'."\n";      $title.='<font size=+1><b>Current Resource: </b>'.$env{'form.probTitle'}.'</font><br />'."\n";
     $title.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n";      $title.='<font size=+1><b>Section: </b>'.$env{'form.section'}.'</font>'."\n";
   
     my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n";      my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n";
     $result.= '<table border="0"><tr bgcolor="#deffff">'.      $result.= '<table border="0"><tr bgcolor="#deffff">'.
Line 2470  sub editgrades { Line 2885  sub editgrades {
     'ungraded' =>'ungraded_attempted',      'ungraded' =>'ungraded_attempted',
     'nothing'  => '',      'nothing'  => '',
     );      );
     my ($classlist,undef,$fullname) = &getclasslist($ENV{'form.section'},'0');      my ($classlist,undef,$fullname) = &getclasslist($env{'form.section'},'0');
   
     my (@partid);      my (@partid);
     my %weight = ();      my %weight = ();
Line 2479  sub editgrades { Line 2894  sub editgrades {
   
     my (@parts) = sort(&getpartlist($url,$symb));      my (@parts) = sort(&getpartlist($url,$symb));
     my $header;      my $header;
     while ($ctr < $ENV{'form.totalparts'}) {      while ($ctr < $env{'form.totalparts'}) {
  my $partid = $ENV{'form.partid_'.$ctr};   my $partid = $env{'form.partid_'.$ctr};
  push @partid,$partid;   push @partid,$partid;
  $weight{$partid} = $ENV{'form.weight_'.$partid};   $weight{$partid} = $env{'form.weight_'.$partid};
  $ctr++;   $ctr++;
     }      }
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
Line 2502  sub editgrades { Line 2917  sub editgrades {
  }   }
     }      }
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
    my $display_part=&get_display_part($partid,$url,$symb);
  $result .= '<td colspan="'.$columns{$partid}.   $result .= '<td colspan="'.$columns{$partid}.
     '" align="center"><b>Part '.$partid.      '" align="center"><b>Part:</b> '.$display_part.
     '</b> (Weight = '.$weight{$partid}.')</td>';      ' (Weight = '.$weight{$partid}.')</td>';
   
     }      }
     $result .= '</tr><tr bgcolor="#deffff">';      $result .= '</tr><tr bgcolor="#deffff">';
Line 2512  sub editgrades { Line 2928  sub editgrades {
     $result .= '</tr>'."\n";      $result .= '</tr>'."\n";
     my $noupdate;      my $noupdate;
     my ($updateCtr,$noupdateCtr) = (1,1);      my ($updateCtr,$noupdateCtr) = (1,1);
     for ($i=0; $i<$ENV{'form.total'}; $i++) {      for ($i=0; $i<$env{'form.total'}; $i++) {
  my $line;   my $line;
  my $user = $ENV{'form.ctr'.$i};   my $user = $env{'form.ctr'.$i};
  my $usercolon = $user;   my ($uname,$udom)=split(/:/,$user);
  $usercolon =~s/_/:/;  
  my ($uname,$udom)=split(/_/,$user);  
  my %newrecord;   my %newrecord;
  my $updateflag = 0;   my $updateflag = 0;
  $line .= '<td>'.&nameUserString(undef,$$fullname{$usercolon},$uname,$udom).'</td>';   $line .= '<td>'.&nameUserString(undef,$$fullname{$user},$uname,$udom).'</td>';
  my $usec=$classlist->{"$uname:$udom"}[5];   my $usec=$classlist->{"$uname:$udom"}[5];
  if (!&canmodify($usec)) {   if (!&canmodify($usec)) {
     my $numcols=scalar(@partid)*4+2;      my $numcols=scalar(@partid)*4+2;
     $noupdate.=$line."<td colspan=\"$numcols\"><font color=\"red\">Not allowed to modify student</font></td></tr>";      $noupdate.=$line."<td colspan=\"$numcols\"><font color=\"red\">Not allowed to modify student</font></td></tr>";
     next;      next;
  }   }
           my %aggregate = ();
           my $aggregateflag = 0;
    $user=~s/:/_/; # colon doen't work in javascript for names
  foreach (@partid) {   foreach (@partid) {
     my $old_aw    = $ENV{'form.GD_'.$user.'_'.$_.'_awarded_s'};      my $old_aw    = $env{'form.GD_'.$user.'_'.$_.'_awarded_s'};
     my $old_part_pcr = $old_aw/($weight{$_} ne '0' ? $weight{$_}:1);      my $old_part_pcr = $old_aw/($weight{$_} ne '0' ? $weight{$_}:1);
     my $old_part  = $old_aw eq '' ? '' : $old_part_pcr;      my $old_part  = $old_aw eq '' ? '' : $old_part_pcr;
     my $old_score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_solved_s'}};      my $old_score = $scoreptr{$env{'form.GD_'.$user.'_'.$_.'_solved_s'}};
       my $awarded   = $env{'form.GD_'.$user.'_'.$_.'_awarded'};
     my $awarded   = $ENV{'form.GD_'.$user.'_'.$_.'_awarded'};  
     my $pcr       = $awarded/($weight{$_} ne '0' ? $weight{$_} : 1);      my $pcr       = $awarded/($weight{$_} ne '0' ? $weight{$_} : 1);
     my $partial   = $awarded eq '' ? '' : $pcr;      my $partial   = $awarded eq '' ? '' : $pcr;
     my $score;      my $score;
     if ($partial eq '') {      if ($partial eq '') {
  $score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_solved_s'}};   $score = $scoreptr{$env{'form.GD_'.$user.'_'.$_.'_solved_s'}};
     } elsif ($partial > 0) {      } elsif ($partial > 0) {
  $score = 'correct_by_override';   $score = 'correct_by_override';
     } elsif ($partial == 0) {      } elsif ($partial == 0) {
  $score = 'incorrect_by_override';   $score = 'incorrect_by_override';
     }      }
     my $dropMenu = $ENV{'form.GD_'.$user.'_'.$_.'_solved'};      my $dropMenu = $env{'form.GD_'.$user.'_'.$_.'_solved'};
     $score = 'excused' if (($dropMenu eq 'excused') && ($score ne 'excused'));      $score = 'excused' if (($dropMenu eq 'excused') && ($score ne 'excused'));
   
       $newrecord{'resource.'.$_.'.regrader'}=
    "$env{'user.name'}:$env{'user.domain'}";
     if ($dropMenu eq 'reset status' &&      if ($dropMenu eq 'reset status' &&
  $old_score ne '') { # ignore if no previous attempts => nothing to reset   $old_score ne '') { # ignore if no previous attempts => nothing to reset
  $newrecord{'resource.'.$_.'.tries'} = 0;   $newrecord{'resource.'.$_.'.tries'} = '';
  $newrecord{'resource.'.$_.'.solved'} = '';   $newrecord{'resource.'.$_.'.solved'} = '';
  $newrecord{'resource.'.$_.'.award'} = '';   $newrecord{'resource.'.$_.'.award'} = '';
  $newrecord{'resource.'.$_.'.awarded'} = 0;   $newrecord{'resource.'.$_.'.awarded'} = '';
  $newrecord{'resource.'.$_.'.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";  
  $updateflag = 1;   $updateflag = 1;
                   if ($env{'form.GD_'.$user.'_'.$_.'_aggtries'} > 0) {
                       my $aggtries = $env{'form.GD_'.$user.'_'.$_.'_aggtries'};
                       my $totaltries = $env{'form.GD_'.$user.'_'.$_.'_totaltries'};
                       my $solvedstatus = $env{'form.GD_'.$user.'_'.$_.'_solved_s'};
                       &decrement_aggs($symb,$_,\%aggregate,$aggtries,$totaltries,$solvedstatus);
                       $aggregateflag = 1;
                   }
     } elsif (!($old_part eq $partial && $old_score eq $score)) {      } elsif (!($old_part eq $partial && $old_score eq $score)) {
  $updateflag = 1;   $updateflag = 1;
  $newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';   $newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';
Line 2572  sub editgrades { Line 2996  sub editgrades {
  my ($part,$type) = &split_part_type($stores);   my ($part,$type) = &split_part_type($stores);
  if ($part !~ m/^\Q$partid\E/) { next;}   if ($part !~ m/^\Q$partid\E/) { next;}
  if ($type eq 'awarded' || $type eq 'solved') { next; }   if ($type eq 'awarded' || $type eq 'solved') { next; }
  my $old_aw    = $ENV{'form.GD_'.$user.'_'.$part.'_'.$type.'_s'};   my $old_aw    = $env{'form.GD_'.$user.'_'.$part.'_'.$type.'_s'};
  my $awarded   = $ENV{'form.GD_'.$user.'_'.$part.'_'.$type};   my $awarded   = $env{'form.GD_'.$user.'_'.$part.'_'.$type};
  if ($awarded ne '' && $awarded ne $old_aw) {   if ($awarded ne '' && $awarded ne $old_aw) {
     $newrecord{'resource.'.$part.'.'.$type}= $awarded;      $newrecord{'resource.'.$part.'.'.$type}= $awarded;
     $newrecord{'resource.'.$part.'.regrader'}="$ENV{'user.name'}:$ENV{'user.domain'}";      $newrecord{'resource.'.$part.'.regrader'}="$env{'user.name'}:$env{'user.domain'}";
     $updateflag=1;      $updateflag=1;
  }   }
  $line .= '<td align="center">'.$old_aw.'&nbsp;</td>'.   $line .= '<td align="center">'.$old_aw.'&nbsp;</td>'.
Line 2584  sub editgrades { Line 3008  sub editgrades {
     }      }
  }   }
  $line.='</tr>'."\n";   $line.='</tr>'."\n";
   
    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
   
  if ($updateflag) {   if ($updateflag) {
     $count++;      $count++;
     &Apache::lonnet::cstore(\%newrecord,$symb,$ENV{'request.course.id'},      &Apache::lonnet::cstore(\%newrecord,$symb,$env{'request.course.id'},
     $udom,$uname);      $udom,$uname);
   
       if (&Apache::bridgetask::in_queue('gradingqueue',$symb,$cdom,
         $cnum,$udom,$uname)) {
    # need to figure out if should be in queue.
    my %record =  
       &Apache::lonnet::restore($symb,$env{'request.course.id'},
        $udom,$uname);
    my $all_graded = 1;
    my $none_graded = 1;
    foreach my $part (@parts) {
       if ( $record{'resource.'.$part.'.awarded'} eq '' ) {
    $all_graded = 0;
       } else {
    $none_graded = 0;
       }
    }
   
    if ($all_graded || $none_graded) {
       &Apache::bridgetask::remove_from_queue('gradingqueue',
      $symb,$cdom,$cnum,
      $udom,$uname);
    }
       }
   
     $result.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$updateCtr.'&nbsp;</td>'.$line;      $result.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$updateCtr.'&nbsp;</td>'.$line;
     $updateCtr++;      $updateCtr++;
  } else {   } else {
     $noupdate.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$noupdateCtr.'&nbsp;</td>'.$line;      $noupdate.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$noupdateCtr.'&nbsp;</td>'.$line;
     $noupdateCtr++;      $noupdateCtr++;
  }   }
           if ($aggregateflag) {
               &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
     $cdom,$cnum);
           }
     }      }
     if ($noupdate) {      if ($noupdate) {
 # my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;  # my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;
  my $numcols=scalar(@partid)*4+2;   my $numcols=scalar(@partid)*4+2;
  $result .= '<tr bgcolor="#ffffff"><td align="center" colspan="'.$numcols.'">No Changes Occurred For the Students Below</td></tr>'.$noupdate;   $result .= '<tr bgcolor="#ffffff"><td align="center" colspan="'.$numcols.'">No Changes Occurred For the Students Below</td></tr><tr bgcolor="#ffffde">'.$noupdate;
     }      }
     $result .= '</table></td></tr></table>'."\n".      $result .= '</table></td></tr></table>'."\n".
  &show_grading_menu_form ($symb,$url);   &show_grading_menu_form ($symb,$url);
     my $msg = '<br /><b>Number of records updated = '.$rec_update.      my $msg = '<br /><b>Number of records updated = '.$rec_update.
  ' for '.$count.' student'.($count <= 1 ? '' : 's').'.</b><br />'.   ' for '.$count.' student'.($count <= 1 ? '' : 's').'.</b><br />'.
  '<b>Total number of students = '.$ENV{'form.total'}.'</b><br />';   '<b>Total number of students = '.$env{'form.total'}.'</b><br />';
     return $title.$msg.$result;      return $title.$msg.$result;
 }  }
   
Line 2627  sub split_part_type { Line 3083  sub split_part_type {
 #  #
 #--- Javascript to handle csv upload  #--- Javascript to handle csv upload
 sub csvupload_javascript_reverse_associate {  sub csvupload_javascript_reverse_associate {
       my $error1=&mt('You need to specify the username or ID');
       my $error2=&mt('You need to specify at least one grading field');
   return(<<ENDPICK);    return(<<ENDPICK);
   function verify(vf) {    function verify(vf) {
     var foundsomething=0;      var foundsomething=0;
     var founduname=0;      var founduname=0;
     var founddomain=0;      var foundID=0;
     for (i=0;i<=vf.nfields.value;i++) {      for (i=0;i<=vf.nfields.value;i++) {
       tw=eval('vf.f'+i+'.selectedIndex');        tw=eval('vf.f'+i+'.selectedIndex');
       if (i==0 && tw!=0) { founduname=1; }        if (i==0 && tw!=0) { foundID=1; }
       if (i==1 && tw!=0) { founddomain=1; }        if (i==1 && tw!=0) { founduname=1; }
       if (i!=0 && i!=1 && tw!=0) { foundsomething=1; }        if (i!=0 && i!=1 && i!=2 && tw!=0) { foundsomething=1; }
     }      }
     if (founduname==0 || founddomain==0) {      if (founduname==0 && foundID==0) {
       alert('You need to specify at both the username and domain');   alert('$error1');
       return;   return;
     }      }
     if (foundsomething==0) {      if (foundsomething==0) {
       alert('You need to specify at least one grading field');   alert('$error2');
       return;   return;
     }      }
     vf.submit();      vf.submit();
   }    }
Line 2665  ENDPICK Line 3123  ENDPICK
 }  }
   
 sub csvupload_javascript_forward_associate {  sub csvupload_javascript_forward_associate {
       my $error1=&mt('You need to specify the username or ID');
       my $error2=&mt('You need to specify at least one grading field');
   return(<<ENDPICK);    return(<<ENDPICK);
   function verify(vf) {    function verify(vf) {
     var foundsomething=0;      var foundsomething=0;
     var founduname=0;      var founduname=0;
     var founddomain=0;      var foundID=0;
     for (i=0;i<=vf.nfields.value;i++) {      for (i=0;i<=vf.nfields.value;i++) {
       tw=eval('vf.f'+i+'.selectedIndex');        tw=eval('vf.f'+i+'.selectedIndex');
       if (tw==1) { founduname=1; }        if (tw==1) { foundID=1; }
       if (tw==2) { founddomain=1; }        if (tw==2) { founduname=1; }
       if (tw>2) { foundsomething=1; }        if (tw>3) { foundsomething=1; }
     }      }
     if (founduname==0 || founddomain==0) {      if (founduname==0 && foundID==0) {
       alert('You need to specify at both the username and domain');   alert('$error1');
       return;   return;
     }      }
     if (foundsomething==0) {      if (foundsomething==0) {
       alert('You need to specify at least one grading field');   alert('$error2');
       return;   return;
     }      }
     vf.submit();      vf.submit();
   }    }
Line 2702  ENDPICK Line 3162  ENDPICK
 sub csvuploadmap_header {  sub csvuploadmap_header {
     my ($request,$symb,$url,$datatoken,$distotal)= @_;      my ($request,$symb,$url,$datatoken,$distotal)= @_;
     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();
     }      }
   
     my ($result) = &showResourceInfo($url,$ENV{'form.probTitle'});      my ($result) = &showResourceInfo($url,$env{'form.probTitle'});
       my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
       my $ignore=&mt('Ignore First Line');
     $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><font color="#339933">Uploading Class Grades</font></h3>  <h3><font color="#339933">Uploading Class Grades</font></h3>
Line 2720  Total number of records found in file: $ Line 3181  Total number of records found in file: $
 Enter as many fields as you can. The system will inform you and bring you back  Enter as many fields as you can. The system will inform you and bring you back
 to this page if the data selected is insufficient to run your class.<hr />  to this page if the data selected is insufficient to run your class.<hr />
 <input type="button" value="Reverse Association" onClick="javascript:this.form.associate.value='Reverse Association';submit(this.form);" />  <input type="button" value="Reverse Association" onClick="javascript:this.form.associate.value='Reverse Association';submit(this.form);" />
   <label><input type="checkbox" name="noFirstLine" $checked />$ignore</label>
 <input type="hidden" name="associate"  value="" />  <input type="hidden" name="associate"  value="" />
 <input type="hidden" name="phase"      value="three" />  <input type="hidden" name="phase"      value="three" />
 <input type="hidden" name="datatoken"  value="$datatoken" />  <input type="hidden" name="datatoken"  value="$datatoken" />
 <input type="hidden" name="fileupload" value="$ENV{'form.fileupload'}" />  <input type="hidden" name="fileupload" value="$env{'form.fileupload'}" />
 <input type="hidden" name="upfiletype" value="$ENV{'form.upfiletype'}" />  <input type="hidden" name="upfiletype" value="$env{'form.upfiletype'}" />
 <input type="hidden" name="upfile_associate"   <input type="hidden" name="upfile_associate" 
                                        value="$ENV{'form.upfile_associate'}" />                                         value="$env{'form.upfile_associate'}" />
 <input type="hidden" name="symb"       value="$symb" />  <input type="hidden" name="symb"       value="$symb" />
 <input type="hidden" name="url"        value="$url" />  <input type="hidden" name="url"        value="$url" />
 <input type="hidden" name="saveState"  value="$ENV{'form.saveState'}" />  <input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
 <input type="hidden" name="probTitle"  value="$ENV{'form.probTitle'}" />  <input type="hidden" name="probTitle"  value="$env{'form.probTitle'}" />
 <input type="hidden" name="command"    value="csvuploadassign" />  <input type="hidden" name="command"    value="csvuploadoptions" />
 <hr />  <hr />
 <script type="text/javascript" language="Javascript">  <script type="text/javascript" language="Javascript">
 $javascript  $javascript
Line 2744  ENDPICK Line 3206  ENDPICK
 sub csvupload_fields {  sub csvupload_fields {
     my ($url,$symb) = @_;      my ($url,$symb) = @_;
     my (@parts) = &getpartlist($url,$symb);      my (@parts) = &getpartlist($url,$symb);
     my @fields=(['username','Student Username'],['domain','Student Domain']);      my @fields=(['ID','Student ID'],
    ['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);
    if ($name=~/^stores_(.*)_awarded/) {
       push(@fields,['stores_'.$1.'_points',"Points [Part: $1]"]);
    }
  push(@fields,\@datum);   push(@fields,\@datum);
     }      }
     return (@fields);      return (@fields);
Line 2767  sub csvuploadmap_footer { Line 3234  sub csvuploadmap_footer {
 ENDPICK  ENDPICK
 }  }
   
 sub upcsvScores_form {  sub checkforfile_js {
     my ($request) = shift;  
     my ($symb,$url)=&get_symb_and_url($request);  
     if (!$symb) {return '';}  
     my $result =<<CSVFORMJS;      my $result =<<CSVFORMJS;
 <script type="text/javascript" language="javascript">  <script type="text/javascript" language="javascript">
     function checkUpload(formname) {      function checkUpload(formname) {
Line 2782  sub upcsvScores_form { Line 3246  sub upcsvScores_form {
     }      }
     </script>      </script>
 CSVFORMJS  CSVFORMJS
     $ENV{'form.probTitle'} = &Apache::lonnet::gettitle($symb);      return $result;
     my ($table) = &showResourceInfo($url,$ENV{'form.probTitle'});  }
   
   sub upcsvScores_form {
       my ($request) = shift;
       my ($symb,$url)=&get_symb_and_url($request);
       if (!$symb) {return '';}
       my $result=&checkforfile_js();
       $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb);
       my ($table) = &showResourceInfo($url,$env{'form.probTitle'});
     $result.=$table;      $result.=$table;
     $result.='<br /><table width=100% border=0><tr><td bgcolor="#777777">'."\n";      $result.='<br /><table width=100% border=0><tr><td bgcolor="#777777">'."\n";
     $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";      $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n";
Line 2791  CSVFORMJS Line 3263  CSVFORMJS
  '.</b></td></tr>'."\n";   '.</b></td></tr>'."\n";
     $result.='<tr bgcolor=#ffffe6><td>'."\n";      $result.='<tr bgcolor=#ffffe6><td>'."\n";
     my $upfile_select=&Apache::loncommon::upfile_select_html();      my $upfile_select=&Apache::loncommon::upfile_select_html();
       my $ignore=&mt('Ignore First Line');
     $result.=<<ENDUPFORM;      $result.=<<ENDUPFORM;
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <input type="hidden" name="symb" value="$symb" />  <input type="hidden" name="symb" value="$symb" />
 <input type="hidden" name="url" value="$url" />  <input type="hidden" name="url" value="$url" />
 <input type="hidden" name="command" value="csvuploadmap" />  <input type="hidden" name="command" value="csvuploadmap" />
 <input type="hidden" name="probTitle" value="$ENV{'form.probTitle'}" />  <input type="hidden" name="probTitle" value="$env{'form.probTitle'}" />
 <input type="hidden" name="saveState"  value="$ENV{'form.saveState'}" />  <input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
 $upfile_select  $upfile_select
 <br /><input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Scores" />  <br /><input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Scores" />
   <label><input type="checkbox" name="noFirstLine" />$ignore</label>
 </form>  </form>
 ENDUPFORM  ENDUPFORM
     $result.='</td></tr></table>'."\n";      $result.='</td></tr></table>'."\n";
Line 2816  sub csvuploadmap { Line 3289  sub csvuploadmap {
     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 {      } else {
  $datatoken=$ENV{'form.datatoken'};   $datatoken=$env{'form.datatoken'};
  &Apache::loncommon::load_tmp_file($request);   &Apache::loncommon::load_tmp_file($request);
     }      }
     my @records=&Apache::loncommon::upfile_record_sep();      my @records=&Apache::loncommon::upfile_record_sep();
       if ($env{'form.noFirstLine'}) { shift(@records); }
     &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);      &csvuploadmap_header($request,$symb,$url,$datatoken,$#records+1);
     my ($i,$keyfields);      my ($i,$keyfields);
     if (@records) {      if (@records) {
  my @fields=&csvupload_fields($url,$symb);   my @fields=&csvupload_fields($url,$symb);
   
  if ($ENV{'form.upfile_associate'} eq 'reverse') {   if ($env{'form.upfile_associate'} eq 'reverse') {
     &Apache::loncommon::csv_print_samples($request,\@records);      &Apache::loncommon::csv_print_samples($request,\@records);
     $i=&Apache::loncommon::csv_print_select_table($request,\@records,      $i=&Apache::loncommon::csv_print_select_table($request,\@records,
   \@fields);    \@fields);
Line 2848  sub csvuploadmap { Line 3322  sub csvuploadmap {
     return '';      return '';
 }  }
   
 sub csvuploadassign {  sub csvuploadoptions {
     my ($request)= @_;      my ($request)= @_;
     my ($symb,$url)=&get_symb_and_url($request);      my ($symb,$url)=&get_symb_and_url($request);
     if (!$symb) {return '';}      my $checked=(($env{'form.noFirstLine'})?'1':'0');
     &Apache::loncommon::load_tmp_file($request);      my $ignore=&mt('Ignore First Line');
     my @gradedata = &Apache::loncommon::upfile_record_sep();      $request->print(<<ENDPICK);
     my @keyfields = split(/\,/,$ENV{'form.keyfields'});  <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
     my %fields=();  <h3><font color="#339933">Uploading Class Grade Options</font></h3>
     for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) {  <input type="hidden" name="command"    value="csvuploadassign" />
  if ($ENV{'form.upfile_associate'} eq 'reverse') {  <!--
     if ($ENV{'form.f'.$i} ne 'none') {  <p>
  $fields{$keyfields[$i]}=$ENV{'form.f'.$i};  <label>
      <input type="checkbox" name="show_full_results" />
      Show a table of all changes
   </label>
   </p>
   -->
   <p>
   <label>
      <input type="checkbox" name="overwite_scores" checked="checked" />
      Overwrite any existing score
   </label>
   </p>
   ENDPICK
       my %fields=&get_fields();
       if (!defined($fields{'domain'})) {
    my $domform = &Apache::loncommon::select_dom_form($env{'request.role.domain'},'default_domain');
    $request->print("\n<p> Users are in domain: ".$domform."</p>\n");
       }
       foreach my $key (sort(keys(%env))) {
    if ($key !~ /^form\.(.*)$/) { next; }
    my $cleankey=$1;
    if ($cleankey eq 'command') { next; }
    $request->print('<input type="hidden" name="'.$cleankey.
    '"  value="'.$env{$key}.'" />'."\n");
       }
       # FIXME do a check for any duplicated user ids...
       # FIXME do a check for any invalid user ids?...
       $request->print('<input type="submit" value="Assign Grades" /><br />
   <hr /></form>'."\n");
       $request->print(&show_grading_menu_form($symb,$url));
       return '';
   }
   
   sub get_fields {
       my %fields;
       my @keyfields = split(/\,/,$env{'form.keyfields'});
       for (my $i=0; $i<=$env{'form.nfields'}; $i++) {
    if ($env{'form.upfile_associate'} eq 'reverse') {
       if ($env{'form.f'.$i} ne 'none') {
    $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];
     }      }
  }   }
     }      }
       return %fields;
   }
   
   sub csvuploadassign {
       my ($request)= @_;
       my ($symb,$url)=&get_symb_and_url($request);
       if (!$symb) {return '';}
       &Apache::loncommon::load_tmp_file($request);
       my @gradedata = &Apache::loncommon::upfile_record_sep();
       if ($env{'form.noFirstLine'}) { shift(@gradedata); }
       my %fields=&get_fields();
     $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 ($classlist) = &getclasslist('all',0);      my ($classlist) = &getclasslist('all',0);
     my @notallowed;      my @notallowed;
     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 $domain;
    if ($entries{$fields{'domain'}}) {
       $domain=$entries{$fields{'domain'}};
    } else {
       $domain=$env{'form.default_domain'};
    }
    $domain=~s/\s//g;
  my $username=$entries{$fields{'username'}};   my $username=$entries{$fields{'username'}};
  $username=~s/\s//g;   $username=~s/\s//g;
  my $domain=$entries{$fields{'domain'}};   if (!$username) {
  $domain=~s/\s//g;      my $id=$entries{$fields{'ID'}};
       $id=~s/\s//g;
       my %ids=&Apache::lonnet::idget($domain,$id);
       $username=$ids{$id};
    }
  if (!exists($$classlist{"$username:$domain"})) {   if (!exists($$classlist{"$username:$domain"})) {
     push(@skipped,"$username:$domain");      my $id=$entries{$fields{'ID'}};
       $id=~s/\s//g;
       if ($id) {
    push(@skipped,"$id:$domain");
       } else {
    push(@skipped,"$username:$domain");
       }
     next;      next;
  }   }
  my $usec=$classlist->{"$username:$domain"}[5];   my $usec=$classlist->{"$username:$domain"}[5];
Line 2888  sub csvuploadassign { Line 3429  sub csvuploadassign {
     push(@notallowed,"$username:$domain");      push(@notallowed,"$username:$domain");
     next;      next;
  }   }
    my %points;
  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 'ID' || $dest eq 'username' ||
     if ($entries{$fields{$dest}} eq '') { next; }   $dest eq 'domain') { next; }
     my $store_key=$dest;      if ($entries{$fields{$dest}} =~ /^\s*$/) { next; }
     $store_key=~s/^stores/resource/;      if ($dest=~/stores_(.*)_points/) {
     $store_key=~s/_/\./g;   my $part=$1;
     $grades{$store_key}=$entries{$fields{$dest}};   my $wgt =&Apache::lonnet::EXT('resource.'.$part.'.weight',
  }        $symb,$domain,$username);
  $grades{"resource.regrader"}="$ENV{'user.name'}:$ENV{'user.domain'}";   $entries{$fields{$dest}}=~s/\s//g;
  &Apache::lonnet::cstore(\%grades,$symb,$ENV{'request.course.id'},   my $pcr=$entries{$fields{$dest}} / $wgt;
  $domain,$username);   my $award='correct_by_override';
  $request->print('.');   $grades{"resource.$part.awarded"}=$pcr;
    $grades{"resource.$part.solved"}=$award;
    $points{$part}=1;
       } else {
    if ($dest=~/stores_(.*)_awarded/) { if ($points{$1}) {next;} }
    if ($dest=~/stores_(.*)_solved/)  { if ($points{$1}) {next;} }
    my $store_key=$dest;
    $store_key=~s/^stores/resource/;
    $store_key=~s/_/\./g;
    $grades{$store_key}=$entries{$fields{$dest}};
       }
    }
    if (! %grades) { push(@skipped,"$username:$domain no data to store"); }
    $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}";
   # &Apache::lonnet::logthis(" storing ".(join('-',%grades)));
    my $result=&Apache::lonnet::cstore(\%grades,$symb,
      $env{'request.course.id'},
      $domain,$username);
    if ($result eq 'ok') {
       $request->print('.');
    } else {
       $request->print("<p>
                                 <font color='red'>
                                    Failed to store student $username\@$domain.
                                    Message when trying to store was ($result)
                                 </font>
                                </p>" );
    }
  $request->rflush();   $request->rflush();
  $countdone++;   $countdone++;
     }      }
Line 2945  function checkPickOne(formname) { Line 3514  function checkPickOne(formname) {
 LISTJAVASCRIPT  LISTJAVASCRIPT
     &commonJSfunctions($request);      &commonJSfunctions($request);
     my ($symb,$url) = &get_symb_and_url($request);      my ($symb,$url) = &get_symb_and_url($request);
     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'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
   
     my $result='<h3><font color="#339933">&nbsp;'.      my $result='<h3><font color="#339933">&nbsp;'.
  'Manual Grading by Page or Sequence</font></h3>';   'Manual Grading by Page or Sequence</font></h3>';
Line 2977  LISTJAVASCRIPT Line 3546  LISTJAVASCRIPT
     $result.='<input type="hidden" name="page" />'."\n".      $result.='<input type="hidden" name="page" />'."\n".
  '<input type="hidden" name="title" />'."\n";   '<input type="hidden" name="title" />'."\n";
   
     $result.='&nbsp;<b>View Problems Text: </b><input type="radio" name="vProb" value="no" checked="on" /> no '."\n".      $result.='&nbsp;<b>View Problems Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
  '<input type="radio" name="vProb" value="yes" /> yes '."<br>\n";   '<label><input type="radio" name="vProb" value="yes" /> yes </label>'."<br />\n";
   
     $result.='&nbsp;<b>Submission Details: </b>'.      $result.='&nbsp;<b>Submission Details: </b>'.
  '<input type="radio" name="lastSub" value="none" /> none'."\n".   '<label><input type="radio" name="lastSub" value="none" /> none</label>'."\n".
  '<input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions'."\n".   '<label><input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions</label>'."\n".
  '<input type="radio" name="lastSub" value="all" /> all details'."\n";   '<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
   
     $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".      $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
  '<input type="hidden" name="Status"  value="'.$ENV{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
  '<input type="hidden" name="command" value="displayPage" />'."\n".   '<input type="hidden" name="command" value="displayPage" />'."\n".
  '<input type="hidden" name="url"     value="'.$url.'" />'."\n".   '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
  '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
  '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."<br />\n";   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n";
   
     $result.='&nbsp;<input type="button" '.      $result.='&nbsp;<input type="button" '.
  'onClick="javascript:checkPickOne(this.form);"value="Next->" /><br />'."\n";   'onClick="javascript:checkPickOne(this.form);"value="Next->" /><br />'."\n";
Line 3007  LISTJAVASCRIPT Line 3576  LISTJAVASCRIPT
     
     my (undef,undef,$fullname) = &getclasslist($getsec,'1');      my (undef,undef,$fullname) = &getclasslist($getsec,'1');
     my $ptr = 1;      my $ptr = 1;
     foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {      foreach my $student (sort 
    {
        if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
    return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
        }
        return $a cmp $b;
    } (keys(%$fullname))) {
  my ($uname,$udom) = split(/:/,$student);   my ($uname,$udom) = split(/:/,$student);
  $studentTable.=($ptr%2 == 1 ? '<tr bgcolor="#ffffe6">' : '</td>');   $studentTable.=($ptr%2 == 1 ? '<tr bgcolor="#ffffe6">' : '</td>');
  $studentTable.='<td align="right">'.$ptr.'&nbsp;</td>';   $studentTable.='<td align="right">'.$ptr.'&nbsp;</td>';
  $studentTable.='<td>&nbsp;<input type="radio" name="student" value="'.$student.'" /> '   $studentTable.='<td>&nbsp;<label><input type="radio" name="student" value="'.$student.'" /> '
     .&nameUserString(undef,$$fullname{$student},$uname,$udom)."\n";      .&nameUserString(undef,$$fullname{$student},$uname,$udom)."</label>\n";
  $studentTable.=($ptr%2 == 0 ? '</td></tr>' : '');   $studentTable.=($ptr%2 == 0 ? '</td></tr>' : '');
  $ptr++;   $ptr++;
     }      }
Line 3036  sub getSymbMap { Line 3611  sub getSymbMap {
     my $minder = 0;      my $minder = 0;
   
     # Gather every sequence that has problems.      # Gather every sequence that has problems.
     my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); }, 1);      my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); },
          1,0,1);
     for my $sequence ($navmap->getById('0.0'), @sequences) {      for my $sequence ($navmap->getById('0.0'), @sequences) {
  if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) {   if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) {
     my $title = $minder.'.'.$sequence->compTitle();      my $title = $minder.'.'.$sequence->compTitle();
Line 3045  sub getSymbMap { Line 3621  sub getSymbMap {
     $minder++;      $minder++;
  }   }
     }      }
   
     $navmap->untieHashes();  
     return \@titles,\%symbx;      return \@titles,\%symbx;
 }  }
   
Line 3056  sub displayPage { Line 3630  sub displayPage {
     my ($request) = shift;      my ($request) = shift;
   
     my ($symb,$url) = &get_symb_and_url($request);      my ($symb,$url) = &get_symb_and_url($request);
     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'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
     my $pageTitle = $ENV{'form.page'};      my $pageTitle = $env{'form.page'};
     my ($classlist,undef,$fullname) = &getclasslist($getsec,'1');      my ($classlist,undef,$fullname) = &getclasslist($getsec,'1');
     my ($uname,$udom) = split(/:/,$ENV{'form.student'});      my ($uname,$udom) = split(/:/,$env{'form.student'});
     my $usec=$classlist->{$ENV{'form.student'}}[5];      my $usec=$classlist->{$env{'form.student'}}[5];
   
     #need to make sure we have the correct data for later EXT calls,       #need to make sure we have the correct data for later EXT calls, 
     #thus invalidate the cache      #thus invalidate the cache
     &Apache::lonnet::devalidatecourseresdata(      &Apache::lonnet::devalidatecourseresdata(
                  $ENV{'course.'.$ENV{'request.course.id'}.'.num'},                   $env{'course.'.$env{'request.course.id'}.'.num'},
                  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'});                   $env{'course.'.$env{'request.course.id'}.'.domain'});
     &Apache::lonnet::clear_EXT_cache_status();      &Apache::lonnet::clear_EXT_cache_status();
   
     if (!&canview($usec)) {      if (!&canview($usec)) {
  $request->print('<font color="red">Unable to view requested student.('.$ENV{'form.student'}.')</font>');   $request->print('<font color="red">Unable to view requested student.('.$env{'form.student'}.')</font>');
  $request->print(&show_grading_menu_form($symb,$url));   $request->print(&show_grading_menu_form($symb,$url));
  return;   return;
     }      }
     my $result='<h3><font color="#339933">&nbsp;'.$ENV{'form.title'}.'</font></h3>';      my $result='<h3><font color="#339933">&nbsp;'.$env{'form.title'}.'</font></h3>';
     $result.='<h3>&nbsp;Student: '.&nameUserString(undef,$$fullname{$ENV{'form.student'}},$uname,$udom).      $result.='<h3>&nbsp;Student: '.&nameUserString(undef,$$fullname{$env{'form.student'}},$uname,$udom).
  '</h3>'."\n";   '</h3>'."\n";
     &sub_page_js($request);      &sub_page_js($request);
     $request->print($result);      $request->print($result);
   
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($ENV{'form.page'});      my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps      my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
       if (!$map) {
    $request->print('<font color="red">Unable to view requested sequence. ('.$resUrl.')</font>');
    $request->print(&show_grading_menu_form($symb,$url));
    return; 
       }
     my $iterator = $navmap->getIterator($map->map_start(),      my $iterator = $navmap->getIterator($map->map_start(),
  $map->map_finish());   $map->map_finish());
   
     my $studentTable='<form action="/adm/grades" method="post" name="gradePage">'."\n".      my $studentTable='<form action="/adm/grades" method="post" name="gradePage">'."\n".
  '<input type="hidden" name="command" value="gradeByPage" />'."\n".   '<input type="hidden" name="command" value="gradeByPage" />'."\n".
  '<input type="hidden" name="fullname" value="'.$$fullname{$ENV{'form.student'}}.'" />'."\n".   '<input type="hidden" name="fullname" value="'.$$fullname{$env{'form.student'}}.'" />'."\n".
  '<input type="hidden" name="student" value="'.$ENV{'form.student'}.'" />'."\n".   '<input type="hidden" name="student" value="'.$env{'form.student'}.'" />'."\n".
  '<input type="hidden" name="page"    value="'.$pageTitle.'" />'."\n".   '<input type="hidden" name="page"    value="'.$pageTitle.'" />'."\n".
  '<input type="hidden" name="title"   value="'.$ENV{'form.title'}.'" />'."\n".   '<input type="hidden" name="title"   value="'.$env{'form.title'}.'" />'."\n".
  '<input type="hidden" name="url"     value="'.$url.'" />'."\n".   '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
  '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
  '<input type="hidden" name="overRideScore" value="no" />'."\n".   '<input type="hidden" name="overRideScore" value="no" />'."\n".
  '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n";   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n";
   
     my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').      my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL').
  '/check.gif" height="16" border="0" />';   '/check.gif" height="16" border="0" />';
Line 3108  sub displayPage { Line 3686  sub displayPage {
  '<table border="0"><tr><td bgcolor="#777777">'.   '<table border="0"><tr><td bgcolor="#777777">'.
  '<table border="0"><tr bgcolor="#e6ffff">'.   '<table border="0"><tr bgcolor="#e6ffff">'.
  '<td align="center"><b>&nbsp;Prob.&nbsp;</b></td>'.   '<td align="center"><b>&nbsp;Prob.&nbsp;</b></td>'.
  '<td><b>&nbsp;'.($ENV{'form.vProb'} eq 'no' ? 'Title' : 'Problem Text').'/Grade</b></td></tr>';   '<td><b>&nbsp;'.($env{'form.vProb'} eq 'no' ? 'Title' : 'Problem Text').'/Grade</b></td></tr>';
   
     my ($depth,$question,$prob) = (1,1,1);      my ($depth,$question,$prob) = (1,1,1);
     $iterator->next(); # skip the first BEGIN_MAP      $iterator->next(); # skip the first BEGIN_MAP
Line 3117  sub displayPage { Line 3695  sub displayPage {
         if($curRes == $iterator->BEGIN_MAP) { $depth++; }          if($curRes == $iterator->BEGIN_MAP) { $depth++; }
         if($curRes == $iterator->END_MAP) { $depth--; }          if($curRes == $iterator->END_MAP) { $depth--; }
   
         if (ref($curRes) && $curRes->is_problem()) {          if (ref($curRes) && $curRes->is_problem() && !$curRes->randomout) {
     my $parts = $curRes->parts();      my $parts = $curRes->parts();
             my $title = $curRes->compTitle();              my $title = $curRes->compTitle();
     my $symbx = $curRes->symb();      my $symbx = $curRes->symb();
     $studentTable.='<tr bgcolor="#ffffe6"><td align="center" valign="top" >'.$prob.      $studentTable.='<tr bgcolor="#ffffe6"><td align="center" valign="top" >'.$prob.
  (scalar(@{$parts}) == 1 ? '' : '<br>('.scalar(@{$parts}).'&nbsp;parts)').'</td>';   (scalar(@{$parts}) == 1 ? '' : '<br>('.scalar(@{$parts}).'&nbsp;parts)').'</td>';
     $studentTable.='<td valign="top">';      $studentTable.='<td valign="top">';
     if ($ENV{'form.vProb'} eq 'yes' ) {      if ($env{'form.vProb'} eq 'yes' ) {
  $studentTable.=&show_problem($request,$symbx,$uname,$udom,1,   $studentTable.=&show_problem($request,$symbx,$uname,$udom,1,
      undef,'both');       undef,'both');
     } else {      } else {
  my $companswer = &Apache::loncommon::get_student_answers($symbx,$uname,$udom,$ENV{'request.course.id'});   my $companswer = &Apache::loncommon::get_student_answers($symbx,$uname,$udom,$env{'request.course.id'});
  $companswer =~ s|<form(.*?)>||g;   $companswer =~ s|<form(.*?)>||g;
  $companswer =~ s|</form>||g;   $companswer =~ s|</form>||g;
 # while ($companswer =~ /(<a href\=\"javascript:newWindow.*?Script Vars<\/a>)/s) { #<a href="javascript:newWindow</a>  # while ($companswer =~ /(<a href\=\"javascript:newWindow.*?Script Vars<\/a>)/s) { #<a href="javascript:newWindow</a>
Line 3139  sub displayPage { Line 3717  sub displayPage {
  $studentTable.='&nbsp;<b>'.$title.'</b>&nbsp;<br>&nbsp;<b>Correct answer:</b><br>'.$companswer;   $studentTable.='&nbsp;<b>'.$title.'</b>&nbsp;<br>&nbsp;<b>Correct answer:</b><br>'.$companswer;
     }      }
   
     my %record = &Apache::lonnet::restore($symbx,$ENV{'request.course.id'},$udom,$uname);      my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname);
   
     if ($ENV{'form.lastSub'} eq 'datesub') {      if ($env{'form.lastSub'} eq 'datesub') {
  if ($record{'version'} eq '') {   if ($record{'version'} eq '') {
     $studentTable.='<br />&nbsp;<font color="red">No recorded submission for this problem</font><br />';      $studentTable.='<br />&nbsp;<font color="red">No recorded submission for this problem</font><br />';
  } else {   } else {
Line 3158  sub displayPage { Line 3736  sub displayPage {
     $studentTable.= &displaySubByDates($symbx,\%record,$parts,\%responseType,$checkIcon,$uname,$udom);      $studentTable.= &displaySubByDates($symbx,\%record,$parts,\%responseType,$checkIcon,$uname,$udom);
   
  }   }
     } elsif ($ENV{'form.lastSub'} eq 'all') {      } elsif ($env{'form.lastSub'} eq 'all') {
  my $last = ($ENV{'form.lastSub'} eq 'last' ? 'last' : '');   my $last = ($env{'form.lastSub'} eq 'last' ? 'last' : '');
  $studentTable.=&Apache::loncommon::get_previous_attempt($symbx,$uname,$udom,   $studentTable.=&Apache::loncommon::get_previous_attempt($symbx,$uname,$udom,
  $ENV{'request.course.id'},   $env{'request.course.id'},
  '','.submission');   '','.submission');
     
     }      }
Line 3179  sub displayPage { Line 3757  sub displayPage {
         $curRes = $iterator->next();          $curRes = $iterator->next();
     }      }
   
     $navmap->untieHashes();  
   
     $studentTable.='</td></tr></table></td></tr></table>'."\n".      $studentTable.='</td></tr></table></td></tr></table>'."\n".
  '<input type="button" value="Save" '.   '<input type="button" value="Save" '.
  'onClick="javascript:checkSubmitPage(this.form,'.$question.');" TARGET=_self />'.   'onClick="javascript:checkSubmitPage(this.form,'.$question.');" TARGET=_self />'.
Line 3193  sub displayPage { Line 3769  sub displayPage {
   
 sub displaySubByDates {  sub displaySubByDates {
     my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;      my ($symb,$record,$parts,$responseType,$checkIcon,$uname,$udom) = @_;
       my $isCODE=0;
       if (exists($record->{'resource.CODE'})) { $isCODE=1; }
     my $studentTable='<table border="0" width="100%"><tr><td bgcolor="#777777">'.      my $studentTable='<table border="0" width="100%"><tr><td bgcolor="#777777">'.
  '<table border="0" width="100%"><tr bgcolor="#e6ffff">'.   '<table border="0" width="100%"><tr bgcolor="#e6ffff">'.
  '<td><b>Date/Time</b></td>'.   '<td><b>Date/Time</b></td>'.
    ($isCODE?'<td><b>CODE</b></td>':'').
  '<td><b>Submission</b></td>'.   '<td><b>Submission</b></td>'.
  '<td><b>Status&nbsp;</b></td></tr>';   '<td><b>Status&nbsp;</b></td></tr>';
     my ($version);      my ($version);
Line 3208  sub displaySubByDates { Line 3787  sub displaySubByDates {
     for ($version=1;$version<=$$record{'version'};$version++) {      for ($version=1;$version<=$$record{'version'};$version++) {
  my $timestamp = scalar(localtime($$record{$version.':timestamp'}));   my $timestamp = scalar(localtime($$record{$version.':timestamp'}));
  $studentTable.='<tr bgcolor="#ffffff" valign="top"><td>'.$timestamp.'</td>';   $studentTable.='<tr bgcolor="#ffffff" valign="top"><td>'.$timestamp.'</td>';
    if ($isCODE) {
       $studentTable.='<td>'.$record->{$version.':resource.CODE'}.'</td>';
    }
  my @versionKeys = split(/\:/,$$record{$version.':keys'});   my @versionKeys = split(/\:/,$$record{$version.':keys'});
  my @displaySub = ();   my @displaySub = ();
  foreach my $partid (@{$parts}) {   foreach my $partid (@{$parts}) {
     my @matchKey = sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys);      my @matchKey = sort(grep /^resource\.\Q$partid\E\..*?\.submission$/,@versionKeys);
 #    next if ($$record{"$version:resource.$partid.solved"} eq '');  #    next if ($$record{"$version:resource.$partid.solved"} eq '');
       my $display_part=&get_display_part($partid,undef,$symb);
     foreach my $matchKey (@matchKey) {      foreach my $matchKey (@matchKey) {
  if (exists($$record{$version.':'.$matchKey}) &&   if (exists($$record{$version.':'.$matchKey}) &&
     $$record{$version.':'.$matchKey} ne '') {      $$record{$version.':'.$matchKey} ne '') {
     my ($responseId)=($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/);      my ($responseId)=($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/);
     $displaySub[0].='<b>Part&nbsp;'.$partid.'&nbsp;';      $displaySub[0].='<b>Part:</b>&nbsp;'.$display_part.'&nbsp;';
     $displaySub[0].='<font color="#999999">(ID&nbsp;'.      $displaySub[0].='<font color="#999999">(ID&nbsp;'.
  $responseId.')</font>&nbsp;';   $responseId.')</font>&nbsp;<b>';
     if ($$record{"$version:resource.$partid.tries"} eq '') {      if ($$record{"$version:resource.$partid.tries"} eq '') {
  $displaySub[0].='Trial&nbsp;not&nbsp;counted';   $displaySub[0].='Trial&nbsp;not&nbsp;counted';
     } else {      } else {
Line 3237  sub displaySubByDates { Line 3820  sub displaySubByDates {
  }   }
     }      }
     if (exists $$record{"$version:resource.$partid.award"}) {      if (exists $$record{"$version:resource.$partid.award"}) {
  $displaySub[1].='<b>Part&nbsp;'.$partid.'</b> &nbsp;'.   $displaySub[1].='<b>Part:</b>&nbsp;'.$display_part.' &nbsp;'.
     lc($$record{"$version:resource.$partid.award"}).' '.      lc($$record{"$version:resource.$partid.award"}).' '.
     $mark{$$record{"$version:resource.$partid.solved"}}.      $mark{$$record{"$version:resource.$partid.solved"}}.
     '<br />';      '<br />';
     }      }
     if (exists $$record{"$version:resource.$partid.regrader"}) {      if (exists $$record{"$version:resource.$partid.regrader"}) {
  $displaySub[2].=$$record{"$version:resource.$partid.regrader"}.   $displaySub[2].=$$record{"$version:resource.$partid.regrader"}.
     ' (<b>'.&mt('Part').':</b> '.$partid.')';      ' (<b>'.&mt('Part').':</b> '.$display_part.')';
     }      }
  }   }
  # needed because old essay regrader has not parts info   # needed because old essay regrader has not parts info
Line 3265  sub displaySubByDates { Line 3848  sub displaySubByDates {
 sub updateGradeByPage {  sub updateGradeByPage {
     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'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
     my $pageTitle = $ENV{'form.page'};      my $pageTitle = $env{'form.page'};
     my ($classlist,undef,$fullname) = &getclasslist($getsec,'1');      my ($classlist,undef,$fullname) = &getclasslist($getsec,'1');
     my ($uname,$udom) = split(/:/,$ENV{'form.student'});      my ($uname,$udom) = split(/:/,$env{'form.student'});
     my $usec=$classlist->{$ENV{'form.student'}}[5];      my $usec=$classlist->{$env{'form.student'}}[5];
     if (!&canmodify($usec)) {      if (!&canmodify($usec)) {
  $request->print('<font color="red">Unable to modify requested student.('.$ENV{'form.student'}.'</font>');   $request->print('<font color="red">Unable to modify requested student.('.$env{'form.student'}.'</font>');
  $request->print(&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'}));   $request->print(&show_grading_menu_form($env{'form.symb'},$env{'form.url'}));
  return;   return;
     }      }
     my $result='<h3><font color="#339933">&nbsp;'.$ENV{'form.title'}.'</font></h3>';      my $result='<h3><font color="#339933">&nbsp;'.$env{'form.title'}.'</font></h3>';
     $result.='<h3>&nbsp;Student: '.&nameUserString(undef,$ENV{'form.fullname'},$uname,$udom).      $result.='<h3>&nbsp;Student: '.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).
  '</h3>'."\n";   '</h3>'."\n";
   
     $request->print($result);      $request->print($result);
   
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $ENV{'form.page'});      my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps      my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
       if (!$map) {
    $request->print('<font color="red">Unable to grade requested sequence. ('.$resUrl.')</font>');
    my ($symb,$url)=&get_symb_and_url($request);
    $request->print(&show_grading_menu_form($symb,$url));
    return; 
       }
     my $iterator = $navmap->getIterator($map->map_start(),      my $iterator = $navmap->getIterator($map->map_start(),
  $map->map_finish());   $map->map_finish());
   
Line 3314  sub updateGradeByPage { Line 3902  sub updateGradeByPage {
   
     my %newrecord=();      my %newrecord=();
     my @displayPts=();      my @displayPts=();
               my %aggregate = ();
               my $aggregateflag = 0;
     foreach my $partid (@{$parts}) {      foreach my $partid (@{$parts}) {
  my $newpts = $ENV{'form.GD_BOX'.$question.'_'.$partid};   my $newpts = $env{'form.GD_BOX'.$question.'_'.$partid};
  my $oldpts = $ENV{'form.oldpts'.$question.'_'.$partid};   my $oldpts = $env{'form.oldpts'.$question.'_'.$partid};
   
  my $wgt = $ENV{'form.WGT'.$question.'_'.$partid} != 0 ?    my $wgt = $env{'form.WGT'.$question.'_'.$partid} != 0 ? 
     $ENV{'form.WGT'.$question.'_'.$partid} : 1;      $env{'form.WGT'.$question.'_'.$partid} : 1;
  my $partial = $newpts/$wgt;   my $partial = $newpts/$wgt;
  my $score;   my $score;
  if ($partial > 0) {   if ($partial > 0) {
Line 3327  sub updateGradeByPage { Line 3917  sub updateGradeByPage {
  } elsif ($newpts ne '') { #empty is taken as 0   } elsif ($newpts ne '') { #empty is taken as 0
     $score = 'incorrect_by_override';      $score = 'incorrect_by_override';
  }   }
  my $dropMenu = $ENV{'form.GD_SEL'.$question.'_'.$partid};   my $dropMenu = $env{'form.GD_SEL'.$question.'_'.$partid};
  if ($dropMenu eq 'excused') {   if ($dropMenu eq 'excused') {
     $partial = '';      $partial = '';
     $score = 'excused';      $score = 'excused';
  } elsif ($dropMenu eq 'reset status'   } elsif ($dropMenu eq 'reset status'
  && $ENV{'form.solved'.$question.'_'.$partid} ne '') { #update only if previous record exists   && $env{'form.solved'.$question.'_'.$partid} ne '') { #update only if previous record exists
     $newrecord{'resource.'.$partid.'.tries'} = 0;      $newrecord{'resource.'.$partid.'.tries'} = 0;
     $newrecord{'resource.'.$partid.'.solved'} = '';      $newrecord{'resource.'.$partid.'.solved'} = '';
     $newrecord{'resource.'.$partid.'.award'} = '';      $newrecord{'resource.'.$partid.'.award'} = '';
     $newrecord{'resource.'.$partid.'.awarded'} = 0;      $newrecord{'resource.'.$partid.'.awarded'} = 0;
     $newrecord{'resource.'.$partid.'.regrader'} = "$ENV{'user.name'}:$ENV{'user.domain'}";      $newrecord{'resource.'.$partid.'.regrader'} = "$env{'user.name'}:$env{'user.domain'}";
     $changeflag++;      $changeflag++;
     $newpts = '';      $newpts = '';
  }                      
                       my $aggtries =  $env{'form.aggtries'.$question.'_'.$partid};
  my $oldstatus = $ENV{'form.solved'.$question.'_'.$partid};                      my $totaltries = $env{'form.totaltries'.$question.'_'.$partid};
  $displayPts[0].='&nbsp;<b>Part</b> '.$partid.' = '.                      my $solvedstatus = $env{'form.solved'.$question.'_'.$partid};
                       if ($aggtries > 0) {
                           &decrement_aggs($symbx,$partid,\%aggregate,$aggtries,$totaltries,$solvedstatus);
                           $aggregateflag = 1;
                       }
    }
    my $display_part=&get_display_part($partid,undef,
      $curRes->symb());
    my $oldstatus = $env{'form.solved'.$question.'_'.$partid};
    $displayPts[0].='&nbsp;<b>Part:</b> '.$display_part.' = '.
     (($oldstatus eq 'excused') ? 'excused' : $oldpts).      (($oldstatus eq 'excused') ? 'excused' : $oldpts).
     '&nbsp;<br>';      '&nbsp;<br>';
  $displayPts[1].='&nbsp;<b>Part</b> '.$partid.' = '.   $displayPts[1].='&nbsp;<b>Part:</b> '.$display_part.' = '.
      (($score eq 'excused') ? 'excused' : $newpts).       (($score eq 'excused') ? 'excused' : $newpts).
     '&nbsp;<br>';      '&nbsp;<br>';
   
Line 3355  sub updateGradeByPage { Line 3954  sub updateGradeByPage {
   
  $newrecord{'resource.'.$partid.'.awarded'}  = $partial if $partial ne '';   $newrecord{'resource.'.$partid.'.awarded'}  = $partial if $partial ne '';
  $newrecord{'resource.'.$partid.'.solved'}   = $score if $score ne '';   $newrecord{'resource.'.$partid.'.solved'}   = $score if $score ne '';
  $newrecord{'resource.'.$partid.'.regrader'} = "$ENV{'user.name'}:$ENV{'user.domain'}"   $newrecord{'resource.'.$partid.'.regrader'} = "$env{'user.name'}:$env{'user.domain'}"
     if (scalar(keys(%newrecord)) > 0);      if (scalar(keys(%newrecord)) > 0);
   
  $changeflag++;   $changeflag++;
     }      }
     if (scalar(keys(%newrecord)) > 0) {      if (scalar(keys(%newrecord)) > 0) {
  &Apache::lonnet::cstore(\%newrecord,$symbx,$ENV{'request.course.id'},   &Apache::lonnet::cstore(\%newrecord,$symbx,$env{'request.course.id'},
  $udom,$uname);   $udom,$uname);
     }      }
               if ($aggregateflag) {
                   &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
                         $env{'course.'.$env{'request.course.id'}.'.domain'},
                         $env{'course.'.$env{'request.course.id'}.'.num'});
               }
   
     $studentTable.='<td valign="top">'.$displayPts[0].'</td>'.      $studentTable.='<td valign="top">'.$displayPts[0].'</td>'.
  '<td valign="top">'.$displayPts[1].'</td>'.   '<td valign="top">'.$displayPts[1].'</td>'.
Line 3374  sub updateGradeByPage { Line 3978  sub updateGradeByPage {
         $curRes = $iterator->next();          $curRes = $iterator->next();
     }      }
   
     $navmap->untieHashes();  
   
     $studentTable.='</td></tr></table></td></tr></table>';      $studentTable.='</td></tr></table></td></tr></table>';
     $studentTable.=&show_grading_menu_form($ENV{'form.symb'},$ENV{'form.url'});      $studentTable.=&show_grading_menu_form($env{'form.symb'},$env{'form.url'});
     my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' :      my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' :
   'The scores were changed for '.    'The scores were changed for '.
   $changeflag.' problem'.($changeflag == 1 ? '.' : 's.'));    $changeflag.' problem'.($changeflag == 1 ? '.' : 's.'));
Line 3399  sub defaultFormData { Line 4001  sub defaultFormData {
     return '      return '
       <input type="hidden" name="symb"    value="'.$symb.'" />'."\n".        <input type="hidden" name="symb"    value="'.$symb.'" />'."\n".
      '<input type="hidden" name="url"     value="'.$url.'" />'."\n".       '<input type="hidden" name="url"     value="'.$url.'" />'."\n".
      '<input type="hidden" name="saveState" value="'.$ENV{'form.saveState'}.'" />'."\n".       '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
      '<input type="hidden" name="probTitle" value="'.$ENV{'form.probTitle'}.'" />'."\n";       '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
 }  }
   
 sub getSequenceDropDown {  sub getSequenceDropDown {
Line 3420  sub getSequenceDropDown { Line 4022  sub getSequenceDropDown {
     return $result;      return $result;
 }  }
   
 sub scantron_uploads {  sub scantron_filenames {
     if (!-e $Apache::lonnet::perlvar{'lonScansDir'}) { return ''};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my $result= '<select name="scantron_selectfile">';      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};  
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};  
     my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname,      my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname,
     &Apache::loncommon::propath($cdom,$cname));      &Apache::loncommon::propath($cdom,$cname));
     $result.="<option></option>";      my @possiblenames;
     foreach my $filename (sort(@files)) {      foreach my $filename (sort(@files)) {
  ($filename)=split(/&/,$filename);   ($filename)=split(/&/,$filename);
  if ($filename!~/^scantron_orig_/) { next ; }   if ($filename!~/^scantron_orig_/) { next ; }
  $filename=~s/^scantron_orig_//;   $filename=~s/^scantron_orig_//;
  $result.="<option>$filename</option>\n";   push(@possiblenames,$filename);
       }
       return @possiblenames;
   }
   
   sub scantron_uploads {
       my ($file2grade) = @_;
       my $result= '<select name="scantron_selectfile">';
       $result.="<option></option>";
       foreach my $filename (sort(&scantron_filenames())) {
    $result.="<option".($filename eq $file2grade ? ' selected="on"':'').">$filename</option>\n";
     }      }
     $result.="</select>";      $result.="</select>";
     return $result;      return $result;
Line 3453  sub scantron_scantab { Line 4063  sub scantron_scantab {
 }  }
   
 sub scantron_CODElist {  sub scantron_CODElist {
     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 @names=&Apache::lonnet::getkeys('CODEs',$cdom,$cnum);      my @names=&Apache::lonnet::getkeys('CODEs',$cdom,$cnum);
     my $namechoice='<option></option>';      my $namechoice='<option></option>';
     foreach my $name (sort(@names)) {      foreach my $name (sort {uc($a) cmp uc($b)} @names) {
  if ($name =~ /^error: 2 /) { next; }   if ($name =~ /^error: 2 /) { next; }
    if ($name =~ /^type\0/) { next; }
  $namechoice.='<option value="'.$name.'">'.$name.'</option>';   $namechoice.='<option value="'.$name.'">'.$name.'</option>';
     }      }
     $namechoice='<select name="scantron_CODElist">'.$namechoice.'</select>';      $namechoice='<select name="scantron_CODElist">'.$namechoice.'</select>';
Line 3467  sub scantron_CODElist { Line 4078  sub scantron_CODElist {
   
 sub scantron_CODEunique {  sub scantron_CODEunique {
     my $result='<nobr>      my $result='<nobr>
                  <input type="radio" name="scantron_CODEunique"                   <label><input type="radio" name="scantron_CODEunique"
                         value="Yes" checked="on" /> Yes                          value="Yes" checked="on" /> Yes </label>
                 </nobr>                  </nobr>
                 <nobr>                  <nobr>
                  <input type="radio" name="scantron_CODEunique"                   <label><input type="radio" name="scantron_CODEunique"
                         value="No" /> No                          value="No" /> No </label>
                 </nobr>';                  </nobr>';
     return $result;      return $result;
 }  }
   
 sub scantron_selectphase {  sub scantron_selectphase {
     my ($r) = @_;      my ($r,$file2grade) = @_;
     my ($symb,$url)=&get_symb_and_url($r);      my ($symb,$url)=&get_symb_and_url($r);
     if (!$symb) {return '';}      if (!$symb) {return '';}
     my $sequence_selector=&getSequenceDropDown($r,$symb);      my $sequence_selector=&getSequenceDropDown($r,$symb);
     my $default_form_data=&defaultFormData($symb,$url);      my $default_form_data=&defaultFormData($symb,$url);
     my $grading_menu_button=&show_grading_menu_form($symb,$url);      my $grading_menu_button=&show_grading_menu_form($symb,$url);
     my $file_selector=&scantron_uploads();      my $file_selector=&scantron_uploads($file2grade);
     my $format_selector=&scantron_scantab();      my $format_selector=&scantron_scantab();
     my $CODE_selector=&scantron_CODElist();      my $CODE_selector=&scantron_CODElist();
     my $CODE_unique=&scantron_CODEunique();      my $CODE_unique=&scantron_CODEunique();
Line 3494  sub scantron_selectphase { Line 4105  sub scantron_selectphase {
     $result.= <<SCANTRONFORM;      $result.= <<SCANTRONFORM;
     <table width="100%" border="0">      <table width="100%" border="0">
     <tr>      <tr>
        <form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantron_process">
       <td bgcolor="#777777">        <td bgcolor="#777777">
        <form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantron_process">         <input type="hidden" name="command" value="scantron_warning" />
        <input type="hidden" name="command" value="scantron_validate" />  
         $default_form_data          $default_form_data
         <table width="100%" border="0">          <table width="100%" border="0">
           <tr bgcolor="#e6ffff">            <tr bgcolor="#e6ffff">
Line 3522  sub scantron_selectphase { Line 4133  sub scantron_selectphase {
           <tr bgcolor="#ffffe6">            <tr bgcolor="#ffffe6">
     <td> Options: </td>      <td> Options: </td>
             <td>              <td>
                 <input type="checkbox" name="scantron_options_redo" value="redo_skipped"/> Do only previously skipped records <br />         <label><input type="checkbox" name="scantron_options_redo" value="redo_skipped"/> Do only previously skipped records</label> <br />
                 <input type="checkbox" name="scantron_options_ignore" value="ignore_corrections"/> Remove all exisiting corrections                 <label><input type="checkbox" name="scantron_options_ignore" value="ignore_corrections"/> Remove all exisiting corrections</label>
     </td>      </td>
           </tr>            </tr>
           <tr bgcolor="#ffffe6">            <tr bgcolor="#ffffe6">
             <td colspan="2">              <td colspan="2">
               <input type="submit" value="Validate Scantron Records" />                <input type="submit" value="Grading: Validate Scantron Records" />
             </td>              </td>
           </tr>            </tr>
         </table>          </table>
        </form>         </td>
       </td>       </form>
     </tr>      </tr>
 SCANTRONFORM  SCANTRONFORM
         
     $r->print($result);      $r->print($result);
   
     if (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'}) ||      if (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) ||
         &Apache::lonnet::allowed('usc',$ENV{'request.course.id'})) {          &Apache::lonnet::allowed('usc',$env{'request.course.id'})) {
   
         $r->print(<<SCANTRONFORM);          $r->print(<<SCANTRONFORM);
     <tr>      <tr>
Line 3555  SCANTRONFORM Line 4166  SCANTRONFORM
             <td>              <td>
 SCANTRONFORM  SCANTRONFORM
     my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));      my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));
     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'};
     $r->print(<<UPLOAD);      $r->print(<<UPLOAD);
               <script type="text/javascript" language="javascript">                <script type="text/javascript" language="javascript">
     function checkUpload(formname) {      function checkUpload(formname) {
Line 3589  SCANTRONFORM Line 4200  SCANTRONFORM
     }      }
     $r->print(<<SCANTRONFORM);      $r->print(<<SCANTRONFORM);
     <tr>      <tr>
       <td bgcolor="#777777">        <form action='/adm/grades' name='scantron_download'>
         <form action='/adm/grades' name='scantron_download'>          <td bgcolor="#777777">
           <input type="hidden" name="command" value="scantron_download" />            <input type="hidden" name="command" value="scantron_download" />
           <table width="100%" border="0">            <table width="100%" border="0">
             <tr bgcolor="#e6ffff">              <tr bgcolor="#e6ffff">
Line 3602  SCANTRONFORM Line 4213  SCANTRONFORM
               <td> Filename of scoring office file: </td><td> $file_selector </td>                <td> Filename of scoring office file: </td><td> $file_selector </td>
             </tr>              </tr>
             <tr bgcolor="#ffffe6">              <tr bgcolor="#ffffe6">
       <td>  
                 Records to download  
               </td>  
               <td>  
                   <input type="radio" name="scantron_options" value="download_skipped"/> Skipped Records <br />  
                   <input type="radio" name="scantron_options" value="download_corrected"/> Corrected Records <br />  
                   <input checked="on" type="radio" name="scantron_options" value="dowload_orig"/> Original Records  
               </td>  
             </tr>  
             <tr bgcolor="#ffffe6">  
               <td colspan="2">                <td colspan="2">
                 <input type="submit" value="Validate Scantron Records" />                  <input type="submit" value="Download: Show List of Associated Files" />
               </td>                </td>
             </tr>              </tr>
           </table>            </table>
         </form>          </td>
       </td>        </form>
     </tr>      </tr>
 SCANTRONFORM  SCANTRONFORM
   
     $r->print(<<SCANTRONFORM);      $r->print(<<SCANTRONFORM);
   </table>    </table>
 </form>  
 $grading_menu_button  $grading_menu_button
 SCANTRONFORM  SCANTRONFORM
   
Line 3713  sub scantron_fixup_scanline { Line 4313  sub scantron_fixup_scanline {
     &scan_data($scan_data,      &scan_data($scan_data,
        "$whichline.no_bubble.".$args->{'question'},'1');         "$whichline.no_bubble.".$args->{'question'},'1');
  } else {   } else {
     substr($answer,$args->{'response'},1)=$on;      if ($on eq 'letter') {
    my @alphabet=('A'..'Z');
    $answer=$alphabet[$args->{'response'}];
       } elsif ($on eq 'number') {
    $answer=$args->{'response'}+1;
       } else {
    substr($answer,$args->{'response'},1)=$on;
       }
     &scan_data($scan_data,      &scan_data($scan_data,
        "$whichline.no_bubble.".$args->{'question'},undef,'1');         "$whichline.no_bubble.".$args->{'question'},undef,'1');
  }   }
Line 3725  sub scantron_fixup_scanline { Line 4332  sub scantron_fixup_scanline {
   
 sub scan_data {  sub scan_data {
     my ($scan_data,$key,$value,$delete)=@_;      my ($scan_data,$key,$value,$delete)=@_;
     my $filename=$ENV{'form.scantron_selectfile'};      my $filename=$env{'form.scantron_selectfile'};
     if (defined($value)) {      if (defined($value)) {
  $scan_data->{$filename.'_'.$key} = $value;   $scan_data->{$filename.'_'.$key} = $value;
     }      }
Line 3738  sub scantron_parse_scanline { Line 4345  sub scantron_parse_scanline {
     my %record;      my %record;
     my $questions=substr($line,$$scantron_config{'Qstart'}-1);      my $questions=substr($line,$$scantron_config{'Qstart'}-1);
     my $data=substr($line,0,$$scantron_config{'Qstart'}-1);      my $data=substr($line,0,$$scantron_config{'Qstart'}-1);
     if ($$scantron_config{'CODElocation'} ne 0) {      if (!($$scantron_config{'CODElocation'} eq 0 ||
  if ($$scantron_config{'CODElocation'} < 0) {    $$scantron_config{'CODElocation'} eq 'none')) {
    if ($$scantron_config{'CODElocation'} < 0 ||
       $$scantron_config{'CODElocation'} eq 'letter' ||
       $$scantron_config{'CODElocation'} eq 'number') {
     $record{'scantron.CODE'}=substr($data,      $record{'scantron.CODE'}=substr($data,
     $$scantron_config{'CODEstart'}-1,      $$scantron_config{'CODEstart'}-1,
     $$scantron_config{'CODElength'});      $$scantron_config{'CODElength'});
Line 3773  sub scantron_parse_scanline { Line 4383  sub scantron_parse_scanline {
  my $currentquest=substr($questions,0,$$scantron_config{'Qlength'});   my $currentquest=substr($questions,0,$$scantron_config{'Qlength'});
  substr($questions,0,$$scantron_config{'Qlength'})='';   substr($questions,0,$$scantron_config{'Qlength'})='';
  if (length($currentquest) < $$scantron_config{'Qlength'}) { next; }   if (length($currentquest) < $$scantron_config{'Qlength'}) { next; }
  my @array=split($$scantron_config{'Qon'},$currentquest,-1);   if ($$scantron_config{'Qon'} eq 'letter') {
  if (length($array[0]) eq $$scantron_config{'Qlength'}) {      if ($currentquest eq '?') {
     $record{"scantron.$questnum.answer"}='';   push(@{$record{'scantron.doubleerror'}},$questnum);
     if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {   $record{"scantron.$questnum.answer"}='';
  push(@{$record{"scantron.missingerror"}},$questnum);      } elsif (!$currentquest 
      }       || $currentquest eq $$scantron_config{'Qoff'}
        || $currentquest !~ /^[A-Z]$/) {
    $record{"scantron.$questnum.answer"}='';
    if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
       push(@{$record{"scantron.missingerror"}},$questnum);
    }
       } else {
    $record{"scantron.$questnum.answer"}=$currentquest;
       }
    } elsif ($$scantron_config{'Qon'} eq 'number') {
       if ($currentquest eq '?') {
    push(@{$record{'scantron.doubleerror'}},$questnum);
    $record{"scantron.$questnum.answer"}='';
    } elsif (!$currentquest 
    || $currentquest eq $$scantron_config{'Qoff'} 
    || $currentquest !~ /^\d$/) {
    $record{"scantron.$questnum.answer"}='';
    if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
       push(@{$record{"scantron.missingerror"}},$questnum);
    }
       } else {
    $record{"scantron.$questnum.answer"}=
       $alphabet[$currentquest-1];
       }
  } else {   } else {
     $record{"scantron.$questnum.answer"}=$alphabet[length($array[0])];      my @array=split($$scantron_config{'Qon'},$currentquest,-1);
       if (length($array[0]) eq $$scantron_config{'Qlength'}) {
    $record{"scantron.$questnum.answer"}='';
    if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
       push(@{$record{"scantron.missingerror"}},$questnum);
    }
       } else {
    $record{"scantron.$questnum.answer"}=
       $alphabet[length($array[0])];
       }
       if (scalar(@array) gt 2) {
    push(@{$record{'scantron.doubleerror'}},$questnum);
    my @ans=@array;
    my $i=length($ans[0]);shift(@ans);
    while ($#ans) {
       $i+=length($ans[0])+1;
       $record{"scantron.$questnum.answer"}.=$alphabet[$i];
       shift(@ans);
    }
       }
  }   }
   if (scalar(@array) gt 2) {  
      push(@{$record{'scantron.doubleerror'}},$questnum);  
      my @ans=@array;  
      my $i=length($ans[0]);shift(@ans);  
     while ($#ans) {  
   $i+=length($ans[0])+1;  
   $record{"scantron.$questnum.answer"}.=$alphabet[$i];  
   shift(@ans);  
      }  
   }  
     }      }
     $record{'scantron.maxquest'}=$questnum;      $record{'scantron.maxquest'}=$questnum;
     return \%record;      return \%record;
Line 3821  sub scantron_find_student { Line 4463  sub scantron_find_student {
   
 sub scantron_filter {  sub scantron_filter {
     my ($curres)=@_;      my ($curres)=@_;
     if (ref($curres) && $curres->is_problem() && !$curres->randomout) {                          # randomout is dysfunctional at best for this purpose
       if (ref($curres) && $curres->is_problem()) { #&& !$curres->randomout) {
  return 1;   return 1;
     }      }
     return 0;      return 0;
Line 3829  sub scantron_filter { Line 4472  sub scantron_filter {
   
 sub scantron_process_corrections {  sub scantron_process_corrections {
     my ($r) = @_;      my ($r) = @_;
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
     my $which=$ENV{'form.scantron_line'};      my $which=$env{'form.scantron_line'};
     my $line=&scantron_get_line($scanlines,$scan_data,$which);      my $line=&scantron_get_line($scanlines,$scan_data,$which);
     my ($skip,$err,$errmsg);      my ($skip,$err,$errmsg);
     if ($ENV{'form.scantron_skip_record'}) {      if ($env{'form.scantron_skip_record'}) {
  $skip=1;   $skip=1;
     } elsif ($ENV{'form.scantron_corrections'} =~ /^(duplicate|incorrect)ID$/) {      } elsif ($env{'form.scantron_corrections'} =~ /^(duplicate|incorrect)ID$/) {
  my $newstudent=$ENV{'form.scantron_username'}.':'.   my $newstudent=$env{'form.scantron_username'}.':'.
     $ENV{'form.scantron_domain'};      $env{'form.scantron_domain'};
  my $newid=$classlist->{$newstudent}->[&Apache::loncoursedata::CL_ID];   my $newid=$classlist->{$newstudent}->[&Apache::loncoursedata::CL_ID];
  ($line,$err,$errmsg)=   ($line,$err,$errmsg)=
     &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,$which,      &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,$which,
      'ID',{'newid'=>$newid,       'ID',{'newid'=>$newid,
     'username'=>$ENV{'form.scantron_username'},      'username'=>$env{'form.scantron_username'},
     'domain'=>$ENV{'form.scantron_domain'}});      'domain'=>$env{'form.scantron_domain'}});
     } elsif ($ENV{'form.scantron_corrections'} =~ /^(duplicate|incorrect)CODE$/) {      } elsif ($env{'form.scantron_corrections'} =~ /^(duplicate|incorrect)CODE$/) {
  my $resolution=$ENV{'form.scantron_CODE_resolution'};   my $resolution=$env{'form.scantron_CODE_resolution'};
  my $newCODE;   my $newCODE;
  my %args;   my %args;
  if      ($resolution eq 'use_unfound') {   if      ($resolution eq 'use_unfound') {
     $newCODE='use_unfound';      $newCODE='use_unfound';
  } elsif ($resolution eq 'use_found') {   } elsif ($resolution eq 'use_found') {
     $newCODE=$ENV{'form.scantron_CODE_selectedvalue'};      $newCODE=$env{'form.scantron_CODE_selectedvalue'};
  } elsif ($resolution eq 'use_typed') {   } elsif ($resolution eq 'use_typed') {
     $newCODE=$ENV{'form.scantron_CODE_newvalue'};      $newCODE=$env{'form.scantron_CODE_newvalue'};
  } elsif ($resolution =~ /^use_closest_(\d+)/) {   } elsif ($resolution =~ /^use_closest_(\d+)/) {
     $newCODE=$ENV{"form.scantron_CODE_closest_$1"};      $newCODE=$env{"form.scantron_CODE_closest_$1"};
  }   }
  if ($ENV{'form.scantron_corrections'} eq 'duplicateCODE') {   if ($env{'form.scantron_corrections'} eq 'duplicateCODE') {
     $args{'CODE_ignore_dup'}=1;      $args{'CODE_ignore_dup'}=1;
  }   }
  $args{'CODE'}=$newCODE;   $args{'CODE'}=$newCODE;
  ($line,$err,$errmsg)=   ($line,$err,$errmsg)=
     &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,$which,      &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,$which,
      'CODE',\%args);       'CODE',\%args);
     } elsif ($ENV{'form.scantron_corrections'} =~ /^(missing|double)bubble$/) {      } elsif ($env{'form.scantron_corrections'} =~ /^(missing|double)bubble$/) {
  foreach my $question (split(',',$ENV{'form.scantron_questions'})) {   foreach my $question (split(',',$env{'form.scantron_questions'})) {
     ($line,$err,$errmsg)=      ($line,$err,$errmsg)=
  &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,   &scantron_fixup_scanline(\%scantron_config,$scan_data,$line,
  $which,'answer',   $which,'answer',
  { 'question'=>$question,   { 'question'=>$question,
        'response'=>$ENV{"form.scantron_correct_Q_$question"}});         'response'=>$env{"form.scantron_correct_Q_$question"}});
     if ($err) { last; }      if ($err) { last; }
  }   }
     }      }
     if ($err) {      if ($err) {
  $r->print("Unable to accept last correction, an error occurred :$errmsg:");   $r->print("<font color='red'>Unable to accept last correction, an error occurred :$errmsg:</font>");
     } else {      } else {
  &scantron_put_line($scanlines,$scan_data,$which,$line,$skip);   &scantron_put_line($scanlines,$scan_data,$which,$line,$skip);
  &scantron_putfile($scanlines,$scan_data);   &scantron_putfile($scanlines,$scan_data);
Line 3899  sub allow_skipping { Line 4542  sub allow_skipping {
   
 sub should_be_skipped {  sub should_be_skipped {
     my ($scan_data,$i)=@_;      my ($scan_data,$i)=@_;
     if ($ENV{'form.scantron_options_redo'} !~ /^redo_/) {      if ($env{'form.scantron_options_redo'} !~ /^redo_/) {
  # not redoing old skips   # not redoing old skips
  return 0;   return 0;
     }      }
Line 3928  sub check_for_error { Line 4571  sub check_for_error {
     }      }
 }  }
   
   sub scantron_warning_screen {
       my ($button_text)=@_;
       my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});
       my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
       my $CODElist="a";
       if ($scantron_config{'CODElocation'} &&
    $scantron_config{'CODEstart'} &&
    $scantron_config{'CODElength'}) {
    $CODElist=$env{'form.scantron_CODElist'};
    if ($CODElist eq '') { $CODElist='<font color="red">None</font>'; }
    $CODElist=
       '<tr><td><b>List of CODES to validate against:</b></td><td><tt>'.
       $CODElist.'</tt></td></tr>';
       }
       return (<<STUFF);
   <p>
   <font color="red">Please double check the information
                    below before clicking on '$button_text'</font>
   </p>
   <table>
   <tr><td><b>Sequence to be Graded:</b></td><td>$title</td></tr>
   <tr><td><b>Data File that will be used:</b></td><td><tt>$env{'form.scantron_selectfile'}</tt></td></tr>
   $CODElist
   </table>
   </font>
   <br />
   <p> If this information is correct, please click on '$button_text'.</p>
   <p> If something is incorrect, please click the 'Grading Menu' button to start over.</p>
   
   <br />
   STUFF
   }
   
   sub scantron_do_warning {
       my ($r)=@_;
       my ($symb,$url)=&get_symb_and_url($r);
       if (!$symb) {return '';}
       my $default_form_data=&defaultFormData($symb,$url);
       $r->print(&scantron_form_start().$default_form_data);
       if ( $env{'form.selectpage'} eq '' ||
    $env{'form.scantron_selectfile'} eq '' ||
    $env{'form.scantron_format'} eq '' ) {
    $r->print("<p>You have forgetten to specify some information. Please go Back and try again.</p>");
    if ( $env{'form.selectpage'} eq '') {
       $r->print('<p><font color="red">You have not selected a Sequence to grade</font></p>');
    } 
    if ( $env{'form.scantron_selectfile'} eq '') {
       $r->print('<p><font color="red">You have not selected a file that contains the student\'s response data.</font></p>');
    } 
    if ( $env{'form.scantron_format'} eq '') {
       $r->print('<p><font color="red">You have not selected a the format of the student\'s response data.</font></p>');
    } 
       } else {
    my $warning=&scantron_warning_screen('Grading: Validate Records');
    $r->print(<<STUFF);
   $warning
   <input type="submit" name="submit" value="Grading: Validate Records" />
   <input type="hidden" name="command" value="scantron_validate" />
   STUFF
       }
       $r->print("</form><br />".&show_grading_menu_form($symb,$url)."</body></html>");
       return '';
   }
   
   sub scantron_form_start {
       my ($max_bubble)=@_;
       my $result= <<SCANTRONFORM;
   <form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantronupload">
     <input type="hidden" name="selectpage" value="$env{'form.selectpage'}" />
     <input type="hidden" name="scantron_format" value="$env{'form.scantron_format'}" />
     <input type="hidden" name="scantron_selectfile" value="$env{'form.scantron_selectfile'}" />
     <input type="hidden" name="scantron_maxbubble" value="$max_bubble" />
     <input type="hidden" name="scantron_CODElist" value="$env{'form.scantron_CODElist'}" />
     <input type="hidden" name="scantron_CODEunique" value="$env{'form.scantron_CODEunique'}" />
     <input type="hidden" name="scantron_options_redo" value="$env{'form.scantron_options_redo'}" />
     <input type="hidden" name="scantron_options_ignore" value="$env{'form.scantron_options_ignore'}" />
   SCANTRONFORM
       return $result;
   }
   
 sub scantron_validate_file {  sub scantron_validate_file {
     my ($r) = @_;      my ($r) = @_;
     my ($symb,$url)=&get_symb_and_url($r);      my ($symb,$url)=&get_symb_and_url($r);
Line 3936  sub scantron_validate_file { Line 4659  sub scantron_validate_file {
           
     # do the detection of only doing skipped records first befroe we delete      # do the detection of only doing skipped records first befroe we delete
     # them  when doing the corrections reset      # them  when doing the corrections reset
     if ($ENV{'form.scantron_options_redo'} ne 'redo_skipped_ready') {      if ($env{'form.scantron_options_redo'} ne 'redo_skipped_ready') {
  &reset_skipping_status();   &reset_skipping_status();
     }      }
     if ($ENV{'form.scantron_options_redo'} eq 'redo_skipped') {      if ($env{'form.scantron_options_redo'} eq 'redo_skipped') {
  &remember_current_skipped();   &remember_current_skipped();
  &scantron_remove_file('skipped');   &scantron_remove_file('skipped');
  $ENV{'form.scantron_options_redo'}='redo_skipped_ready';   $env{'form.scantron_options_redo'}='redo_skipped_ready';
     }      }
   
     if ($ENV{'form.scantron_options_ignore'} eq 'ignore_corrections') {      if ($env{'form.scantron_options_ignore'} eq 'ignore_corrections') {
  &check_for_error($r,&scantron_remove_file('corrected'));   &check_for_error($r,&scantron_remove_file('corrected'));
  &check_for_error($r,&scantron_remove_file('skipped'));   &check_for_error($r,&scantron_remove_file('skipped'));
  &check_for_error($r,&scantron_remove_scan_data());   &check_for_error($r,&scantron_remove_scan_data());
  $ENV{'form.scantron_options_ignore'}='done';   $env{'form.scantron_options_ignore'}='done';
     }      }
   
     if ($ENV{'form.scantron_corrections'}) {      if ($env{'form.scantron_corrections'}) {
  &scantron_process_corrections($r);   &scantron_process_corrections($r);
     }      }
     $r->print("<p>Gathering neccessary info.</p>");$r->rflush();      $r->print("<p>Gathering neccessary info.</p>");$r->rflush();
     my $max_bubble=&scantron_get_maxbubble($r);  
     #get the student pick code ready      #get the student pick code ready
     $r->print(&Apache::loncommon::studentbrowser_javascript());      $r->print(&Apache::loncommon::studentbrowser_javascript());
     my $result= <<SCANTRONFORM;      my $max_bubble=&scantron_get_maxbubble($r);
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="scantronupload">      my $result=&scantron_form_start($max_bubble).$default_form_data;
   <input type="hidden" name="selectpage" value="$ENV{'form.selectpage'}" />  
   <input type="hidden" name="scantron_format" value="$ENV{'form.scantron_format'}" />  
   <input type="hidden" name="scantron_selectfile" value="$ENV{'form.scantron_selectfile'}" />  
   <input type="hidden" name="scantron_maxbubble" value="$max_bubble'" />  
   <input type="hidden" name="scantron_CODElist" value="$ENV{'form.scantron_CODElist'}" />  
   <input type="hidden" name="scantron_CODEunique" value="$ENV{'form.scantron_CODEunique'}" />  
   <input type="hidden" name="scantron_options_redo" value="$ENV{'form.scantron_options_redo'}" />  
   <input type="hidden" name="scantron_options_ignore" value="$ENV{'form.scantron_options_ignore'}" />  
   $default_form_data  
 SCANTRONFORM  
     $r->print($result);      $r->print($result);
           
     my @validate_phases=( 'ID',      my @validate_phases=( 'ID',
   'CODE',    'CODE',
   'doublebubble',    'doublebubble',
   'missingbubbles');    'missingbubbles');
     if (!$ENV{'form.validatepass'}) {      if (!$env{'form.validatepass'}) {
  $ENV{'form.validatepass'} = 0;   $env{'form.validatepass'} = 0;
     }      }
     my $currentphase=$ENV{'form.validatepass'};      my $currentphase=$env{'form.validatepass'};
   
     my $stop=0;      my $stop=0;
     while (!$stop && $currentphase < scalar(@validate_phases)) {      while (!$stop && $currentphase < scalar(@validate_phases)) {
Line 3993  SCANTRONFORM Line 4705  SCANTRONFORM
  }   }
     }      }
     if (!$stop) {      if (!$stop) {
  $r->print("Validation process complete.<br />");   my $warning=&scantron_warning_screen('Start Grading');
  $r->print('<input type="submit" name="submit" value="Start Grading" />');   $r->print(<<STUFF);
  $r->print('<input type="hidden" name="command" value="scantron_process" />');  Validation process complete.<br />
   $warning
   <input type="submit" name="submit" value="Start Grading" />
   <input type="hidden" name="command" value="scantron_process" />
   STUFF
   
     } else {      } else {
  $r->print('<input type="hidden" name="command" value="scantron_validate" />');   $r->print('<input type="hidden" name="command" value="scantron_validate" />');
  $r->print("<input type='hidden' name='validatepass' value='".$currentphase."' />");   $r->print("<input type='hidden' name='validatepass' value='".$currentphase."' />");
Line 4013  SCANTRONFORM Line 4730  SCANTRONFORM
   
 sub scantron_remove_file {  sub scantron_remove_file {
     my ($which)=@_;      my ($which)=@_;
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my $file='scantron_';      my $file='scantron_';
     if ($which eq 'corrected' || $which eq 'skipped') {      if ($which eq 'corrected' || $which eq 'skipped') {
  $file.=$which.'_';   $file.=$which.'_';
     } else {      } else {
  return 'refused';   return 'refused';
     }      }
     $file.=$ENV{'form.scantron_selectfile'};      $file.=$env{'form.scantron_selectfile'};
     return &Apache::lonnet::removeuserfile($cname,$cdom,$file);      return &Apache::lonnet::removeuserfile($cname,$cdom,$file);
 }  }
   
 sub scantron_remove_scan_data {  sub scantron_remove_scan_data {
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my @keys=&Apache::lonnet::getkeys('nohist_scantrondata',$cdom,$cname);      my @keys=&Apache::lonnet::getkeys('nohist_scantrondata',$cdom,$cname);
     my @todelete;      my @todelete;
     my $filename=$ENV{'form.scantron_selectfile'};      my $filename=$env{'form.scantron_selectfile'};
     foreach my $key (@keys) {      foreach my $key (@keys) {
  if ($key=~/^\Q$filename\E_/) {   if ($key=~/^\Q$filename\E_/) {
     if ($ENV{'form.scantron_options_redo'} eq 'redo_skipped_ready' &&      if ($env{'form.scantron_options_redo'} eq 'redo_skipped_ready' &&
  $key=~/remember_skipping/) {   $key=~/remember_skipping/) {
  next;   next;
     }      }
Line 4049  sub scantron_remove_scan_data { Line 4766  sub scantron_remove_scan_data {
   
 sub scantron_getfile {  sub scantron_getfile {
     #FIXME really would prefer a scantron directory      #FIXME really would prefer a scantron directory
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my $lines;      my $lines;
     $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.      $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.
        'scantron_orig_'.$ENV{'form.scantron_selectfile'});         'scantron_orig_'.$env{'form.scantron_selectfile'});
     my %scanlines;      my %scanlines;
     $scanlines{'orig'}=[(split("\n",$lines,-1))];      $scanlines{'orig'}=[(split("\n",$lines,-1))];
     my $temp=$scanlines{'orig'};      my $temp=$scanlines{'orig'};
     $scanlines{'count'}=$#$temp;      $scanlines{'count'}=$#$temp;
   
     $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.      $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.
        'scantron_corrected_'.$ENV{'form.scantron_selectfile'});         'scantron_corrected_'.$env{'form.scantron_selectfile'});
     if ($lines eq '-1') {      if ($lines eq '-1') {
  $scanlines{'corrected'}=[];   $scanlines{'corrected'}=[];
     } else {      } else {
  $scanlines{'corrected'}=[(split("\n",$lines,-1))];   $scanlines{'corrected'}=[(split("\n",$lines,-1))];
     }      }
     $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.      $lines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.
        'scantron_skipped_'.$ENV{'form.scantron_selectfile'});         'scantron_skipped_'.$env{'form.scantron_selectfile'});
     if ($lines eq '-1') {      if ($lines eq '-1') {
  $scanlines{'skipped'}=[];   $scanlines{'skipped'}=[];
     } else {      } else {
Line 4081  sub scantron_getfile { Line 4798  sub scantron_getfile {
   
 sub lonnet_putfile {  sub lonnet_putfile {
     my ($contents,$filename)=@_;      my ($contents,$filename)=@_;
     my $docuname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $docudom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my $docuhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};      $env{'form.sillywaytopassafilearound'}=$contents;
     $ENV{'form.sillywaytopassafilearound'}=$contents;      &Apache::lonnet::finishuserfileupload($docuname,$docudom,'sillywaytopassafilearound',$filename);
     &Apache::lonnet::finishuserfileupload($docuname,$docudom,$docuhome,'sillywaytopassafilearound',$filename);  
   
 }  }
   
 sub scantron_putfile {  sub scantron_putfile {
     my ($scanlines,$scan_data) = @_;      my ($scanlines,$scan_data) = @_;
     #FIXME really would prefer a scantron directory      #FIXME really would prefer a scantron directory
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     if ($scanlines) {      if ($scanlines) {
  my $prefix='scantron_';   my $prefix='scantron_';
 # no need to update orig, shouldn't change  # no need to update orig, shouldn't change
 #   &lonnet_putfile(join("\n",@{$scanlines->{'orig'}}),$prefix.'orig_'.  #   &lonnet_putfile(join("\n",@{$scanlines->{'orig'}}),$prefix.'orig_'.
 #    $ENV{'form.scantron_selectfile'});  #    $env{'form.scantron_selectfile'});
  &lonnet_putfile(join("\n",@{$scanlines->{'corrected'}}),   &lonnet_putfile(join("\n",@{$scanlines->{'corrected'}}),
  $prefix.'corrected_'.   $prefix.'corrected_'.
  $ENV{'form.scantron_selectfile'});   $env{'form.scantron_selectfile'});
  &lonnet_putfile(join("\n",@{$scanlines->{'skipped'}}),   &lonnet_putfile(join("\n",@{$scanlines->{'skipped'}}),
  $prefix.'skipped_'.   $prefix.'skipped_'.
  $ENV{'form.scantron_selectfile'});   $env{'form.scantron_selectfile'});
     }      }
     &Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname);      &Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname);
 }  }
Line 4146  sub scantron_validate_ID { Line 4862  sub scantron_validate_ID {
     my %idmap=&username_to_idmap($classlist);      my %idmap=&username_to_idmap($classlist);
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
   
     my %found=('ids'=>{},'usernames'=>{});      my %found=('ids'=>{},'usernames'=>{});
Line 4215  sub scantron_get_correction { Line 4931  sub scantron_get_correction {
  $r->print(" in scanline $i <pre>".   $r->print(" in scanline $i <pre>".
   $line."</pre> \n");    $line."</pre> \n");
     }      }
       my $message="<p>The ID on the form is  <tt>".
    $$scan_record{'scantron.ID'}."</tt><br />\n".
    "The name on the paper is ".
    $$scan_record{'scantron.LastName'}.",".
    $$scan_record{'scantron.FirstName'}."</p>";
   
     $r->print('<input type="hidden" name="scantron_corrections" value="'.$error.'" />'."\n");      $r->print('<input type="hidden" name="scantron_corrections" value="'.$error.'" />'."\n");
     $r->print('<input type="hidden" name="scantron_line" value="'.$i.'" />'."\n");      $r->print('<input type="hidden" name="scantron_line" value="'.$i.'" />'."\n");
     if ($error =~ /ID$/) {      if ($error =~ /ID$/) {
Line 4223  sub scantron_get_correction { Line 4945  sub scantron_get_correction {
  } elsif ($error eq 'duplicateID') {   } elsif ($error eq 'duplicateID') {
     $r->print("The encoded ID has also been used by a previous paper $arg</p>\n");      $r->print("The encoded ID has also been used by a previous paper $arg</p>\n");
  }   }
  $r->print("<p>The ID on the form is  <tt>".   $r->print($message);
   $$scan_record{'scantron.ID'}."</tt><br />\n");  
  $r->print("The name on the paper is ".  
   $$scan_record{'scantron.LastName'}.",".  
   $$scan_record{'scantron.FirstName'}."</p>");  
  $r->print("<p>How should I handle this? <br /> \n");   $r->print("<p>How should I handle this? <br /> \n");
  $r->print("\n<ul><li> ");   $r->print("\n<ul><li> ");
  #FIXME it would be nice if this sent back the user ID and   #FIXME it would be nice if this sent back the user ID and
Line 4236  sub scantron_get_correction { Line 4954  sub scantron_get_correction {
        'scantron_username','scantron_domain'));         'scantron_username','scantron_domain'));
  $r->print(": <input type='text' name='scantron_username' value='' />");   $r->print(": <input type='text' name='scantron_username' value='' />");
  $r->print("\n@".   $r->print("\n@".
  &Apache::loncommon::select_dom_form($ENV{'request.role.domain'},'scantron_domain'));   &Apache::loncommon::select_dom_form($env{'request.role.domain'},'scantron_domain'));
   
  $r->print('</li>');   $r->print('</li>');
     } elsif ($error =~ /CODE$/) {      } elsif ($error =~ /CODE$/) {
Line 4245  sub scantron_get_correction { Line 4963  sub scantron_get_correction {
  } elsif ($error eq 'duplicateCODE') {   } elsif ($error eq 'duplicateCODE') {
     $r->print("</p><p>The encoded CODE has also been used by a previous paper ".join(', ',@{$arg}).", and CODEs are supposed to be unique</p>\n");      $r->print("</p><p>The encoded CODE has also been used by a previous paper ".join(', ',@{$arg}).", and CODEs are supposed to be unique</p>\n");
  }   }
  $r->print("<p>The CODE on the form is  <tt>".   $r->print("<p>The CODE on the form is  <tt>'".
   $$scan_record{'scantron.CODE'}."</tt><br />\n");    $$scan_record{'scantron.CODE'}."'</tt><br />\n");
  $r->print("<p>The ID on the form is  <tt>".   $r->print($message);
   $$scan_record{'scantron.ID'}."</tt><br />\n");  
  $r->print("The name on the paper is ".  
   $$scan_record{'scantron.LastName'}.",".  
   $$scan_record{'scantron.FirstName'}."</p>");  
  $r->print("<p>How should I handle this? <br /> \n");   $r->print("<p>How should I handle this? <br /> \n");
  $r->print("\n<br /> ");   $r->print("\n<br /> ");
  my $i=0;   my $i=0;
  if ($error eq 'incorrectCODE') {   if ($error eq 'incorrectCODE' 
       && $$scan_record{'scantron.CODE'}=~/\S/ ) {
     my ($max,$closest)=&scantron_get_closely_matching_CODEs($arg,$$scan_record{'scantron.CODE'});      my ($max,$closest)=&scantron_get_closely_matching_CODEs($arg,$$scan_record{'scantron.CODE'});
     foreach my $testcode (@{$closest}) {      if ($closest > 0) {
  my $checked='';   foreach my $testcode (@{$closest}) {
  if (!$i) { $checked=' checked="on" '; }      my $checked='';
  $r->print("<input type='radio' name='scantron_CODE_resolution' value='use_closest_$i' $checked /> Use the similar CODE <b><tt>".$testcode."</tt></b> instead.<input type='hidden' name='scantron_CODE_closest_$i' value='$testcode' />");      if (!$i) { $checked=' checked="on" '; }
  $r->print("\n<br />");      $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_closest_$i' $checked /> Use the similar CODE <b><tt>".$testcode."</tt></b> instead.</label><input type='hidden' name='scantron_CODE_closest_$i' value='$testcode' />");
  $i++;      $r->print("\n<br />");
       $i++;
    }
     }      }
  }   }
  my $checked; if (!$i) { $checked=' checked="on" '; }   if ($$scan_record{'scantron.CODE'}=~/\S/ ) {
  $r->print("<input type='radio' name='scantron_CODE_resolution' value='use_unfound' $checked /> Use the CODE <b><tt>".$$scan_record{'scantron.CODE'}."</tt></b> that is was on the paper, ignoring the error.");      my $checked; if (!$i) { $checked=' checked="on" '; }
  $r->print("\n<br />");      $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_unfound' $checked /> Use the CODE <b><tt>".$$scan_record{'scantron.CODE'}."</tt></b> that is was on the paper, ignoring the error.</label>");
       $r->print("\n<br />");
    }
   
  $r->print(<<ENDSCRIPT);   $r->print(<<ENDSCRIPT);
 <script type="text/javascript">  <script type="text/javascript">
Line 4282  function change_radio(field) { Line 5001  function change_radio(field) {
 ENDSCRIPT  ENDSCRIPT
  my $href="/adm/pickcode?".   my $href="/adm/pickcode?".
    "form=".&Apache::lonnet::escape("scantronupload").     "form=".&Apache::lonnet::escape("scantronupload").
    "&scantron_format=".&Apache::lonnet::escape($ENV{'form.scantron_format'}).     "&scantron_format=".&Apache::lonnet::escape($env{'form.scantron_format'}).
    "&scantron_CODElist=".&Apache::lonnet::escape($ENV{'form.scantron_CODElist'}).     "&scantron_CODElist=".&Apache::lonnet::escape($env{'form.scantron_CODElist'}).
    "&curCODE=".&Apache::lonnet::escape($$scan_record{'scantron.CODE'}).     "&curCODE=".&Apache::lonnet::escape($$scan_record{'scantron.CODE'}).
    "&scantron_selectfile=".&Apache::lonnet::escape($ENV{'form.scantron_selectfile'});     "&scantron_selectfile=".&Apache::lonnet::escape($env{'form.scantron_selectfile'});
  $r->print("<input type='radio' name='scantron_CODE_resolution' value='use_found' /> <a target='_blank' href='$href'>Select</a> a CODE from the list of all CODEs and use it. Selected CODE is <input readonly='true' type='text' size='8' name='scantron_CODE_selectedvalue' onfocus=\"javascript:change_radio('use_found')\" onchange=\"javascript:change_radio('use_found')\" />");   $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_found' /> <a target='_blank' href='$href'>Select</a> a CODE from the list of all CODEs and use it.</label> Selected CODE is <input readonly='true' type='text' size='8' name='scantron_CODE_selectedvalue' onfocus=\"javascript:change_radio('use_found')\" onchange=\"javascript:change_radio('use_found')\" />");
  $r->print("\n<br />");   $r->print("\n<br />");
  $r->print("<input type='radio' name='scantron_CODE_resolution' value='use_typed' /> Use <input type='text' size='8' name='scantron_CODE_newvalue' onfocus=\"javascript:change_radio('use_typed')\" onkeypress=\"javascript:change_radio('use_typed')\" /> as the CODE.");   $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_typed' /> Use </label><input type='text' size='8' name='scantron_CODE_newvalue' onfocus=\"javascript:change_radio('use_typed')\" onkeypress=\"javascript:change_radio('use_typed')\" /> as the CODE.");
  $r->print("\n<br /><br />");   $r->print("\n<br /><br />");
     } elsif ($error eq 'doublebubble') {      } elsif ($error eq 'doublebubble') {
  $r->print("<p>There have been multiple bubbles scanned for a some question(s)</p>\n");   $r->print("<p>There have been multiple bubbles scanned for a some question(s)</p>\n");
  $r->print('<input type="hidden" name="scantron_questions" value="'.   $r->print('<input type="hidden" name="scantron_questions" value="'.
   join(',',@{$arg}).'" />');    join(',',@{$arg}).'" />');
    $r->print($message);
  $r->print("<p>Please indicate which bubble should be used for grading</p>");   $r->print("<p>Please indicate which bubble should be used for grading</p>");
  foreach my $question (@{$arg}) {   foreach my $question (@{$arg}) {
     my $selected=$$scan_record{"scantron.$question.answer"};      my $selected=$$scan_record{"scantron.$question.answer"};
Line 4301  ENDSCRIPT Line 5021  ENDSCRIPT
  }   }
     } elsif ($error eq 'missingbubble') {      } elsif ($error eq 'missingbubble') {
  $r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n");   $r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n");
    $r->print($message);
  $r->print("<p>Please indicate which bubble should be used for grading</p>");   $r->print("<p>Please indicate which bubble should be used for grading</p>");
  $r->print("Some questions have no scanned bubbles\n");   $r->print("Some questions have no scanned bubbles\n");
  $r->print('<input type="hidden" name="scantron_questions" value="'.   $r->print('<input type="hidden" name="scantron_questions" value="'.
Line 4319  ENDSCRIPT Line 5040  ENDSCRIPT
 sub scantron_bubble_selector {  sub scantron_bubble_selector {
     my ($r,$scan_config,$quest,@selected)=@_;      my ($r,$scan_config,$quest,@selected)=@_;
     my $max=$$scan_config{'Qlength'};      my $max=$$scan_config{'Qlength'};
   
       my $scmode=$$scan_config{'Qon'};
       if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; }     
   
     my @alphabet=('A'..'Z');      my @alphabet=('A'..'Z');
     $r->print("<table border='1'><tr><td rowspan='2'>$quest</td>");      $r->print("<table border='1'><tr><td rowspan='2'>$quest</td>");
     for (my $i=0;$i<$max+1;$i++) {      for (my $i=0;$i<$max+1;$i++) {
  $r->print('<td align="center">');   $r->print("\n".'<td align="center">');
  if ($selected[0] eq $alphabet[$i]) { $r->print('X'); shift(@selected) }   if ($selected[0] eq $alphabet[$i]) { $r->print('X'); shift(@selected) }
  else { $r->print('&nbsp;'); }   else { $r->print('&nbsp;'); }
  $r->print('</td>');   $r->print('</td>');
     }      }
     $r->print('<td></td></tr><tr>');      $r->print('</tr><tr>');
     for (my $i=0;$i<$max;$i++) {      for (my $i=0;$i<$max;$i++) {
  $r->print('<td><input type="radio" name="scantron_correct_Q_'.$quest.   $r->print("\n".
   '" value="'.$i.'" />'.$alphabet[$i]."</td>");    '<td><label><input type="radio" name="scantron_correct_Q_'.
     $quest.'" value="'.$i.'" />'.$alphabet[$i]."</label></td>");
     }      }
     $r->print('<td><input type="radio" name="scantron_correct_Q_'.$quest.      $r->print('<td><label><input type="radio" name="scantron_correct_Q_'.
       '" value="none" /> No bubble </td>');        $quest.'" value="none" /> No bubble </label></td>');
     $r->print('</tr></table>');      $r->print('</tr></table>');
 }  }
   
Line 4359  sub scantron_get_closely_matching_CODEs Line 5085  sub scantron_get_closely_matching_CODEs
 }  }
   
 sub get_codes {  sub get_codes {
     my $old_name=$ENV{'form.scantron_CODElist'};      my ($old_name, $cdom, $cnum) = @_;
     my $cdom =$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      if (!$old_name) {
     my $cnum =$ENV{'course.'.$ENV{'request.course.id'}.'.num'};   $old_name=$env{'form.scantron_CODElist'};
     my %result=&Apache::lonnet::get('CODEs',[$old_name],$cdom,$cnum);      }
     my %allcodes=map {(&Apache::lonprintout::num_to_letters($_),1)} split(',',$result{$old_name});      if (!$cdom) {
    $cdom =$env{'course.'.$env{'request.course.id'}.'.domain'};
       }
       if (!$cnum) {
    $cnum =$env{'course.'.$env{'request.course.id'}.'.num'};
       }
       my %result=&Apache::lonnet::get('CODEs',[$old_name,"type\0$old_name"],
       $cdom,$cnum);
       my %allcodes;
       if ($result{"type\0$old_name"} eq 'number') {
    %allcodes=map {($_,1)} split(',',$result{$old_name});
       } else {
    %allcodes=map {(&Apache::lonprintout::num_to_letters($_),1)} split(',',$result{$old_name});
       }
     return %allcodes;      return %allcodes;
 }  }
   
 sub scantron_validate_CODE {  sub scantron_validate_CODE {
     my ($r,$currentphase) = @_;      my ($r,$currentphase) = @_;
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     if ($scantron_config{'CODElocation'} &&      if ($scantron_config{'CODElocation'} &&
  $scantron_config{'CODEstart'} &&   $scantron_config{'CODEstart'} &&
  $scantron_config{'CODElength'}) {   $scantron_config{'CODElength'}) {
  if (!defined($ENV{'form.scantron_CODElist'})) {   if (!defined($env{'form.scantron_CODElist'})) {
     &FIXME_blow_up()      &FIXME_blow_up()
  }   }
     } else {      } else {
Line 4392  sub scantron_validate_CODE { Line 5131  sub scantron_validate_CODE {
  $scan_data);   $scan_data);
  my $CODE=$$scan_record{'scantron.CODE'};   my $CODE=$$scan_record{'scantron.CODE'};
  my $error=0;   my $error=0;
  if (!exists($allcodes{$CODE}) && !$$scan_record{'scantron.useCODE'}) {   if (!&Apache::lonnet::validCODE($CODE)) {
     &scantron_get_correction($r,$i,$scan_record,      &scantron_get_correction($r,$i,$scan_record,
      \%scantron_config,       \%scantron_config,
      $line,'incorrectCODE',\%allcodes);       $line,'incorrectCODE',\%allcodes);
     return(1,$currentphase);      return(1,$currentphase);
  }   }
  if (exists($usedCODEs{$CODE}) && $ENV{'form.scantron_CODEunique'}   if (%allcodes && !exists($allcodes{$CODE}) 
       && !$$scan_record{'scantron.useCODE'}) {
       &scantron_get_correction($r,$i,$scan_record,
        \%scantron_config,
        $line,'incorrectCODE',\%allcodes);
       return(1,$currentphase);
    }
    if (exists($usedCODEs{$CODE}) 
       && $env{'form.scantron_CODEunique'} eq 'yes'
     && !$$scan_record{'scantron.CODE_ignore_dup'}) {      && !$$scan_record{'scantron.CODE_ignore_dup'}) {
     &scantron_get_correction($r,$i,$scan_record,      &scantron_get_correction($r,$i,$scan_record,
      \%scantron_config,       \%scantron_config,
Line 4417  sub scantron_validate_doublebubble { Line 5164  sub scantron_validate_doublebubble {
     my %idmap=&username_to_idmap($classlist);      my %idmap=&username_to_idmap($classlist);
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     for (my $i=0;$i<=$scanlines->{'count'};$i++) {      for (my $i=0;$i<=$scanlines->{'count'};$i++) {
  my $line=&scantron_get_line($scanlines,$scan_data,$i);   my $line=&scantron_get_line($scanlines,$scan_data,$i);
Line 4435  sub scantron_validate_doublebubble { Line 5182  sub scantron_validate_doublebubble {
   
 sub scantron_get_maxbubble {  sub scantron_get_maxbubble {
     my ($r)=@_;      my ($r)=@_;
     if (defined($ENV{'form.scantron_maxbubble'}) &&      if (defined($env{'form.scantron_maxbubble'}) &&
  $ENV{'form.scantron_maxbubble'}) {   $env{'form.scantron_maxbubble'}) {
  return $ENV{'form.scantron_maxbubble'};   return $env{'form.scantron_maxbubble'};
     }      }
     my $navmap=Apache::lonnavmaps::navmap->new();      my $navmap=Apache::lonnavmaps::navmap->new();
     my (undef,undef,$sequence)=      my (undef,undef,$sequence)=
  &Apache::lonnet::decode_symb($ENV{'form.selectpage'});   &Apache::lonnet::decode_symb($env{'form.selectpage'});
     my $map=$navmap->getResourceByUrl($sequence);      my $map=$navmap->getResourceByUrl($sequence);
     my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);      my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
     &Apache::lonnet::delenv('form.counter');      &Apache::lonnet::delenv('form.counter');
     foreach my $resource (@resources) {      foreach my $resource (@resources) {
  my $result=&Apache::lonnet::ssi($resource->src());   my $result=&Apache::lonnet::ssi($resource->src().'?symb='.&Apache::lonnet::escape($resource->symb()));
     }      }
     &Apache::lonnet::delenv('scantron\.');      &Apache::lonnet::delenv('scantron\.');
     my $envfile=$ENV{'user.environment'};      my $envfile=$env{'user.environment'};
     $envfile=~/\/([^\/]+)\.id$/;      $envfile=~/\/([^\/]+)\.id$/;
     $envfile=$1;      $envfile=$1;
     &Apache::lonnet::transfer_profile_to_env($r->dir_config('lonIDsDir'),      &Apache::lonnet::transfer_profile_to_env($r->dir_config('lonIDsDir'),
      $envfile);       $envfile);
     $ENV{'form.scantron_maxbubble'}=$ENV{'form.counter'}-1;      $env{'form.scantron_maxbubble'}=$env{'form.counter'}-1;
     return $ENV{'form.scantron_maxbubble'};      return $env{'form.scantron_maxbubble'};
 }  }
   
 sub scantron_validate_missingbubbles {  sub scantron_validate_missingbubbles {
Line 4465  sub scantron_validate_missingbubbles { Line 5212  sub scantron_validate_missingbubbles {
     my %idmap=&username_to_idmap($classlist);      my %idmap=&username_to_idmap($classlist);
   
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     my $max_bubble=&scantron_get_maxbubble();      my $max_bubble=&scantron_get_maxbubble();
     if (!$max_bubble) { $max_bubble=2**31; }      if (!$max_bubble) { $max_bubble=2**31; }
Line 4492  sub scantron_validate_missingbubbles { Line 5239  sub scantron_validate_missingbubbles {
   
 sub scantron_process_students {  sub scantron_process_students {
     my ($r) = @_;      my ($r) = @_;
     my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($ENV{'form.selectpage'});      my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'});
     my ($symb,$url)=&get_symb_and_url($r);      my ($symb,$url)=&get_symb_and_url($r);
     if (!$symb) {return '';}      if (!$symb) {return '';}
     my $default_form_data=&defaultFormData($symb,$url);      my $default_form_data=&defaultFormData($symb,$url);
   
     my %scantron_config=&get_scantron_config($ENV{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     my $classlist=&Apache::loncoursedata::get_classlist();      my $classlist=&Apache::loncoursedata::get_classlist();
     my %idmap=&username_to_idmap($classlist);      my %idmap=&username_to_idmap($classlist);
Line 4558  SCANTRONFORM Line 5305  SCANTRONFORM
       'grade_target'  =>'grade',        'grade_target'  =>'grade',
       'grade_username'=>$uname,        'grade_username'=>$uname,
       'grade_domain'  =>$udom,        'grade_domain'  =>$udom,
       'grade_courseid'=>$ENV{'request.course.id'},        'grade_courseid'=>$env{'request.course.id'},
       'grade_symb'    =>$resource->symb());        'grade_symb'    =>$resource->symb());
     if (exists($scan_record->{'scantron.CODE'}) &&      if (exists($scan_record->{'scantron.CODE'}) &&
  $scan_record->{'scantron.CODE'}) {   $scan_record->{'scantron.CODE'}) {
  $form{'CODE'}=$scan_record->{'scantron.CODE'};   $form{'CODE'}=$scan_record->{'scantron.CODE'};
       } else {
    $form{'CODE'}='';
     }      }
     my $result=&Apache::lonnet::ssi($resource->src(),%form);      my $result=&Apache::lonnet::ssi($resource->src(),%form);
       if ($result ne '') {
    &Apache::lonnet::logthis("scantron grading error -> $result");
    &Apache::lonnet::logthis("scantron grading error info name $uname domain $udom course $env{'request.course.id'} url ".$resource->src());
       }
       if (&Apache::loncommon::connection_aborted($r)) { last; }
  }   }
  $completedstudents{$uname}={'line'=>$line};   $completedstudents{$uname}={'line'=>$line};
    if (&Apache::loncommon::connection_aborted($r)) { last; }
     } continue {      } continue {
  &Apache::lonnet::delenv('form.counter');   &Apache::lonnet::delenv('form.counter');
  &Apache::lonnet::delenv('scantron\.');   &Apache::lonnet::delenv('scantron\.');
Line 4576  SCANTRONFORM Line 5330  SCANTRONFORM
 #    my $lasttime = &Time::HiRes::time()-$start;  #    my $lasttime = &Time::HiRes::time()-$start;
 #    $r->print("<p>took $lasttime</p>");  #    $r->print("<p>took $lasttime</p>");
   
     $navmap->untieHashes();  
     $r->print("</form>");      $r->print("</form>");
     $r->print(&show_grading_menu_form($symb,$url));      $r->print(&show_grading_menu_form($symb,$url));
     return '';      return '';
Line 4584  SCANTRONFORM Line 5337  SCANTRONFORM
   
 sub scantron_upload_scantron_data {  sub scantron_upload_scantron_data {
     my ($r)=@_;      my ($r)=@_;
     $r->print(&Apache::loncommon::coursebrowser_javascript($ENV{'request.role.domain'}));      $r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'}));
     my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',      my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',
   'domainid',    'domainid',
   'coursename');    'coursename');
     my $domsel=&Apache::loncommon::select_dom_form($ENV{'request.role.domain'},      my $domsel=&Apache::loncommon::select_dom_form($env{'request.role.domain'},
    'domainid');     'domainid');
     my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));      my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));
     $r->print(<<UPLOAD);      $r->print(<<UPLOAD);
Line 4626  sub scantron_upload_scantron_data_save { Line 5379  sub scantron_upload_scantron_data_save {
  '<input type="hidden" name="command" value="scantronupload" />'."\n".   '<input type="hidden" name="command" value="scantronupload" />'."\n".
  '<input type="submit" name="submit" value="Do Another Upload" />'."\n".   '<input type="submit" name="submit" value="Do Another Upload" />'."\n".
  '</form>'."\n";   '</form>'."\n";
     if (!&Apache::lonnet::allowed('usc',$ENV{'form.domainid'}) &&      if (!&Apache::lonnet::allowed('usc',$env{'form.domainid'}) &&
  !&Apache::lonnet::allowed('usc',   !&Apache::lonnet::allowed('usc',
     $ENV{'form.domainid'}.'_'.$ENV{'form.courseid'})) {      $env{'form.domainid'}.'_'.$env{'form.courseid'})) {
  $r->print("You are not allowed to upload Scantron data to the requested course.<br />");   $r->print("You are not allowed to upload Scantron data to the requested course.<br />");
  if ($symb) {   if ($symb) {
     $r->print(&show_grading_menu_form($symb,$url));      $r->print(&show_grading_menu_form($symb,$url));
Line 4637  sub scantron_upload_scantron_data_save { Line 5390  sub scantron_upload_scantron_data_save {
  }   }
  return '';   return '';
     }      }
     $r->print("Doing upload to ".$ENV{'form.courseid'}." <br />");      my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'});
     my $home=&Apache::lonnet::homeserver($ENV{'form.courseid'},      $r->print("Doing upload to ".$coursedata{'description'}." <br />");
  $ENV{'form.domainid'});      my $fname=$env{'form.upfile.filename'};
     my $fname=$ENV{'form.upfile.filename'};  
     #FIXME      #FIXME
     #copied from lonnet::userfileupload()      #copied from lonnet::userfileupload()
     #make that function able to target a specified course      #make that function able to target a specified course
Line 4654  sub scantron_upload_scantron_data_save { Line 5406  sub scantron_upload_scantron_data_save {
     $fname=~s/[^\w\.\-]//g;      $fname=~s/[^\w\.\-]//g;
     # See if there is anything left      # See if there is anything left
     unless ($fname) { return 'error: no uploaded file'; }      unless ($fname) { return 'error: no uploaded file'; }
       my $uploadedfile=$fname;
     $fname='scantron_orig_'.$fname;      $fname='scantron_orig_'.$fname;
     if (length($ENV{'form.upfile'}) < 2) {      if (length($env{'form.upfile'}) < 2) {
  $r->print("<font color='red'>Error:</font> The file you attempted to upload, <tt>".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"')."</tt>, contained no information. Please check that you entered the correct filename.");   $r->print("<font color='red'>Error:</font> The file you attempted to upload, <tt>".&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."</tt>, contained no information. Please check that you entered the correct filename.");
     } else {      } else {
  my $result=&Apache::lonnet::finishuserfileupload($ENV{'form.courseid'},$ENV{'form.domainid'},$home,'upfile',$fname);   my $result=&Apache::lonnet::finishuserfileupload($env{'form.courseid'},$env{'form.domainid'},'upfile',$fname);
  if ($result =~ m|^/uploaded/|) {   if ($result =~ m|^/uploaded/|) {
     $r->print("<font color='green'>Success:</font> Successfully uploaded ".(length($ENV{'form.upfile'})-1)." bytes of data into location <tt>".$result."</tt>");      $r->print("<font color='green'>Success:</font> Successfully uploaded ".(length($env{'form.upfile'})-1)." bytes of data into location <tt>".$result."</tt>");
  } else {   } else {
     $r->print("<font color='red'>Error:</font> An error (".$result.") occured when attempting to upload the file, <tt>".&HTML::Entities::encode($ENV{'form.upfile.filename'},'<>&"')."</tt>");      $r->print("<font color='red'>Error:</font> An error (".$result.") occurred when attempting to upload the file, <tt>".&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."</tt>");
  }   }
     }      }
     if ($symb) {      if ($symb) {
  $r->print(&show_grading_menu_form($symb,$url));   $r->print(&scantron_selectphase($r,$uploadedfile));
     } else {      } else {
  $r->print($doanotherupload);   $r->print($doanotherupload);
     }      }
     return '';      return '';
 }  }
   
   sub valid_file {
       my ($requested_file)=@_;
       foreach my $filename (sort(&scantron_filenames())) {
    &Apache::lonnet::logthis("$requested_file  $filename");
    if ($requested_file eq $filename) { return 1; }
       }
       return 0;
   }
   
   sub scantron_download_scantron_data {
       my ($r)=@_;
       my $default_form_data=&defaultFormData(&get_symb_and_url($r,1));
       my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
       my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
       my $file=$env{'form.scantron_selectfile'};
       if (! &valid_file($file)) {
    $r->print(<<ERROR);
    <p>
       The requested file name was invalid.
           </p>
   ERROR
    $r->print(&show_grading_menu_form(&get_symb_and_url($r,1)));
    return;
       }
       my $orig='/uploaded/'.$cdom.'/'.$cname.'/scantron_orig_'.$file;
       my $corrected='/uploaded/'.$cdom.'/'.$cname.'/scantron_corrected_'.$file;
       my $skipped='/uploaded/'.$cdom.'/'.$cname.'/scantron_skipped_'.$file;
       &Apache::lonnet::allowuploaded('/adm/grades',$orig);
       &Apache::lonnet::allowuploaded('/adm/grades',$corrected);
       &Apache::lonnet::allowuploaded('/adm/grades',$skipped);
       $r->print(<<DOWNLOAD);
       <p>
    <a href="$orig">Original</a> file as uploaded by the scantron office.
       </p>
       <p>
    <a href="$corrected">Corrections</a>, a file of corrected records that were used in grading.
       </p>
       <p>
    <a href="$skipped">Skipped</a>, a file of records that were skipped.
       </p>
   DOWNLOAD
       $r->print(&show_grading_menu_form(&get_symb_and_url($r,1)));
       return '';
   }
   
 #-------- end of section for handling grading scantron forms -------  #-------- end of section for handling grading scantron forms -------
 #  #
 #-------------------------------------------------------------------  #-------------------------------------------------------------------
   
   
 #-------------------------- Menu interface -------------------------  #-------------------------- Menu interface -------------------------
 #  #
 #--- Show a Grading Menu button - Calls the next routine ---  #--- Show a Grading Menu button - Calls the next routine ---
Line 4687  sub show_grading_menu_form { Line 5483  sub show_grading_menu_form {
     my $result.='<br /><form action="/adm/grades" method="post">'."\n".      my $result.='<br /><form action="/adm/grades" method="post">'."\n".
  '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".   '<input type="hidden" name="symb" value="'.$symb.'" />'."\n".
  '<input type="hidden" name="url" value="'.$url.'" />'."\n".   '<input type="hidden" name="url" value="'.$url.'" />'."\n".
  '<input type="hidden" name="saveState"  value="'.$ENV{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="command" value="gradingmenu" />'."\n".   '<input type="hidden" name="command" value="gradingmenu" />'."\n".
  '<input type="submit" name="submit" value="Grading Menu" />'."\n".   '<input type="submit" name="submit" value="Grading Menu" />'."\n".
  '</form>'."\n";   '</form>'."\n";
Line 4697  sub show_grading_menu_form { Line 5493  sub show_grading_menu_form {
 # -- Retrieve choices for grading form  # -- Retrieve choices for grading form
 sub savedState {  sub savedState {
     my %savedState = ();      my %savedState = ();
     if ($ENV{'form.saveState'}) {      if ($env{'form.saveState'}) {
  foreach (split(/:/,$ENV{'form.saveState'})) {   foreach (split(/:/,$env{'form.saveState'})) {
     my ($key,$value) = split(/=/,$_,2);      my ($key,$value) = split(/=/,$_,2);
     $savedState{$key} = $value;      $savedState{$key} = $value;
  }   }
Line 4731  sub gradingmenu { Line 5527  sub gradingmenu {
     if (!checkReceiptNo(formname,'notOK')) { return false;}      if (!checkReceiptNo(formname,'notOK')) { return false;}
     formname.submit();      formname.submit();
  }   }
    if (val < 7) formname.submit();
     }      }
   
     function checkReceiptNo(formname,nospace) {      function checkReceiptNo(formname,nospace) {
Line 4783  GRADINGMENUJS Line 5580  GRADINGMENUJS
  ($saveSec eq $_ ? 'selected="on"':'').'>'.$_.'</option>'."\n";   ($saveSec eq $_ ? 'selected="on"':'').'>'.$_.'</option>'."\n";
  }   }
     }      }
     $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</select> &nbsp; ';      $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="on"' : ''). '>all</option></select> &nbsp; ';
   
     $result.=&mt('Student Status').':</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);      $result.=&mt('Student Status').':</b>'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);
   
     if (ref($sections) && (grep /no/,@$sections)) {  
  $result.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />';  
     }  
     $result.='</td></tr>';      $result.='</td></tr>';
   
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.      $result.='<tr bgcolor="#ffffe6"valign="top"><td><label>'.
  '<input type="radio" name="radioChoice" value="submission" '.   '<input type="radio" name="radioChoice" value="submission" '.
  ($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').   ($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
  ' <select name="submitonly">'.   '</label> <select name="submitonly">'.
  '<option value="yes" '.   '<option value="yes" '.
  ($saveSub eq 'yes' ? 'selected="on"' : '').'>with submissions</option>'.   ($saveSub eq 'yes' ? 'selected="on"' : '').'>'.&mt('with submissions').'</option>'.
    '<option value="queued" '.
    ($saveSub eq 'queued' ? 'selected="on"' : '').'>'.&mt('in grading queue').'</option>'.
  '<option value="graded" '.   '<option value="graded" '.
  ($saveSub eq 'graded' ? 'selected="on"' : '').'>with ungraded submissions</option>'.   ($saveSub eq 'graded' ? 'selected="on"' : '').'>'.&mt('with ungraded submissions').'</option>'.
  '<option value="incorrect" '.   '<option value="incorrect" '.
  ($saveSub eq 'incorrect' ? 'selected="on"' : '').'>with incorrect submissions</option>'.   ($saveSub eq 'incorrect' ? 'selected="on"' : '').'>'.&mt('with incorrect submissions').'</option>'.
  '<option value="all" '.   '<option value="all" '.
  ($saveSub eq 'all' ? 'selected="on"' : '').'>with any status</option></select></td></tr>'."\n";   ($saveSub eq 'all' ? 'selected="on"' : '').'>'.&mt('with any status').'</option></select></td></tr>'."\n";
   
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.      $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
  '<input type="radio" name="radioChoice" value="viewgrades" '.   '<label><input type="radio" name="radioChoice" value="viewgrades" '.
  ($saveCmd eq 'viewgrades' ? 'checked' : '').'> '.   ($saveCmd eq 'viewgrades' ? 'checked' : '').'> '.
  '<b>Current Resource:</b> For all students in selected section or course</td></tr>'."\n";   '<b>Current Resource:</b> For all students in selected section or course</label></td></tr>'."\n";
   
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.      $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.
  '<input type="radio" name="radioChoice" value="pickStudentPage" '.   '<label><input type="radio" name="radioChoice" value="pickStudentPage" '.
  ($saveCmd eq 'pickStudentPage' ? 'checked' : '').'> '.   ($saveCmd eq 'pickStudentPage' ? 'checked' : '').'> '.
  'The <b>complete</b> set/page/sequence: For one student</td></tr>'."\n";   'The <b>complete</b> set/page/sequence: For one student</label></td></tr>'."\n";
   
     $result.='<tr bgcolor="#ffffe6"><td><br />'.      $result.='<tr bgcolor="#ffffe6"><td><br />'.
  '<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="Next->" />'.   '<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="Next->" />'.
Line 4830  GRADINGMENUJS Line 5626  GRADINGMENUJS
  '<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'.   '<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'.
  '" value="'.&mt('Grade').'" /> scantron forms</td></tr>'."\n";   '" value="'.&mt('Grade').'" /> scantron forms</td></tr>'."\n";
   
     if ((&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) && ($symb)) {      if ((&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) && ($symb)) {
  $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.   $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
     '<input type="button" onClick="javascript:checkChoice(this.form,\'5\',\'verify\');" value="'.&mt('Verify').'" />'.      '<input type="button" onClick="javascript:checkChoice(this.form,\'5\',\'verify\');" value="'.&mt('Verify').'" />'.
     ' '.&mt('receipt').': '.      ' '.&mt('receipt').': '.
     &Apache::lonnet::recprefix($ENV{'request.course.id'}).      &Apache::lonnet::recprefix($env{'request.course.id'}).
     '-<input type="text" name="receipt" size="4" onChange="javascript:checkReceiptNo(this.form,\'OK\')">'.      '-<input type="text" name="receipt" size="4" onChange="javascript:checkReceiptNo(this.form,\'OK\')">'.
     '</td></tr>'."\n";      '</td></tr>'."\n";
     }       } 
       $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.
    '<input type="button" onClick="javascript:this.form.action=\'/adm/helper/resettimes.helper\';this.form.submit();'.
    '" value="'.&mt('Manage').'" /> access times.</td></tr>'."\n";
       $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.
    '<input type="button" onClick="javascript:this.form.command.value=\'codelist\';this.form.action=\'/adm/pickcode\';this.form.submit();'.
    '" value="'.&mt('View').'" /> saved CODEs.</td></tr>'."\n";
   
     $result.='</form></td></tr></table>'."\n".      $result.='</form></td></tr></table>'."\n".
  '</td></tr></table>'."\n".   '</td></tr></table>'."\n".
Line 4845  GRADINGMENUJS Line 5647  GRADINGMENUJS
     return $result;      return $result;
 }  }
   
   sub reset_perm {
       undef(%perm);
   }
   
   sub init_perm {
       &reset_perm();
       foreach my $test_perm ('vgr','mgr','opa') {
   
    my $scope = $env{'request.course.id'};
    if (!($perm{$test_perm}=&Apache::lonnet::allowed($test_perm,$scope))) {
   
       $scope .= '/'.$env{'request.course.sec'};
       if ( $perm{$test_perm}=
    &Apache::lonnet::allowed($test_perm,$scope)) {
    $perm{$test_perm.'_section'}=$env{'request.course.sec'};
       } else {
    delete($perm{$test_perm});
       }
    }
       }
   }
   
 sub handler {  sub handler {
     my $request=$_[0];      my $request=$_[0];
   
     undef(%perm);      &reset_perm();
     if ($ENV{'browser.mathml'}) {      if ($env{'browser.mathml'}) {
  &Apache::loncommon::content_type($request,'text/xml');   &Apache::loncommon::content_type($request,'text/xml');
     } else {      } else {
  &Apache::loncommon::content_type($request,'text/html');   &Apache::loncommon::content_type($request,'text/html');
Line 4857  sub handler { Line 5681  sub handler {
     $request->send_http_header;      $request->send_http_header;
     return '' if $request->header_only;      return '' 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 @commands=&Apache::loncommon::get_env_multiple('form.command');      my @commands=&Apache::loncommon::get_env_multiple('form.command');
     my $command=$commands[0];      my $command=$commands[0];
     if ($#commands > 0) {      if ($#commands > 0) {
Line 4866  sub handler { Line 5690  sub handler {
     }      }
     if (!$url) {      if (!$url) {
  my ($temp1,$temp2);   my ($temp1,$temp2);
  ($temp1,$temp2,$ENV{'form.url'})=&Apache::lonnet::decode_symb($symb);   ($temp1,$temp2,$env{'form.url'})=&Apache::lonnet::decode_symb($symb);
  $url = $ENV{'form.url'};   $url = $env{'form.url'};
     }      }
     &send_header($request);      &send_header($request);
     if ($url eq '' && $symb eq '' && $command eq '') {      if ($url eq '' && $symb eq '' && $command 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) {
Line 4897  sub handler { Line 5721  sub handler {
     }      }
  }   }
     } else {      } else {
  if (!($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}))) {   &init_perm();
     if ($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) {  
  $perm{'vgr_section'}=$ENV{'request.course.sec'};  
     } else {  
  delete($perm{'vgr'});  
     }  
  }  
  if (!($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'}))) {  
     if ($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'}.'/'.$ENV{'request.course.sec'})) {  
  $perm{'mgr_section'}=$ENV{'request.course.sec'};  
     } else {  
  delete($perm{'mgr'});  
     }  
  }  
  if ($command eq 'submission' && $perm{'vgr'}) {   if ($command eq 'submission' && $perm{'vgr'}) {
     ($ENV{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0));      ($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0));
  } elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) {   } elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) {
     &pickStudentPage($request);      &pickStudentPage($request);
  } elsif ($command eq 'displayPage' && $perm{'vgr'}) {   } elsif ($command eq 'displayPage' && $perm{'vgr'}) {
Line 4937  sub handler { Line 5748  sub handler {
     $request->print(&csvupload($request));      $request->print(&csvupload($request));
  } elsif ($command eq 'csvuploadmap' && $perm{'mgr'} ) {   } elsif ($command eq 'csvuploadmap' && $perm{'mgr'} ) {
     $request->print(&csvuploadmap($request));      $request->print(&csvuploadmap($request));
  } elsif ($command eq 'csvuploadassign' && $perm{'mgr'}) {   } elsif ($command eq 'csvuploadoptions' && $perm{'mgr'}) {
     if ($ENV{'form.associate'} ne 'Reverse Association') {      if ($env{'form.associate'} ne 'Reverse Association') {
  $request->print(&csvuploadassign($request));   $request->print(&csvuploadoptions($request));
     } else {      } else {
  if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {   if ( $env{'form.upfile_associate'} ne 'reverse' ) {
     $ENV{'form.upfile_associate'} = 'reverse';      $env{'form.upfile_associate'} = 'reverse';
  } else {   } else {
     $ENV{'form.upfile_associate'} = 'forward';      $env{'form.upfile_associate'} = 'forward';
  }   }
  $request->print(&csvuploadmap($request));   $request->print(&csvuploadmap($request));
     }      }
    } elsif ($command eq 'csvuploadassign' && $perm{'mgr'} ) {
       $request->print(&csvuploadassign($request));
  } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {   } elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {
     $request->print(&scantron_selectphase($request));      $request->print(&scantron_selectphase($request));
   } elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {    } elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {
      $request->print(&scantron_validate_file($request));       $request->print(&scantron_do_warning($request));
  } elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {   } elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {
     $request->print(&scantron_validate_file($request));      $request->print(&scantron_validate_file($request));
  } elsif ($command eq 'scantron_process' && $perm{'mgr'}) {   } elsif ($command eq 'scantron_process' && $perm{'mgr'}) {
     $request->print(&scantron_process_students($request));      $request->print(&scantron_process_students($request));
   } elsif ($command eq 'scantronupload' &&     } elsif ($command eq 'scantronupload' && 
   (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})||    (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
   &Apache::lonnet::allowed('usc',$ENV{'request.course.id'}))) {    &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
      $request->print(&scantron_upload_scantron_data($request));        $request->print(&scantron_upload_scantron_data($request)); 
   } elsif ($command eq 'scantronupload_save' &&    } elsif ($command eq 'scantronupload_save' &&
   (&Apache::lonnet::allowed('usc',$ENV{'request.role.domain'})||    (&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
   &Apache::lonnet::allowed('usc',$ENV{'request.course.id'}))) {    &Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
      $request->print(&scantron_upload_scantron_data_save($request));       $request->print(&scantron_upload_scantron_data_save($request));
   } elsif ($command eq 'scantrondownload' &&    } elsif ($command eq 'scantron_download' &&
  &Apache::lonnet::allowed('usc',$ENV{'request.course.id'})) {   &Apache::lonnet::allowed('usc',$env{'request.course.id'})) {
      $request->print(&scantron_download_scantron_data($request));       $request->print(&scantron_download_scantron_data($request));
  } elsif ($command) {   } elsif ($command) {
     $request->print("Access Denied ($command)");      $request->print("Access Denied ($command)");
Line 4989  sub send_header { Line 5802  sub send_header {
   
 sub send_footer {  sub send_footer {
     my ($request)= @_;      my ($request)= @_;
     $request->print('</body>');      $request->print('</body></html>');
     $request->print(&Apache::lontexconvert::footer());  
 }  }
   
 1;  1;

Removed from v.1.201  
changed lines
  Added in v.1.305


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