--- loncom/interface/spreadsheet/assesscalc.pm	2003/05/19 15:48:18	1.2
+++ loncom/interface/spreadsheet/assesscalc.pm	2003/09/17 17:32:56	1.23
@@ -1,5 +1,5 @@
 #
-# $Id: assesscalc.pm,v 1.2 2003/05/19 15:48:18 matthew Exp $
+# $Id: assesscalc.pm,v 1.23 2003/09/17 17:32:56 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -44,6 +44,8 @@ assesscalc
 package Apache::assesscalc;
 
 use strict;
+use warnings FATAL=>'all';
+no warnings 'uninitialized';
 use Apache::Constants qw(:common :http);
 use Apache::lonnet;
 use Apache::loncommon;
@@ -88,6 +90,7 @@ use Time::HiRes;
 ########################################################
 
 my %Exportrows;
+my %newExportrows;
 
 my $current_name;
 my $current_domain;
@@ -97,6 +100,7 @@ my %parmhash;
 my %nice_parameter_name;
 
 my %useropt;
+my %userdata;
 my %courseopt;
 
 ########################################################
@@ -108,21 +112,44 @@ my %courseopt;
 
 =item &clear_package()
 
-Reset all package variables.  
+Reset all package variables and clean up caches.
 
 =cut
 
 ########################################################
 ########################################################
 sub clear_package {
+    if (defined($current_name) &&
+        defined($current_domain) &&
+        defined($current_course) &&
+        $current_course eq $ENV{'request.course.id'} &&
+        %newExportrows) {
+        &save_cached_export_rows($current_name,$current_domain);
+    }
     undef(%Exportrows);
+    undef(%newExportrows);
     undef($current_name);
     undef($current_domain);
     undef($current_course);
     undef(%useropt);
+    undef(%userdata);
     undef(%courseopt);
 }
 
+sub save_cached_export_rows {
+    my ($sname,$sdomain) = @_;
+    my $start = Time::HiRes::time;
+    my $result = &Apache::lonnet::put
+        ('nohist_calculatedsheets_'.$ENV{'request.course.id'},
+         $newExportrows{$sname.':'.$sdomain},
+         $sdomain,$sname);
+    delete($newExportrows{$sname.':'.$sdomain});
+}
+
+sub initialize {
+    &clear_package();
+}
+
 ########################################################
 ########################################################
 
@@ -136,14 +163,19 @@ sub clear_package {
 ########################################################
 sub initialize_package {
     my ($sname,$sdomain) = @_;
-    $current_course = $ENV{'request.course.id'};
     $current_name   = $sname;
     $current_domain = $sdomain;
-    undef(%courseopt);
+    undef(%useropt);
+    undef(%userdata);
+    if ($current_course ne $ENV{'request.course.id'}) {
+        $current_course = $ENV{'request.course.id'};
+        undef(%courseopt);
+    }
     &load_cached_export_rows();
     &load_parameter_caches();
 }
 
+
 ########################################################
 ########################################################
 
@@ -161,18 +193,16 @@ sub load_parameter_caches {
     #
     # Course Parameters Cache
     if (! %courseopt) {
-        &Apache::lonnet::logthis("loading course options");
         $current_course = $ENV{'request.course.id'};
         undef(%courseopt);
         if (! defined($current_name) || ! defined($current_domain)) {
-            &Apache::lonnet::logthis('bad call to setup_parameter_caches');
             return;
         }
         my $dom = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
         my $id  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};
         my %Tmp = &Apache::lonnet::dump('resourcedata',$dom,$id);
         while (my ($name,$value) = each(%Tmp)) {
-            $courseopt{$userprefix.$name}=$value;
+            $courseopt{$name}=$value;
         }
     }
     if (! %useropt) {
@@ -185,7 +215,14 @@ sub load_parameter_caches {
             }
             $useropt{$userprefix.$name}=$value;
         }
+        $useropt{'loadtime'} = time;
+    }
+    if (! %userdata) {
+        %userdata = &Apache::loncoursedata::get_current_state($current_name,
+                                                              $current_domain);
+        $userdata{'loadtime'} = time;
     }
+    return;
 }
 
 ########################################################
