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

stredwic lon-capa-cvs@mail.lon-capa.org
Fri, 28 Jun 2002 18:06:14 -0000


This is a MIME encoded message

--stredwic1025287574
Content-Type: text/plain

stredwic		Fri Jun 28 14:06:14 2002 EDT

  Modified files:              
    /loncom/interface	lonchart.pm 
  Log:
  This commit involves bugs: 522, 484, 497, and 218.
  
  A rework of the internal layout and clean up of code has completely changed
  this module internally.  The output is basically the same except that there
  are header for the columns.  The headers are the title of the sequence or 
  page in which the problems reside.  This relates to bug 218.  The width of
  the column is now determined by the max of the width of the title and the
  number of problems(plus number of correct problems).
  
  This version also displays problems that reside in the top level map.  The
  only problem with this currently is that the problems are displayed after
  all the sequences that reside in the top sequence have been displayed.  This
  also applies to any sequence that contains a mixture of problems and 
  sequences.  This relates to bugs 522 and 497.  The other current problem is
  that the heading is missing for the top level sequence's problem's column.
  
  Lastly, this version contains the ability to stop the download of material
  using the browser stop button.  This relates to bug 484.  The ties to the
  hash are kept down for writing, and there is a some give for tieing to 
  a the cached data if another daemon is using it.  This give corresponds
  to a total maximum sleep time of three seconds before giving up on tieing
  the hash for the current httpd daemon.
  
  Overall, there was a lot of code movement within the module and function
  renaming.  Some of the algorithms like tracetable were reworked and
  added too.  There is now a test procedure for this module call 
  lonchart.test_procedure which is kept in doc/homework.
  
  
--stredwic1025287574
Content-Type: text/plain
Content-Disposition: attachment; filename="stredwic-20020628140614.txt"

Index: loncom/interface/lonchart.pm
diff -u loncom/interface/lonchart.pm:1.43 loncom/interface/lonchart.pm:1.44
--- loncom/interface/lonchart.pm:1.43	Wed Jun  5 01:05:38 2002
+++ loncom/interface/lonchart.pm	Fri Jun 28 14:06:14 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonchart.pm,v 1.43 2002/06/05 05:05:38 stredwic Exp $
+# $Id: lonchart.pm,v 1.44 2002/06/28 18:06:14 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -55,167 +55,191 @@
 use HTML::TokeParser;
 use GDBM_File;
 
-# -------------------------------------------------------------- Module Globals
-my %hash;
-my %CachData;
-my @cols;
-my $r;
-my $c;
- 
-# ------------------------------------------------------------- Find out status
+#my $jr; 
+# ----- FORMAT PRINT DATA ----------------------------------------------
 
