Diff for /loncom/interface/Attic/lonspreadsheet.pm between versions 1.105 and 1.111

version 1.105, 2002/08/30 20:56:08 version 1.111, 2002/09/27 18:29:15
Line 26 Line 26
 # The LearningOnline Network with CAPA  # The LearningOnline Network with CAPA
 # Spreadsheet/Grades Display Handler  # Spreadsheet/Grades Display Handler
 #  #
 # 11/11,11/15,11/27,12/04,12/05,12/06,12/07,  
 # 12/08,12/09,12/11,12/12,12/15,12/16,12/18,12/19,12/30,  
 # 01/01/01,02/01,03/01,19/01,20/01,22/01,  
 # 03/05,03/08,03/10,03/12,03/13,03/15,03/17,  
 # 03/19,03/20,03/21,03/27,04/05,04/09,  
 # 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17,  
 # 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer  
 # 01/14/02 Matthew  
 # 02/04/02 Matthew  
   
 # POD required stuff:  # POD required stuff:
   
 =head1 NAME  =head1 NAME
Line 54  not the grades of their peers.  The spre Line 44  not the grades of their peers.  The spre
 offering the ability to use Perl code to manipulate data, as well as many  offering the ability to use Perl code to manipulate data, as well as many
 built-in functions.  built-in functions.
   
   
 =head2 Functions available to user of lonspreadsheet  =head2 Functions available to user of lonspreadsheet
   
 =over 4  =over 4
Line 167  $chome= ''; Line 156  $chome= '';
 $cnum = '';  $cnum = '';
 $cdom = '';  $cdom = '';
 $cid  = '';  $cid  = '';
 $cfn  = '';  $coursefilename  = '';
   
 # symb  # symb
   
