[LON-CAPA-cvs] cvs: loncom /interface lonspreadsheet.pm

matthew lon-capa-cvs@mail.lon-capa.org
Fri, 30 Aug 2002 19:47:47 -0000


This is a MIME encoded message

--matthew1030736867
Content-Type: text/plain

matthew		Fri Aug 30 15:47:47 2002 EDT

  Modified files:              
    /loncom/interface	lonspreadsheet.pm 
  Log:
  Many changes that should have been checked in one at a time....
  Replaced %v with %sheet_values.
  Many indentation and whitespace changes.
  Some changes in logic.
  No new features have been added, but tests have been done to exercise the
  code.  Nevertheless, this should *not* be included in 0.5a.
  
  
--matthew1030736867
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20020830154747.txt"

Index: loncom/interface/lonspreadsheet.pm
diff -u loncom/interface/lonspreadsheet.pm:1.103 loncom/interface/lonspreadsheet.pm:1.104
--- loncom/interface/lonspreadsheet.pm:1.103	Thu Aug 29 11:35:01 2002
+++ loncom/interface/lonspreadsheet.pm	Fri Aug 30 15:47:47 2002
@@ -1,5 +1,5 @@
 #
-# $Id: lonspreadsheet.pm,v 1.103 2002/08/29 15:35:01 matthew Exp $
+# $Id: lonspreadsheet.pm,v 1.104 2002/08/30 19:47:47 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -142,41 +142,39 @@
 # rl: row label
 # os: other spreadsheets (for student spreadsheet only)
 
-undef %v; 
+undef %sheet_values; 
 undef %t;
 undef %f;
 undef %c;
 undef %rowlabel;
 undef @os;
 
-$maxrow=0;
-$sheettype='';
+$maxrow = 0;
+$sheettype = '';
 
 # filename/reference of the sheet
-
-$filename='';
+$filename = '';
 
 # user data
-$uname='';
-$uhome='';
-$udom='';
+$uname = '';
+$uhome = '';
+$udom  = '';
 
 # course data
 
-$csec='';
-$chome='';
-$cnum='';
-$cdom='';
-$cid='';
-$cfn='';
+$csec = '';
+$chome= '';
+$cnum = '';
+$cdom = '';
+$cid  = '';
+$cfn  = '';
 
 # symb
 
-$usymb='';
+$usymb = '';
 
 # error messages
-
-$errormsg='';
+$errormsg = '';
 
 sub mask {
     my ($lower,$upper)=@_;
@@ -385,8 +383,8 @@
     if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
 	my $keymask = &mask($key);
 	# Assume the keys are addresses
-	my @Temp = grep /$keymask/,keys(%v);
-	@Keys = $v{@Temp};
+	my @Temp = grep /$keymask/,keys(%sheet_values);
+	@Keys = $sheet_values{@Temp};
     } else {
 	$Keys[0]= $key;
     }
@@ -397,8 +395,8 @@
     @Keys = @Temp;
     if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
 	my $valmask = &mask($value);
-	my @Temp = grep /$valmask/,keys(%v);
-	@Values =$v{@Temp};
+	my @Temp = grep /$valmask/,keys(%sheet_values);
+	@Values =$sheet_values{@Temp};
     } else {
 	$Values[0]= $value;
     }
@@ -432,7 +430,7 @@
 	$index = 0;
     }
     if ($key =~ /^[A-z]\d+$/) {
-	$key = $v{$key};
+	$key = $sheet_values{$key};
     }
     return $hashes{$name}->{$key}->[$index];
 }
@@ -489,8 +487,8 @@
     if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
 	my $keymask = &mask($key);
 	# Assume the keys are addresses
-	my @Temp = grep /$keymask/,keys(%v);
-	@Keys = $v{@Temp};
+	my @Temp = grep /$keymask/,keys(%sheet_values);
+	@Keys = $sheet_values{@Temp};
     } else {
 	$Keys[0]= $key;
     }
@@ -502,8 +500,8 @@
     # Check to see if we have multiple $value(s) 
     if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
 	my $valmask = &mask($value);
-	my @Temp = grep /$valmask/,keys(%v);
-	@Values =$v{@Temp};
+	my @Temp = grep /$valmask/,keys(%sheet_values);
+	@Values =$sheet_values{@Temp};
     } else {
 	$Values[0]= $value;
     }
@@ -532,7 +530,7 @@
 #-------------------------------------------------------
 sub NUM {
     my $mask=mask(@_);
-    my $num= $#{@{grep(/$mask/,keys(%v))}}+1;
+    my $num= $#{@{grep(/$mask/,keys(%sheet_values))}}+1;
     return $num;   
 }
 
@@ -540,8 +538,8 @@
     my ($low,$high,$lower,$upper)=@_;
     my $mask=mask($lower,$upper);
     my $num=0;