-sub ExtractStudentData {
-    my ($name,$coid)=@_;
+sub FormatStudentInformation {
+    my ($cache,$name,$studentInformation,$spacePadding)=@_;
+    my $Str='<pre>';
+
+    foreach (@$studentInformation) {
+	my $data=$cache->{$name.':'.$_};
+	$Str .= $data;
+
+	my @dataLength=split(//,$data);
+	my $length=scalar @dataLength;
+	$Str .= (' 'x($cache->{$_.'Length'}-$length));
+	$Str .= $spacePadding;
+    }
+
+    return $Str;
+}
+
+sub FormatStudentData {
+    my ($name,$coid,$studentInformation,$spacePadding,$ChartDB)=@_;
     my ($sname,$sdom) = split(/\:/,$name);
-    my $ResId;
-    my $Code;
-    my $Tries;
-    my $Wrongs;
-    my %TempHash;
-    my $Version;
-    my $problemsCorrect;
-    my $problemsSolved;
-    my $totalProblems;
-    my $LatestVersion;
     my $Str;
+    my %CacheData;
 
+    unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
+        return '';
+    }
     # Handle Student information ------------------------------------------
+    # Handle user data
+    $Str=&FormatStudentInformation(\%CacheData, $name, $studentInformation, 
+                                   $spacePadding);
+
     # Handle errors
-#    if($CachData{$name.':error'} =~ /environment/) {
-#	my $errorMessage = $CachData{$name.':error'};
+    if($CacheData{$name.':error'} =~ /environment/) {
+        untie(%CacheData);
+        $Str .= '</pre>';
+        return $Str;
+#	my $errorMessage = $CacheData{$name.':error'};
 #	return '<td>'.$sname.'</td><td>'.$sdom.
 #	    '</td><td><font color="#000088">'.$errorMessage.'</font></td>';
-#    }
-
-    # Handle user data
-    $Str  = '<td><pre>'.$sname.'</pre></td><td><pre>'.$sdom;
-    $Str .= '</pre></td><td><pre>'.$CachData{$name.':section'};
-    $Str .= '</pre></td><td><pre>'.$CachData{$name.':id'};
-    $Str .= '</pre></td><td><pre>'.$CachData{$name.':fullname'};
-    $Str .= '</pre></td>';
+    }
 
-    if($CachData{$name.':error'} =~ /course/) {
+    if($CacheData{$name.':error'} =~ /course/) {
+        untie(%CacheData);
+        $Str .= '</pre>';
 	return $Str;
 #	my $errorMessage = 'May have no course data or '.
-#	                   $CachData{$name.':error'};
+#	                   $CacheData{$name.':error'};
 #	return '<td>'.$sname.'</td><td>'.$sdom.
 #	    '</td><td><font color="#000088">'.$errorMessage.'</font></td>';
     }
 
     # Handle problem data ------------------------------------------------
-    $Str .= '<td><pre>';
-    $problemsCorrect = 0;
-    $totalProblems = 0;
-    $problemsSolved = 0;
-    my $IterationNo = 0;
-    foreach $ResId (@cols) {
-	if ($IterationNo == 0) {
-	    # Looks to be skipping start resource
-	    $IterationNo++; 
-	    next;
-	}
-
-	# ResId is 0 for sequences and pages, 
-	# please check tracetable for changes
-	if (!$ResId) {
-	    my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
-	    $Str .= '<font color="#007700">'.$outputProblemsCorrect.
-		    '</font></pre></td>';
-	    $Str .= '<td><pre>';
-	    $problemsSolved += $problemsCorrect;
-	    $problemsCorrect=0;
-	    next; 
-	}
-
-	# Set $1 and $2
-	$ResId=~/(\d+)\.(\d+)/;
-	my $meta=$hash{'src_'.$ResId};
-	my $numberOfParts = 0;
-	undef %TempHash;
-	foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
-#----------- Overwrite $1 in next statement ---------------------------------
-	    if ($_=~/^stores\_(\d+)\_tries$/) {
-		my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
-		if ( $TempHash{"$Part"} eq '' ) { 
-		    $TempHash{"$Part"} = $Part;
-		    $TempHash{$numberOfParts}=$Part;
-		    $TempHash{"$Part.Code"} = ' ';  
-		    $numberOfParts++;
-		}
-	    }
-	}
-
-#----------- Using $1 and $2 -----------------------------------------------
-	my $Prob = &Apache::lonnet::symbclean(
-		       &Apache::lonnet::declutter($hash{'map_id_'.$1} ).
-                       '___'.$2.'___'.
-                       &Apache::lonnet::declutter( $hash{'src_'.$ResId} ));
-	$Code=' ';
-	$Tries = 0;
-	$LatestVersion = $CachData{$name.":version:$Prob"};
-
-	if ( $LatestVersion ) {
-	    for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {
-		my $vkeys = $CachData{$name.":$Version:keys:$Prob"};
-		my @keys = split(/\:/,$vkeys);		  
-
-		foreach my $Key (@keys) {
-#---------------------- Changing $1 -------------------------------------------
-		    if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {
-#---------------------- Using $1 -----------------------------------------------
-			my $Part = $1;
-			$Tries = $CachData{$name.":$Version:$Prob".
-					   ":resource.$Part.tries"};
-			$TempHash{"$Part.Tries"}=($Tries) ? $Tries : 0;
-			my $Val = $CachData{$name.":$Version:$Prob".
-					    ":resource.$Part.solved"};
-			if    ($Val eq 'correct_by_student')   {$Code = '*';} 
-			elsif ($Val eq 'correct_by_override')  {$Code = '+';}
-			elsif ($Val eq 'incorrect_attempted')  {$Code = '.';} 
-			elsif ($Val eq 'incorrect_by_override'){$Code = '-';}
-			elsif ($Val eq 'excused')              {$Code = 'x';}
-			elsif ($Val eq 'ungraded_attempted')   {$Code = '#';}
-			else                                   {$Code = ' ';}
+    my $Version;
+    my $problemsCorrect = 0;
+    my $totalProblems   = 0;
+    my $problemsSolved  = 0;
+    my $numberOfParts   = 0;
+    foreach my $sequence (split(/\:/,$CacheData{'orderedSequences'})) {
+	my $characterCount=0;
+	foreach my $problemID (split(/\:/,$CacheData{$sequence.':problems'})) {
+	    my $problem = $CacheData{$problemID.':problem'};
+	    my $LatestVersion = $CacheData{$name.":version:$problem"};
+
+            if(!$LatestVersion) {
+                foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+                                                        $problemID.
+                                                        ':parts'})) {
+                    $Str .= ' ';
+                    $totalProblems++;
+                    $characterCount++;
+                }
+                next;
+            }
+
+            my %partData=undef;
+            #initialize data, displays skips correctly
+            foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+                                                    $problemID.
+                                                    ':parts'})) {
+                $partData{$part.':tries'}=0;
+                $partData{$part.':code'}=' ';
+            }
+	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
+                foreach my $part (split(/\:/,$CacheData{$sequence.':'.
+                                                        $problemID.
+                                                        ':parts'})) {
+
+                    if(!defined($CacheData{$name.":$Version:$problem".
+                                               ":resource.$part.solved"})) {
+                        next;
+                    }
+
+                    my $tries=0;
+                    my $code=' ';
+
+                    $tries = $CacheData{$name.":$Version:$problem".
+                                        ":resource.$part.tries"};
+                    $partData{$part.':tries'}=($tries) ? $tries : 0;
+
+                    my $val = $CacheData{$name.":$Version:$problem".
+                                         ":resource.$part.solved"};
+                    if    ($val eq 'correct_by_student')   {$code = '*';} 
+                    elsif ($val eq 'correct_by_override')  {$code = '+';}
+                    elsif ($val eq 'incorrect_attempted')  {$code = '.';} 
+                    elsif ($val eq 'incorrect_by_override'){$code = '-';}
+                    elsif ($val eq 'excused')              {$code = 'x';}
+                    elsif ($val eq 'ungraded_attempted')   {$code = '#';}
+                    else                                   {$code = ' ';}
+                    $partData{$part.':code'}=$code;
+                }
+            }
 
-			$TempHash{"$Part.Code"} = $Code;
-		    }
-		}
-	    }
-# Actually append problem to output (all parts)
-	    $Str.='<a href="/adm/grades?symb='.
-                &Apache::lonnet::escape($Prob).
+            $Str.='<a href="/adm/grades?symb='.
+                &Apache::lonnet::escape($problem).
                 '&student='.$sname.'&domain='.$sdom.'&command=submission">'; 
-	    for(my $n = 0; $n < $numberOfParts; $n++) {		  
-		my $part = $TempHash{$n};
-		my $code2 = $TempHash{"$part.Code"};
-		if($code2 eq '*') {
-		    $problemsCorrect++;
-# !!!!!!!!!!!------------------------- Should 10 not be maxtries? ------------
-		    if (($TempHash{"$part.Tries"}<10) ||
-			($TempHash{"$part.Tries"} eq '')) {
-			$TempHash{"$part.Code"}=$TempHash{"$part.Tries"};
-		    }
-		} elsif($code2 eq '+') {
-		    $problemsCorrect++;
-		}
+            foreach(split(/\:/,$CacheData{$sequence.':'.$problemID.
+                                          ':parts'})) {
+                if($partData{$_.':code'} eq '*') {
+                    $problemsCorrect++;
+                    if (($partData{$_.':tries'}<10) &&
+                        ($partData{$_.':tries'} ne '')) {
+                        $partData{$_.':code'}=$partData{$_.':tries'};
+                    }
+                } elsif($partData{$_.':code'} eq '+') {
+                    $problemsCorrect++;
+                }
+
+                $Str .= $partData{$_.':code'};
+                $characterCount++;
+
+                if($partData{$_.':code'} ne 'x') {
+                    $totalProblems++;
+                }
+            }
+            $Str.='</a>';
+        }
+
+        my $spacesNeeded=$CacheData{$sequence.':columnWidth'}-$characterCount;
+        $spacesNeeded -= 3;
+        $Str .= (' 'x$spacesNeeded);
+
+	my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
+	$Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
+	$problemsSolved += $problemsCorrect;
+	$problemsCorrect=0;
+
+        $Str .= $spacePadding;
+    }
 