@@ -199,19 +236,27 @@ sub load_parameter_caches {
 
 ########################################################
 ########################################################
-
-sub ensure_current_parameter_caches {
+sub ensure_current_caches {
     my $self = shift;
+    ##
+    ## Check for a modified parameters
+    ##
     if (! defined($current_course) || 
         $current_course ne $ENV{'request.course.id'} ) {
         $current_course = $ENV{'request.course.id'};
         undef(%courseopt); 
+        undef(%useropt);
+        undef(%userdata);
     }
+    ##
+    ## Check for new user
+    ##
     if (! defined($current_name)   || $current_name ne $self->{'name'} ||
         ! defined($current_domain) || $current_domain ne $self->{'domain'}) {
         $current_domain = $self->{'domain'};
         $current_name   = $self->{'name'};
         undef(%useropt);
+        undef(%userdata);
     }
     &load_parameter_caches();
 }
@@ -242,7 +287,7 @@ this user and course.
 ##################################################
 sub parmval {
     my $self = shift;
-    my ($what,$symb,$uname,$udom,$csec)=@_;
+    my ($what,$symb,$uname,$udom,$csec,$recurse)=@_;
     $uname = $self->{'name'}    if (! defined($uname));
     $udom  = $self->{'domain'}  if (! defined($udom));
     $csec  = $self->{'section'} if (! defined($csec));
@@ -251,7 +296,7 @@ sub parmval {
     my $result='';
     #
     # This should be a 
-    my ($mapname,$id,$fn)=split(/___/,$symb);
+    my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb);
     # Cascading lookup scheme
     my $rwhat=$what;
     $what =~ s/^parameter\_//;
@@ -259,20 +304,25 @@ sub parmval {
     #
     my $symbparm = $symb.'.'.$what;
     my $mapparm  = $mapname.'___(all).'.$what;
+    my $courseprefix = $self->{'cid'};
     my $usercourseprefix = $uname.'_'.$udom.'_'.$self->{'cid'};
     #
-    my $seclevel  = $usercourseprefix.'.['.$csec.'].'.$what;
-    my $seclevelr = $usercourseprefix.'.['.$csec.'].'.$symbparm;
-    my $seclevelm = $usercourseprefix.'.['.$csec.'].'.$mapparm;
-    #
-    my $courselevel  = $usercourseprefix.'.'.$what;
-    my $courselevelr = $usercourseprefix.'.'.$symbparm;
-    my $courselevelm = $usercourseprefix.'.'.$mapparm;
+    my $seclevel  = $courseprefix.'.['.$csec.'].'.$what;
+    my $seclevelr = $courseprefix.'.['.$csec.'].'.$symbparm;
+    my $seclevelm = $courseprefix.'.['.$csec.'].'.$mapparm;
+    #
+    my $courselevel  = $courseprefix.'.'.$what;
+    my $courselevelr = $courseprefix.'.'.$symbparm;
+    my $courselevelm = $courseprefix.'.'.$mapparm;
+    #
+    my $ucourselevel  = $usercourseprefix.'.'.$what;
+    my $ucourselevelr = $usercourseprefix.'.'.$symbparm;
+    my $ucourselevelm = $usercourseprefix.'.'.$mapparm;
    # check user
     if (defined($uname)) {
-        return $useropt{$courselevelr} if (defined($useropt{$courselevelr}));
-        return $useropt{$courselevelm} if (defined($useropt{$courselevelm}));
-        return $useropt{$courselevel}  if (defined($useropt{$courselevel}));
+        return $useropt{$ucourselevelr} if (defined($useropt{$ucourselevelr}));
+        return $useropt{$ucourselevelm} if (defined($useropt{$ucourselevelm}));
+        return $useropt{$ucourselevel}  if (defined($useropt{$ucourselevel}));
     }
     # check section
     if (defined($csec)) {
@@ -302,25 +352,40 @@ sub parmval {
 	if ($part eq '') { $part='0'; }
 	my $newwhat=$rwhat;
 	$newwhat=~s/\Q$space\E/$part/;
-	my $partgeneral=$self->parmval($newwhat,$symb,$uname,$udom,$csec);
+	my $partgeneral=$self->parmval($newwhat,$symb,$uname,$udom,$csec,1);
 	if (defined($partgeneral)) { return $partgeneral; }
     }
+    if ($recurse) { return undef; }
+    my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$what);
+    if (defined($pack_def)) { return $pack_def; }
     #nothing defined
     return '';
 }
 
+sub get_html_title {
+    my $self = shift;
+    my ($assess_title,$name,$time) = $self->get_title();
+    my $title = '<h1>'.$assess_title.'</h1>'.
+        '<h2>'.$name.', '.
+        &Apache::loncommon::aboutmewrapper
+                         ($self->{'name'}.'@'.$self->{'domain'},
+                          $self->{'name'},$self->{'domain'});
+    $title .= '<h3>'.$time.'</h3>';
+    return $title;
+}
+
 sub get_title {
     my $self = shift;
-    my $title;
-    if (($self->{'usymb'} eq '_feedback') ||
-        ($self->{'usymb'} eq '_evaluation') ||
-        ($self->{'usymb'} eq '_discussion') ||
-        ($self->{'usymb'} eq '_tutoring')) {
-        $title = $self->{'usymb'};
-        $title =~ s/^_//;
-        $title = '<h1>'.ucfirst($title)."</h1>\n";
+    my @title = ();
+    if (($self->{'symb'} eq '_feedback') ||
+        ($self->{'symb'} eq '_evaluation') ||
+        ($self->{'symb'} eq '_discussion') ||
+        ($self->{'symb'} eq '_tutoring')) {
+        my $assess_title = ucfirst($self->{'symb'});
+        $assess_title =~ s/^_//;
+        push(@title,$assess_title);
     } else {
-        $title = '<h1>'.&Apache::lonnet::gettitle($self->{'symb'})."</h1>\n";
+        push(@title,&Apache::lonnet::gettitle($self->{'symb'}));
     }
     # Look up the users identifying information
     # Get the users information
@@ -329,13 +394,9 @@ sub get_title {
     my $name = 
         join(' ',@userenv{'firstname','middlename','lastname','generation'});
     $name =~ s/\s+$//;
-    $title .= '<h2>'.$name.', '.
-        &Apache::loncommon::aboutmewrapper($self->{'name'}.'@'.$self->{'domain'},
-                                           $self->{'name'},$self->{'domain'}).
-                                           "</h2>\n";
-    $title .= '<h3>'.localtime(time).'</h3>';
-    #
-    return $title;
+    push (@title,$name);
+    push (@title,scalar(localtime(time)));
+    return @title;
 }
 
 sub parent_link {
@@ -353,13 +414,15 @@ sub outsheet_html {
     ###################################
     # Determine table structure
     ###################################
+    my $importcolor = '#FFFFFF';
+    my $exportcolor = '#FFFFAA';
     my $num_uneditable = 1;
     my $num_left = 52-$num_uneditable;
     my $tableheader =<<"END";
 <table border="2">
 <tr>
   <th colspan="2" rowspan="2"><font size="+2">Assessment</font></th>
-  <td bgcolor="#FFDDDD" colspan="$num_uneditable">&nbsp;</td>
+  <td bgcolor="$importcolor" colspan="$num_uneditable">&nbsp;</td>
   <td colspan="$num_left">
       <b><font size="+1">Calculations</font></b></td>
 </tr><tr>
@@ -367,7 +430,7 @@ END
     my $label_num = 0;
     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
         if ($label_num<$num_uneditable) { 
-            $tableheader .= '<td bgcolor="#FFDDDD">';
+            $tableheader .= '<td bgcolor="'.$importcolor.'">';
         } else {
             $tableheader .= '<td>';
         }
@@ -380,11 +443,12 @@ END
     #
     # Print out template row
     $r->print('<tr><td>Template</td><td>&nbsp;</td>'.
-	      $self->html_template_row($num_uneditable)."</tr>\n");
+	      $self->html_template_row($num_uneditable,$importcolor).
+              "</tr>\n");
     #
     # Print out summary/export row
     $r->print('<tr><td>Export</td><td>0</td>'.
-	      $self->html_export_row()."</tr>\n");
+	      $self->html_export_row($exportcolor)."</tr>\n");
     #
     # Prepare to output rows
     $tableheader =<<"END";
@@ -393,7 +457,7 @@ END
 END
     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
 	if ($label_num<$num_uneditable) { 
-            $tableheader.='<th bgcolor="#FFDDDD">';
+            $tableheader.='<th bgcolor="'.$importcolor.'">';
         } else {
             $tableheader.='<th>';
         }
@@ -401,12 +465,12 @@ END
     }
     #
     my $num_output = 0;
-    foreach my $rownum ($self->rows()) {
+    foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
 	if ($num_output++ % 50 == 0) {
 	    $r->print("</table>\n".$tableheader);
 	}
 	$r->print('<tr><td>'.$rownum.'</td>'.
-                  $self->assess_html_row($num_uneditable,$rownum)."</tr>\n");
+                  $self->assess_html_row($rownum,$importcolor)."</tr>\n");
     }
     $r->print("</table>\n");
     return;
@@ -414,8 +478,7 @@ END
 
 sub assess_html_row {
     my $self = shift();
-    my ($num_uneditable,$row) = @_;
-    my $requester_is_student = ($ENV{'request.role'} =~ /^st\./);
+    my ($row,$importcolor) = @_;
     my $parameter_name = $self->{'formulas'}->{'A'.$row};
     my @rowdata = $self->get_row($row);
     my $num_cols_output = 0;
@@ -428,49 +491,81 @@ sub assess_html_row {
         $row_html .= '<td>'.$parameter_name.'</td>';
     }
     foreach my $cell (@rowdata) {
-	if ($requester_is_student || 
-	    $num_cols_output++ < $num_uneditable) {
-	    $row_html .= '<td bgcolor="#FFDDDD">';
-	    $row_html .= &Apache::Spreadsheet::html_uneditable_cell($cell,'#FFDDDD');
-	} else {
-	    $row_html .= '<td bgcolor="#EOFFDD">';
-	    $row_html .= &Apache::Spreadsheet::html_editable_cell($cell,'#E0FFDD');
-	}
+        if ($num_cols_output < 1) {
+            $row_html .= '<td bgcolor="'.$importcolor.'">';
+            $row_html .= &Apache::Spreadsheet::html_uneditable_cell($cell,
+                                                                    '#FFDDDD');
+        } else {
+            $row_html .= '<td bgcolor="#EOFFDD">';
+            $row_html .= &Apache::Spreadsheet::html_editable_cell($cell,
+                                                                  '#E0FFDD',1);
+        }
 	$row_html .= '</td>';
+        $num_cols_output++;
     }
     return $row_html;
 }
 
-sub outsheet_csv {
-    my $self = shift;
-    my ($r)=@_;
-}
-
-sub outsheet_excel {
-    my $self = shift;
-    my ($r)=@_;
+sub csv_rows {
+    # writes the meat of the spreadsheet to an excel worksheet.  Called
+    # by Spreadsheet::outsheet_excel;
+    my $self = shift;
+    my ($filehandle) = @_;
+    #
+    # Write a header row
+    $self->csv_output_row($filehandle,undef,
+                          ('Parameter','Description','Value'));
+    #
+    # Write each row
+    foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
+        my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
+        my $description = '';
+        if (exists($nice_parameter_name{$parameter_name})) {
+            $description = $nice_parameter_name{$parameter_name};
+        }
+        $self->csv_output_row($filehandle,$rownum,
+                              $parameter_name,$description);
+    }
+    return;
 }
 
-sub display {
-    my $self = shift;
-    my ($r) = @_;
-    $self->compute();
-    $self->outsheet_html($r);
+sub excel_rows {
+    # writes the meat of the spreadsheet to an excel worksheet.  Called
+    # by Spreadsheet::outsheet_excel;
+    my $self = shift;
+    my ($worksheet,$cols_output,$rows_output) = @_;
+    #
+    # Write a header row
+    $cols_output = 0;
+    foreach my $value ('Parameter','Description','Value') {
+        $worksheet->write($rows_output,$cols_output++,$value);
+    }
+    $rows_output++;    
+    #
+    # Write each row
+    foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
+        my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
+        my $description = '';
+        if (exists($nice_parameter_name{$parameter_name})) {
+            $description = $nice_parameter_name{$parameter_name};
+        }
+        $self->excel_output_row($worksheet,$rownum,$rows_output++,
+                                $parameter_name,$description);
+    }
+    return;
 }
 
-sub compute {
+##
+## Routines to support assesscalc::compute
+##
+sub get_parm_names {
     my $self = shift;
-    $self->logthis('computing');
-    $self->initialize_safe_space();
-    #
-    # Definitions
-    undef(%nice_parameter_name);
-    my %parameters;   # holds underscored parameters by name
+    my @Mandatory_parameters = @_;
+    my %parameters_and_names;
     #
-    # Get the metadata fields and determine their proper names
-    my ($symap,$syid,$srcf)=split(/___/,$self->{'symb'});
+    my ($symap,$syid,$srcf) = &Apache::lonnet::decode_symb($self->{'symb'});
     my @Metadata = split(/\,/,&Apache::lonnet::metadata($srcf,'keys'));
-    foreach my $parm (@Metadata) {
+    foreach my $parm (@Mandatory_parameters,@Metadata) {
         next if ($parm !~ /^(resource\.|stores|parameter)_/);
         my $cleaned_name = $parm;
         $cleaned_name =~ s/^resource\./stores_/;
@@ -480,23 +575,97 @@ sub compute {
         if (! $display) {
             $display .= &Apache::lonnet::metadata($srcf,$cleaned_name.'.name');
         }
-        $parameters{$cleaned_name}++;
-        $nice_parameter_name{$cleaned_name} = $display;
+        $parameters_and_names{$cleaned_name}=$display;
+    }
+    return (%parameters_and_names);
+}
+
+sub get_parameter_values {
+    my $self = shift();
+    my @Parameters;
+    my ($parameters) = @_;
+    if (!ref($parameters)) {
+        @Parameters = @_;
+    } elsif (ref($parameters) eq 'ARRAY') {
+        @Parameters = @$parameters;
+    } elsif (ref($parameters) eq 'HASH') {
+        @Parameters = keys(%$parameters);
     }
     #
-    # Get the values of the metadata fields
-    $self->ensure_current_parameter_caches();
+    my %parameters;
+    #
     my $filename = $self->{'coursefilename'}.'_parms.db';
     if (tie(%parmhash,'GDBM_File',
             $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) {
-        foreach my $parmname (keys(%parameters)) {
-            my $value =  $self->parmval($parmname);
+        foreach my $parmname (@Parameters) {
+            my $value = $self->parmval($parmname);
             $parameters{$parmname} =$value;
         }
         untie(%parmhash);
     } else {
         $self->logthis('unable to tie '.$filename);
     }
+    return %parameters;
+}
+
+sub deal_with_export_row {
+    my $self = shift();
+    my @exportarray = @_;
+    $Exportrows{$self->{'symb'}}->{'time'} = time;
+    $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray;
+    #
+    # Save the export data
+    $self->save_export_data();
+    return;
+}
+
+sub get_problem_state {
+    my $self = shift;
+    my %student_parameters;
+    if (exists($userdata{$self->{'symb'}}) && 
+        ref($userdata{$self->{'symb'}}) eq 'HASH') {
+        %student_parameters = %{$userdata{$self->{'symb'}}};
+    }
+    return %student_parameters;
+}
+
+sub compute {
+    my $self = shift;
+    my ($r) = @_;
+    my $connection = $r->connection();
+    if ($connection->aborted()) { $self->cleanup(); return; }
+    $self->initialize_safe_space();
+    #########################################
+    #########################################
+    ###                                   ###
+    ###  Retrieve the problem parameters  ###
+    ###                                   ###
+    #########################################
+    #########################################
+    my @Mandatory_parameters = ("stores_0_solved",
+                                "stores_0_awarddetail",
+                                "stores_0_awarded",
+                                "timestamp",
+                                "stores_0_tries",
+                                "stores_0_award");
+    #
+    # Definitions
+    undef(%nice_parameter_name);
+    my %parameters;   # holds underscored parameters by name
+    #
+    # Get the metadata fields and determine their proper names
+    my %nice_parm_names = $self->get_parm_names(@Mandatory_parameters);
+    while (my($cleaned_name,$display) = each(%nice_parm_names)) {
+        $parameters{$cleaned_name}++;
+        $nice_parameter_name{$cleaned_name} = $display;
+    }
+    #
+    # Get the values of the metadata fields
+    if ($connection->aborted()) { $self->cleanup(); return; }
+    $self->ensure_current_caches();
+    if ($connection->aborted()) { $self->cleanup(); return; }
+    %parameters = $self->get_parameter_values(keys(%parameters));
+    if ($connection->aborted()) { $self->cleanup(); return; }
     #
     # Clean out unnecessary parameters
     foreach (keys(%parameters)) {
@@ -504,11 +673,7 @@ sub compute {
     }
     #
     # Get the students performance data
-    my %student_parameters = 
-        &Apache::loncoursedata::get_current_state($self->{'name'},
-                                                  $self->{'domain'},
-                                                  $self->{'symb'},
-                                                  $self->{'cid'});
+    my %student_parameters = $self->get_problem_state();
     while (my ($parm,$value) = each(%student_parameters)) {
         $parm =~ s/^resource\./stores_/;
         $parm =~ s/\./_/g;
@@ -519,22 +684,41 @@ sub compute {
     my %f=$self->formulas();
     my %c;
     #
+    # Check for blackout requirements
+    if ((!exists($ENV{'request.role.adv'}) || !$ENV{'request.role.adv'})) {
+        while (my ($parm,$value) = each(%parameters)) {
+            last if ($self->blackout());
+            next if ($parm !~ /^(parameter_.*)_problemstatus$/);
+            if ($parameters{$1.'_answerdate'} eq '' ||
+                $parameters{$1.'_answerdate'} < time) {
+                next;
+            }
+            if (lc($value) eq 'no') {
+                # We must blackout this sheet
+                $self->blackout(1);
+            }
+        }
+    }
+    if ($connection->aborted()) { $self->cleanup(); return; }
+    #
+    # Move the parameters into the spreadsheet
+    if ($connection->aborted()) { $self->cleanup(); return; }
     while (my ($parm,$value) = each(%parameters)) {
         my $cell = 'A'.$self->get_row_number_from_key($parm);
         $f{$cell} = $parm;
+        $value = '"'.$value.'"' if ($value =~/[^0-9.]/);
         $c{$parm} = $value;
     }
-    $self->formulas(%f);
-    $self->constants(%c);
+    $self->formulas(\%f);
+    $self->constants(\%c);
+    if ($connection->aborted()) { $self->cleanup(); return; }
     $self->calcsheet();
     #
     # Store export row in cache
     my @exportarray = $self->exportrow();
-    $Exportrows{$self->{'symb'}}->{'time'} = time;
-    $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray;
-    #
-    # Save the export data
-    $self->save_export_data();
+    $self->deal_with_export_row(@exportarray);
+    $self->save() if ($self->need_to_save());
+    if ($connection->aborted()) { $self->cleanup(); return; }
     return;
 }
 
@@ -603,8 +787,7 @@ These rows are saved in the students dir
 ########################################################
 ########################################################
 sub load_cached_export_rows {
-    %Exportrows = undef;
-    &Apache::lonnet::logthis("loading cached assess sheets for $current_name $current_domain");
+    undef(%Exportrows);
     my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets_'.
                                     $ENV{'request.course.id'},
                                     $current_domain,$current_name,undef);
@@ -645,13 +828,19 @@ spreadsheet only if necessary.
 #############################################
 sub export_data {
     my $self = shift;
+    my ($r) = @_;
+    my $connection = $r->connection();
     my $symb = $self->{'symb'};
-    if (! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb})  ||
+    if (! exists($ENV{'request.role.adv'}) || ! $ENV{'request.role.adv'} ||
+        ! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb})  ||
         ! $self->check_expiration_time($Exportrows{$symb}->{'time'}) ||
         ! exists($Exportrows{$symb}->{$self->{'filename'}}) ||
-        ! defined($Exportrows{$symb}->{$self->{'filename'}})) {
-        $self->compute();
+        ! defined($Exportrows{$symb}->{$self->{'filename'}}) ||
+        ! ref($Exportrows{$symb}->{$self->{'filename'}}) 
+        ) {
+        $self->compute($r);
     }
+    if ($connection->aborted()) { $self->cleanup(); return; }
     my @Data = @{$Exportrows{$symb}->{$self->{'filename'}}};
     if ($Data[0] =~ /^(.*)___=___/) {
         $self->{'sheetname'} = $1;
@@ -678,6 +867,7 @@ Writes the export data for this spreadsh
 #############################################
 sub save_export_data {
     my $self = shift;
+    return if ($self->temporary());
     my $student = $self->{'name'}.':'.$self->{'domain'};
     my $symb    = $self->{'symb'};
     if (! exists($Exportrows{$symb}) || 
@@ -686,15 +876,12 @@ sub save_export_data {
     }
     my $key = join(':',($self->{'name'},$self->{'domain'},'assesscalc',$symb));
     my $timekey = $key.'.time';
-    my $newstore= join('___;___',@{$Exportrows{$symb}->{$self->{'filename'}}});
+    my $newstore= join('___;___',
+                       map {s/[^[:print:]]//g;$_;} # strip out unprintable
+                                @{$Exportrows{$symb}->{$self->{'filename'}}});
     $newstore = $self->{'filename'}.'___=___'.$newstore;
-    my $result = &Apache::lonnet::put
-        ('nohist_calculatedsheets_'.$ENV{'request.course.id'},
-         { $key     => $newstore,
-           $timekey => $Exportrows{$symb}->{'time'} },
-         $self->{'domain'},
-         $self->{'name'});
-
+    $newExportrows{$student}->{$key} = $newstore;
+    $newExportrows{$student}->{$timekey} = $Exportrows{$symb}->{'time'};
     return;
 }