-    foreach (grep /$mask/,keys(%v)) {
-        if (($v{$_}>=$low) && ($v{$_}<=$high)) {
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        if (($sheet_values{$_}>=$low) && ($sheet_values{$_}<=$high)) {
             $num++;
         }
     }
@@ -561,8 +559,8 @@
 sub SUM {
     my $mask=mask(@_);
     my $sum=0;
-    foreach (grep /$mask/,keys(%v)) {
-        $sum+=$v{$_};
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        $sum+=$sheet_values{$_};
     }
     return $sum;   
 }
@@ -579,8 +577,8 @@
 sub MEAN {
     my $mask=mask(@_);
     my $sum=0; my $num=0;
-    foreach (grep /$mask/,keys(%v)) {
-        $sum+=$v{$_};
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        $sum+=$sheet_values{$_};
         $num++;
     }
     if ($num) {
@@ -602,15 +600,15 @@
 sub STDDEV {
     my $mask=mask(@_);
     my $sum=0; my $num=0;
-    foreach (grep /$mask/,keys(%v)) {
-        $sum+=$v{$_};
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        $sum+=$sheet_values{$_};
         $num++;
     }
     unless ($num>1) { return undef; }
     my $mean=$sum/$num;
     $sum=0;
-    foreach (grep /$mask/,keys(%v)) {
-        $sum+=($v{$_}-$mean)**2;
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        $sum+=($sheet_values{$_}-$mean)**2;
     }
     return sqrt($sum/($num-1));    
 }
@@ -627,8 +625,8 @@
 sub PROD {
     my $mask=mask(@_);
     my $prod=1;
-    foreach (grep /$mask/,keys(%v)) {
-        $prod*=$v{$_};
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        $prod*=$sheet_values{$_};
     }
     return $prod;   
 }
@@ -645,9 +643,9 @@
 sub MAX {
     my $mask=mask(@_);
     my $max='-';
-    foreach (grep /$mask/,keys(%v)) {
-        unless ($max) { $max=$v{$_}; }
-        if (($v{$_}>$max) || ($max eq '-')) { $max=$v{$_}; }
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        unless ($max) { $max=$sheet_values{$_}; }
+        if (($sheet_values{$_}>$max) || ($max eq '-')) { $max=$sheet_values{$_}; }
     } 
     return $max;   
 }
@@ -664,9 +662,11 @@
 sub MIN {
     my $mask=mask(@_);
     my $min='-';
-    foreach (grep /$mask/,keys(%v)) {
-        unless ($max) { $max=$v{$_}; }
-        if (($v{$_}<$min) || ($min eq '-')) { $min=$v{$_}; }
+    foreach (grep /$mask/,keys(%sheet_values)) {
+        unless ($max) { $max=$sheet_values{$_}; }
+        if (($sheet_values{$_}<$min) || ($min eq '-')) { 
+            $min=$sheet_values{$_}; 
+        }
     }
     return $min;   
 }
@@ -685,8 +685,8 @@
     my ($num,$lower,$upper)=@_;
     my $mask=mask($lower,$upper);
     my @inside=();
-    foreach (grep /$mask/,keys(%v)) {
-	push (@inside,$v{$_});
+    foreach (grep /$mask/,keys(%sheet_values)) {
+	push (@inside,$sheet_values{$_});
     }
     @inside=sort(@inside);
     my $sum=0; my $i;
@@ -710,8 +710,8 @@
     my ($num,$lower,$upper)=@_;
     my $mask=mask($lower,$upper);
     my @inside=();
-    foreach (grep /$mask/,keys(%v)) {
-	$inside[$#inside+1]=$v{$_};
+    foreach (grep /$mask/,keys(%sheet_values)) {
+	$inside[$#inside+1]=$sheet_values{$_};
     }
     @inside=sort(@inside);
     my $sum=0; my $i;
@@ -838,36 +838,30 @@
     } else {
         $pattern='[A-Z]';
     }
-
-# Deal with the template row
+    # Deal with the template row
     foreach (keys(%f)) {
-	if ($_=~/template\_(\w)/) {
-	  my $col=$1;
-          unless ($col=~/^$pattern/) {
-	    foreach (keys(%f)) {
-	      if ($_=~/A(\d+)/) {
-		my $trow=$1;
-                if ($trow) {
-                    # Get the name of this cell
-		    my $lb=$col.$trow;
-                    # Grab the template declaration
-                    $t{$lb}=$f{'template_'.$col};
-                    # Replace '#' with the row number
-                    $t{$lb}=~s/\#/$trow/g;
-                    # Replace '....' with ','
-                    $t{$lb}=~s/\.\.+/\,/g;
-                    # Replace 'A0' with the value from 'A0'
-                    $t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
-                    # Replace parameters
-                    $t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
-                }
-	      }
-	    }
-	  }
-      }
+	next if ($_!~/template\_(\w)/);
+        my $col=$1;
+        next if ($col=~/^$pattern/);
+        foreach (keys(%f)) {
+            next if ($_!~/A(\d+)/);
+            my $trow=$1;
+            next if (! $trow);
+            # Get the name of this cell
+            my $lb=$col.$trow;
+            # Grab the template declaration
+            $t{$lb}=$f{'template_'.$col};
+            # Replace '#' with the row number
+            $t{$lb}=~s/\#/$trow/g;
+            # Replace '....' with ','
+            $t{$lb}=~s/\.\.+/\,/g;
+            # Replace 'A0' with the value from 'A0'
+            $t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
+            # Replace parameters
+            $t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
+        }
     }
-
-# Deal with the normal cells
+    # Deal with the normal cells
     foreach (keys(%f)) {
 	if (($f{$_}) && ($_!~/template\_/)) {
             my $matches=($_=~/^$pattern(\d+)/);
@@ -878,36 +872,34 @@
             } else {
 	       $t{$_}=$f{$_};
                $t{$_}=~s/\.\.+/\,/g;
-               $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
+               $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
                $t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
             }
         }
     }
-# For inserted lines, [B-Z] is also valid
-
+    # For inserted lines, [B-Z] is also valid
     unless ($sheettype eq 'assesscalc') {
        foreach (keys(%f)) {
 	   if ($_=~/[B-Z](\d+)/) {
 	       if ($f{'A'.$1}=~/^[\~\-]/) {
   	          $t{$_}=$f{$_};
                   $t{$_}=~s/\.\.+/\,/g;
-                  $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
+                  $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
                   $t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
                }
            }
        }
     }
-
     # For some reason 'A0' gets special treatment...  This seems superfluous
     # but I imagine it is here for a reason.
     $t{'A0'}=$f{'A0'};
     $t{'A0'}=~s/\.\.+/\,/g;
-    $t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
+    $t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
     $t{'A0'}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
 }
 
 sub calc {
-    undef %v;
+    undef %sheet_values;
     &sett();
     my $notfinished=1;
     my $lastcalc='';
@@ -915,17 +907,17 @@
     while ($notfinished) {
 	$notfinished=0;
         foreach (keys(%t)) {
-            my $old=$v{$_};
-            $v{$_}=eval $t{$_};
+            my $old=$sheet_values{$_};
+            $sheet_values{$_}=eval $t{$_};
 	    if ($@) {
-		undef %v;
+		undef %sheet_values;
                 return $_.': '.$@;
             }
-	    if ($v{$_} ne $old) { $notfinished=1; $lastcalc=$_; }
+	    if ($sheet_values{$_} ne $old) { $notfinished=1; $lastcalc=$_; }
         }
         $depth++;
         if ($depth>100) {
-	    undef %v;
+	    undef %sheet_values;
             return $lastcalc.': Maximum calculation depth exceeded';
         }
     }
@@ -941,31 +933,38 @@
 	     'n','o','p','q','r','s','t','u','v','w','x','y','z') {
         my $fm=$f{'template_'.$_};
         $fm=~s/[\'\"]/\&\#34;/g;
-        $cols[$#cols+1]="'template_$_','$fm'".'___eq___'.$fm;
+        push(@cols,"'template_$_','$fm'".'___eq___'.$fm);
     }
     return @cols;
 }
 
+#
+# This is actually used for the student spreadsheet, not the assessment sheet
+# Do not be fooled by the name!
+#
 sub outrowassess {
+    # $n is the current row number
     my $n=shift;
     my @cols=();
     if ($n) {
-       my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n});
-      if ($rowlabel{$usy}) {
-       $cols[0]=$rowlabel{$usy}.'<br>'.
-                '<select name="sel_'.$n.'" onChange="changesheet('.$n.
-                ')"><option name="default">Default</option>';
-      } else { $cols[0]=''; }
-       foreach (@os) {
-           $cols[0].='<option name="'.$_.'"';
+        my ($usy,$ufn)=split(/__&&&\__/,$f{'A'.$n});
+        if ($rowlabel{$usy}) {
+            $cols[0]=$rowlabel{$usy}.'<br>'.
+                '<select name="sel_'.$n.'" onChange="changesheet('.$n.')">'.
+                    '<option name="default">Default</option>';
+        } else { 
+            $cols[0]=''; 
+        }
+        foreach (@os) {
+            $cols[0].='<option name="'.$_.'"';
             if ($ufn eq $_) {
-               $cols[0].=' selected';
+                $cols[0].=' selected';
             }
             $cols[0].='>'.$_.'</option>';
-       }
-       $cols[0].='</select>';
+        }
+        $cols[0].='</select>';
     } else {
-       $cols[0]='<b><font size=+1>Export</font></b>';
+        $cols[0]='<b><font size=+1>Export</font></b>';
     }
     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',
@@ -973,7 +972,7 @@
 	     'n','o','p','q','r','s','t','u','v','w','x','y','z') {
         my $fm=$f{$_.$n};
         $fm=~s/[\'\"]/\&\#34;/g;
-        push(@cols,"'$_$n','$fm'".'___eq___'.$v{$_.$n});
+        push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n});
     }
     return @cols;
 }
@@ -992,7 +991,7 @@
 	     'n','o','p','q','r','s','t','u','v','w','x','y','z') {
         my $fm=$f{$_.$n};
         $fm=~s/[\'\"]/\&\#34;/g;
-        $cols[$#cols+1]="'$_$n','$fm'".'___eq___'.$v{$_.$n};
+        push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n});
     }
     return @cols;
 }
@@ -1001,7 +1000,7 @@
     my @exportarray=();
     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') {
-	$exportarray[$#exportarray+1]=$v{$_.'0'};
+	push(@exportarray,$sheet_values{$_.'0'});
     } 
     return @exportarray;
 }
@@ -1051,7 +1050,7 @@
 
 sub getvalues {
     my $safeeval=shift;
-    return $safeeval->reval('%v');
+    return $safeeval->reval('%sheet_values');
 }
 
 # ---------------------------------------------------------------- Get formulas
@@ -1220,7 +1219,11 @@
         $maxred=26;
     }
     if (&getfa($safeeval,$n)=~/^[\~\-]/) { $maxred=1; }
-    if ($n eq '-') { $proc='&templaterow'; $n=-1; $dataflag=1; }
+    if ($n eq '-') { 
+        $proc='&templaterow'; 
+        $n=-1; 
+        $dataflag=1; 
+    }
     foreach ($safeeval->reval($proc.'('.$n.')')) {
        my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');
        my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);