-		$Str .= $TempHash{"$part.Code"};
+    $Str .= '<font color="#000088">'.$problemsSolved.
+	    ' / '.$totalProblems.'</font></pre>';
 
-		if($code2 ne 'x') {
-		    $totalProblems++;
-		}
-	    }
-	    $Str.='</a>';
-	} else {
-	    for(my $n=0; $n<$numberOfParts; $n++) {
-		$Str.=' ';
-		$totalProblems++;
-	    }
-	}
+    untie(%CacheData);
+    return $Str;
+}
+
+sub CreateTableHeadings {
+    my ($CacheData,$studentInformation,$headings,$spacePadding)=@_;
+    my $Str='<pre>';
+
+    for(my $index=0; $index<(scalar @$headings); $index++) {
+	my $data=$$headings[$index];
+	$Str .= $data;
+
+	my @dataLength=split(//,$data);
+	my $length=scalar @dataLength;
+	$Str .= (' 'x($CacheData->{$$studentInformation[$index].'Length'}-
+                      $length));
+	$Str .= $spacePadding;
+    }
+
+    foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) {
+	$Str .= $CacheData->{$sequence.':title'};
+	my @titleLength=split(//,$CacheData->{$sequence.':title'});
+	my $leftover=$CacheData->{$sequence.':columnWidth'}-
+                     (scalar @titleLength);
+	$Str .= (' 'x$leftover);
+	$Str .= $spacePadding;
     }
 
-    $Str .= '<td><pre><font color="#000088">'.$problemsSolved.
-	    ' / '.$totalProblems.'</font></pre></td>';
+    $Str .= 'Total Solved/Total Problems';
+    $Str .= '</pre>';
 
     return $Str;
 }
@@ -229,14 +253,14 @@
     elsif ($Status eq 'Expired' ) { $OpSel2 = 'selected'; }
     else { $OpSel1 = 'selected'; }
 
-    my $Ptr = '<form name=stat method=post action="/adm/chart" >'."\n";
+    my $Ptr = '<form name="stat" method="post" action="/adm/chart" >'."\n";
     $Ptr .= '<b> Sort by: &nbsp; </b>'."\n";
     $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type=submit name=sort value="User Name" />'."\n";
+    $Ptr .= '<input type="submit" name="sort" value="User Name" />'."\n";
     $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type=submit name=sort value="Last Name" />'."\n";
+    $Ptr .= '<input type="submit" name="sort" value="Last Name" />'."\n";
     $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type=submit name=sort value="Section"/>'."\n";
+    $Ptr .= '<input type="submit" name="sort" value="Section"/>'."\n";
     $Ptr .= '<br><br>';
     $Ptr .= '<b> Student Status: &nbsp; </b>'."\n".
             '<select name="status">'. 
@@ -244,99 +268,291 @@
             '<option '.$OpSel2.' >Expired</option>'."\n".
 	    '<option '.$OpSel3.' >Any</option> </select> '."\n";
     $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type=submit name=sort value="Recalculate Chart"/>'."\n";
+    $Ptr .= '<input type="submit" name="sort" value="Recalculate Chart"/>';
+    $Ptr .= "\n";
     $Ptr .= '</form>'."\n";
-    $r->print( $Ptr );
+
+    return $Ptr;
 }
 