Line 1111  sub getcid { Line 1100  sub getcid {
   
 # --------------------------------------------------------- Get course filename  # --------------------------------------------------------- Get course filename
   
 sub getcfn {  sub getcoursefilename {
     my $safeeval=shift;      my $safeeval=shift;
     return $safeeval->reval('$cfn');      return $safeeval->reval('$coursefilename');
 }  }
   
 # ----------------------------------------------------------- Get course number  # ----------------------------------------------------------- Get course number
Line 1194  sub rown { Line 1183  sub rown {
     my $rowdata='';      my $rowdata='';
     my $dataflag=0;      my $dataflag=0;
     unless ($n eq '-') {      unless ($n eq '-') {
        $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF';          $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF';
     } else {      } else {
        $defaultbg='#E0FF';          $defaultbg='#E0FF';
     }      }
     unless ($ENV{'form.showcsv'}) {      unless ($ENV{'form.showcsv'}) {
        $rowdata.="\n<tr><td><b><font size=+1>$n</font></b></td>";          $rowdata.="\n<tr><td><b><font size=+1>$n</font></b></td>";
     } else {      } else {
        $rowdata.="\n".'"'.$n.'"';          $rowdata.="\n".'"'.$n.'"';
     }      }
     my $showf=0;      my $showf=0;
     my $proc;      my $proc;
Line 1225  sub rown { Line 1214  sub rown {
         $dataflag=1;           $dataflag=1; 
     }      }
     foreach ($safeeval->reval($proc.'('.$n.')')) {      foreach ($safeeval->reval($proc.'('.$n.')')) {
        my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');          my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');
        my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);          my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);
        if ((($vl ne '') || ($vl eq '0')) &&          if ((($vl ne '') || ($vl eq '0')) &&
            (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; }              (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; }
        if ($showf==0) { $vl=$_; }          if ($showf==0) { $vl=$_; }
       unless ($ENV{'form.showcsv'}) {          unless ($ENV{'form.showcsv'}) {
        if ($showf<=$maxred) { $bgcolor='#FFDDDD'; }              if ($showf<=$maxred) { $bgcolor='#FFDDDD'; }
        if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; }               if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; } 
        if (($showf>$maxred) || ((!$n) && ($showf>0))) {              if (($showf>$maxred) || ((!$n) && ($showf>0))) {
    if ($vl eq '') {                  if ($vl eq '') {
        $vl='<font size=+2 color='.$bgcolor.'>&#35;</font>';                      $vl='<font size=+2 color='.$bgcolor.'>&#35;</font>';
            }                  }
            $rowdata.=                  $rowdata.='<td bgcolor='.$bgcolor.'>';
        '<td bgcolor='.$bgcolor.'><a href="javascript:celledit('.$fm.');">'.$vl.                  if ($ENV{'request.role'} =~ /^st\./) {
        '</a></td>';                      $rowdata.=$vl;
        } else {                  } else {
            $rowdata.='<td bgcolor='.$bgcolor.'>&nbsp;'.$vl.'&nbsp;</td>';                      $rowdata.='<a href="javascript:celledit('.$fm.');">'.
        }                          $vl.'</a>';
       } else {                  }
   $rowdata.=',"'.$vl.'"';                  $rowdata.='</td>';
       }              } else {
        $showf++;                  $rowdata.='<td bgcolor='.$bgcolor.'>&nbsp;'.$vl.'&nbsp;</td>';
               }
           } else {
               $rowdata.=',"'.$vl.'"';
           }
           $showf++;
     }  # End of foreach($safeval...)      }  # End of foreach($safeval...)
     if ($ENV{'form.showall'} || ($dataflag)) {      if ($ENV{'form.showall'} || ($dataflag)) {
        return $rowdata.($ENV{'form.showcsv'}?'':'</tr>');          return $rowdata.($ENV{'form.showcsv'}?'':'</tr>');
     } else {      } else {
        return '';          return '';
     }      }
 }  }
   
 # ------------------------------------------------------------- Print out sheet  # ------------------------------------------------------------- Print out sheet
   
 sub outsheet {  sub outsheet {
     my ($r,$safeeval)=@_;      my ($r,$safeeval,$sheetdata)=@_;
     my $maxred;      my $maxred = 26;    # The maximum number of cells to show as 
     my $realm;                          # red (uneditable) 
     if (&gettype($safeeval) eq 'assesscalc') {                          # To make student sheets uneditable could we 
                           # set $maxred = 52?
                           #
       my $realm='Course'; # 'assessment', 'user', or 'course' sheet
       if ($sheetdata->{'sheettype'} eq 'assesscalc') {
         $maxred=1;          $maxred=1;
         $realm='Assessment';          $realm='Assessment';
     } elsif (&gettype($safeeval) eq 'studentcalc') {      } elsif ($sheetdata->{'sheettype'} eq 'studentcalc') {
         $maxred=26;          $maxred=26;
         $realm='User';          $realm='User';
     } else {  
         $maxred=26;  
         $realm='Course';  
     }      }
     my $maxyellow=52-$maxred;      #
       # Column label
     my $tabledata;      my $tabledata;
     unless ($ENV{'form.showcsv'}) {      if ($ENV{'form.showcsv'}) {
        $tabledata=          $tabledata='<pre>';
         '<table border=2><tr><th colspan=2 rowspan=2><font size=+2>'.      } else { 
                   $realm.'</font></th>'.          $tabledata='<table border=2><tr><th colspan=2 rowspan=2>'.
               '<font size=+2>'.$realm.'</font></th>'.
                   '<td bgcolor=#FFDDDD colspan='.$maxred.                    '<td bgcolor=#FFDDDD colspan='.$maxred.
                   '><b><font size=+1>Import</font></b></td>'.                    '><b><font size=+1>Import</font></b></td>'.
                   '<td colspan='.$maxyellow.                    '<td colspan='.(52-$maxred).
   '><b><font size=+1>Calculations</font></b></td></tr><tr>';    '><b><font size=+1>Calculations</font></b></td></tr><tr>';
        my $showf=0;          my $showf=0;
        foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',          foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
                 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',                   'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
                 'a','b','c','d','e','f','g','h','i','j','k','l','m',                   'a','b','c','d','e','f','g','h','i','j','k','l','m',
                 'n','o','p','q','r','s','t','u','v','w','x','y','z') {                   'n','o','p','q','r','s','t','u','v','w','x','y','z') {
            $showf++;              $showf++;
            if ($showf<=$maxred) {               if ($showf<=$maxred) { 
                $tabledata.='<td bgcolor="#FFDDDD">';                   $tabledata.='<td bgcolor="#FFDDDD">'; 
            } else {              } else {
                $tabledata.='<td>';                  $tabledata.='<td>';
            }              }
            $tabledata.="<b><font size=+1>$_</font></b></td>";              $tabledata.="<b><font size=+1>$_</font></b></td>";
        }          }
        $tabledata.='</tr>'.&rown($safeeval,'-').&rown($safeeval,0);          $tabledata.='</tr>'.&rown($safeeval,'-').&rown($safeeval,0);
    } else { $tabledata='<pre>'; }      }
   
     $r->print($tabledata);      $r->print($tabledata);
       #
       # Prepare to output rows
     my $row;      my $row;
     my $maxrow=&getmaxrow($safeeval);      my $maxrow=&getmaxrow($safeeval);
       #
     my @sortby=();      my @sortby=();
     my @sortidx=();      my @sortidx=();
     for ($row=1;$row<=$maxrow;$row++) {      for ($row=1;$row<=$maxrow;$row++) {
        $sortby[$row-1]=$safeeval->reval('$f{"A'.$row.'"}');          push (@sortby, $safeeval->reval('$f{"A'.$row.'"}'));
        $sortidx[$row-1]=$row-1;          push (@sortidx, $row-1);
     }      }
     @sortidx=sort { $sortby[$a] cmp $sortby[$b]; } @sortidx;      @sortidx=sort { lc($sortby[$a]) cmp lc($sortby[$b]); } @sortidx;
         my $what='Student';      #
         if (&gettype($safeeval) eq 'assesscalc') {      # Determine the type of child spreadsheets
     $what='Item';      my $what='Student';
  } elsif (&gettype($safeeval) eq 'studentcalc') {      if ($sheetdata->{'sheettype'} eq 'assesscalc') {
             $what='Assessment';          $what='Item';
         }      } elsif ($sheetdata->{'sheettype'} eq 'studentcalc') {
           $what='Assessment';
       }
       #
       # Loop through the rows and output them one at a time
     my $n=0;      my $n=0;
     for ($row=0;$row<$maxrow;$row++) {      for ($row=0;$row<$maxrow;$row++) {
         my $thisrow=&rown($safeeval,$sortidx[$row]+1);          my $thisrow=&rown($safeeval,$sortidx[$row]+1);
Line 1324  sub outsheet { Line 1324  sub outsheet {
                 $r->print("</table>\n<br>\n");                  $r->print("</table>\n<br>\n");
                 $r->rflush();                  $r->rflush();
                 $r->print('<table border=2><tr><td>&nbsp;<td>'.$what.'</td>');                  $r->print('<table border=2><tr><td>&nbsp;<td>'.$what.'</td>');
                 $r->print('<td>'.join('</td><td>',                  $r->print('<td>'.
                                       (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.                            join('</td><td>',
                                             'abcdefghijklmnopqrstuvwxyz'))).                                 (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
                                         'abcdefghijklmnopqrstuvwxyz'))).
                           "</td></tr>\n");                            "</td></tr>\n");
             }              }
             $n++;              $n++;