@@ -1339,9 +1342,9 @@
 sub othersheets {
     my ($safeeval,$stype)=@_;
     #
-    my $cnum=&getcnum($safeeval);
-    my $cdom=&getcdom($safeeval);
-    my $chome=&getchome($safeeval);
+    my $cnum  = &getcnum($safeeval);
+    my $cdom  = &getcdom($safeeval);
+    my $chome = &getchome($safeeval);
     #
     my @alternatives=();
     my %results=&Apache::lonnet::dump($stype.'_spreadsheets',$cdom,$cnum);
@@ -1386,77 +1389,71 @@
 #
 
 sub readsheet {
-  my ($safeeval,$fn)=@_;
-  my $stype=&gettype($safeeval);
-  my $cnum=&getcnum($safeeval);
-  my $cdom=&getcdom($safeeval);
-  my $chome=&getchome($safeeval);
-
-  if (! defined($fn)) {
-      # There is no filename. Look for defaults in course and global, cache
-      unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {
-          my %tmphash = &Apache::lonnet::get('environment',
-                                             ['spreadsheet_default_'.$stype],
-                                             $cdom,$cnum);
-          my ($tmp) = keys(%tmphash);
-          if ($tmp =~ /^(con_lost|error|no_such_host)/i) {
-              $fn = 'default_'.$stype;
-          } else {
-              $fn = $tmphash{'spreadsheet_default_'.$stype};
-          } 
-          unless (($fn) && ($fn!~/^error\:/)) {
- 	     $fn='default_'.$stype;
-          }
-          $defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn; 
-      }
-  }
-
-# ---------------------------------------------------------- fn now has a value
-
-  &setfilename($safeeval,$fn);
-
-# ------------------------------------------------------ see if sheet is cached
-  my $fstring='';
-  if ($fstring=$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}) {
-      &setformulas($safeeval,split(/\_\_\_\;\_\_\_/,$fstring));
-  } else {
-
-# ---------------------------------------------------- Not cached, need to read
-
-     my %f=();
-
-     if ($fn=~/^default\_/) {
-         my $sheetxml='';
-         my $fh;
-         my $dfn=$fn;
-         $dfn=~s/\_/\./g;
-         if ($fh=Apache::File->new($includedir.'/'.$dfn)) {
-             $sheetxml=join('',<$fh>);
-         } else {
-             $sheetxml='<field row="0" col="A">"Error"</field>';
-         }
-         %f=%{&parse_sheet(\$sheetxml)};
-     } elsif($fn=~/\/*\.spreadsheet$/) {
-         my $sheetxml=&Apache::lonnet::getfile
-             (&Apache::lonnet::filelocation('',$fn));
-         if ($sheetxml == -1) {
-             $sheetxml='<field row="0" col="A">"Error loading spreadsheet '
-                 .$fn.'"</field>';
-         }
-         %f=%{&parse_sheet(\$sheetxml)};
-     } else {
-         my $sheet='';
-         my %tmphash = &Apache::lonnet::dump($fn,$cdom,$cnum);
-         my ($tmp) = keys(%tmphash);
-         unless ($tmp =~ /^(con_lost|error|no_such_host)/i) {
-             foreach (keys(%tmphash)) {
-                 $f{$_}=$tmphash{$_};
-             }
-         }
-     }
-# --------------------------------------------------------------- Cache and set
-       $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);  
-       &setformulas($safeeval,%f);
+    my ($safeeval,$fn)=@_;
+    my $stype = &gettype($safeeval);
+    my $cnum  = &getcnum($safeeval);
+    my $cdom  = &getcdom($safeeval);
+    my $chome = &getchome($safeeval);
+
+    if (! defined($fn)) {
+        # There is no filename. Look for defaults in course and global, cache
+        unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {
+            my %tmphash = &Apache::lonnet::get('environment',
+                                               ['spreadsheet_default_'.$stype],
+                                               $cdom,$cnum);
+            my ($tmp) = keys(%tmphash);
+            if ($tmp =~ /^(con_lost|error|no_such_host)/i) {
+                $fn = 'default_'.$stype;
+            } else {
+                $fn = $tmphash{'spreadsheet_default_'.$stype};
+            } 
+            unless (($fn) && ($fn!~/^error\:/)) {
+                $fn='default_'.$stype;
+            }
+            $defaultsheets{$cnum.'_'.$cdom.'_'.$stype}=$fn; 
+        }
+    }
+    # $fn now has a value
+    &setfilename($safeeval,$fn);
+    # see if sheet is cached
+    my $fstring='';
+    if ($fstring=$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}) {
+        &setformulas($safeeval,split(/\_\_\_\;\_\_\_/,$fstring));
+    } else {
+        # Not cached, need to read
+        my %f=();
+        if ($fn=~/^default\_/) {
+            my $sheetxml='';
+            my $fh;
+            my $dfn=$fn;
+            $dfn=~s/\_/\./g;
+            if ($fh=Apache::File->new($includedir.'/'.$dfn)) {
+                $sheetxml=join('',<$fh>);
+            } else {
+                $sheetxml='<field row="0" col="A">"Error"</field>';
+            }
+            %f=%{&parse_sheet(\$sheetxml)};
+        } elsif($fn=~/\/*\.spreadsheet$/) {
+            my $sheetxml=&Apache::lonnet::getfile
+                (&Apache::lonnet::filelocation('',$fn));
+            if ($sheetxml == -1) {
+                $sheetxml='<field row="0" col="A">"Error loading spreadsheet '
+                    .$fn.'"</field>';
+            }
+            %f=%{&parse_sheet(\$sheetxml)};
+        } else {
+            my $sheet='';
+            my %tmphash = &Apache::lonnet::dump($fn,$cdom,$cnum);
+            my ($tmp) = keys(%tmphash);
+            unless ($tmp =~ /^(con_lost|error|no_such_host)/i) {
+                foreach (keys(%tmphash)) {
+                    $f{$_}=$tmphash{$_};
+                }
+            }
+        }
+        # Cache and set
+        $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);  
+        &setformulas($safeeval,%f);
     }
 }
 
@@ -1484,52 +1481,51 @@
 # ------------------------------------------------------------ Save spreadsheet
 
 sub writesheet {
-  my ($safeeval,$makedef)=@_;
-  my $cid=&getcid($safeeval);
-  if (&Apache::lonnet::allowed('opa',$cid)) {
-    my %f=&getformulas($safeeval);
-    my $stype=&gettype($safeeval);
-    my $cnum=&getcnum($safeeval);
-    my $cdom=&getcdom($safeeval);
-    my $chome=&getchome($safeeval);
-    my $fn=&getfilename($safeeval);
-
-# ------------------------------------------------------------- Cache new sheet
-    $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);    
-# ----------------------------------------------------------------- Write sheet
-    my $sheetdata='';
-    foreach (keys(%f)) {
-     unless ($f{$_} eq 'import') {
-       $sheetdata.=&Apache::lonnet::escape($_).'='.
-	   &Apache::lonnet::escape($f{$_}).'&';
-     }
-    }
-    $sheetdata=~s/\&$//;
-    my $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.$fn.':'.
-              $sheetdata,$chome);
-    if ($reply eq 'ok') {
-          $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.
-              $stype.'_spreadsheets:'.
-              &Apache::lonnet::escape($fn).'='.$ENV{'user.name'}.'@'.
-                                               $ENV{'user.domain'},
-              $chome);
-          if ($reply eq 'ok') {
-              if ($makedef) { 
-                return &Apache::lonnet::reply('put:'.$cdom.':'.$cnum.
-                                ':environment:spreadsheet_default_'.$stype.'='.
-                                &Apache::lonnet::escape($fn),
-                                $chome);
-	      } else {
-		  return $reply;
-    	      }
-	   } else {
-	       return $reply;
-           }
-      } else {
-	  return $reply;
-      }
-  }
-  return 'unauthorized';
+    my ($safeeval,$makedef)=@_;
+    my $cid=&getcid($safeeval);
+    if (&Apache::lonnet::allowed('opa',$cid)) {
+        my %f=&getformulas($safeeval);
+        my $stype=&gettype($safeeval);
+        my $cnum=&getcnum($safeeval);
+        my $cdom=&getcdom($safeeval);
+        my $chome=&getchome($safeeval);
+        my $fn=&getfilename($safeeval);
+        # Cache new sheet
+        $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);
+        # Write sheet
+        my $sheetdata='';
+        foreach (keys(%f)) {
+            unless ($f{$_} eq 'import') {
+                $sheetdata.=&Apache::lonnet::escape($_).'='.
+                    &Apache::lonnet::escape($f{$_}).'&';
+            }
+        }
+        $sheetdata=~s/\&$//;
+        my $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.$fn.':'.
+                                         $sheetdata,$chome);
+        if ($reply eq 'ok') {
+            $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.
+                                          $stype.'_spreadsheets:'.
+                                          &Apache::lonnet::escape($fn).
+                                          '='.$ENV{'user.name'}.'@'.
+                                          $ENV{'user.domain'},
+                                          $chome);
+            if ($reply eq 'ok') {
+                if ($makedef) { 
+                    return &Apache::lonnet::reply('put:'.$cdom.':'.$cnum.
+                                                  ':environment:'.
+                                                  'spreadsheet_default_'.
+                                                  $stype.'='.
+                                                  &Apache::lonnet::escape($fn),
+                                                  $chome);
+                } 
+                return $reply;
+            } 
+            return $reply;
+        } 
+        return $reply;
+    }
+    return 'unauthorized';
 }
 
 # ----------------------------------------------- Make a temp copy of the sheet
@@ -1539,7 +1535,7 @@
 sub tmpwrite {
     my $safeeval=shift;
     my $fn=$ENV{'user.name'}.'_'.
-           $ENV{'user.domain'}.'_spreadsheet_'.&getusymb($safeeval).'_'.
+        $ENV{'user.domain'}.'_spreadsheet_'.&getusymb($safeeval).'_'.
            &getfilename($safeeval);
     $fn=~s/\W/\_/g;
     $fn=$tmpdir.$fn.'.tmp';
@@ -1594,96 +1590,82 @@
     &setformulas($safeeval,%fo);
 }
 
-# ================================================================== Parameters
-# -------------------------------------------- Figure out a cascading parameter
-#
-# For this function to work
-#
-# * parmhash needs to be tied
-# * courseopt and useropt need to be initialized for this user and course
-#
+##################################################
+##################################################
 
-sub parmval {
-    my ($what,$safeeval)=@_;
-    my $cid=&getcid($safeeval);
-    my $csec=&getcsec($safeeval);
-    my $uname=&getuname($safeeval);
-    my $udom=&getudom($safeeval);
-    my $symb=&getusymb($safeeval);
-
-    unless ($symb) { return ''; }
-    my $result='';
-
-    my ($mapname,$id,$fn)=split(/\_\_\_/,$symb);
-# ----------------------------------------------------- Cascading lookup scheme
-       my $rwhat=$what;
-       $what=~s/^parameter\_//;
-       $what=~s/\_([^\_]+)$/\.$1/;
-
-       my $symbparm=$symb.'.'.$what;
-       my $mapparm=$mapname.'___(all).'.$what;
-       my $usercourseprefix=$uname.'_'.$udom.'_'.$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;
-
-# ---------------------------------------------------------- fourth, check user
-      
-      if ($uname) { 
-
-       if ($useropt{$courselevelr}) { return $useropt{$courselevelr}; }
-
-       if ($useropt{$courselevelm}) { return $useropt{$courselevelm}; }
-
-       if ($useropt{$courselevel}) { return $useropt{$courselevel}; }
-
-      }
-
-# --------------------------------------------------------- third, check course
-     
-       if ($csec) {
- 
-        if ($courseopt{$seclevelr}) { return $courseopt{$seclevelr}; }
-
-        if ($courseopt{$seclevelm}) { return $courseopt{$seclevelm}; }  
-
-        if ($courseopt{$seclevel}) { return $courseopt{$seclevel}; }
-  
-      }
+=pod
 
-       if ($courseopt{$courselevelr}) { return $courseopt{$courselevelr}; }
+=item &parmval()
 
-       if ($courseopt{$courselevelm}) { return $courseopt{$courselevelm}; }
+Determine the value of a parameter.
 
-       if ($courseopt{$courselevel}) { return $courseopt{$courselevel}; }
+Inputs: $what, the parameter needed, $safeeval, the safe space
 
-# ----------------------------------------------------- second, check map parms
+Returns: The value of a parameter, or '' if none.
 
-       my $thisparm=$parmhash{$symbparm};
-       if ($thisparm) { return $thisparm; }
+This function cascades through the possible levels searching for a value for
+a parameter.  The levels are checked in the following order:
+user, course (at section level and course level), map, and lonnet::metadata.
+This function uses %parmhash, which must be tied prior to calling it.
+This function also requires %courseopt and %useropt to be initialized for
+this user and course.
 
-# -------------------------------------------------------- first, check default
+=cut
 
-       return &Apache::lonnet::metadata($fn,$rwhat.'.default');
-        
+##################################################
+##################################################
+sub parmval {
+    my ($what,$safeeval)=@_;
+    my $symb  = &getusymb($safeeval);
+    unless ($symb) { return ''; }
+    #
+    my $cid   = &getcid($safeeval);
+    my $csec  = &getcsec($safeeval);
+    my $uname = &getuname($safeeval);
+    my $udom  = &getudom($safeeval);
+    my $result='';
+    #
+    my ($mapname,$id,$fn)=split(/\_\_\_/,$symb);
+    # Cascading lookup scheme
+    my $rwhat=$what;
+    $what =~ s/^parameter\_//;
+    $what =~ s/\_([^\_]+)$/\.$1/;
+    #
+    my $symbparm = $symb.'.'.$what;
+    my $mapparm  = $mapname.'___(all).'.$what;
+    my $usercourseprefix = $uname.'_'.$udom.'_'.$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;
+    # fourth, check user
+    if ($uname) { 
+        return $useropt{$courselevelr} if ($useropt{$courselevelr});
+        return $useropt{$courselevelm} if ($useropt{$courselevelm});
+        return $useropt{$courselevel} if ($useropt{$courselevel});
+    }
+    # third, check course
+    if ($csec) {
+        return $courseopt{$seclevelr} if ($courseopt{$seclevelr});
+        return $courseopt{$seclevelm} if ($courseopt{$seclevelm});
+        return $courseopt{$seclevel} if ($courseopt{$seclevel});
+    }
+    #
+    return $courseopt{$courselevelr} if ($courseopt{$courselevelr});
+    return $courseopt{$courselevelm} if ($courseopt{$courselevelm});
+    return $courseopt{$courselevel} if ($courseopt{$courselevel});
+    # second, check map parms
+    my $thisparm = $parmhash{$symbparm};
+    return $thisparm if ($thisparm);
+    # first, check default
+    return &Apache::lonnet::metadata($fn,$rwhat.'.default');
 }
 
 # ---------------------------------------------- Update rows for course listing
-
 sub updateclasssheet {
     my $safeeval=shift;
     my $cnum=&getcnum($safeeval);
@@ -1788,19 +1770,23 @@
 }
 
 # ----------------------------------- Update rows for student and assess sheets
-
 sub updatestudentassesssheet {
     my $safeeval=shift;
     my %bighash;
     my $stype=&gettype($safeeval);
     my %current=();
-    unless ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) {
-# -------------------------------------------------------------------- Tie hash
-      if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
-                       &GDBM_READER(),0640)) {
-# --------------------------------------------------------- Get all assessments
-
-	my %allkeys=('timestamp' => 
+    if  ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) {
+        %current=split(/\_\_\_\;\_\_\_/,
+		       $updatedata{$ENV{'request.course.fn'}.'_'.$stype});
+    } else {
+        # Tie hash
+        tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
+            &GDBM_READER(),0640);
+        if (! tied(%bighash)) {
+            return 'Could not access course data';
+        }
+        # Get all assessments
+        my %allkeys=('timestamp' => 
                      'Timestamp of Last Transaction<br>timestamp',
                      'subnumber' =>
                      'Number of Submissions<br>subnumber',
@@ -1808,125 +1794,101 @@
                      'Number of Tutor Responses<br>tutornumber',
                      'totalpoints' =>
                      'Total Points Granted<br>totalpoints');
-
         my $adduserstr='';
         if ((&getuname($safeeval) ne $ENV{'user.name'}) ||
             (&getudom($safeeval) ne $ENV{'user.domain'})) {
             $adduserstr='&uname='.&getuname($safeeval).
-		'&udom='.&getudom($safeeval);
+                '&udom='.&getudom($safeeval);
         }
-
-        my %allassess=('_feedback' =>
-	              '<a href="/adm/assesscalc?usymb=_feedback'.$adduserstr.
-                       '">Feedback</a>',
-                       '_evaluation' =>
-	              '<a href="/adm/assesscalc?usymb=_evaluation'.$adduserstr.
-                       '">Evaluation</a>',
-                       '_tutoring' =>
-	              '<a href="/adm/assesscalc?usymb=_tutoring'.$adduserstr.
-                       '">Tutoring</a>',
-                       '_discussion' =>
-	              '<a href="/adm/assesscalc?usymb=_discussion'.$adduserstr.
-                       '">Discussion</a>'
-        );
-
+        my %allassess =
+            ('_feedback' =>'<a href="/adm/assesscalc?usymb=_feedback'.
+             $adduserstr.'">Feedback</a>',
+             '_evaluation' =>'<a href="/adm/assesscalc?usymb=_evaluation'.
+             $adduserstr.'">Evaluation</a>',
+             '_tutoring' =>'<a href="/adm/assesscalc?usymb=_tutoring'.
+             $adduserstr.'">Tutoring</a>',
+             '_discussion' =>'<a href="/adm/assesscalc?usymb=_discussion'.
+             $adduserstr.'">Discussion</a>'
+             );
         foreach (keys(%bighash)) {
-	    if ($_=~/^src\_(\d+)\.(\d+)$/) {
-	       my $mapid=$1;
-               my $resid=$2;
-               my $id=$mapid.'.'.$resid;
-               my $srcf=$bighash{$_};
-               if ($srcf=~/\.(problem|exam|quiz|assess|survey|form)$/) {
-                 my $symb=
-                     &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}).
-			    '___'.$resid.'___'.
-			    &Apache::lonnet::declutter($srcf);
-		 $allassess{$symb}=
-	            '<a href="/adm/assesscalc?usymb='.$symb.$adduserstr.'">'.
-                     $bighash{'title_'.$id}.'</a>';
-                 if ($stype eq 'assesscalc') {
-		     foreach (split(/\,/,
-				    &Apache::lonnet::metadata($srcf,'keys'))) {
-                       if (($_=~/^stores\_(.*)/) || ($_=~/^parameter\_(.*)/)) {
-			  my $key=$_;
-                          my $display=
-			      &Apache::lonnet::metadata($srcf,$key.'.display');
-                          unless ($display) {
-                              $display.=
-			         &Apache::lonnet::metadata($srcf,$key.'.name');
-                          }
-                          $display.='<br>'.$key;
-                          $allkeys{$key}=$display;
-		       }
-                   } # end of foreach
-	         }
-	      }
-	   }
+            next if ($_!~/^src\_(\d+)\.(\d+)$/);
+            my $mapid=$1;
+            my $resid=$2;
+            my $id=$mapid.'.'.$resid;
+            my $srcf=$bighash{$_};
+            if ($srcf=~/\.(problem|exam|quiz|assess|survey|form)$/) {
+                my $symb=
+                    &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}).
+                        '___'.$resid.'___'.&Apache::lonnet::declutter($srcf);
+                $allassess{$symb}=
+                    '<a href="/adm/assesscalc?usymb='.$symb.$adduserstr.'">'.
+                        $bighash{'title_'.$id}.'</a>';
+                next if ($stype ne 'assesscalc');
+                foreach my $key (split(/\,/,
+                                       &Apache::lonnet::metadata($srcf,'keys')
+                                       )) {
+                    next if ($key !~ /^(stores|parameter)_/);
+                    my $display=
+                        &Apache::lonnet::metadata($srcf,$key.'.display');
+                    unless ($display) {
+                        $display.=
+                            &Apache::lonnet::metadata($srcf,$key.'.name');
+                    }
+                    $display.='<br>'.$key;
+                    $allkeys{$key}=$display;
+                } # end of foreach
+            }
         } # end of foreach (keys(%bighash))
         untie(%bighash);
-    
-#
-# %allkeys has a list of storage and parameter displays by unikey
-# %allassess has a list of all resource displays by symb
-#
-
+        #
+        # %allkeys has a list of storage and parameter displays by unikey
+        # %allassess has a list of all resource displays by symb
+        #
         if ($stype eq 'assesscalc') {
-	    %current=%allkeys;
+            %current=%allkeys;
         } elsif ($stype eq 'studentcalc') {
             %current=%allassess;
         }
         $updatedata{$ENV{'request.course.fn'}.'_'.$stype}=
-	    join('___;___',%current);
-    } else {
-        return 'Could not access course data';
-    }
-# ------------------------------------------------------ Get current from cache
-    } else {
-        %current=split(/\_\_\_\;\_\_\_/,
-		       $updatedata{$ENV{'request.course.fn'}.'_'.$stype});
+            join('___;___',%current);
+        # Get current from cache
     }
-# -------------------- Find discrepancies between the course row table and this
-#
-        my %f=&getformulas($safeeval);
-        my $changed=0;
-
-        my $maxrow=0;
-        my %existing=();
-
-# ----------------------------------------------------------- Now obsolete rows
-	foreach (keys(%f)) {
-	    if ($_=~/^A(\d+)/) {
-                $maxrow=($1>$maxrow)?$1:$maxrow;
-                my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_});
-                $existing{$usy}=1;
-		unless ((defined($current{$usy})) || (!$1) ||
-                        ($f{$_}=~/^(\~\~\~|\-\-\-)/)){
- 		   $f{$_}='!!! Obsolete';
-                   $changed=1;
-	        } elsif ($ufn) {
-		    $current{$usy}
-                       =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;
-                }
-            }
+    # Find discrepancies between the course row table and this
+    #
+    my %f=&getformulas($safeeval);
+    my $changed=0;
+    
+    my $maxrow=0;
+    my %existing=();
+    # Now obsolete rows
+    foreach (keys(%f)) {
+        next if ($_!~/^A(\d+)/);
+        $maxrow=($1>$maxrow)?$1:$maxrow;
+        my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_});
+        $existing{$usy}=1;
+        unless ((defined($current{$usy})) || (!$1) ||
+                ($f{$_}=~/^(\~\~\~|\-\-\-)/)){
+            $f{$_}='!!! Obsolete';
+            $changed=1;
+        } elsif ($ufn) {
+            $current{$usy}
+            =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;
         }
-
-# -------------------------------------------------------- New and unknown keys
-     
-        foreach (keys(%current)) {
-            unless ($existing{$_}) {
-		$changed=1;
-                $maxrow++;
-                $f{'A'.$maxrow}=$_;
-            }
+    }
+    # New and unknown keys
+    foreach (keys(%current)) {
+        unless ($existing{$_}) {
+            $changed=1;
+            $maxrow++;
+            $f{'A'.$maxrow}=$_;
         }
-    
-        if ($changed) { &setformulas($safeeval,%f); }
-
-        &setmaxrow($safeeval,$maxrow);
-        &setrowlabels($safeeval,%current);
- 
-        undef %current;
-        undef %existing;
+    }
+    if ($changed) { &setformulas($safeeval,%f); }
+    &setmaxrow($safeeval,$maxrow);
+    &setrowlabels($safeeval,%current);
+    #
+    undef %current;
+    undef %existing;
 }
 
 # ------------------------------------------------ Load data for one assessment
@@ -1948,30 +1910,28 @@
     # 
     my @assessdata=();
     foreach (keys(%f)) {
-	if ($_=~/^A(\d+)/) {
-	   my $row=$1;
-           unless (($f{$_}=~/^[\!\~\-]/) || ($row==0)) {
-	      my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
-	      @assessdata=&exportsheet(&getuname($safeeval),
-                                       &getudom($safeeval),
-                                       'assesscalc',$usy,$ufn);
-              my $index=0;
-              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') {
-                  if ($assessdata[$index]) {
-		     my $col=$_;
-		     if ($assessdata[$index]=~/\D/) {
-                         $c{$col.$row}="'".$assessdata[$index]."'";
- 		     } else {
-		         $c{$col.$row}=$assessdata[$index];
-		     }
-                     unless ($col eq 'A') { 
-			 $f{$col.$row}='import';
-                     }
-		  }
-                  $index++;
-              }
-	   }
+	next if ($_!~/^A(\d+)/);
+        my $row=$1;
+        next if (($f{$_}=~/^[\!\~\-]/) || ($row==0));
+        my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
+        @assessdata=&exportsheet(&getuname($safeeval),
+                                 &getudom($safeeval),
+                                 'assesscalc',$usy,$ufn);
+        my $index=0;
+        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') {
+            if ($assessdata[$index]) {
+                my $col=$_;
+                if ($assessdata[$index]=~/\D/) {
+                    $c{$col.$row}="'".$assessdata[$index]."'";
+                } else {
+                    $c{$col.$row}=$assessdata[$index];
+                }
+                unless ($col eq 'A') { 
+                    $f{$col.$row}='import';
+                }
+            }
+            $index++;
         }
     }
     $cachedassess='';
@@ -2007,35 +1967,33 @@
 ENDPOP
     $r->rflush();
     foreach (keys(%f)) {
-	if ($_=~/^A(\d+)/) {
-	   my $row=$1;
-           unless (($f{$_}=~/^[\!\~\-]/)  || ($row==0)) {
-	      my @studentdata=&exportsheet(split(/\:/,$f{$_}),
-                                           'studentcalc');
-              undef %userrdatas;
-              $now++;
-              $r->print('<script>popwin.document.popremain.remaining.value="'.
+	next if ($_!~/^A(\d+)/);
+        my $row=$1;
+        next if (($f{$_}=~/^[\!\~\-]/)  || ($row==0));
+        my @studentdata=&exportsheet(split(/\:/,$f{$_}),
+                                     'studentcalc');
+        undef %userrdatas;
+        $now++;
+        $r->print('<script>popwin.document.popremain.remaining.value="'.
                   $now.'/'.$total.': '.int((time-$since)/$now*($total-$now)).
-                        ' secs remaining";</script>');
-              $r->rflush(); 
-
-              my $index=0;
-              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') {
-                  if ($studentdata[$index]) {
-                      my $col=$_;
-                      if ($studentdata[$index]=~/\D/) {
-                          $c{$col.$row}="'".$studentdata[$index]."'";
-                      } else {
-                          $c{$col.$row}=$studentdata[$index];
-                      }
-                      unless ($col eq 'A') { 
-                          $f{$col.$row}='import';
-                      }
-		  }
-                  $index++;
-              }
-	   }
+                  ' secs remaining";</script>');
+        $r->rflush(); 
+        #
+        my $index=0;
+        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') {
+            if ($studentdata[$index]) {
+                my $col=$_;
+                if ($studentdata[$index]=~/\D/) {
+                    $c{$col.$row}="'".$studentdata[$index]."'";
+                } else {
+                    $c{$col.$row}=$studentdata[$index];
+                }
+                unless ($col eq 'A') { 
+                    $f{$col.$row}='import';
+                }
+                $index++;
+            }
         }
     }
     &setformulas($safeeval,%f);
@@ -2049,60 +2007,52 @@
 sub loadassessment {
     my $safeeval=shift;
 
-    my $uhome=&getuhome($safeeval);
-    my $uname=&getuname($safeeval);
-    my $udom=&getudom($safeeval);
-    my $symb=&getusymb($safeeval);
-    my $cid=&getcid($safeeval);
-    my $cnum=&getcnum($safeeval);
-    my $cdom=&getcdom($safeeval);
-    my $chome=&getchome($safeeval);
+    my $uhome = &getuhome($safeeval);
+    my $uname = &getuname($safeeval);
+    my $udom  = &getudom($safeeval);
+    my $symb  = &getusymb($safeeval);
+    my $cid   = &getcid($safeeval);
+    my $cnum  = &getcnum($safeeval);
+    my $cdom  = &getcdom($safeeval);
+    my $chome = &getchome($safeeval);
 
     my $namespace;
     unless ($namespace=$cid) { return ''; }
-
-# ----------------------------------------------------------- Get stored values
-
-   my %returnhash=();
-
-   if ($cachedassess eq $uname.':'.$udom) {
-#
-# get data out of the dumped stores
-# 
-
-       my $version=$cachedstores{'version:'.$symb};
-       my $scope;
-       for ($scope=1;$scope<=$version;$scope++) {
-           foreach (split(/\:/,$cachedstores{$scope.':keys:'.$symb})) {
-               $returnhash{$_}=$cachedstores{$scope.':'.$symb.':'.$_};
-           } 
-       }
-
-   } else {
-#
-# restore individual
-#
-
-    my $answer=&Apache::lonnet::reply(
-       "restore:$udom:$uname:".
-       &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'})) {
-          $returnhash{$_}=$returnhash{$version.':'.$_};
-       } 
+    # Get stored values
+    my %returnhash=();
+    if ($cachedassess eq $uname.':'.$udom) {
+        #
+        # get data out of the dumped stores
+        # 
+        my $version=$cachedstores{'version:'.$symb};
+        my $scope;
+        for ($scope=1;$scope<=$version;$scope++) {
+            foreach (split(/\:/,$cachedstores{$scope.':keys:'.$symb})) {
+                $returnhash{$_}=$cachedstores{$scope.':'.$symb.':'.$_};
+            } 
+        }
+    } else {
+        #
+        # restore individual
+        #
+        my $answer=&Apache::lonnet::reply(
+                                          "restore:$udom:$uname:".
+                                          &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'})) {
+                $returnhash{$_}=$returnhash{$version.':'.$_};
+            } 
+        }
     }
-   }
-# ----------------------------- returnhash now has all stores for this resource
-
-# --------- convert all "_" to "." to be able to use libraries, multiparts, etc
-
+    # returnhash now has all stores for this resource
+    # convert all "_" to "." to be able to use libraries, multiparts, etc
     my @oldkeys=keys %returnhash;
 
     foreach (@oldkeys) {
@@ -2112,88 +2062,82 @@
         $name=~s/\_/\./g;
         $returnhash{$name}=$value;
     }
-
-# ---------------------------- initialize coursedata and userdata for this user
+    # initialize coursedata and userdata for this user
     undef %courseopt;
     undef %useropt;
 
     my $userprefix=$uname.'_'.$udom.'_';
-
+    
     unless ($uhome eq 'no_host') { 
-# -------------------------------------------------------------- Get coursedata
-      unless
-        ((time-$courserdatas{$cid.'.last_cache'})<240) {
-         my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
-              ':resourcedata',$chome);
-         if ($reply!~/^error\:/) {
-            $courserdatas{$cid}=$reply;
-            $courserdatas{$cid.'.last_cache'}=time;
-         }
-      }
-      foreach (split(/\&/,$courserdatas{$cid})) {
-         my ($name,$value)=split(/\=/,$_);
-         $courseopt{$userprefix.&Apache::lonnet::unescape($name)}=
-                    &Apache::lonnet::unescape($value);  
-      }
-# --------------------------------------------------- Get userdata (if present)
-      unless
-        ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
-         my $reply=
-       &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
-         if ($reply!~/^error\:/) {
-	     $userrdatas{$uname.'___'.$udom}=$reply;
-	     $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;
-         }
-      }
-      foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) {
-         my ($name,$value)=split(/\=/,$_);
-         $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
-	          &Apache::lonnet::unescape($value);
-      }
+        # Get coursedata
+        unless
+            ((time-$courserdatas{$cid.'.last_cache'})<240) {
+                my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
+                                                 ':resourcedata',$chome);
+                if ($reply!~/^error\:/) {
+                    $courserdatas{$cid}=$reply;
+                    $courserdatas{$cid.'.last_cache'}=time;
+                }
+            }
+        foreach (split(/\&/,$courserdatas{$cid})) {
+            my ($name,$value)=split(/\=/,$_);
+            $courseopt{$userprefix.&Apache::lonnet::unescape($name)}=
+                &Apache::lonnet::unescape($value);  
+        }
+        # Get userdata (if present)
+        unless
+            ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
+                my $reply=
+                    &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
+                if ($reply!~/^error\:/) {
+                    $userrdatas{$uname.'___'.$udom}=$reply;
+                    $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;
+                }
+            }
+        foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) {
+            my ($name,$value)=split(/\=/,$_);
+            $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
+                &Apache::lonnet::unescape($value);
+        }
     }
-# ----------------- now courseopt, useropt initialized for this user and course
-# (used by parmval)
-
-#
-# Load keys for this assessment only
-#
+    # now courseopt, useropt initialized for this user and course
+    # (used by parmval)
+    #
+    # Load keys for this assessment only
+    #
     my %thisassess=();
     my ($symap,$syid,$srcf)=split(/\_\_\_/,$symb);
-    
     foreach (split(/\,/,&Apache::lonnet::metadata($srcf,'keys'))) {
         $thisassess{$_}=1;
     } 
-#
-# Load parameters
-#
-   my %c=();
-
-   if (tie(%parmhash,'GDBM_File',
-           &getcfn($safeeval).'_parms.db',&GDBM_READER(),0640)) {
-    my %f=&getformulas($safeeval);
-    foreach (keys(%f))  {
-	if ($_=~/^A/) {
-            unless ($f{$_}=~/^[\!\~\-]/) {
-  	       if ($f{$_}=~/^parameter/) {
-		if ($thisassess{$f{$_}}) {
-                  my $val=&parmval($f{$_},$safeeval);
-                  $c{$_}=$val;
-                  $c{$f{$_}}=$val;
-	        }
-	       } else {
-		  my $key=$f{$_};
-                  my $ckey=$key;
-                  $key=~s/^stores\_/resource\./;
-                  $key=~s/\_/\./g;
- 	          $c{$_}=$returnhash{$key};
-                  $c{$ckey}=$returnhash{$key};
-	       }
-	   }
+    #
+    # Load parameters
+    #
+    my %c=();
+    if (tie(%parmhash,'GDBM_File',
+            &getcfn($safeeval).'_parms.db',&GDBM_READER(),0640)) {
+        my %f=&getformulas($safeeval);
+        foreach (keys(%f))  {
+            next if ($_!~/^A/);
+            next if  ($f{$_}=~/^[\!\~\-]/);
+            if ($f{$_}=~/^parameter/) {
+                if ($thisassess{$f{$_}}) {
+                    my $val=&parmval($f{$_},$safeeval);
+                    $c{$_}=$val;
+                    $c{$f{$_}}=$val;
+                }
+            } else {
+                my $key=$f{$_};
+                my $ckey=$key;
+                $key=~s/^stores\_/resource\./;
+                $key=~s/\_/\./g;
+                $c{$_}=$returnhash{$key};
+                $c{$ckey}=$returnhash{$key};
+            }
         }
+        untie(%parmhash);
     }
-    untie(%parmhash);
-   }
-   &setconstants($safeeval,%c);
+    &setconstants($safeeval,%c);
 }
 
 # --------------------------------------------------------- Various form fields
@@ -2201,7 +2145,7 @@
 sub textfield {
     my ($title,$name,$value)=@_;
     return "\n<p><b>$title:</b><br>".
-           '<input type=text name="'.$name.'" size=80 value="'.$value.'">';
+        '<input type=text name="'.$name.'" size=80 value="'.$value.'">';
 }
 
 sub hiddenfield {
@@ -2258,6 +2202,7 @@
     my ($keyname,$time)=@_;
     return ($time<$expiredates{$keyname});
 }
+
 sub forcedrecalc {
     my ($uname,$udom,$stype,$usymb)=@_;
     my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
@@ -2289,131 +2234,122 @@
 #
 
 sub exportsheet {
- my ($uname,$udom,$stype,$usymb,$fn)=@_;
- my @exportarr=();
-
- if (($usymb=~/^\_(\w+)/) && (!$fn)) {
-    $fn='default_'.$1;
- }
-
-#
-# Check if cached
-#
-
- my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
- my $found='';
-
- if ($oldsheets{$key}) {
-     foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {
-         my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);
-         if ($name eq $fn) {
-	     $found=$value;
-         }
-     }
- }
-
- unless ($found) {
-     &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom));
-     if ($oldsheets{$key}) {
-	foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {
+    my ($uname,$udom,$stype,$usymb,$fn)=@_;
+    my @exportarr=();
+    if (($usymb=~/^\_(\w+)/) && (!$fn)) {
+        $fn='default_'.$1;
+    }
+    #
+    # Check if cached
+    #
+    my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
+    my $found='';
+    if ($oldsheets{$key}) {
+        foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {
             my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);
             if ($name eq $fn) {
-	        $found=$value;
+                $found=$value;
             }
-        } 
-     }
- }
-#
-# Check if still valid
-#
- if ($found) {
-     if (&forcedrecalc($uname,$udom,$stype,$usymb)) {
-	 $found='';
-     }
- }
- 
- if ($found) {
-#
-# Return what was cached
-#
-     @exportarr=split(/\_\_\_\;\_\_\_/,$found);
-
- } else {
-#
-# Not cached
-#        
-
-    my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb);
-    &readsheet($thissheet,$fn);
-    &updatesheet($thissheet);
-    &loadrows($thissheet);
-    &calcsheet($thissheet); 
-    @exportarr=&exportdata($thissheet);
-#
-# Store now
-#
-    my $cid=$ENV{'request.course.id'}; 
-    my $current='';
-    if ($stype eq 'studentcalc') {
-       $current=&Apache::lonnet::reply('get:'.
-                                     $ENV{'course.'.$cid.'.domain'}.':'.
-                                     $ENV{'course.'.$cid.'.num'}.
-				     ':nohist_calculatedsheets:'.
-                                     &Apache::lonnet::escape($key),
-                                     $ENV{'course.'.$cid.'.home'});
-    } else {
-       $current=&Apache::lonnet::reply('get:'.
-                                     &getudom($thissheet).':'.
-                                     &getuname($thissheet).
-				     ':nohist_calculatedsheets_'.
-                                     $ENV{'request.course.id'}.':'.
-                                     &Apache::lonnet::escape($key),
-                                     &getuhome($thissheet));
-
+        }
     }
-    my %currentlystored=();
-    unless ($current=~/^error\:/) {
-       foreach (split(/\_\_\_\&\_\_\_/,&Apache::lonnet::unescape($current))) {
-           my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);
-           $currentlystored{$name}=$value;
-       }
+    unless ($found) {
+        &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom));
+        if ($oldsheets{$key}) {
+            foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {
+                my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);
+                if ($name eq $fn) {
+                    $found=$value;
+                }
+            } 
+        }
     }
-    $currentlystored{$fn}=join('___;___',@exportarr);
-
-    my $newstore='';
-    foreach (keys(%currentlystored)) {
-        if ($newstore) { $newstore.='___&___'; }
-        $newstore.=$_.'___=___'.$currentlystored{$_};
+    #
+    # Check if still valid
+    #
+    if ($found) {
+        if (&forcedrecalc($uname,$udom,$stype,$usymb)) {
+            $found='';
+        }
+    }
+    if ($found) {
+        #
+        # Return what was cached
+        #
+        @exportarr=split(/\_\_\_\;\_\_\_/,$found);
+    } else {
+        #
+        # Not cached
+        #        
+        my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb);
+        &readsheet($thissheet,$fn);
+        &updatesheet($thissheet);
+        &loadrows($thissheet);
+        &calcsheet($thissheet); 
+        @exportarr=&exportdata($thissheet);
+        #
+        # Store now
+        #
+        my $cid=$ENV{'request.course.id'}; 
+        my $current='';
+        if ($stype eq 'studentcalc') {
+            $current=&Apache::lonnet::reply('get:'.
+                                            $ENV{'course.'.$cid.'.domain'}.':'.
+                                            $ENV{'course.'.$cid.'.num'}.
+                                            ':nohist_calculatedsheets:'.
+                                            &Apache::lonnet::escape($key),
+                                            $ENV{'course.'.$cid.'.home'});
+        } else {
+            $current=&Apache::lonnet::reply('get:'.
+                                            &getudom($thissheet).':'.
+                                            &getuname($thissheet).
+                                            ':nohist_calculatedsheets_'.
+                                            $ENV{'request.course.id'}.':'.
+                                            &Apache::lonnet::escape($key),
+                                            &getuhome($thissheet));
+        }
+        my %currentlystored=();
+        unless ($current=~/^error\:/) {
+            foreach (split(/___&\___/,&Apache::lonnet::unescape($current))) {
+                my ($name,$value)=split(/___=___/,$_);
+                $currentlystored{$name}=$value;
+            }
+        }
+        $currentlystored{$fn}=join('___;___',@exportarr);
+        #
+        my $newstore='';
+        foreach (keys(%currentlystored)) {
+            if ($newstore) { $newstore.='___&___'; }
+            $newstore.=$_.'___=___'.$currentlystored{$_};
+        }
+        my $now=time;
+        if ($stype eq 'studentcalc') {
+            &Apache::lonnet::reply('put:'.
+                                   $ENV{'course.'.$cid.'.domain'}.':'.
+                                   $ENV{'course.'.$cid.'.num'}.
+                                   ':nohist_calculatedsheets:'.
+                                   &Apache::lonnet::escape($key).'='.
+                                   &Apache::lonnet::escape($newstore).'&'.
+                                   &Apache::lonnet::escape($key).'.time='.$now,
+                                   $ENV{'course.'.$cid.'.home'});
+        } else {
+            &Apache::lonnet::reply('put:'.
+                                   &getudom($thissheet).':'.
+                                   &getuname($thissheet).
+                                   ':nohist_calculatedsheets_'.
+                                   $ENV{'request.course.id'}.':'.
+                                   &Apache::lonnet::escape($key).'='.
+                                   &Apache::lonnet::escape($newstore).'&'.
+                                   &Apache::lonnet::escape($key).'.time='.$now,
+                                   &getuhome($thissheet));
+        }
     }
-    my $now=time;
-    if ($stype eq 'studentcalc') {
-       &Apache::lonnet::reply('put:'.
-                         $ENV{'course.'.$cid.'.domain'}.':'.
-                         $ENV{'course.'.$cid.'.num'}.
-			 ':nohist_calculatedsheets:'.
-                         &Apache::lonnet::escape($key).'='.
-			 &Apache::lonnet::escape($newstore).'&'.
-                         &Apache::lonnet::escape($key).'.time='.$now,
-                         $ENV{'course.'.$cid.'.home'});
-   } else {
-       &Apache::lonnet::reply('put:'.
-                         &getudom($thissheet).':'.
-                         &getuname($thissheet).
-			 ':nohist_calculatedsheets_'.
-                         $ENV{'request.course.id'}.':'.
-                         &Apache::lonnet::escape($key).'='.
-			 &Apache::lonnet::escape($newstore).'&'.
-                         &Apache::lonnet::escape($key).'.time='.$now,
-                         &getuhome($thissheet));
-   }
- }
- return @exportarr;
+    return @exportarr;
 }
+
 # ============================================================ Expiration Dates
 #
 # Load previously cached student spreadsheets for this course
 #
-
 sub expirationdates {
     undef %expiredates;
     my $cid=$ENV{'request.course.id'};
@@ -2490,59 +2426,45 @@
 
 sub handler {
     my $r=shift;
-
     if ($r->header_only) {
-      $r->content_type('text/html');
-      $r->send_http_header;
-      return OK;
-    }
-
-# ---------------------------------------------------- Global directory configs
-
-$includedir=$r->dir_config('lonIncludes');
-$tmpdir=$r->dir_config('lonDaemons').'/tmp/';
-
-# ----------------------------------------------------- Needs to be in a course
-
-  if ($ENV{'request.course.fn'}) { 
-
-# --------------------------- Get query string for limited number of parameters
-
-    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-                                            ['uname','udom','usymb','ufn']);
-
-    if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {
-	$ENV{'form.ufn'}='default_'.$1;
-    }
-
-# -------------------------------------- Interactive loading of specific sheet?
-    if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
-	$ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
-    }
-# ------------------------------------------- Nothing there? Must be login user
-
-    my $aname;
-    my $adom;
-
-    unless ($ENV{'form.uname'}) {
-	$aname=$ENV{'user.name'};
-        $adom=$ENV{'user.domain'};
-    } else {
-        $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>');
-    $r->print(<<ENDSCRIPT);
+        $r->content_type('text/html');
+        $r->send_http_header;
+        return OK;
+    }
+    # Global directory configs
+    $includedir=$r->dir_config('lonIncludes');
+    $tmpdir=$r->dir_config('lonDaemons').'/tmp/';
+    # Needs to be in a course
+    if ($ENV{'request.course.fn'}) { 
+        # Get query string for limited number of parameters
+        &Apache::loncommon::get_unprocessed_cgi
+            ($ENV{'QUERY_STRING'},['uname','udom','usymb','ufn']);
+        if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {
+            $ENV{'form.ufn'}='default_'.$1;
+        }
+        # Interactive loading of specific sheet?
+        if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
+            $ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
+        }
+        # Nothing there? Must be login user
+        my $aname;
+        my $adom;
+
+        unless ($ENV{'form.uname'}) {
+            $aname=$ENV{'user.name'};
+            $adom=$ENV{'user.domain'};
+        } else {
+            $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>');
+        $r->print(<<ENDSCRIPT);
 <script language="JavaScript">
 
     function celledit(cn,cf) {
@@ -2568,186 +2490,155 @@
 
 </script>
 ENDSCRIPT
-   $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').
-       '<form action="'.$r->uri.'" name=sheet method=post>'.
-       &hiddenfield('uname',$ENV{'form.uname'}).
-       &hiddenfield('udom',$ENV{'form.udom'}).
-       &hiddenfield('usymb',$ENV{'form.usymb'}).
-       &hiddenfield('unewfield','').
-       &hiddenfield('unewformula',''));
-
-# ---------------------- Make sure that this gets out, even if user hits "stop"
-
-    $r->rflush();
-
-# ---------------------------------------------------------------- Full recalc?
-
-
-    if ($ENV{'form.forcerecalc'}) {
-	$r->print('<h4>Completely Recalculating Sheet ...</h4>');
-        undef %spreadsheets;
-        undef %courserdatas;
-        undef %userrdatas;
-        undef %defaultsheets;
-        undef %updatedata;
-   }
- 
-# ---------------------------------------- Read new sheet or modified worksheet
-
-    $r->uri=~/\/(\w+)$/;
-
-    my $asheet=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});
-
-# ------------------------ If a new formula had been entered, go from work copy
-
-    if ($ENV{'form.unewfield'}) {
-        $r->print('<h2>Modified Workcopy</h2>');
-        $ENV{'form.unewformula'}=~s/\'/\"/g;
-        $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.
-                  $ENV{'form.unewformula'}.'<p>');
-        &setfilename($asheet,$ENV{'form.ufn'});
-	&tmpread($asheet,
-                 $ENV{'form.unewfield'},$ENV{'form.unewformula'});
-
-     } elsif ($ENV{'form.saveas'}) {
-        &setfilename($asheet,$ENV{'form.ufn'});
-	&tmpread($asheet);
-    } else {
-        &readsheet($asheet,$ENV{'form.ufn'});
-    }
-
-# -------------------------------------------------- Print out user information
-
-    unless (&gettype($asheet) eq 'classcalc') {
-        $r->print('<p><b>User:</b> '.&getuname($asheet).
-                  '<br><b>Domain:</b> '.&getudom($asheet));
-        if (&getcsec($asheet) eq '-1') {
-           $r->print('<h3><font color=red>'.
-                     'Not a student in this course</font></h3>');
+        $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').
+                  '<form action="'.$r->uri.'" name=sheet method=post>'.
+                  &hiddenfield('uname',$ENV{'form.uname'}).
+                  &hiddenfield('udom',$ENV{'form.udom'}).
+                  &hiddenfield('usymb',$ENV{'form.usymb'}).
+                  &hiddenfield('unewfield','').
+                  &hiddenfield('unewformula',''));
+        # Send this out right away
+        $r->rflush();
+        # Full recalc?
+        if ($ENV{'form.forcerecalc'}) {
+            $r->print('<h4>Completely Recalculating Sheet ...</h4>');
+            undef %spreadsheets;
+            undef %courserdatas;
+            undef %userrdatas;
+            undef %defaultsheets;
+            undef %updatedata;
+        }
+        # Read new sheet or modified worksheet
+        $r->uri=~/\/(\w+)$/;
+        my $asheet=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});
+        # If a new formula had been entered, go from work copy
+        if ($ENV{'form.unewfield'}) {
+            $r->print('<h2>Modified Workcopy</h2>');
+            $ENV{'form.unewformula'}=~s/\'/\"/g;
+            $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.
+                      $ENV{'form.unewformula'}.'<p>');
+            &setfilename($asheet,$ENV{'form.ufn'});
+            &tmpread($asheet,
+                     $ENV{'form.unewfield'},$ENV{'form.unewformula'});
+            
+        } elsif ($ENV{'form.saveas'}) {
+            &setfilename($asheet,$ENV{'form.ufn'});
+            &tmpread($asheet);
         } else {
-           $r->print('<br><b>Section/Group:</b> '.&getcsec($asheet));
+            &readsheet($asheet,$ENV{'form.ufn'});
         }
-        if ($ENV{'form.usymb'}) {
-           $r->print('<br><b>Assessment:</b> <tt>'.$ENV{'form.usymb'}.'</tt>');
+        # Print out user information
+        unless (&gettype($asheet) eq 'classcalc') {
+            $r->print('<p><b>User:</b> '.&getuname($asheet).
+                      '<br><b>Domain:</b> '.&getudom($asheet));
+            if (&getcsec($asheet) eq '-1') {
+                $r->print('<h3><font color=red>'.
+                          'Not a student in this course</font></h3>');
+            } else {
+                $r->print('<br><b>Section/Group:</b> '.&getcsec($asheet));
+            }
+            if ($ENV{'form.usymb'}) {
+                $r->print('<br><b>Assessment:</b> <tt>'.
+                          $ENV{'form.usymb'}.'</tt>');
+            }
         }
-    }
-
-# ---------------------------------------------------- See if user can see this
-
-    if ((&gettype($asheet) eq 'classcalc') || 
-        (&getuname($asheet) ne $ENV{'user.name'}) ||
-        (&getudom($asheet) ne $ENV{'user.domain'})) {
-        unless (&Apache::lonnet::allowed('vgr',&getcid($asheet))) {
-	    $r->print(
-           '<h1>Access Permission Denied</h1></form></body></html>');
-            return OK;
+        # See if user can see this
+        if ((&gettype($asheet) eq 'classcalc') || 
+            (&getuname($asheet) ne $ENV{'user.name'}) ||
+            (&getudom($asheet) ne $ENV{'user.domain'})) {
+            unless (&Apache::lonnet::allowed('vgr',&getcid($asheet))) {
+                $r->print('<h1>Access Permission Denied</h1>'.
+                          '</form></body></html>');
+                return OK;
+            }
         }
-    }
-
-# ---------------------------------------------------------- Additional options
-
-    $r->print(
+        # Additional options
+        $r->print(
  '<input type=submit name=forcerecalc value="Completely Recalculate Sheet"><p>'
-		 );
-    if (&gettype($asheet) eq 'assesscalc') {
-       $r->print ('<p><font size=+2><a href="/adm/studentcalc?uname='.
-                                               &getuname($asheet).
-                                               '&udom='.&getudom($asheet).
-                  '">Level up: Student Sheet</a></font><p>');
-    }
-    
-    if ((&gettype($asheet) eq 'studentcalc') && 
-        (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) {
-       $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,&gettype($asheet))) {
-	    $r->print('<option name="'.$_.'"');
-            if ($ENV{'form.ufn'} eq $_) {
-               $r->print(' selected');
+                  );
+        if (&gettype($asheet) eq 'assesscalc') {
+            $r->print ('<p><font size=+2><a href="/adm/studentcalc?uname='.
+                       &getuname($asheet).'&udom='.&getudom($asheet).'">'.
+                       'Level up: Student Sheet</a></font><p>');
+        }
+        if ((&gettype($asheet) eq 'studentcalc') && 
+            (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) {
+            $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,&gettype($asheet))) {
+                $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'));
             }
-            $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 (&gettype($asheet) eq 'classcalc') {
-        $r->print("Loading previously calculated student sheets ...<br>\n");
+        # Cached sheets
+        &expirationdates();
+        undef %oldsheets;
+        undef %loadedcaches;
+        if (&gettype($asheet) eq 'classcalc') {
+            $r->print
+                ("Loading previously calculated student sheets ...<br>\n");
+            $r->rflush();
+            &cachedcsheets();
+        } elsif (&gettype($asheet) eq 'studentcalc') {
+            $r->print
+                ("Loading previously calculated assessment sheets ...<br>\n");
+            $r->rflush();
+            &cachedssheets(&getuname($asheet),&getudom($asheet),
+                           &getuhome($asheet));
+        }
+        # Update sheet, load rows
+        $r->print("Loaded sheet(s), updating rows ...<br>\n");
         $r->rflush();
-        &cachedcsheets();
-    } elsif (&gettype($asheet) eq 'studentcalc') {
-        $r->print("Loading previously calculated assessment sheets ...<br>\n");
+        #
+        &updatesheet($asheet);
+        $r->print("Updated rows, loading row data ...<br>\n");
         $r->rflush();
-        &cachedssheets(&getuname($asheet),&getudom($asheet),
-                       &getuhome($asheet));
-    }
-
-# ----------------------------------------------------- Update sheet, load rows
-
-    $r->print("Loaded sheet(s), updating rows ...<br>\n");
-    $r->rflush();
-
-    &updatesheet($asheet);
-
-    $r->print("Updated rows, loading row data ...<br>\n");
-    $r->rflush();
-
-    &loadrows($asheet,$r);
-
-    $r->print("Loaded row data, calculating sheet ...<br>\n");
-    $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.='_'.&gettype($asheet);
-            &setfilename($asheet,$fname);
-            $ENV{'form.ufn'}=$fname;
-	    $r->print('<p>Saving spreadsheet: '.
-                         &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');
-	}
-    }
-
-# ------------------------------------------------ Write the modified worksheet
+        #
+        &loadrows($asheet,$r);
+        $r->print("Loaded row data, calculating sheet ...<br>\n");
+        $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.='_'.&gettype($asheet);
+                &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>');
 

--matthew1030736867--