-sub CreateTableHeadings {
-    $r->print('<tr>');
-    $r->print('<td>User Name</td>');
-    $r->print('<td>Domain</td>');
-    $r->print('<td>Section</td>');
-    $r->print('<td>PID</td>');
-    $r->print('<td>Full Name</td>');
-
-    my $ResId;
-    my $IterationNo = 0;
-    foreach $ResId (@cols) {
-	if ($IterationNo == 0) {$IterationNo++; next;}
-	if (!$ResId) { 
-#	    my $PrNo = sprintf( "%3d", $ProbNo );
-#	    $Str .= '<td><font color="#007700">Chapter '.$PrNo.'</font></td>';
-	    $r->print('<td><font color="#007700">Chapter '.'0'.'</font></td>');
-	}
-    }
+sub CreateLegend {
+    my $Str = '<h1>'.$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
+              '</h1><h3>'.localtime().
+              "</h3><p><pre>1..9: correct by student in 1..9 tries\n".
+              "   *: correct by student in more than 9 tries\n".
+	      "   +: correct by override\n".
+              "   -: incorrect by override\n".
+	      "   .: incorrect attempted\n".
+	      "   #: ungraded attempted\n".
+              "    : not attempted\n".
+	      "   x: excused</pre><p>"; 
+    return $Str;
+}
 
-    $r->print('</tr>');
-    $r->rflush();
+sub StartDocument {
+    my $Str = '';
+    $Str .= '<html>';
+    $Str .= '<head><title>';
+    $Str .= 'LON-CAPA Assessment Chart</title></head>';
+    $Str .= '<body bgcolor="#FFFFFF">';
+    $Str .= '<script>window.focus();</script>';
+    $Str .= '<img align=right src=/adm/lonIcons/lonlogos.gif>';
+    $Str .= '<h1>Assessment Chart</h1>';
 
-    return;
+    return $Str;
 }
 
-# ------------------------------------------------------------ Build page table
+# ----- END FORMAT PRINT DATA ------------------------------------------
+
+# ----- DOWNLOAD INFORMATION -------------------------------------------
+
+sub DownloadPrerequisiteData {
+    my ($courseID, $c)=@_;
+    my ($courseDomain,$courseNumber)=split(/\_/,$courseID);
+
+    my %classlist=&Apache::lonnet::dump('classlist',$courseDomain,
+                                        $courseNumber);
+    my ($checkForError)=keys (%classlist);
+    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+        return \%classlist;
+    }
+
+    foreach my $name (keys(%classlist)) {
+        if($c->aborted()) {
+            $classlist{'error'}='aborted';
+            return \%classlist;
+        }
+
+        my ($studentName,$studentDomain) = split(/\:/,$name);
+        # Download student environment data, specifically the full name and id.
+        my %studentInformation=&Apache::lonnet::get('environment',
+                                                    ['lastname','generation',
+                                                     'firstname','middlename',
+                                                     'id'],
+                                                    $studentDomain,
+                                                    $studentName);
+        $classlist{$name.':studentInformation'}=\%studentInformation;
 
-sub tracetable {
-    my ($rid,$beenhere)=@_;
-    unless ($beenhere=~/\&$rid\&/) {
-       $beenhere.=$rid.'&';  
-# new ... updating the map according to sequence and page
-       if (defined($hash{'is_map_'.$rid})) {
-	   my $cmap=$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}};
-           if ( $cmap eq 'sequence' || $cmap eq 'page' ) { 
-               $cols[$#cols+1]=0; 
-           }
-           if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
-               (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) {
-              my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
-
-                &tracetable($hash{'map_start_'.$hash{'src_'.$rid}},
-                '&'.$frid.'&');
-
-              if ($hash{'src_'.$frid}) {
-                 if ($hash{'src_'.$frid}=~
-                                 /\.(problem|exam|quiz|assess|survey|form)$/) {
-		     $cols[$#cols+1]=$frid;
-                 }
-	      }
-
-	   }
-       } else {
-          if ($hash{'src_'.$rid}) {
-             if ($hash{'src_'.$rid}=~
-                                 /\.(problem|exam|quiz|assess|survey|form)$/) {
-	         $cols[$#cols+1]=$rid;
-             }
-          }
-       }
-       if (defined($hash{'to_'.$rid})) {
-          foreach (split(/\,/,$hash{'to_'.$rid})){
-              &tracetable($hash{'goesto_'.$_},$beenhere);
-          }
-       }
+        if($c->aborted()) {
+            $classlist{'error'}='aborted';
+            return \%classlist;
+        }
+
+        #Section
+        my %section=&Apache::lonnet::dump('roles',$studentDomain,$studentName);
+        $classlist{$name.':section'}=\%section;
     }
+
+    return \%classlist;
 }
 
-sub usection {
-    my ($udom,$unam,$courseid,$ActiveFlag)=@_;
-    $courseid=~s/\_/\//g;
-    $courseid=~s/^(\w)/\/$1/;
+sub DownloadStudentCourseInformation {
+    my ($name,$courseID)=@_;
+    my ($studentName,$studentDomain) = split(/\:/,$name);
 
-    my %result=&Apache::lonnet::dump('roles',$udom,$unam);
+    # Download student course data
+    my %courseData=&Apache::lonnet::dump($courseID,$studentDomain,
+					 $studentName);
+    return \%courseData;
+}
 
-    my($checkForError)=keys (%result);
-    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
-	return -1;
+# ----- END DOWNLOAD INFORMATION ---------------------------------------
+
+# ----- END PROCESSING FUNCTIONS ---------------------------------------
+
+sub ProcessTopResourceMap {
+    my ($ChartDB,$c)=@_;
+    my %hash;
+    my $fn=$ENV{'request.course.fn'};
+    if(-e "$fn.db") {
+	my $tieTries=0;
+	while($tieTries < 3) {
+	    if(tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {
+		last;
+	    }
+	    $tieTries++;
+	    sleep 1;
+	}
+	if($tieTries >= 3) {
+            return 'Coursemap undefined.';
+        }
+    } else {
+        return 'Can not open Coursemap.';
     }
 
+    my %CacheData;
+    unless(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+        untie(%hash);
+	return 'Could not tie cache hash.';
+    }
+
+    my (@sequences, @currentResource, @finishResource);
+    my ($currentSequence, $currentResourceID, $lastResourceID);
+
+    $currentResourceID=$hash{'ids_/res/'.$ENV{'request.course.uri'}};
+    $lastResourceID=-1;
+    $currentSequence=-1;
+    my $topLevelSequenceNumber = $currentSequence;
+
+    while(1) {
+        if($c->aborted()) {
+            last;
+        }
+	# HANDLE NEW SEQUENCE!
+	#if page || sequence
+	if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}})) {
+	    push(@sequences, $currentSequence);
+	    push(@currentResource, $currentResourceID);
+	    push(@finishResource, $lastResourceID);
+
+	    $currentSequence=$hash{'map_pc_'.$hash{'src_'.$currentResourceID}};
+	    $lastResourceID=$hash{'map_finish_'.
+				  $hash{'src_'.$currentResourceID}};
+	    $currentResourceID=$hash{'map_start_'.
+				     $hash{'src_'.$currentResourceID}};
+
+	    if(!($currentResourceID) || !($lastResourceID)) {
+		$currentSequence=pop(@sequences);
+		$currentResourceID=pop(@currentResource);
+		$lastResourceID=pop(@finishResource);
+		if($currentSequence eq $topLevelSequenceNumber) {
+		    last;
+		}
+	    }
+	}
+
+	# Handle gradable resources: exams, problems, etc
+	$currentResourceID=~/(\d+)\.(\d+)/;
+        my $partA=$1;
+        my $partB=$2;
+	if($hash{'src_'.$currentResourceID}=~
+	   /\.(problem|exam|quiz|assess|survey|form)$/ &&
+	   $partA eq $currentSequence) {
+	    my $Problem = &Apache::lonnet::symbclean(
+			  &Apache::lonnet::declutter($hash{'map_id_'.$partA}).
+			  '___'.$partB.'___'.
+			  &Apache::lonnet::declutter($hash{'src_'.
+							 $currentResourceID}));
+
+	    $CacheData{$currentResourceID.':problem'}=$Problem;
+	    if(!defined($CacheData{$currentSequence.':problems'})) {
+		$CacheData{$currentSequence.':problems'}=$currentResourceID;
+	    } else {
+		$CacheData{$currentSequence.':problems'}.=
+		    ':'.$currentResourceID;
+	    }
+
+            #Get Parts for problem
+	    my $meta=$hash{'src_'.$currentResourceID};
+	    foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
+		if($_=~/^stores\_(\d+)\_tries$/) {
+		    my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
+                    if(!defined($CacheData{$currentSequence.':'.
+                                          $currentResourceID.':parts'})) {
+                        $CacheData{$currentSequence.':'.$currentResourceID.
+                                   ':parts'}=$Part;
+                    } else {
+                        $CacheData{$currentSequence.':'.$currentResourceID.
+                                   ':parts'}.=':'.$Part;
+                    }
+		}
+	    }
+	}
+
+	#if resource == finish resource
+	if($currentResourceID eq $lastResourceID) {
+	    #pop off last resource of sequence
+	    $currentResourceID=pop(@currentResource);
+	    #pop to get last resource in previous sequence
+	    $currentResourceID=pop(@currentResource);
+	    $lastResourceID=pop(@finishResource);
+
+	    if(defined($CacheData{$currentSequence.':problems'})) {
+		# Capture sequence information here
+		if(!defined($CacheData{'orderedSequences'})) {
+		    $CacheData{'orderedSequences'}=$currentSequence;
+		} else {
+		    $CacheData{'orderedSequences'}.=':'.$currentSequence;
+		}
+
+		$CacheData{$currentSequence.':title'}=
+		    $hash{'title_'.$currentResourceID};
+
+                my $totalProblems=0;
+                foreach (split(/\:/,$CacheData{$currentSequence.
+                                               ':problems'})) {
+                    foreach ($CacheData{$currentSequence.':'.$_.':parts'}) {
+                        $totalProblems++;
+                    }
+                }
+		my @titleLength=split(//,$CacheData{$currentSequence.
+                                                    ':title'});
+                # $extra is 3 for problems correct and 3 for space
+                # between problems correct and problem output
+                my $extra = 6;
+		if(($totalProblems + $extra) > (scalar @titleLength)) {
+		    $CacheData{$currentSequence.':columnWidth'}=
+                        $totalProblems + $extra;
+		} else {
+		    $CacheData{$currentSequence.':columnWidth'}=
+                        (scalar @titleLength);
+		}
+	    }
+
+	    $currentSequence=pop(@sequences);
+	    if($currentSequence eq $topLevelSequenceNumber) {
+		last;
+	    }
+	#else
+	}
+
+	# MOVE!!!
+	#move to next resource
+	unless(defined($hash{'to_'.$currentResourceID})) {
+	    # big problem, need to handle.  Next is probably wrong
+	    last;
+	}
+	my @nextResources=();
+	foreach (split(/\,/,$hash{'to_'.$currentResourceID})) {
+	    push(@nextResources, $hash{'goesto_'.$_});
+	}
+	pop(@currentResource);
+	push(@currentResource, @nextResources);
+	# Set the next resource to be popped(processed)
+	$currentResourceID=$currentResource[-1];
+    }
+
+    unless (untie(%hash)) {
+        &Apache::lonnet::logthis("<font color=blue>WARNING: ".
+                                 "Could not untie coursemap $fn (browse)".
+                                 ".</font>"); 
+    }
+
+    unless (untie(%CacheData)) {
+        &Apache::lonnet::logthis("<font color=blue>WARNING: ".
+                                 "Could not untie Cache Hash (browse)".
+                                 ".</font>"); 
+    }
+
+    return 'OK';
+}
+
+sub ProcessSection {
+    my ($sectionData, $courseid,$ActiveFlag)=@_;
+    $courseid=~s/\_/\//g;
+    $courseid=~s/^(\w)/\/$1/;
+
     my $cursection='-1';
     my $oldsection='-1';
     my $status='Expired';
-    foreach my $key (keys (%result)) {
-	my $value = $result{$key};
+    my $section='';
+    foreach my $key (keys (%$sectionData)) {
+	my $value = $sectionData->{$key};
         if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
-            my $section=$1;
-            if ($key eq $courseid.'_st') { $section=''; }
+	    $section=$1;
+	    if($key eq $courseid.'_st') {
+		$section='';
+	    }
 	    my ($dummy,$end,$start)=split(/\_/,$value);
 	    my $now=time;
 	    my $notactive=0;
@@ -353,6 +569,7 @@
 	    if($notactive == 0) {
 		$status='Active';
 		$cursection=$section;
+		last;
 	    }
 	    if($notactive == 1) {
 		$oldsection=$section;
@@ -374,38 +591,133 @@
     return '-1';
 }
 
+sub ProcessStudentInformation {
+    my ($CacheData,$studentInformation,$section,$date,$name,$courseID,$c)=@_;
+    my ($studentName,$studentDomain) = split(/\:/,$name);
+
+    $CacheData->{$name.':username'}=$studentName;
+    $CacheData->{$name.':domain'}=$studentDomain;
+    $CacheData->{$name.':date'}=$date;
+
+    my ($checkForError)=keys(%$studentInformation);
+    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+	$CacheData->{$name.':error'}=
+	    'Could not download student environment data.';
+	$CacheData->{$name.':fullname'}='';
+	$CacheData->{$name.':id'}='';
+    } else {
+	$CacheData->{$name.':fullname'}=&ProcessFullName(
+                                          $studentInformation->{'lastname'},
+				          $studentInformation->{'generation'},
+				          $studentInformation->{'firstname'},
+                                          $studentInformation->{'middlename'});
+	$CacheData->{$name.':id'}=$studentInformation->{'id'};
+    }
+
+    # Get student's section number
+    my $sec=&ProcessSection($section, $courseID, $ENV{'form.status'});
+    if($sec != -1) {
+	$CacheData->{$name.':section'}=$sec;
+    } else {
+	$CacheData->{$name.':section'}='';
+    }
+
+    return 0;
+}
+
+sub ProcessClassList {
+    my ($classlist,$courseID,$ChartDB,$c)=@_;
+    my @names=();
+
+    my %CacheData;
+    if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+        foreach my $name (keys(%$classlist)) {
+            if($name =~ /\:section/ || $name =~ /\:studentInformation/) {
+                next;
+            }
+            if($c->aborted()) {
+                last;
+            }
+            push(@names,$name);
+            &ProcessStudentInformation(
+                                    \%CacheData,
+                                    $classlist->{$name.':studentInformation'},
+                                    $classlist->{$name.':section'},
+                                    $classlist->{$name},
+                                    $name,$courseID,$c);
+        }
+
+        $CacheData{'NamesOfStudents'}=join(":::",@names);
+#        $CacheData{'NamesOfStudents'}=&Apache::lonnet::arrayref2str(\@names);
+	untie(%CacheData);
+    }
+
+    return @names;
+}
+
+# ----- END PROCESSING FUNCTIONS ---------------------------------------
+
+# ----- HELPER FUNCTIONS -----------------------------------------------
+
+sub SpaceColumns {
+    my ($students,$studentInformation,$headings,$ChartDB)=@_;
+
+    my %CacheData;
+    if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+        # Initialize Lengths
+        for(my $index=0; $index<(scalar @$headings); $index++) {
+	    my @titleLength=split(//,$$headings[$index]);
+	    $CacheData{$$studentInformation[$index].'Length'}=
+                scalar @titleLength;
+	}
+
+        foreach my $name (@$students) {
+            foreach (@$studentInformation) {
+		my @dataLength=split(//,$CacheData{$name.':'.$_});
+		my $length=scalar @dataLength;
+		if($length > $CacheData{$_.'Length'}) {
+		    $CacheData{$_.'Length'}=$length;
+		}
+            }
+        }
+        untie(%CacheData);
+    }
+
+    return;
+}
+
 sub ProcessFullName {
-    my ($name)=@_;
+    my ($lastname, $generation, $firstname, $middlename)=@_;
     my $Str = '';
 
-    if($CachData{$name.':lastname'} ne '') {
-	$Str .= $CachData{$name.':lastname'}.' ';
-	if($CachData{$name.':generation'} ne '') {
-	    $Str .= $CachData{$name.':generation'};
+    if($lastname ne '') {
+	$Str .= $lastname.' ';
+	if($generation ne '') {
+	    $Str .= $generation;
 	} else {
 	    chop($Str);
 	}
 	$Str .= ', ';
-	if($CachData{$name.':firstname'} ne '') {
-	    $Str .= $CachData{$name.':firstname'}.' ';
+	if($firstname ne '') {
+	    $Str .= $firstname.' ';
 	}
-	if($CachData{$name.':middlename'} ne '') {
-	    $Str .= $CachData{$name.':middlename'};
+	if($middlename ne '') {
+	    $Str .= $middlename;
 	} else {
 	    chop($Str);
-	    if($CachData{$name.'firstname'} eq '') {
+	    if($firstname eq '') {
 		chop($Str);
 	    }
 	}
     } else {
-	if($CachData{$name.':firstname'} ne '') {
-	    $Str .= $CachData{$name.':firstname'}.' ';
+	if($firstname ne '') {
+	    $Str .= $firstname.' ';
 	}
-	if($CachData{$name.':middlename'} ne '') {
-	    $Str .= $CachData{$name.':middlename'}.' ';
+	if($middlename ne '') {
+	    $Str .= $middlename.' ';
 	}
-	if($CachData{$name.':generation'} ne '') {
-	    $Str .= $CachData{$name.':generation'};
+	if($generation ne '') {
+	    $Str .= $generation;
 	} else {
 	    chop($Str);
 	}
@@ -414,90 +726,45 @@
     return $Str;
 }
 
-sub DownloadStudentInformation {
-    my ($name,$courseID)=@_;
-    my ($studentName,$studentDomain) = split(/\:/,$name);
-    my $checkForError;
-    my $key;
-    my $Status=$CachData{$name.':Status'};
-
-#-----------------------------------------------------------------
-    # Download student environment data, specifically the full name and id.
-    my %studentInformation=&Apache::lonnet::get('environment',
-						['lastname','generation',
-						 'firstname','middlename',
-						 'id'],
-						$studentDomain,$studentName);
-    if($c->aborted()) {
-	return;
-    }
-    ($checkForError)=keys (%studentInformation);
-    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
-	$CachData{$name.':error'}=
-	    'Could not download student environment data.';
-#	return;
-	$CachData{$name.':lastname'}='';
-	$CachData{$name.':generation'}='';
-	$CachData{$name.':firstname'}='';
-	$CachData{$name.':middlename'}='';
-	$CachData{$name.':fullname'}='';
-	$CachData{$name.':id'}='';
-    } else {
-	$CachData{$name.':lastname'}=$studentInformation{'lastname'};
-	$CachData{$name.':generation'}=$studentInformation{'generation'};
-	$CachData{$name.':firstname'}=$studentInformation{'firstname'};
-	$CachData{$name.':middlename'}=$studentInformation{'middlename'};
-	$CachData{$name.':fullname'}=&ProcessFullName($name);
-	$CachData{$name.':id'}=$studentInformation{'id'};
-    }
-
-    # Download student course data
-    my %courseData=&Apache::lonnet::dump($courseID,$studentDomain,
-					 $studentName);
-    if($c->aborted()) {
-	return;
-    }
-    ($checkForError)=keys (%courseData);
-    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
-	$CachData{$name.':error'}='Could not download course data.';
-#	return;
-    } else {
-	foreach $key (keys (%courseData)) {
-	    $CachData{$name.':'.$key}=$courseData{$key};
-	}
-    }
-
-    # Get student's section number
-    my $sec=&usection($studentDomain, $studentName, $courseID, $Status);
-    if($sec != -1) {
-	$CachData{$name.':section'}=sprintf('%3s',$sec);
-    } else {
-	$CachData{$name.':section'}='';
+sub SortStudents {
+    my ($CacheData)=@_;
+    my @students = split(/:::/,$CacheData->{'NamesOfStudents'});
+#    my @students=&Apache::lonnet::str2array($CacheData->{'NamesOfStudents'});
+
+    my @sorted1Students=();
+    foreach (@students) {
+        my ($end,$start)=split(/\:/,$CacheData->{$_.':date'});
+        my $active=1;
+        my $now=time;
+        my $Status=$ENV{'form.status'};
+        $Status = ($Status) ? $Status : 'Active';
+        if((($end) && $now > $end) && (($Status eq 'Active'))) { 
+            $active=0; 
+        }
+        if(($Status eq 'Expired') && ($end == 0 || $now < $end)) {
+            $active=0;
+        }
+        if($active) {
+            push(@sorted1Students, $_);
+        }
     }
 
-    return;
-}
-
-sub SortStudents {
-# --------------------------------------------------------------- Sort Students
     my $Pos = $ENV{'form.sort'};
-    my @students = split(/:::/,$CachData{'NamesOfStudents'});
     my %sortData;
-
     if($Pos eq 'Last Name') {
-	for(my $index=0; $index<$#students+1; $index++) {
-	    $sortData{$CachData{$students[$index].':fullname'}}=
-		$students[$index];
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$CacheData->{$sorted1Students[$index].':fullname'}}=
+		$sorted1Students[$index];
 	}
     } elsif($Pos eq 'Section') {
-	for(my $index=0; $index<$#students+1; $index++) {
-	    $sortData{$CachData{$students[$index].':section'}.
-		      $students[$index]}=$students[$index];
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$CacheData->{$sorted1Students[$index].':section'}.
+		      $sorted1Students[$index]}=$sorted1Students[$index];
 	}
     } else {
 	# Sort by user name
-	for(my $index=0; $index<$#students+1; $index++) {
-	    $sortData{$students[$index]}=$students[$index];
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$sorted1Students[$index]}=$sorted1Students[$index];
 	}
     }
 
@@ -509,205 +776,193 @@
     return @order;
 }
 
-sub CollectClasslist {
-# -------------------------------------------------------------- Get class list
-    my $cid=$ENV{'request.course.id'};
-    my $chome=$ENV{'course.'.$cid.'.home'};
-    my ($cdom,$cnum)=split(/\_/,$cid);
-    my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);
-    my @names = ();
+sub TestCacheData {
+    my ($ChartDB)=@_;
+    my $isCached=-1;
+    my %testData;
+    my $tieTries=0;
 
-    my($checkForError)=keys (%classlist);
-    if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
-	$r->print('<h1>Could not access course data</h1>');
-	push (@names, 'error');
-	return @names;
+    if ((-e "$ChartDB") && ($ENV{'form.sort'} ne 'Recalculate Chart')) {
+	$isCached = 1;
+    } else {
+	$isCached = 0;
     }
 
-# ------------------------------------- Calculate Status and number of students
-    my $now=time;
-    foreach my $name (sort(keys(%classlist))) {
-	my $value=$classlist{$name};
-	my ($end,$start)=split(/\:/,$value);
-	my $active=1;
-	my $Status=$ENV{'form.status'};
-	$Status = ($Status) ? $Status : 'Active';
-	if((($end) && $now > $end) && (($Status eq 'Active'))) { 
-	    $active=0; 
-	}
-	if(($Status eq 'Expired') && ($end == 0 || $now < $end)) {
-	    $active=0;
-	}
-	if($active) {
-	    push(@names,$name);
-	    $CachData{$name.':Status'}=$Status;
-	}
+    while($tieTries < 3) {
+        my $result=0;
+        if($isCached) {
+            $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_READER,0640);
+        } else {
+            $result=tie(%testData,'GDBM_File',$ChartDB,&GDBM_NEWDB,0640);
+        }
+        if($result) {
+            last;
+        }
+        $tieTries++;
+        sleep 1;
+    }
+    if($tieTries >= 3) {
+        return -1;
     }
 
-    $CachData{'NamesOfStudents'}=join(":::",@names);
+    untie(%testData);
 
-    return @names;
+    return $isCached;
 }
 
-sub BuildChart {
-# ----------------------- Get first and last resource, see if there is anything
-    my $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
-    my $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
-    if (!($firstres) || !($lastres)) {
-	$r->print('<h3>Undefined course sequence</h3>');
-	return;
+sub ExtractStudentData {
+    my ($courseData, $name, $ChartDB)=@_;
+
+    my %CacheData;
+    if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+        my ($checkForError) = keys(%$courseData);
+        if($checkForError =~ /^(con_lost|error|no_such_host)/i) {
+            $CacheData{$name.':error'}='Could not download course data.';
+        } else {
+            foreach my $key (keys (%$courseData)) {
+                $CacheData{$name.':'.$key}=$courseData->{$key};
+            }
+        }
+        untie(%CacheData);
     }
 
-# --------------- Find all assessments and put them into some linear-like order
-    &tracetable($firstres,'&'.$lastres.'&');
+    return;
+}
+
+# ----- END HELPER FUNCTIONS --------------------------------------------
+
+sub BuildChart {
+    my ($r)=@_;
+    my $c = $r->connection;
 
-# ----------------------------------------------------------------- Render page
-    &CreateForm();
+    # Start the lonchart document
+    $r->content_type('text/html');
+    $r->send_http_header;
+    $r->print(&StartDocument());
+    $r->rflush();
 
+    # Test for access to the CacheData
+    my $isCached=0;
     my $cid=$ENV{'request.course.id'};
     my $ChartDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
                   "_$ENV{'user.domain'}_$cid\_chart.db";
-    my $isCached = 0;
-    my @students;
-    if ((-e "$ChartDB") && ($ENV{'form.sort'} ne 'Recalculate Chart')) {
-	if (tie(%CachData,'GDBM_File',"$ChartDB",&GDBM_READER,0640)) {
-	    $isCached = 1;
-	    @students=&SortStudents();
-	} else {
-	    $r->print("Unable to tie hash to db file");
-	    $r->rflush();
-	    return;
-	}
+
+    $isCached=&TestCacheData($ChartDB);
+    if($isCached < 0) {
+        $r->print("Unable to tie hash to db file");
+        $r->rflush();
+        return;
+    }
+
+    # Download class list information if not using cached data
+    my @students=();
+    my @studentInformation=('username','domain','section','id','fullname');
+    my @headings=('User Name','Domain','Section','PID','Full Name');
+    my $spacePadding='   ';
+    if(!$isCached) {
+        my $processTopResourceMapReturn=&ProcessTopResourceMap($ChartDB,$c);
+        if($processTopResourceMapReturn ne 'OK') {
+            $r->print($processTopResourceMapReturn);
+            return;
+        }
+        if($c->aborted()) { return; }
+        my $classlist=&DownloadPrerequisiteData($cid, $c);
+        my ($checkForError)=keys(%$classlist);
+        if($checkForError =~ /^(con_lost|error|no_such_host)/i ||
+           defined($classlist->{'error'})) {
+            return;
+        }
+        if($c->aborted()) { return; }
+        @students=&ProcessClassList($classlist,$cid,$ChartDB,$c);
+        if($c->aborted()) { return; }
+        &SpaceColumns(\@students,\@studentInformation,\@headings,
+                      $ChartDB);
+        if($c->aborted()) { return; }
+    }
+
+    # Sort students and print out table desciptive data
+    my %CacheData;
+    if(tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_READER,0640)) {
+        if(!$c->aborted()) { @students=&SortStudents(\%CacheData); }
+	if(!$c->aborted()) { $r->print(&CreateLegend()); }
+	if(!$c->aborted()) { $r->print(&CreateForm()); }
+	if(!$c->aborted()) { $r->print('<h3>'.(scalar @students).
+                                       ' students</h3>'); }
+	if(!$c->aborted()) { $r->rflush(); }
+	if(!$c->aborted()) { $r->print(&CreateTableHeadings(
+                                                         \%CacheData,
+                                                         \@studentInformation, 
+							 \@headings, 
+							 $spacePadding)); }
+	untie(%CacheData);
     } else {
-	if (tie(%CachData,'GDBM_File',$ChartDB,&GDBM_NEWDB,0640)) {
-	    $isCached = 0;
-	    @students=&CollectClasslist();
-	    if($students[0] eq 'error') {
-		return;
-	    }
-	} else {
-	    $r->print("Unable to tie hash to db file");
-	    return;
-	}
+	$r->print("Init2: Unable to tie hash to db file");
+	return;
     }
 
-    $r->print('<h3>'.($#students+1).' students</h3>');
-    $r->rflush();
-
-# ----------------------------------------------------------------- Start table
-    $r->print('<table><tbody>');
-#    &CreateTableHeadings();
     my @updateStudentList = ();
-    foreach my $student (@students) {
-	if($c->aborted()) {
-	    if($isCached == 0) {
-		$CachData{'NamesOfStudents'}=join(":::",@updateStudentList);
-	    }
-	    last;
-	}
-	if($isCached == 0) {
-	    &DownloadStudentInformation($student,$cid);
-	    push (@updateStudentList, $student);
-	}
-	my $Str=&ExtractStudentData($student,$cid);
-	$r->print('<tr>'.$Str.'</tr>');
+    my $courseData;
+    foreach (@students) {
+        if($c->aborted()) {
+            if(!$isCached && 
+               tie(%CacheData,'GDBM_File',$ChartDB,&GDBM_WRCREAT,0640)) {
+                $CacheData{'NamesOfStudents'}=join(":::", @updateStudentList);
+#		    $CacheData{'NamesOfStudents'}=
+#		            &Apache::lonnet::arrayref2str(\@updateStudentList);
+                untie(%CacheData);
+            }
+            last;
+        }
+
+        if(!$isCached) {
+            $courseData=&DownloadStudentCourseInformation($_, $cid);
+            if($c->aborted()) { next; }
+            push(@updateStudentList, $_);
+            &ExtractStudentData($courseData, $_, $ChartDB);
+        }
+        $r->print(&FormatStudentData($_, $cid, \@studentInformation,
+                                     $spacePadding, $ChartDB));
+        $r->rflush();
     }
-    $r->print('</tbody></table>');
-
-    untie(%CachData);
 
-    return;
-}
-
-sub Start {
-    $r->print('<head><title>'.
-              'LON-CAPA Assessment Chart</title></head>');
-    $r->print('<body bgcolor="#FFFFFF">'.
-              '<script>window.focus();</script>'.
-              '<img align=right src=/adm/lonIcons/lonlogos.gif>'.
-              '<h1>Assessment Chart</h1>');
-# ---------------------------------------------------------------- Course title
-    $r->print('<h1>'.$ENV{'course.'.$ENV{'request.course.id'}.
-              '.description'}.'</h1><h3>'.localtime().
-              "</h3><p><pre>1..9: correct by student in 1..9 tries\n".
-              "   *: correct by student in more than 9 tries\n".
-	      "   +: correct by override\n".
-              "   -: incorrect by override\n".
-	      "   .: incorrect attempted\n".
-	      "   #: ungraded attempted\n".
-              "    : not attempted\n".
-	      "   x: excused</pre><p>"); 
-# ------------------------------- This is going to take a while, produce output
+    $r->print('</body></html>');
     $r->rflush();
 
-    &BuildChart();
-
-    $r->print('</body>');
-
     return;
 }
 
 # ================================================================ Main Handler
 
 sub handler {
-    undef %hash;
-    undef %CachData;
-    undef @cols;
-
-    $r=shift;
-    $c = $r->connection;
-    if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
-# ------------------------------------------- Set document type for header only
-	if ($r->header_only) {
-	    if ($ENV{'browser.mathml'}) {
-		$r->content_type('text/xml');
-	    } else {
-		$r->content_type('text/html');
-	    }
-	    &Apache::loncommon::no_cache($r);
-	    $r->send_http_header;
-	    return OK;
-	}
-
-	my $requrl=$r->uri;
-# ----------------------------------------------------------------- Tie db file
-	if ($ENV{'request.course.fn'}) {
-	    my $fn=$ENV{'request.course.fn'};
-	    if (-e "$fn.db") {
-		if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {
-# ------------------------------------------------------------------- Hash tied
-# ---------------------------------------------------------------- Send headers
-		    $r->content_type('text/html');
-		    $r->send_http_header;
-		    $r->print('<html>');
-		    &Start();
-		    $r->print('</html>');
-		    $r->rflush();
-# ------------------------------------------------------------- End render page
-		} else {
-		    $r->content_type('text/html');
-		    $r->send_http_header;
-		    $r->print('<html><body>Coursemap undefined.</body></html>');
-		}
-# ------------------------------------------------------------------ Untie hash
-		unless (untie(%hash)) {
-		    &Apache::lonnet::logthis("<font color=blue>WARNING: ".
-			     "Could not untie coursemap $fn (browse).</font>"); 
-		}
-
-# -------------------------------------------------------------------- All done
-		return OK;
-# ----------------------------------------------- Errors, hash could no be tied
-	    }
-	} else {
-	    $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
-	    return HTTP_NOT_ACCEPTABLE; 
-	}
-    } else {
+    my $r=shift;
+#    $jr=$r;
+    unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
 	$ENV{'user.error.msg'}=
         $r->uri.":vgr:0:0:Cannot view grades for complete course";
 	return HTTP_NOT_ACCEPTABLE; 
     }
+
+    # Set document type for header only
+    if ($r->header_only) {
+        if($ENV{'browser.mathml'}) {
+            $r->content_type('text/xml');
+        } else {
+            $r->content_type('text/html');
+        }
+        &Apache::loncommon::no_cache($r);
+        $r->send_http_header;
+        return OK;
+    }
+    
+    unless($ENV{'request.course.fn'}) {
+        my $requrl=$r->uri;
+        $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
+        return HTTP_NOT_ACCEPTABLE; 
+    }
+
+    &BuildChart($r);
+
+    return OK;
 }
 1;
 __END__

--stredwic1025287574--