Line 1387  sub parse_sheet { Line 1388  sub parse_sheet {
 #  #
 # -------------------------------------- Read spreadsheet formulas for a course  # -------------------------------------- Read spreadsheet formulas for a course
 #  #
   
 sub readsheet {  sub readsheet {
     my ($safeeval,$fn)=@_;      my ($safeeval,$sheetdata,$fn)=@_;
     my $stype = &gettype($safeeval);      #
     my $cnum  = &getcnum($safeeval);      my $stype = $sheetdata->{'sheettype'};
     my $cdom  = &getcdom($safeeval);      my $cnum  = $sheetdata->{'cnum'};
     my $chome = &getchome($safeeval);      my $cdom  = $sheetdata->{'cdom'};
       my $chome = $sheetdata->{'chome'};
       #
     if (! defined($fn)) {      if (! defined($fn)) {
         # There is no filename. Look for defaults in course and global, cache          # There is no filename. Look for defaults in course and global, cache
         unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {          unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {
Line 1458  sub readsheet { Line 1459  sub readsheet {
 }  }
   
 # -------------------------------------------------------- Make new spreadsheet  # -------------------------------------------------------- Make new spreadsheet
   
 sub makenewsheet {  sub makenewsheet {
     my ($uname,$udom,$stype,$usymb)=@_;      my ($uname,$udom,$stype,$usymb)=@_;
     my %sheetdata=();      my %sheetdata=();
Line 1469  sub makenewsheet { Line 1469  sub makenewsheet {
     $sheetdata{'cid'}   = $ENV{'request.course.id'};      $sheetdata{'cid'}   = $ENV{'request.course.id'};
     $sheetdata{'csec'}  = &Apache::lonnet::usection      $sheetdata{'csec'}  = &Apache::lonnet::usection
                                ($udom,$uname,$ENV{'request.course.id'});                                 ($udom,$uname,$ENV{'request.course.id'});
     $sheetdata{'cfn'}   = $ENV{'request.course.fn'};      $sheetdata{'coursefilename'}   = $ENV{'request.course.fn'};
     $sheetdata{'cnum'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};      $sheetdata{'cnum'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};
     $sheetdata{'cdom'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      $sheetdata{'cdom'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
     $sheetdata{'chome'} = $ENV{'course.'.$ENV{'request.course.id'}.'.home'};      $sheetdata{'chome'} = $ENV{'course.'.$ENV{'request.course.id'}.'.home'};
Line 1485  sub makenewsheet { Line 1485  sub makenewsheet {
 }  }
   
 # ------------------------------------------------------------ Save spreadsheet  # ------------------------------------------------------------ Save spreadsheet
   
 sub writesheet {  sub writesheet {
     my ($safeeval,$makedef)=@_;      my ($safeeval,$makedef)=@_;
     my $cid=&getcid($safeeval);      my $cid=&getcid($safeeval);
Line 1537  sub writesheet { Line 1536  sub writesheet {
 # ----------------------------------------------- Make a temp copy of the sheet  # ----------------------------------------------- Make a temp copy of the sheet
 # "Modified workcopy" - interactive only  # "Modified workcopy" - interactive only
 #  #
   
 sub tmpwrite {  sub tmpwrite {
     my $safeeval=shift;      my $safeeval=shift;
     my $fn=$ENV{'user.name'}.'_'.      my $fn=$ENV{'user.name'}.'_'.
Line 1552  sub tmpwrite { Line 1550  sub tmpwrite {
 }  }
   
 # ---------------------------------------------------------- Read the temp copy  # ---------------------------------------------------------- Read the temp copy
   
 sub tmpread {  sub tmpread {
     my ($safeeval,$nfield,$nform)=@_;      my ($safeeval,$nfield,$nform)=@_;
     my $fn=$ENV{'user.name'}.'_'.      my $fn=$ENV{'user.name'}.'_'.
Line 1673  sub parmval { Line 1670  sub parmval {
   
 # ---------------------------------------------- Update rows for course listing  # ---------------------------------------------- Update rows for course listing
 sub updateclasssheet {  sub updateclasssheet {
     my $safeeval=shift;      my ($safeeval,$sheetdata) = @_;
     my $cnum=&getcnum($safeeval);      my $cnum  =$sheetdata->{'cnum'};
     my $cdom=&getcdom($safeeval);      my $cdom  =$sheetdata->{'cdom'};
     my $cid=&getcid($safeeval);      my $cid   =$sheetdata->{'cid'};
     my $chome=&getchome($safeeval);      my $chome =$sheetdata->{'chome'};
     #      #
     # Read class list and row labels      # Read class list and row labels
     my %classlist;      my %classlist;
Line 1702  sub updateclasssheet { Line 1699  sub updateclasssheet {
             my ($studentName,$studentDomain)=split(/\:/,$student);              my ($studentName,$studentDomain)=split(/\:/,$student);
             my $studentSection=&Apache::lonnet::usection($studentDomain,              my $studentSection=&Apache::lonnet::usection($studentDomain,
                                                          $studentName,$cid);                                                           $studentName,$cid);
             if ($studentSection==-1) {  #            if ($studentSection==-1) {
                 unless ($ENV{'form.showcsv'}) {  #                unless ($ENV{'form.showcsv'}) {
                     $rowlabel='<font color=red>Data not available: '.  #                    $rowlabel='<font color=red>Data not available: '.
                         $studentName.'</font>';  #                        $studentName.'</font>';
                 } else {  #                } else {
                     $rowlabel='ERROR","'.$studentName.  #                    $rowlabel='ERROR","'.$studentName.
                         '","Data not available","","","';  #                        '","Data not available","","","';
                 }  #                }
             } else {  #            } else {
                 my %reply=&Apache::lonnet::idrget($studentDomain,$studentName);                  my %reply=&Apache::lonnet::idrget($studentDomain,$studentName);
                 my %studentInformation=&Apache::lonnet::get                  my %studentInformation=&Apache::lonnet::get
                     ('environment',                      ('environment',
Line 1735  sub updateclasssheet { Line 1732  sub updateclasssheet {
                                          $studentInformation{'generation'})                                           $studentInformation{'generation'})
                                         ).'"';                                          ).'"';
                 }                  }
             }   #           }
             $currentlist{$student}=$rowlabel;              $currentlist{$student}=$rowlabel;
         } # end of if ($active)          } # end of if ($active)
     } # end of foreach my $student (keys(%classlist))      } # end of foreach my $student (keys(%classlist))
Line 1777  sub updateclasssheet { Line 1774  sub updateclasssheet {
   
 # ----------------------------------- Update rows for student and assess sheets  # ----------------------------------- Update rows for student and assess sheets
 sub updatestudentassesssheet {  sub updatestudentassesssheet {
     my $safeeval=shift;      my ($safeeval,$sheetdata) = @_;
     my %bighash;      my %bighash;
     my $stype=&gettype($safeeval);      my $stype=$sheetdata->{'sheettype'};
       my $uname=$sheetdata->{'uname'};
       my $udom =$sheetdata->{'udom'};
     my %current=();      my %current=();
     if  ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) {      if  ($updatedata
            {$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}) {
         %current=split(/\_\_\_\;\_\_\_/,          %current=split(/\_\_\_\;\_\_\_/,
        $updatedata{$ENV{'request.course.fn'}.'_'.$stype});                         $updatedata{$ENV{'request.course.fn'}.
                                          '_'.$stype.'_'.$uname.'_'.$udom});
     } else {      } else {
         # Tie hash          # Tie hash
         tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',          tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
Line 1801  sub updatestudentassesssheet { Line 1802  sub updatestudentassesssheet {
                      'totalpoints' =>                       'totalpoints' =>
                      'Total Points Granted<br>totalpoints');                       'Total Points Granted<br>totalpoints');
         my $adduserstr='';          my $adduserstr='';
         if ((&getuname($safeeval) ne $ENV{'user.name'}) ||          if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})){
             (&getudom($safeeval) ne $ENV{'user.domain'})) {              $adduserstr='&uname='.$uname.'&udom='.$udom;
             $adduserstr='&uname='.&getuname($safeeval).  
                 '&udom='.&getudom($safeeval);  
         }          }
         my %allassess =          my %allassess =
             ('_feedback' =>'<a href="/adm/assesscalc?usymb=_feedback'.              ('_feedback' =>'<a href="/adm/assesscalc?usymb=_feedback'.
Line 1816  sub updatestudentassesssheet { Line 1815  sub updatestudentassesssheet {
              '_discussion' =>'<a href="/adm/assesscalc?usymb=_discussion'.               '_discussion' =>'<a href="/adm/assesscalc?usymb=_discussion'.
              $adduserstr.'">Discussion</a>'               $adduserstr.'">Discussion</a>'
              );               );
         foreach (keys(%bighash)) {          while (($_,undef) = each(%bighash)) {
             next if ($_!~/^src\_(\d+)\.(\d+)$/);              next if ($_!~/^src\_(\d+)\.(\d+)$/);
             my $mapid=$1;              my $mapid=$1;
             my $resid=$2;              my $resid=$2;
Line 1855  sub updatestudentassesssheet { Line 1854  sub updatestudentassesssheet {
         } elsif ($stype eq 'studentcalc') {          } elsif ($stype eq 'studentcalc') {
             %current=%allassess;              %current=%allassess;
         }          }
         $updatedata{$ENV{'request.course.fn'}.'_'.$stype}=          $updatedata{$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}=
             join('___;___',%current);              join('___;___',%current);
         # Get current from cache          # Get current from cache
     }      }
Line 1947  sub loadstudent { Line 1946  sub loadstudent {
 }  }
   
 # --------------------------------------------------- Load data for one student  # --------------------------------------------------- Load data for one student
   #
 sub loadcourse {  sub loadcourse {
     my ($safeeval,$sheetdata,$r)=@_;      my ($safeeval,$sheetdata,$r)=@_;
     my %c=();      my %c=();
Line 2009  ENDPOP Line 2008  ENDPOP
 }  }
   
 # ------------------------------------------------ Load data for one assessment  # ------------------------------------------------ Load data for one assessment
   #
 sub loadassessment {  sub loadassessment {
     my ($safeeval,$sheetdata)=@_;      my ($safeeval,$sheetdata)=@_;
   
Line 2041  sub loadassessment { Line 2040  sub loadassessment {
         #          #
         # restore individual          # restore individual
         #          #
         my $answer=&Apache::lonnet::reply(          %returnhash = &Apache::lonnet::restore($symb,$namespace,$udom,$uname);
                                           "restore:$udom:$uname:".          for (my $version=1;$version<=$returnhash{'version'};$version++) {
                                           &Apache::lonnet::escape($namespace).":".  
                                           &Apache::lonnet::escape($symb),$uhome);  
         foreach (split(/\&/,$answer)) {  
             my ($name,$value)=split(/\=/,$_);  
             $returnhash{&Apache::lonnet::unescape($name)}=  
                 &Apache::lonnet::unescape($value);  
         }  
         my $version;  
         for ($version=1;$version<=$returnhash{'version'};$version++) {  
             foreach (split(/\:/,$returnhash{$version.':keys'})) {              foreach (split(/\:/,$returnhash{$version.':keys'})) {
                 $returnhash{$_}=$returnhash{$version.':'.$_};                  $returnhash{$_}=$returnhash{$version.':'.$_};
             }               } 
         }          }
     }      }
       #
     # returnhash now has all stores for this resource      # returnhash now has all stores for this resource
     # convert all "_" to "." to be able to use libraries, multiparts, etc      # convert all "_" to "." to be able to use libraries, multiparts, etc
       #
       # This is dumb.  It is also necessary :(
     my @oldkeys=keys %returnhash;      my @oldkeys=keys %returnhash;
       #
     foreach (@oldkeys) {      foreach (@oldkeys) {
         my $name=$_;          my $name=$_;
         my $value=$returnhash{$_};          my $value=$returnhash{$_};
Line 2090  sub loadassessment { Line 2083  sub loadassessment {
                 &Apache::lonnet::unescape($value);                    &Apache::lonnet::unescape($value);  
         }          }
         # Get userdata (if present)          # Get userdata (if present)
         unless          unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
             ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {              my $reply=
                 my $reply=                  &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
                     &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);              if ($reply!~/^error\:/) {
                 if ($reply!~/^error\:/) {                  $userrdatas{$uname.'___'.$udom}=$reply;
                     $userrdatas{$uname.'___'.$udom}=$reply;                  $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;
                     $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;  
                 }  
             }              }
           }
         foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) {          foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) {
             my ($name,$value)=split(/\=/,$_);              my ($name,$value)=split(/\=/,$_);
             $useropt{$userprefix.&Apache::lonnet::unescape($name)}=              $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
Line 2120  sub loadassessment { Line 2112  sub loadassessment {
     #      #
     my %c=();      my %c=();
     if (tie(%parmhash,'GDBM_File',      if (tie(%parmhash,'GDBM_File',
             &getcfn($safeeval).'_parms.db',&GDBM_READER(),0640)) {              &getcoursefilename($safeeval).'_parms.db',&GDBM_READER(),0640)) {
         my %f=&getformulas($safeeval);          my %f=&getformulas($safeeval);
         foreach (keys(%f))  {          foreach (keys(%f))  {
             next if ($_!~/^A/);              next if ($_!~/^A/);
Line 2178  sub updatesheet { Line 2170  sub updatesheet {
     my ($safeeval,$sheetdata)=@_;      my ($safeeval,$sheetdata)=@_;
     my $stype=$sheetdata->{'sheettype'};      my $stype=$sheetdata->{'sheettype'};
     if ($stype eq 'classcalc') {      if ($stype eq 'classcalc') {
  return &updateclasssheet($safeeval);   return &updateclasssheet($safeeval,$sheetdata);
     } else {      } else {
         return &updatestudentassesssheet($safeeval);          return &updatestudentassesssheet($safeeval,$sheetdata);
     }      }
 }  }
   
Line 2286  sub exportsheet { Line 2278  sub exportsheet {
         # Not cached          # Not cached
         #                  #        
         my ($thissheet,$sheetdata)=&makenewsheet($uname,$udom,$stype,$usymb);          my ($thissheet,$sheetdata)=&makenewsheet($uname,$udom,$stype,$usymb);
         &readsheet($thissheet,$fn);          &readsheet($thissheet,$sheetdata,$fn);
         &updatesheet($thissheet,$sheetdata);          &updatesheet($thissheet,$sheetdata);
         &loadrows($thissheet,$sheetdata);          &loadrows($thissheet,$sheetdata);
         &calcsheet($thissheet,$sheetdata);           &calcsheet($thissheet,$sheetdata); 
Line 2426  sub cachedssheets { Line 2418  sub cachedssheets {
 # Interactive call to screen  # Interactive call to screen
 #  #
 #  #
   
   
 sub handler {  sub handler {
     my $r=shift;      my $r=shift;
   
       my $loaderror=&Apache::lonnet::overloaderror($r);
       if ($loaderror) { return $loaderror; }
       $loaderror= &Apache::lonnet::overloaderror($r,
                         $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
       if ($loaderror) { return $loaderror; } 
   
     if ($r->header_only) {      if ($r->header_only) {
         $r->content_type('text/html');          $r->content_type('text/html');
         $r->send_http_header;          $r->send_http_header;
         return OK;          return OK;
     }      }
     # Global directory configs      # Global directory configs
     $includedir=$r->dir_config('lonIncludes');      $includedir = $r->dir_config('lonIncludes');
     $tmpdir=$r->dir_config('lonDaemons').'/tmp/';      $tmpdir = $r->dir_config('lonDaemons').'/tmp/';
     # Needs to be in a course      # Needs to be in a course
     if ($ENV{'request.course.fn'}) {       if (! $ENV{'request.course.fn'}) { 
         # Get query string for limited number of parameters          # Not in a course, or not allowed to modify parms
         &Apache::loncommon::get_unprocessed_cgi          $ENV{'user.error.msg'}=
             ($ENV{'QUERY_STRING'},['uname','udom','usymb','ufn']);              $r->uri.":opa:0:0:Cannot modify spreadsheet";
         if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {          return HTTP_NOT_ACCEPTABLE; 
             $ENV{'form.ufn'}='default_'.$1;      }
         }      # Get query string for limited number of parameters
         # Interactive loading of specific sheet?      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
         if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {                                              ['uname','udom','usymb','ufn']);
             $ENV{'form.ufn'}=$ENV{'form.loadthissheet'};      if ($ENV{'request.role'} =~ /^st\./) {
         }          delete $ENV{'form.unewfield'}   if (exists($ENV{'form.unewfield'}));
         # Nothing there? Must be login user          delete $ENV{'form.unewformula'} if (exists($ENV{'form.unewformula'}));
         my $aname;      }
         my $adom;      if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {
           $ENV{'form.ufn'}='default_'.$1;
         unless ($ENV{'form.uname'}) {      }
             $aname=$ENV{'user.name'};      # Interactive loading of specific sheet?
             $adom=$ENV{'user.domain'};      if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
         } else {          $ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
             $aname=$ENV{'form.uname'};      }
             $adom=$ENV{'form.udom'};      #
         }      # Determine the user name and domain for the sheet.
         # Open page      my $aname;
         $r->content_type('text/html');      my $adom;
         $r->header_out('Cache-control','no-cache');      unless ($ENV{'form.uname'}) {
         $r->header_out('Pragma','no-cache');          $aname=$ENV{'user.name'};
         $r->send_http_header;          $adom=$ENV{'user.domain'};
         # Screen output      } else {
         $r->print('<html><head><title>LON-CAPA Spreadsheet</title>');          $aname=$ENV{'form.uname'};
           $adom=$ENV{'form.udom'};
       }
       #
       # Open page
       $r->content_type('text/html');
       $r->header_out('Cache-control','no-cache');
       $r->header_out('Pragma','no-cache');
       $r->send_http_header;
       # Screen output
       $r->print('<html><head><title>LON-CAPA Spreadsheet</title>');
       if ($ENV{'request.role'} !~ /^st\./) {
         $r->print(<<ENDSCRIPT);          $r->print(<<ENDSCRIPT);
 <script language="JavaScript">  <script language="JavaScript">
   
Line 2494  sub handler { Line 2502  sub handler {
   
 </script>  </script>
 ENDSCRIPT  ENDSCRIPT
         $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').      }
                   '<form action="'.$r->uri.'" name=sheet method=post>'.      $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').
                   &hiddenfield('uname',$ENV{'form.uname'}).                '<form action="'.$r->uri.'" name=sheet method=post>');
                   &hiddenfield('udom',$ENV{'form.udom'}).      $r->print(&hiddenfield('uname',$ENV{'form.uname'}).
                   &hiddenfield('usymb',$ENV{'form.usymb'}).                &hiddenfield('udom',$ENV{'form.udom'}).
                   &hiddenfield('unewfield','').                &hiddenfield('usymb',$ENV{'form.usymb'}).
                   &hiddenfield('unewformula',''));                &hiddenfield('unewfield','').
         # Send this out right away                &hiddenfield('unewformula',''));
         $r->rflush();      $r->rflush();
         # Full recalc?      #
         if ($ENV{'form.forcerecalc'}) {      # Full recalc?
             $r->print('<h4>Completely Recalculating Sheet ...</h4>');      if ($ENV{'form.forcerecalc'}) {
             undef %spreadsheets;          $r->print('<h4>Completely Recalculating Sheet ...</h4>');
             undef %courserdatas;          undef %spreadsheets;
             undef %userrdatas;          undef %courserdatas;
             undef %defaultsheets;          undef %userrdatas;
             undef %updatedata;          undef %defaultsheets;
         }          undef %updatedata;
         # Read new sheet or modified worksheet      }
         $r->uri=~/\/(\w+)$/;      # Read new sheet or modified worksheet
         my ($asheet,$asheetdata)=&makenewsheet      $r->uri=~/\/(\w+)$/;
                                       ($aname,$adom,$1,$ENV{'form.usymb'});      my ($asheet,$asheetdata)=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});
         # If a new formula had been entered, go from work copy      #
         if ($ENV{'form.unewfield'}) {      # If a new formula had been entered, go from work copy
             $r->print('<h2>Modified Workcopy</h2>');      if ($ENV{'form.unewfield'}) {
             $ENV{'form.unewformula'}=~s/\'/\"/g;          $r->print('<h2>Modified Workcopy</h2>');
             $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.          $ENV{'form.unewformula'}=~s/\'/\"/g;
                       $ENV{'form.unewformula'}.'<p>');          $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.
             &setfilename($asheet,$ENV{'form.ufn'});                    $ENV{'form.unewformula'}.'<p>');
             &tmpread($asheet,          &setfilename($asheet,$ENV{'form.ufn'});
                      $ENV{'form.unewfield'},$ENV{'form.unewformula'});          &tmpread($asheet,$ENV{'form.unewfield'},$ENV{'form.unewformula'});
                   } elsif ($ENV{'form.saveas'}) {
         } elsif ($ENV{'form.saveas'}) {          &setfilename($asheet,$ENV{'form.ufn'});
             &setfilename($asheet,$ENV{'form.ufn'});          &tmpread($asheet);
             &tmpread($asheet);      } else {
         } else {          &readsheet($asheet,$asheetdata,$ENV{'form.ufn'});
             &readsheet($asheet,$ENV{'form.ufn'});      }
         }      # Print out user information
         # Print out user information      unless ($asheetdata->{'sheettype'} eq 'classcalc') {
         unless ($asheetdata->{'sheettype'} eq 'classcalc') {          $r->print('<p><b>User:</b> '.$asheetdata->{'uname'}.
             $r->print('<p><b>User:</b> '.$asheetdata->{'uname'}.                    '<br><b>Domain:</b> '.$asheetdata->{'udom'});
                       '<br><b>Domain:</b> '.$asheetdata->{'udom'});  #        if (&getcsec($asheet) eq '-1') {
             if (&getcsec($asheet) eq '-1') {  #            $r->print('<h3><font color=red>'.
                 $r->print('<h3><font color=red>'.  #                      'Not a student in this course</font></h3>');
                           'Not a student in this course</font></h3>');  #        } else {
             } else {              $r->print('<br><b>Section/Group:</b> '.$asheetdata->{'csec'});
                 $r->print('<br><b>Section/Group:</b> '.$asheetdata->{'csec'});  #        }
           if ($ENV{'form.usymb'}) {
               $r->print('<br><b>Assessment:</b> <tt>'.
                         $ENV{'form.usymb'}.'</tt>');
           }
       }
       #
       # Check user permissions
       if (($asheetdata->{'sheettype'} eq 'classcalc'       ) || 
           ($asheetdata->{'uname'}     ne $ENV{'user.name'} ) ||
           ($asheetdata->{'udom'}      ne $ENV{'user.domain'})) {
           unless (&Apache::lonnet::allowed('vgr',$asheetdata->{'cid'})) {
               $r->print('<h1>Access Permission Denied</h1>'.
                         '</form></body></html>');
               return OK;
           }
       }
       # Additional options
       $r->print('<br />'.
                 '<input type="submit" name="forcerecalc" '.
                 'value="Completely Recalculate Sheet"><p>');
       if ($asheetdata->{'sheettype'} eq 'assesscalc') {
           $r->print('<p><font size=+2>'.
                     '<a href="/adm/studentcalc?'.
                     'uname='.$asheetdata->{'uname'}.
                     '&udom='.$asheetdata->{'udom'}.'">'.
                     'Level up: Student Sheet</a></font><p>');
       }
       if (($asheetdata->{'sheettype'} eq 'studentcalc') && 
           (&Apache::lonnet::allowed('vgr',$asheetdata->{'cid'}))) {
           $r->print ('<p><font size=+2><a href="/adm/classcalc">'.
                      'Level up: Course Sheet</a></font><p>');
       }
       # Save dialog
       if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
           my $fname=$ENV{'form.ufn'};
           $fname=~s/\_[^\_]+$//;
           if ($fname eq 'default') { $fname='course_default'; }
           $r->print('<input type=submit name=saveas value="Save as ...">'.
                     '<input type=text size=20 name=newfn value="'.$fname.'">'.
                     'make default: <input type=checkbox name="makedefufn"><p>');
       }
       $r->print(&hiddenfield('ufn',&getfilename($asheet)));
       # Load dialog
       if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
           $r->print('<p><input type=submit name=load value="Load ...">'.
                     '<select name="loadthissheet">'.
                     '<option name="default">Default</option>');
           foreach (&othersheets($asheet,$asheetdata->{'sheettype'})) {
               $r->print('<option name="'.$_.'"');
               if ($ENV{'form.ufn'} eq $_) {
                   $r->print(' selected');
             }              }
             if ($ENV{'form.usymb'}) {              $r->print('>'.$_.'</option>');
                 $r->print('<br><b>Assessment:</b> <tt>'.          } 
                           $ENV{'form.usymb'}.'</tt>');          $r->print('</select><p>');
             }          if ($asheetdata->{'sheettype'} eq 'studentcalc') {
         }              &setothersheets($asheet,&othersheets($asheet,'assesscalc'));
         # See if user can see this  
         if (($asheetdata->{'sheettype'} eq 'classcalc'       ) ||   
             ($asheetdata->{'uname'}     ne $ENV{'user.name'} ) ||  
             ($asheetdata->{'udom'}      ne $ENV{'user.domain'})) {  
             unless (&Apache::lonnet::allowed('vgr',$asheetdata->{'cid'})) {  
                 $r->print('<h1>Access Permission Denied</h1>'.  
                           '</form></body></html>');  
                 return OK;  
             }  
         }  
         # Additional options  
         $r->print(  
  '<input type=submit name=forcerecalc value="Completely Recalculate Sheet"><p>'  
                   );  
         if ($asheetdata->{'sheettype'} eq 'assesscalc') {  
             $r->print('<p><font size=+2>'.  
                       '<a href="/adm/studentcalc?'.  
                       'uname='.$asheetdata->{'uname'}.  
                       '&udom='.$asheetdata->{'udom'}.'">'.  
                       'Level up: Student Sheet</a></font><p>');  
         }  
         if (($asheetdata->{'sheettype'} eq 'studentcalc') &&   
             (&Apache::lonnet::allowed('vgr',$asheetdata->{'cid'}))) {  
             $r->print (  
                        '<p><font size=+2><a href="/adm/classcalc">'.  
                        'Level up: Course Sheet</a></font><p>');  
         }  
         # Save dialog  
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {  
             my $fname=$ENV{'form.ufn'};  
             $fname=~s/\_[^\_]+$//;  
             if ($fname eq 'default') { $fname='course_default'; }  
             $r->print  
                 ('<input type=submit name=saveas value="Save as ...">'.  
                  '<input type=text size=20 name=newfn value="'.$fname.'">'.  
                  '(make default: <input type=checkbox name="makedefufn">)<p>');  
         }  
         $r->print(&hiddenfield('ufn',&getfilename($asheet)));  
         # Load dialog  
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {  
             $r->print('<p><input type=submit name=load value="Load ...">'.  
                       '<select name="loadthissheet">'.  
                       '<option name="default">Default</option>');  
             foreach (&othersheets($asheet,$asheetdata->{'sheettype'})) {  
                 $r->print('<option name="'.$_.'"');  
                 if ($ENV{'form.ufn'} eq $_) {  
                     $r->print(' selected');  
                 }  
                 $r->print('>'.$_.'</option>');  
             }   
             $r->print('</select><p>');  
             if (&gettype($asheet) eq 'studentcalc') {  
                 &setothersheets($asheet,&othersheets($asheet,'assesscalc'));  
             }  
         }  
         # Cached sheets  
         &expirationdates();  
         undef %oldsheets;  
         undef %loadedcaches;  
         if ($asheetdata->{'sheettype'} eq 'classcalc') {  
             $r->print  
                 ("Loading previously calculated student sheets ...<br>\n");  
             $r->rflush();  
             &cachedcsheets();  
         } elsif ($asheetdata->{'sheettype'} eq 'studentcalc') {  
             $r->print  
                 ("Loading previously calculated assessment sheets ...<br>\n");  
             $r->rflush();  
             &cachedssheets($asheetdata->{'uname'},$asheetdata->{'udom'},  
                            $asheetdata->{'uhome'});  
         }          }
         # Update sheet, load rows      }
         $r->print("Loaded sheet(s), updating rows ...<br>\n");      # Cached sheets
         $r->rflush();      &expirationdates();
         #      undef %oldsheets;
         &updatesheet($asheet,$asheetdata);      undef %loadedcaches;
         $r->print("Updated rows, loading row data ...<br>\n");      if ($asheetdata->{'sheettype'} eq 'classcalc') {
           $r->print("Loading previously calculated student sheets ...\n");
         $r->rflush();          $r->rflush();
         #          &cachedcsheets();
         &loadrows($asheet,$asheetdata,$r);      } elsif ($asheetdata->{'sheettype'} eq 'studentcalc') {
         $r->print("Loaded row data, calculating sheet ...<br>\n");          $r->print("Loading previously calculated assessment sheets ...\n");
         $r->rflush();          $r->rflush();
         #          &cachedssheets($asheetdata->{'uname'},$asheetdata->{'udom'},
         my $calcoutput=&calcsheet($asheet);                         $asheetdata->{'uhome'});
         $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>');      }
         # See if something to save      # Update sheet, load rows
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {      $r->print("Loaded sheet(s), updating rows ...<br>\n");
             my $fname='';      $r->rflush();
             if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {      #
                 $fname=~s/\W/\_/g;      &updatesheet($asheet,$asheetdata);
                 if ($fname eq 'default') { $fname='course_default'; }      $r->print("Updated rows, loading row data ...\n");
                 $fname.='_'.$asheetdata->{'sheettype'};      $r->rflush();
                 &setfilename($asheet,$fname);      #
                 $ENV{'form.ufn'}=$fname;      &loadrows($asheet,$asheetdata,$r);
                 $r->print('<p>Saving spreadsheet: '.      $r->print("Loaded row data, calculating sheet ...<br>\n");
                           &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');      $r->rflush();
             }      #
       my $calcoutput=&calcsheet($asheet);
       $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>');
       # See if something to save
       if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
           my $fname='';
           if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
               $fname=~s/\W/\_/g;
               if ($fname eq 'default') { $fname='course_default'; }
               $fname.='_'.$asheetdata->{'sheettype'};
               &setfilename($asheet,$fname);
               $ENV{'form.ufn'}=$fname;
               $r->print('<p>Saving spreadsheet: '.
                         &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');
         }          }
         #Write the modified worksheet      }
       #
             $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>');      #Write the modified worksheet
       $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>');
             &tmpwrite($asheet);      &tmpwrite($asheet);
   
     if ($asheetdata->{'sheettype'} eq 'studentcalc') {      if ($asheetdata->{'sheettype'} eq 'studentcalc') {
  $r->print('<br>Show rows with empty A column: ');          $r->print('<br>Show rows with empty A column: ');
     } else {      } else {
         $r->print('<br>Show empty rows: ');          $r->print('<br>Show empty rows: ');
     }       } 
       #
     $r->print(&hiddenfield('userselhidden','true').      $r->print(&hiddenfield('userselhidden','true').
              '<input type=checkbox name=showall onClick="submit()"');                '<input type="checkbox" name="showall" onClick="submit()"');
       #
     if ($ENV{'form.showall'}) {       if ($ENV{'form.showall'}) { 
        $r->print(' checked');           $r->print(' checked'); 
     } else {      } else {
  unless ($ENV{'form.userselhidden'}) {          unless ($ENV{'form.userselhidden'}) {
            unless               unless 
  ($ENV{'course.'.$ENV{'request.course.id'}.'.hideemptyrows'} eq 'yes') {                  ($ENV{'course.'.$ENV{'request.course.id'}.'.hideemptyrows'} eq 'yes') {
           $r->print(' checked');                      $r->print(' checked');
           $ENV{'form.showall'}=1;                      $ENV{'form.showall'}=1;
            }                  }
        }          }
     }      }
     $r->print('>');      $r->print('>');
       #
       # CSV format checkbox (classcalc sheets only)
     if ($asheetdata->{'sheettype'} eq 'classcalc') {      if ($asheetdata->{'sheettype'} eq 'classcalc') {
        $r->print(          $r->print(' Output CSV format: <input type="checkbox" '.
    ' Output CSV format: <input type=checkbox name=showcsv onClick="submit()"');                    'name="showcsv" onClick="submit()"');
        if ($ENV{'form.showcsv'}) { $r->print(' checked'); }          if ($ENV{'form.showcsv'}) { $r->print(' checked'); }
        $r->print('>');          $r->print('>');
     }      }
       #
 # ------------------------------------------------------------------ Insertrows      # Buttons to insert rows
     $r->print('&nbsp;Student Status: '.      $r->print('&nbsp;Student Status: '.
               &Apache::lonhtmlcommon::StatusOptions                &Apache::lonhtmlcommon::StatusOptions
               ($ENV{'form.Status'},'sheet'));                ($ENV{'form.Status'},'sheet'));
       $r->print(<<ENDINSERTBUTTONS);
    $r->print(<<ENDINSERTBUTTONS);  
 <br>  <br>
 <input type='button' onClick='insertrow("top");'   <input type='button' onClick='insertrow("top");' 
 value='Insert Row Top'>  value='Insert Row Top'>
 <input type='button' onClick='insertrow("bottom");'   <input type='button' onClick='insertrow("bottom");' 
 value='Insert Row Bottom'><br>  value='Insert Row Bottom'><br>
 ENDINSERTBUTTONS  ENDINSERTBUTTONS
       # Print out sheet
 # ------------------------------------------------------------- Print out sheet      &outsheet($r,$asheet,$asheetdata);
   
     &outsheet($r,$asheet);  
     $r->print('</form></body></html>');      $r->print('</form></body></html>');
       #  Done
 # ------------------------------------------------------------------------ Done  
   } else {  
 # ----------------------------- Not in a course, or not allowed to modify parms  
       $ENV{'user.error.msg'}=  
         $r->uri.":opa:0:0:Cannot modify spreadsheet";  
       return HTTP_NOT_ACCEPTABLE;   
   }  
     return OK;      return OK;
   
 }  }
   
 1;  1;

Removed from v.1.105  
changed lines
  Added in v.1.111


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