[LON-CAPA-cvs] cvs: loncom / lond /interface loncoursedata.pm lonhtmlcommon.pm lonstatistics.pm /interface/statistics lonproblemanalysis.pm lonproblemstatistics.pm lonstudentassessment.pm

stredwic lon-capa-cvs@mail.lon-capa.org
Tue, 13 Aug 2002 00:37:18 -0000


This is a MIME encoded message

--stredwic1029199038
Content-Type: text/plain

stredwic		Mon Aug 12 20:37:18 2002 EDT

  Modified files:              
    /loncom	lond 
    /loncom/interface	loncoursedata.pm lonhtmlcommon.pm 
                     	lonstatistics.pm 
    /loncom/interface/statistics	lonproblemanalysis.pm 
                                	lonproblemstatistics.pm 
                                	lonstudentassessment.pm 
  Log:
  First, added unescaping of $key in lond dump command.
  Next, I added a new way to download student course data.  There are now
  two functions for storing data, DownloadStudentCourseData and
  DownloadStudentCourseDataSeparate.  These two functions base their running
  on input parameters.  The option parameters are whether or not to check
  the date for downloading, whether or not to store all the dumped data or
  extract out the data you want, whether or not to display a status window.
  The extracting data parameter will be best utilized if someone adds in the
  ability to send a list of what parameters are desired and perhaps some simple
  commands to affect how that data is processed, like tries, sum would
  sum record the sum of all the tries for a student.  This is just an idea.
  
  Currently, I have all the statistics modules using the extract ability.
  This slightly increases in download time, but drastically reduces cache
  size.  Possible ideas include pushing the extract to the lond side with a
  list of parameter/commands, or even downloading everything to a temp cache,
  then extract the necessary data into the cache then removing the temp
  cache.  There are lots of other possibilities, which can change the download
  time, cache size, and other factors.  Now, only loncoursedata handles the
  downloading of data to a hash.
  
  lonstudentassessment was changed slightly to remove ' ' as a link if the
  student actually hadn't attempted the problem.
  
  lonproblemanalysis was updated for the new str2hash type functions.  There
  are a couple of (cludges/fixes) for it.  Depending on whether or not the
  str2hash type functions are changed, these may or may not need to be
  updated.
  
  lonproblemstatistics was drastically overhauled.  Most of the processing
  was removed.  Now, it just does its few statistics functions and outputs
  the table.  Currently, I broke the graph, discussion column, and 
  discriminant factor columns.  These will be fixed on the next commit soon.
  There is also no caching done.  This will also be remedied soon.  The
  problem that will need attention with caching is to know when to update
  the statistics cached data when a student's course data is updated.
  
  Lastly, I plan to add perhaps a toggle legend display button, another graph
  button(percentage correct), a button to send the CSV format(not just display),
  and add a toggle button for sorting within a sequence and sorting all
  the problems.
  
  Also, I changed the look and feel to be the same as the class list page.
  Also, the displaying of sequence headers and child sequences are not
  working.  This will be fixed, but thought will be put into how best to
  make it look and have a similiar fill for all the table combinations.
  
  
--stredwic1029199038
Content-Type: text/plain
Content-Disposition: attachment; filename="stredwic-20020812203718.txt"

Index: loncom/lond
diff -u loncom/lond:1.89 loncom/lond:1.90
--- loncom/lond:1.89	Fri Aug  9 14:18:36 2002
+++ loncom/lond	Mon Aug 12 20:37:18 2002
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.89 2002/08/09 18:18:36 www Exp $
+# $Id: lond,v 1.90 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1214,10 +1214,12 @@
                        my $proname=propath($udom,$uname);
                        my $qresult='';
       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
+                           study($regexp);
                            foreach $key (keys %hash) {
-                               if (eval('$key=~/$regexp/')) {
+                               my $unescapeKey = &unescape($key);
+                               if (eval('$unescapeKey=~/$regexp/')) {
                                   $qresult.="$key=$hash{$key}&";
-			       }
+                              }
                            }
 			   if (untie(%hash)) {
 		              $qresult=~s/\&$//;
Index: loncom/interface/loncoursedata.pm
diff -u loncom/interface/loncoursedata.pm:1.12 loncom/interface/loncoursedata.pm:1.13
--- loncom/interface/loncoursedata.pm:1.12	Mon Aug  5 10:16:19 2002
+++ loncom/interface/loncoursedata.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: loncoursedata.pm,v 1.12 2002/08/05 14:16:19 stredwic Exp $
+# $Id: loncoursedata.pm,v 1.13 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -51,6 +51,7 @@
 use strict;
 use Apache::Constants qw(:common :http);
 use Apache::lonnet();
+use Apache::lonhtmlcommon;
 use HTML::TokeParser;
 use GDBM_File;
 
@@ -190,9 +191,9 @@
                                       $courseID.'.db', 
                                       $Apache::lonnet::perlvar{'lonUsersDir'});
 
-    if($lastDownloadTime >= $modifiedTime) {
-        $courseData{'lastDownloadTime'}=time;
-        $courseData{'UpToDate'} = 'true';
+    if($lastDownloadTime >= $modifiedTime && $modifiedTime >= 0) {
+        $courseData{$namedata.':lastDownloadTime'}=time;
+        $courseData{$namedata.':UpToDate'} = 'true';
         return \%courseData;
     }
 
@@ -203,7 +204,13 @@
     %courseData=&Apache::lonnet::dump($courseID, $domain, $name, $WhatIWant);
     $courseData{'UpToDate'} = 'false';
     $courseData{'lastDownloadTime'}=time;
-    return \%courseData;
+
+    my %newData;
+    foreach (keys(%courseData)) {
+        $newData{$namedata.':'.$_} = $courseData{$_};
+    }
+
+    return \%newData;
 }
 
 # ----- END DOWNLOAD INFORMATION ---------------------------------------
@@ -281,11 +288,7 @@
     $currentSequence=-1;
     my $topLevelSequenceNumber = $currentSequence;
 
-    my $problemCount=0;
-    my $problemCount2=0;
     my %sequenceRecord;
-    my $sequenceCount=0;
-    my $sequenceCount2=0;
     while(1) {
         if($c->aborted()) {
             last;
@@ -294,7 +297,6 @@
 	#if page || sequence
 	if(defined($hash{'map_pc_'.$hash{'src_'.$currentResourceID}}) &&
            !defined($sequenceRecord{$currentResourceID})) {
-            $sequenceCount++;
             $sequenceRecord{$currentResourceID}++;
 	    push(@sequences, $currentSequence);
 	    push(@currentResource, $currentResourceID);
@@ -332,15 +334,11 @@
 	$currentResourceID=~/(\d+)\.(\d+)/;
         my $partA=$1;
         my $partB=$2;
-        if($hash{'src_'.$currentResourceID}=~/\.problem$/) {
-            $problemCount++;
-        }
 	if($hash{'src_'.$currentResourceID}=~
 	   /\.(problem|exam|quiz|assess|survey|form)$/ &&
 	   $partA eq $currentSequence && 
            !defined($sequenceRecord{$currentSequence.':'.
                                     $currentResourceID})) {
-            $problemCount2++;
             $sequenceRecord{$currentSequence.':'.$currentResourceID}++;
 	    my $Problem = &Apache::lonnet::symbclean(
 			  &Apache::lonnet::declutter($hash{'map_id_'.$partA}).
@@ -416,7 +414,6 @@
 	    $lastResourceID=pop(@finishResource);
 
 	    if(defined($cache->{$currentSequence.':problems'})) {
-                $sequenceCount2++;
 		# Capture sequence information here
 		$cache->{$currentSequence.':title'}=
 		    $hash{'title_'.$currentResourceID};
@@ -481,10 +478,6 @@
 	$currentResourceID=pop(@currentResource);
     }
 
-    $cache->{'jasoncount'}=$problemCount;
-    $cache->{'jasoncount2'}=$problemCount2;
-    $cache->{'jasonseq'}=$sequenceCount;
-    $cache->{'jasonseq2'}=$sequenceCount2;
     unless (untie(%hash)) {
         &Apache::lonnet::logthis("<font color=blue>WARNING: ".
                                  "Could not untie coursemap $fn (browse)".
@@ -662,42 +655,170 @@
 sub ProcessStudentData {
     my ($cache,$courseData,$name)=@_;
 
-    if($courseData->{'UpToDate'} eq 'true') {
-        $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};
-        if($courseData->{'lastDownloadTime'} eq 'Not downloaded') {
-            $cache->{$name.':updateTime'} = ' Not updated';
-        } else {
-            $cache->{$name.':updateTime'}=
-                localtime($courseData->{'lastDownloadTime'});
-        }
+    if(!&CheckDateStampError($courseData, $cache, $name)) {
         return;
     }
 
-    my @courseKeys = keys(%$courseData);
-
-    foreach (@courseKeys) {
-        if(/^(con_lost|error|no_such_host)/i) {
-            $cache->{$name.':error'}='Could not download course data.';
-            return;
-        }
+    foreach (keys %$courseData) {
+        $cache->{$_}=$courseData->{$_};
     }
 
-    $cache->{$name.':lastDownloadTime'}=$courseData->{'lastDownloadTime'};
-    if($courseData->{'lastDownloadTime'} eq 'Not downloaded') {
-        $cache->{$name.':updateTime'} = ' Not updated';
-    } else {
-        $cache->{$name.':updateTime'}=
-            localtime($courseData->{'lastDownloadTime'});
+    return;
+}
+
+sub ExtractStudentData {
+    my ($input, $output, $data, $name)=@_;
+
+    if(!&CheckDateStampError($input, $data, $name)) {
+        return;
     }
-    foreach (@courseKeys) {
-        $cache->{$name.':'.$_}=$courseData->{$_};
+
+    my ($username,$domain)=split(':',$name);
+
+    my $Version;
+    my $problemsCorrect = 0;
+    my $totalProblems   = 0;
+    my $problemsSolved  = 0;
+    my $numberOfParts   = 0;
+    foreach my $sequence (split(':', $data->{'orderedSequences'})) {
+        foreach my $problemID (split(':', $data->{$sequence.':problems'})) {
+            my $problem = $data->{$problemID.':problem'};
+            my $LatestVersion = $input->{$name.':version:'.$problem};
+
+            # Output dashes for all the parts of this problem if there
+            # is no version information about the current problem.
+            if(!$LatestVersion) {
+                foreach my $part (split(/\:/,$data->{$sequence.':'.
+                                                      $problemID.
+                                                      ':parts'})) {
+                    $totalProblems++;
+                }
+                $output->{$name.':'.$problemID.':NoVersion'} = 'true';
+                next;
+            }
+
+            my %partData=undef;
+            # Initialize part data, display skips correctly
+            # Skip refers to when a student made no submissions on that
+            # part/problem.
+            foreach my $part (split(/\:/,$data->{$sequence.':'.
+                                                 $problemID.
+                                                 ':parts'})) {
+                $partData{$part.':tries'}=0;
+                $partData{$part.':code'}=' ';
+                $partData{$part.':awarded'}=0;
+                $partData{$part.':timestamp'}=0;
+                foreach my $response (split(':', $data->{$sequence.':'.
+                                                         $problemID.':'.
+                                                         $part.':responseIDs'})) {
+                    $partData{$part.':'.$response.':submission'}='';
+                }
+            }
+
+            # Looping through all the versions of each part, starting with the
+            # oldest version.  Basically, it gets the most recent 
+            # set of grade data for each part.
+            my @submissions = ();
+	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
+                foreach my $part (split(/\:/,$data->{$sequence.':'.
+                                                     $problemID.
+                                                     ':parts'})) {
+
+                    if(!defined($input->{"$name:$Version:$problem".
+                                         ":resource.$part.solved"})) {
+                        # No grade for this submission, so skip
+                        next;
+                    }
+
+                    my $tries=0;
+                    my $code=' ';
+                    my $awarded=0;
+
+                    $tries = $input->{$name.':'.$Version.':'.$problem.
+                                      ':resource.'.$part.'.tries'};
+                    $awarded = $input->{$name.':'.$Version.':'.$problem.
+                                        ':resource.'.$part.'.awarded'};
+
+                    $partData{$part.':awarded'}=($awarded) ? $awarded : 0;
+                    $partData{$part.':tries'}=($tries) ? $tries : 0;
+
+                    $partData{$part.':timestamp'}=$input->{$name.':'.$Version.':'.
+                                                           $problem.
+                                                           ':timestamp'};
+                    if(!$input->{$name.':'.$Version.':'.$problem.':resource.'.$part.
+                                 '.previous'}) {
+                        foreach my $response (split(':',
+                                                   $data->{$sequence.':'.
+                                                           $problemID.':'.
+                                                           $part.':responseIDs'})) {
+                            @submissions=($input->{$name.':'.$Version.':'.
+                                                   $problem.
+                                                   ':resource.'.$part.'.'.
+                                                   $response.'.submission'},
+                                          @submissions);
+                        }
+                    }
+
+                    my $val = $input->{$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;
+                }
+            }
+
+            foreach my $part (split(/\:/,$data->{$sequence.':'.$problemID.
+                                                 ':parts'})) {
+                $output->{$name.':'.$problemID.':'.$part.':wrong'} = 
+                    $partData{$part.':tries'};
+
+                if($partData{$part.':code'} eq '*') {
+                    $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
+                    $problemsCorrect++;
+                } elsif($partData{$part.':code'} eq '+') {
+                    $output->{$name.':'.$problemID.':'.$part.':wrong'}--;
+                    $problemsCorrect++;
+                }
+
+                $output->{$name.':'.$problemID.':'.$part.':tries'} = 
+                    $partData{$part.':tries'};
+                $output->{$name.':'.$problemID.':'.$part.':code'} =
+                    $partData{$part.':code'};
+                $output->{$name.':'.$problemID.':'.$part.':awarded'} =
+                    $partData{$part.':awarded'};
+                $output->{$name.':'.$problemID.':'.$part.':timestamp'} =
+                    $partData{$part.':timestamp'};
+                foreach my $response (split(':', $data->{$sequence.':'.
+                                                         $problemID.':'.
+                                                         $part.':responseIDs'})) {
+                    $output->{$name.':'.$problemID.':'.$part.':'.$response.
+                              ':submission'}=join(':::',@submissions);
+                }
+
+                if($partData{$part.':code'} ne 'x') {
+                    $totalProblems++;
+                }
+            }
+        }
+
+        $output->{$name.':'.$sequence.':problemsCorrect'} = $problemsCorrect;
+        $problemsSolved += $problemsCorrect;
+	$problemsCorrect=0;
     }
 
+    $output->{$name.':problemsSolved'} = $problemsSolved;
+    $output->{$name.':totalProblems'} = $totalProblems;
+
     return;
 }
 
 sub LoadDiscussion {
-    my ( $courseID)=@_;
+    my ($courseID)=@_;
     my %Discuss=();
     my %contrib=&Apache::lonnet::dump(
                 $courseID,
@@ -733,6 +854,36 @@
 
 # ----- HELPER FUNCTIONS -----------------------------------------------
 
+sub CheckDateStampError {
+    my ($courseData, $cache, $name)=@_;
+    if($courseData->{$name.':UpToDate'} eq 'true') {
+        $cache->{$name.':lastDownloadTime'} = 
+            $courseData->{$name.':lastDownloadTime'};
+        if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
+            $cache->{$name.':updateTime'} = ' Not updated';
+        } else {
+            $cache->{$name.':updateTime'}=
+                localtime($courseData->{$name.':lastDownloadTime'});
+        }
+        return 0;
+    }
+
+    $cache->{$name.':lastDownloadTime'}=$courseData->{$name.':lastDownloadTime'};
+    if($courseData->{$name.':lastDownloadTime'} eq 'Not downloaded') {
+        $cache->{$name.':updateTime'} = ' Not updated';
+    } else {
+        $cache->{$name.':updateTime'}=
+            localtime($courseData->{$name.':lastDownloadTime'});
+    }
+
+    if(defined($courseData->{$name.':error'})) {
+        $cache->{$name.':error'}=$courseData->{$name.':error'};
+        return 0;
+    }
+
+    return 1;
+}
+
 =pod
 
 =item &ProcessFullName()
@@ -847,6 +998,215 @@
     return $isCached;
 }
 
+sub DownloadStudentCourseData {
+    my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+
+    my $title = 'LON-CAPA Statistics';
+    my $heading = 'Download and Process Course Data';
+    my $studentCount = scalar(@$students);
+    my %cache;
+
+    my $WhatIWant;
+    $WhatIWant = '(^version:(\w|\/|\.|-)+?$|';
+    $WhatIWant .= '^\d+:(\w|\/|\.|-)+?:(resource\.\d+\.';
+    $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
+    $WhatIWant .= '|timestamp)';
+    $WhatIWant .= ')';
+
+    if($status eq 'true') {
+        &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+    }
+    my $count=1;
+    foreach (@$students) {
+        if($c->aborted()) { return 'Aborted'; }
+
+        if($status eq 'true') {
+            my $displayString = $count.'/'.$studentCount.': '.$_;
+            &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+        }
+
+        my $downloadTime='Not downloaded';
+        if($checkDate eq 'true'  && 
+           tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+            $downloadTime = $cache{$_.':lastDownloadTime'};
+            untie(%cache);
+        }
+
+        if($c->aborted()) { return 'Aborted'; }
+
+        if($downloadTime eq 'Not downloaded') {
+            my $courseData = 
+                &DownloadCourseInformation($_, $courseID, $downloadTime, 
+                                           $WhatIWant);
+            if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+                foreach my $key (keys(%$courseData)) {
+                    if($key =~ /^(con_lost|error|no_such_host)/i) {
+                        $courseData->{$_.':error'} = 'No course data for '.$_;
+                        last;
+                    }
+                }
+                if($extract eq 'true') {
+                    &ExtractStudentData($courseData, \%cache, \%cache, $_);
+                } else {
+                    &ProcessStudentData(\%cache, $courseData, $_);
+                }
+                untie(%cache);
+            } else {
+                next;
+            }
+        }
+        $count++;
+    }
+    if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+    return 'OK';
+}
+
+sub DownloadStudentCourseDataSeparate {
+    my ($students,$checkDate,$cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+    my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
+    my $title = 'LON-CAPA Statistics';
+    my $heading = 'Download Course Data';
+
+    my $WhatIWant;
+    $WhatIWant = '(^version:(\w|\/|\.|-)+?$|';
+    $WhatIWant .= '^\d+:(\w|\/|\.|-)+?:(resource\.\d+\.';
+    $WhatIWant .= '(solved|tries|previous|awarded|(\d+\.submission))\s*$';
+    $WhatIWant .= '|timestamp)';
+    $WhatIWant .= ')';
+
+    &CheckForResidualDownload($courseID, $cacheDB, $students, $c);
+
+    my %cache;
+    my %downloadData;
+    unless(tie(%downloadData,'GDBM_File',$residualFile,&GDBM_NEWDB(),0640)) {
+        return 'Failed to tie temporary download hash.';
+    }
+
+    my $studentCount = scalar(@$students);
+    if($status eq 'true') {
+        &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+    }
+    my $count=1;
+    foreach (@$students) {
+        if($c->aborted()) {
+            untie(%downloadData);
+            return 'Aborted';
+        }
+
+        if($status eq 'true') {
+            my $displayString = $count.'/'.$studentCount.': '.$_;
+            &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+        }
+
+        my $downloadTime='Not downloaded';
+        if($checkDate eq 'true'  && 
+           tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+            $downloadTime = $cache{$_.':lastDownloadTime'};
+            untie(%cache);
+        }
+
+        if($c->aborted()) {
+            untie(%downloadData);
+            return 'Aborted';
+        }
+
+        if($downloadTime eq 'Not downloaded') {
+            my $error = 0;
+            my $courseData = 
+                &DownloadCourseInformation($_, $courseID, $downloadTime,
+                                           $WhatIWant);
+            foreach my $key (keys(%$courseData)) {
+                $downloadData{$key} = $courseData->{$key};
+                if($key =~ /^(con_lost|error|no_such_host)/i) {
+                    $error = 1;
+                    last;
+                }
+            }
+            if($error) {
+                foreach my $deleteKey (keys(%$courseData)) {
+                    delete $downloadData{$deleteKey};
+                }
+                $downloadData{$_.':error'} = 'No course data for '.$_;
+            }
+        }
+        $count++;
+    }
+    if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+    return &CheckForResidualDownload($cacheDB, 'true', 'true', 
+                                     $courseID, $r, $c);
+}
+
+sub CheckForResidualDownload {
+    my ($cacheDB,$extract,$status,$courseID,$r,$c)=@_;
+
+    my $residualFile = '/home/httpd/perl/tmp/'.$courseID.'DownloadFile.db';
+    if(!-e $residualFile) {
+        return;
+    }
+
+    my %downloadData;
+    my %cache;
+    unless(tie(%downloadData,'GDBM_File',$residualFile,&GDBM_READER(),0640) &&
+           tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+        return;
+    }
+
+    my @dataKeys=keys(%downloadData);
+    my @students=();
+    my %checkStudent;
+    foreach(@dataKeys) {
+        my @temp = split(':', $_);
+        my $student = $temp[0].':'.$temp[1];
+        if(!defined($checkStudent{$student})) {
+            $checkStudent{$student}++;
+            push(@students, $student);
+        }
+    }
+
+    my $heading = 'Process Course Data';
+    my $title = 'LON-CAPA Statistics';
+    my $studentCount = scalar(@students);
+    if($status eq 'true') {
+        &Apache::lonhtmlcommon::Create_PrgWin($r, $title, $heading);
+    }
+
+    my $count=1;
+    foreach my $name (@students) {
+        last if($c->aborted());
+
+        if($status eq 'true') {
+            my $displayString = $count.'/'.$studentCount.': '.$_;
+            &Apache::lonhtmlcommon::Update_PrgWin($displayString, $r);
+        }
+
+        if($extract eq 'true') {
+            &ExtractStudentData(\%downloadData, \%cache, \%cache, $name);
+        } else {
+            &ProcessStudentData(\%cache, \%downloadData, $name);
+        }
+        foreach (@dataKeys) {
+            if(/^$name/) {
+                delete $downloadData{$_};
+            }
+        }
+        $count++;
+    }
+
+    if($status eq 'true') { &Apache::lonhtmlcommon::Close_PrgWin($r); }
+
+    untie(%cache);
+    untie(%downloadData);
+
+    if(!$c->aborted()) {
+        my @files = ($residualFile);
+        unlink(@files);
+    }
+
+    return 'OK';
+}
+
 sub GetFileTimestamp {
     my ($studentDomain,$studentName,$filename,$root)=@_;
     $studentDomain=~s/\W//g;
@@ -859,7 +1219,7 @@
                                        $root);
     my $fileStat = $dir[0];
     my @stats = split('&', $fileStat);
-    if(@stats) {
+    if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
         return $stats[9];
     } else {
         return -1;
Index: loncom/interface/lonhtmlcommon.pm
diff -u loncom/interface/lonhtmlcommon.pm:1.6 loncom/interface/lonhtmlcommon.pm:1.7
--- loncom/interface/lonhtmlcommon.pm:1.6	Thu Aug  1 16:49:06 2002
+++ loncom/interface/lonhtmlcommon.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common html routines
 #
-# $Id: lonhtmlcommon.pm,v 1.6 2002/08/01 20:49:06 stredwic Exp $
+# $Id: lonhtmlcommon.pm,v 1.7 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -68,7 +68,7 @@
     my $selected = 0;
     foreach my $sequence (split(':',$data->{'orderedSequences'})) {
 	$Str .= '<option';
-        if($data->{$page.'Map'} eq $data->{$sequence.':title'}) {
+        if($data->{$page.'Maps'} eq $data->{$sequence.':title'}) {
             $Str .= ' selected';
             $selected = 1;
         }
@@ -153,7 +153,7 @@
     my ($sections,$selectedSections)=@_;
 
     my $Str = '';
-    $Str .= '<select name="Section" multiple="" size="4">'."\n";
+    $Str .= '<select name="Section" multiple="true" size="4">'."\n";
 
     foreach (@$sections) {
         $Str .= '<option';
@@ -292,6 +292,38 @@
     }
 
     return $Str;
+}
+
+# Create progress
+sub Create_PrgWin {
+    my ($r, $title, $heading)=@_;
+    $r->print('<script>'.
+    "popwin=open(\'\',\'popwin\',\'width=400,height=100\');".
+    "popwin.document.writeln(\'<html><body bgcolor=\"#88DDFF\">".
+              "<title>$title</title>".
+              "<h4>$heading</h4>".
+              "<form name=popremain>".
+              "<input type=text size=35 name=remaining value=Starting></form>".
+              "</body></html>\');".
+    "popwin.document.close();".
+    "</script>");
+
+    $r->rflush();
+}
+
+# update progress
+sub Update_PrgWin {
+    my ($displayString,$r)=@_;
+    $r->print('<script>popwin.document.popremain.remaining.value="'.
+              $displayString.'";</script>');
+    $r->rflush();
+}
+
+# close Progress Line
+sub Close_PrgWin {
+    my ($r)=@_;
+    $r->print('<script>popwin.close()</script>'."\n");
+    $r->rflush(); 
 }
 
 1;
Index: loncom/interface/lonstatistics.pm
diff -u loncom/interface/lonstatistics.pm:1.40 loncom/interface/lonstatistics.pm:1.41
--- loncom/interface/lonstatistics.pm:1.40	Tue Aug  6 13:39:15 2002
+++ loncom/interface/lonstatistics.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonstatistics.pm,v 1.40 2002/08/06 17:39:15 minaeibi Exp $
+# $Id: lonstatistics.pm,v 1.41 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -47,7 +47,6 @@
 use Apache::lonproblemanalysis;
 use Apache::lonproblemstatistics;
 use Apache::lonstudentassessment;
-use Apache::lonchart;
 use HTML::TokeParser;
 use GDBM_File;
 
@@ -72,7 +71,8 @@
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                             ['sort','download',
                                              'reportSelected',
-                                             'StudentAssessmentStudent']);
+                                             'StudentAssessmentStudent',
+                                             'ProblemStatisticsSort']);
     &CheckFormElement($cache, 'Status', 'Status', 'Active');
     &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list');
     &CheckFormElement($cache, 'reportSelected', 'reportSelected', 
@@ -121,6 +121,8 @@
                       'ProblemStatisticsAscend', 'Ascending');
     &CheckFormElement($cache, 'ProblemStatisticsMaps', 
                       'ProblemStatisticsMaps', 'All Maps');
+    &CheckFormElement($cache, 'ProblemStatisticsSort',
+                      'ProblemStatisticsSort', 'Homework Sets Order');
 
     # Search only form elements
     my @headingColumns=();
@@ -356,13 +358,15 @@
     $cache{'updateTime:columnWidth'}=24;
 
     if($cache{'download'} ne 'false') {
-        my $who = $cache{'download'};
-        my $courseData = 
-            &Apache::loncoursedata::DownloadCourseInformation(
-                                             $who, $courseID, 
-                                             $cache{$who.':lastDownloadTime'});
-        &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, $who);
+        my @who = ($cache{'download'});
         $cache{'download'} = 'false';
+        if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false', 
+                                                             $cacheDB, 'true', 
+                                                             'false', $courseID,
+                                                             $r, $c) ne 'OK') {
+            untie(%cache);
+            return 'Stop at download individual';
+        }
     } elsif($cache{'DownloadAll'} ne 'false') {
         $cache{'DownloadAll'} = 'false';
         my @allStudents;
@@ -371,23 +375,14 @@
         } else {
             @allStudents = split(':::', $cache{'NamesOfStudents'});
         }
-        &Create_PrgWin($r);
-        my $count=1;
-        foreach (@allStudents) {
-            &Update_PrgWin(scalar(@allStudents),$count,$_,$r);
-            my $courseData = 
-                &Apache::loncoursedata::DownloadCourseInformation(
-                                             $_, $courseID, 
-                                             $cache{$_.':lastDownloadTime'});
-            &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, 
-                                                       $_);
-            if($c->aborted()) {
-                untie(%cache);
-                return 'aborted'; 
-            }
-            $count++;
+        if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents, 
+                                                             'false', 
+                                                             $cacheDB, 'true', 
+                                                             'true', $courseID,
+                                                             $r, $c) ne 'OK') {
+            untie(%cache);
+            return 'Stop at download all';
         }
-        &Close_PrgWin($r);
     }
 
     if($c->aborted()) {
@@ -400,43 +395,6 @@
     return ('OK', $students);
 }
 
-
-# Create progress
-sub Create_PrgWin {
-    my ($r)=@_;
-    $r->print(<<ENDPOP);
-    <script>
-    popwin=open('','popwin','width=400,height=100');
-    popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
-      '<title>LON-CAPA Statistics</title>'+
-      '<h4>Computation Progress</h4>'+
-      '<form name=popremain>'+
-      '<input type=text size=35 name=remaining value=Starting></form>'+
-      '</body></html>');
-    popwin.document.close();
-    </script>
-ENDPOP
-
-    $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
-    my ($totalStudents,$index,$name,$r)=@_;
-    $r->print('<script>popwin.document.popremain.remaining.value="'.
-              'Computing '.$index.'/'.$totalStudents.': '.
-              $name.'";</script>');
-    $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
-    my ($r)=@_;
-    $r->print('<script>popwin.close()</script>');
-    $r->rflush(); 
-}
-
-
 sub BuildClasslist {
     my ($cacheDB,$students,$studentInformation,$headings,$r)=@_;
 
@@ -556,13 +514,21 @@
     my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
                   "_$ENV{'user.domain'}_$courseID\_statistics.db";
 
+    $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics'));
+
     my ($returnValue, $students) = &PrepareData($c, $cacheDB, 
                                                 \@studentInformation, 
                                                 \@headings,$r);
     if($returnValue ne 'OK') {
-        $r->print('<html><body>'.$returnValue."\n".'</body></html>');
+        $r->print($returnValue."\n".'</body></html>');
         return OK;
     }
+    if(!$c->aborted()) {
+        &Apache::loncoursedata::CheckForResidualDownload($cacheDB, 
+                                                         'true', 'true',
+                                                         $courseID,
+                                                         $r, $c);
+    }
 
     my $GoToPage;
     if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
@@ -578,7 +544,6 @@
             $reports{'problem_analysis'} = 'Problem Analysis';
         }
 
-        $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics'));
         $r->print('<form name="Statistics" ');
         $r->print('method="post" action="/adm/statistics">');
         $r->print(&CreateMainMenu($cache{'Status'}, \%reports));
Index: loncom/interface/statistics/lonproblemanalysis.pm
diff -u loncom/interface/statistics/lonproblemanalysis.pm:1.4 loncom/interface/statistics/lonproblemanalysis.pm:1.5
--- loncom/interface/statistics/lonproblemanalysis.pm:1.4	Mon Aug  5 16:53:38 2002
+++ loncom/interface/statistics/lonproblemanalysis.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonproblemanalysis.pm,v 1.4 2002/08/05 20:53:38 stredwic Exp $
+# $Id: lonproblemanalysis.pm,v 1.5 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -41,7 +41,7 @@
 use Apache::lonnet();
 use GDBM_File;
 
-#my $jr;
+my $jr;
 
 sub BuildProblemAnalysisPage {
     my ($cacheDB, $r)=@_;
@@ -64,42 +64,24 @@
 sub BuildAnalyzePage {
     my ($cacheDB, $students, $courseID,$r)=@_;
 
-#    $jr = $r;
+    $jr = $r;
     my $c = $r->connection;
 
     my $Str = '</form>';
     my %cache;
-    &Create_PrgWin($r);
-    my $count=0;
-    foreach (@$students) {
-        &Update_PrgWin(scalar(@$students),$count,$_,$r);
-        if($c->aborted) {
-            return $Str;
-        }
-        my $downloadTime='';
-        if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
-            $downloadTime = $cache{$_.':lastDownloadTime'};
-            untie(%cache);
-        }
-        if($downloadTime eq 'Not downloaded') {
-            my $courseData = 
-                &Apache::loncoursedata::DownloadCourseInformation($_, 
-                                                                  $courseID);
-            if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
-                &Apache::loncoursedata::ProcessStudentData(\%cache, 
-                                                           $courseData, $_);
-                untie(%cache);
-            } else {
-                next;
-            }
-        }
-        $count++;
+    if(&Apache::loncoursedata::DownloadStudentCourseDataSeparate($students, 'true', 
+                                                                 $cacheDB, 'true', 
+                                                                 'true', $courseID, 
+                                                                 $r, $c) ne 'OK') {
+        $r->print($Str);
+        return;
     }
-    &Close_PrgWin($r);
+
 
     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
         $Str .= '<html><body>Unable to tie database.</body></html>';
-        return $Str;
+        $r->print($Str);
+        return;
     }
 
     my ($problemId, $part, $responseId)=split(':',$cache{'AnalyzeInfo'});
@@ -115,11 +97,14 @@
     my ($analyzeData) = &InitAnalysis($uri, $part, $responseId, $problem, 
                                       $students->[0], $courseID);
     if(defined($analyzeData->{'error'})) {
-        $Str .= 'Incorrect part requested.<br>';
-        return $Str;
+        $Str .= $analyzeData->{'error'}.'<br>Incorrect part requested.<br>';
+        $r->print($Str);
+        return;
     }
 
-    if($c->aborted()) {  untie(%cache); return $Str; }
+    $r->print($Str);
+    $Str = '';
+    if($c->aborted()) {  untie(%cache); return; }
 
     #compute the intervals
     &Interval($part, $problem, $interval, $analyzeData->{'concepts'}, 
@@ -128,37 +113,39 @@
     $title =~ s/\ /"_"/eg;
     $Str .= '<br><b>'.$uri.'</b>';
 
-    if($c->aborted()) {  untie(%cache); return $Str; }
+    $r->print($Str);
+    $Str = '';
+    if($c->aborted()) {  untie(%cache); return; }
          
     #Java script Progress window
-#    &Create_PrgWin();
-#    &Update_PrgWin("Starting-to-analyze-problem");
     for(my $index=0; $index<(scalar @$students); $index++) {
-        if($c->aborted()) {  untie(%cache); return $Str; }
-#	&Update_PrgWin($index);
-#	&OpStatus($problem, $students->[$index], $courseID, \%ConceptData,
-#                  $analyzeData->{'foil_to_concept'}, $analyzeData, \%cache);
-	&OpStatus($problem, $students->[$index], \%ConceptData, 
+        if($c->aborted()) {  untie(%cache); return; }
+	&OpStatus($problemId, $students->[$index], \%ConceptData, 
                   $analyzeData->{'foil_to_concept'}, $analyzeData, \%cache);
     }
-#    &Close_PrgWin();
 
     $Str .= '<br>';
     for (my $k=0; $k<$interval; $k++ ) {
         if($c->aborted()) {  untie(%cache); return $Str; }
 	$Str .= &DrawGraph($k, $title, $analyzeData->{'concepts'}, 
                            \%ConceptData);
+        $r->print($Str);
+        $Str = '';
     }
     for (my $k=0; $k<$interval; $k++ ) {
         if($c->aborted()) {  untie(%cache); return $Str; }
 	$Str .= &DrawTable($k, $analyzeData->{'concepts'}, \%ConceptData);
+        $r->print($Str);
+        $Str = '';
     }
     my $Answ=&Apache::lonnet::ssi($uri);
     $Str .= '<br><b>Here you can see the Problem:</b><br>'.$Answ;
+    $Str .= '<form>';
+    $r->print($Str);
 
     untie(%cache);
 
-    return $Str.'<form>';
+    return;
 }
 
 #---- Problem Analysis Web Page ----------------------------------------------
@@ -230,76 +217,29 @@
     return $Str;
 }
 
-# Create progress
-sub Create_PrgWin {
-    my ($r)=@_;
-    $r->print(<<ENDPOP);
-    <script>
-    popwin=open('','popwin','width=400,height=100');
-    popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
-      '<title>LON-CAPA Statistics</title>'+
-      '<h4>Computation Progress</h4>'+
-      '<form name=popremain>'+
-      '<input type=text size=35 name=remaining value=Starting></form>'+
-      '</body></html>');
-    popwin.document.close();
-    </script>
-ENDPOP
-
-    $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
-    my ($totalStudents,$index,$name,$r)=@_;
-    $r->print('<script>popwin.document.popremain.remaining.value="'.
-              'Computing '.$index.'/'.$totalStudents.': '.
-              $name.'";</script>');
-    $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
-    my ($r)=@_;
-    $r->print('<script>popwin.close()</script>');
-    $r->rflush(); 
-}
- 
 #---- END Problem Analysis Web Page ------------------------------------------
 
 #---- Analyze Web Page -------------------------------------------------------
 
 #restore the student submissions and finding the result
 sub OpStatus {
-    my ($problem, $student, $ConceptData, $foil_to_concept, 
+    my ($problemID, $student, $ConceptData, $foil_to_concept, 
         $analyzeData, $cache)=@_;
 
     my $ids = $analyzeData->{'parts'};
     my @True = ();
     my @False = ();
     my $flag=0;
-    my $latestVersion = $cache->{$student.':version:'.$problem};
-    if(!$latestVersion) {
-        return;
-    }
 
     my $tries=0;
-    for(my $version=1; $version<=$latestVersion; $version++) {
-        my $time=$cache->{$student.':'.$version.':'.$problem.':timestamp'};
 
-        foreach my $id (@$ids) {
-            my ($currentPart, undef) = split(/\./, $id);
-            #check if this is a repeat submission, if so skip it
-            next if($cache->{$student.':'.$version.':'.$problem.
-                             ':resource.'.$currentPart.'.previous'});
-            #if no solved this wasn't a real submission, ignore it
-            if(!defined($cache->{"$student:$version:$problem".
-                                 ":resource.$currentPart.solved"})) {
-                &Apache::lonxml::debug("skipping ");
-                next;
-            }
-            my $Resp = $cache->{$student.':'.$version.':'.$problem.
-                                ':resource.'.$id.'.submission'};
+    foreach my $id (@$ids) {
+        my ($part, $response) = split(/\./, $id);
+        my $time=$cache->{$student.':'.$problemID.':'.$part.':timestamp'};
+        my @submissions = split(':::', $cache->{$student.':'.$problemID.':'.
+                                                $part.':'.$response.
+                                                ':submission'});
+        foreach my $Resp (@submissions) {
             my %submission=&Apache::lonnet::str2hash($Resp);
             foreach (keys(%submission)) {
                 if($submission{$_}) {
@@ -441,14 +381,17 @@
                                         'grade_domain'   => $domain,
                                         'grade_courseid' => $courseID,
                                         'grade_symb'     => $problem));
-
-    my %Answer=();
-    %Answer=&Apache::lonnet::str2hash($Answ);
+    my ($a)=&Apache::lonnet::str2hashref($Answ);
+    my %b;
+    foreach (keys(%$a)) {
+        $b{&Apache::lonnet::unescape($_)} = $a->{$_};
+    }
+    my $Answer=\%b;
 
     my $found = 0;
     my @parts=();
     if(defined($responseId)) {
-        foreach (@{$Answer{'parts'}}) {
+        foreach (@{$Answer->{'parts'}}) {
             if($_ eq $part.'.'.$responseId) {
                 push(@parts, $_);
                 $found = 1;
@@ -456,7 +399,7 @@
             }
         }
     } else {
-        foreach (@{$Answer{'parts'}}) {
+        foreach (@{$Answer->{'parts'}}) {
             if($_ =~ /$part/) {
                 push(@parts, $_);
                 $found = 1;
@@ -473,23 +416,23 @@
     my @Concepts=();
     my %foil_to_concept;
     foreach my $currentPart (@parts) {
-        if(defined($Answer{$currentPart.'.concepts'})) {
-            foreach my $concept (@{$Answer{$currentPart.'.concepts'}}) {
+        if(defined($Answer->{$currentPart.'.concepts'})) {
+            foreach my $concept (@{$Answer->{$currentPart.'.concepts'}}) {
                 push(@Concepts, $concept);
-                foreach my $foil (@{$Answer{$currentPart.'.concept.'.
+                foreach my $foil (@{$Answer->{$currentPart.'.concept.'.
                                             $concept}}) {
                     $analyzeData{$currentPart.'.foil.value.'.$foil} =
-                        $Answer{$currentPart.'.foil.value.'.$foil};
+                        $Answer->{$currentPart.'.foil.value.'.$foil};
                     $foil_to_concept{$foil} = $concept;
                 }
             }
         } else {
-            foreach (keys(%Answer)) {
+            foreach (keys(%$Answer)) {
                 if(/$currentPart.foil\.value\.(.*)$/) {
                     push(@Concepts, $1);
                     $foil_to_concept{$1} = $1;
                     $analyzeData{$currentPart.'.foil.value.'.$1} =
-                        $Answer{$currentPart.'.foil.value.'.$1};
+                        $Answer->{$currentPart.'.foil.value.'.$1};
                 }
             }
         }
Index: loncom/interface/statistics/lonproblemstatistics.pm
diff -u loncom/interface/statistics/lonproblemstatistics.pm:1.18 loncom/interface/statistics/lonproblemstatistics.pm:1.19
--- loncom/interface/statistics/lonproblemstatistics.pm:1.18	Mon Aug 12 14:21:42 2002
+++ loncom/interface/statistics/lonproblemstatistics.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonproblemstatistics.pm,v 1.18 2002/08/12 18:21:42 albertel Exp $
+# $Id: lonproblemstatistics.pm,v 1.19 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -43,11 +43,14 @@
 use Apache::loncoursedata;
 use GDBM_File;
 
+my $jr;
 
 sub BuildProblemStatisticsPage {
     my ($cacheDB, $students, $courseID, $c, $r)=@_;
     my %cache;
 
+    $jr = $r;
+
     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
         return '<html><body>Unable to tie database.</body></html>';
     }
@@ -73,345 +76,69 @@
     $r->rflush();
 
     untie(%cache);
-    &Create_PrgWin($r);
-    my $count=0;
-    foreach (@$students) {
-        &Update_PrgWin(scalar(@$students),$count,$_,$r);
-        my $courseData = 
-            &Apache::loncoursedata::DownloadCourseInformation($_, $courseID);
-        last if ($c->aborted());
-        if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
-            &Apache::loncoursedata::ProcessStudentData(\%cache, 
-                                                       $courseData, $_);
-            untie(%cache);
-        }
-        $count++;
-    }
-    &Close_PrgWin($r);
+
+    &Apache::loncoursedata::DownloadStudentCourseDataSeparate($students,'true',
+                                                              $cacheDB,'true', 
+                                                              'true',$courseID,
+                                                              $r, $c);
     if($c->aborted()) { return; }
 
     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
         return '<html><body>Unable to tie database.</body></html>';
     }
 
-    my %Header = (0,"Homework Sets Order",1,"#Stdnts",2,"Tries",3,"Mod",
-                  4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"DoDiff",
-                  9,"S.D.",10,"Skew.",11,"D.F.1st",12,"D.F.2nd", 13, "Disc.");
+    my @Header = ("Homework Sets Order","#Stdnts","Tries","Mod",
+                  "Mean","#YES","#yes","%Wrng","DoDiff",
+                  "S.D.","Skew.","D.F.1st","D.F.2nd","Disc.");
     my $color=&setbgcolor(0);
 
-    my $state=$ENV{'form.ProblemStatisticsHeading'}; 
-
-    my $TempCache;
-
-    if ($state) {
-	$TempCache=&CacheStatisticsTable($state,\%cache,\%Header,
-					 $r,$color);
-    } else {    
-	my %discriminant=();
-	my @list=();
-	my %Discuss=&Apache::loncoursedata::LoadDiscussion($courseID);
-	my $index=0;
-	foreach (@$students) {
-	    $index++;
-	    &ExtractStudentData(\%cache, $_, \@list,\%Discuss, $r,
-                                \%discriminant);
-	}
-	my ($upper, $lower) = &Discriminant(\%discriminant,$r);
-	$TempCache= &BuildStatisticsTable(\%cache, $upper, $lower, 
-					   \@list, \%Header, $students,
-					   $r, $color);
-    }
+#    my %Discuss=&Apache::loncoursedata::LoadDiscussion($courseID);
+#    my ($upper, $lower) = &Discriminant(\%discriminant,$r);
+    my ($problemData) = &ExtractStudentData(\%cache, $students);
+    &CalculateStatistics($problemData);
+    &SortProblems($problemData, $cache{'ProblemStatisticsSort'},
+                  $cache{'ProblemStatisticsAscend'});
+    #$TempCache=
+    &BuildStatisticsTable(\%cache, $cache{'DisplayFormat'},
+                          $problemData, \@Header, $r, $color);
     untie(%cache);
 
-    foreach (keys %$TempCache) {
-        last if ($c->aborted());
-        if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
-	    $cache{$_}=$TempCache->{$_};
+#    foreach (keys %$TempCache) {
+#        last if ($c->aborted());
+#        if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
+#	    $cache{$_}=$TempCache->{$_};
+#            untie(%cache);
+#        }
+#    }
 
-            untie(%cache);
-        }
-    }
-    if($c->aborted()) { return; }
-    untie(%cache);
+#    if($c->aborted()) { return; }
+#    untie(%cache);
+
+    return;
 }
 
 
 #---- Problem Statistics Web Page ---------------------------------------
 
 sub CreateProblemStatisticsTableHeading {
-    my ($displayFormat,$sequenceSource,$sequenceTitle,$headings,$r)=@_;
-    if($displayFormat eq 'Display CSV Format') {
-        $r->print('<br>"'.$sequenceTitle.'","');
-        $r->print($sequenceSource.'"');
-	return;
-    }
-    if ($sequenceSource eq 'Sorted by: ') {
-	$r->print('<br><b>'.$sequenceSource.$sequenceTitle.'</b>');
-    } else {
-        $r->print('<br><a href="'.$sequenceSource.
-		  '" target="_blank">'.$sequenceTitle.'</a>');
-    }
-    my $Result = "\n".'<table border=2><tr><th>P#</th>'."\n";
-    for(my $nIndex=0; $nIndex < (scalar (keys %$headings)); $nIndex++) { 
-	$Result .= '<th>'.'<input type="submit" name="';
-        $Result .= 'ProblemStatisticsHeading" value="';
-        $Result .= $headings->{$nIndex}.'" />'.'</th>'."\n";
-    }
-    $Result .= "\n".'</tr>'."\n";    
-    $r->print($Result);
-    $r->rflush();
-}
-
-sub CloseTable {
-    my ($cache,$r)=@_;
-    if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
-	return;
-    }    
-    $r->print("\n".'</table>'."\n");
-    $r->rflush();
-}
-
-
-# Create progress
-sub Create_PrgWin {
-    my ($r)=@_;
-    $r->print(<<ENDPOP);
-    <script>
-    popwin=open('','popwin','width=400,height=100');
-    popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
-      '<title>LON-CAPA Statistics</title>'+
-      '<h4>Computation Progress</h4>'+
-      '<form name=popremain>'+
-      '<input type=text size=35 name=remaining value=Starting></form>'+
-      '</body></html>');
-    popwin.document.close();
-    </script>
-ENDPOP
-
-    $r->rflush();
-}
-
-# update progress
-sub Update_PrgWin {
-    my ($totalStudents,$index,$name,$r)=@_;
-    $r->print('<script>popwin.document.popremain.remaining.value="'.
-              'Computing '.$index.'/'.$totalStudents.': '.
-              $name.'";</script>');
-    $r->rflush();
-}
-
-# close Progress Line
-sub Close_PrgWin {
-    my ($r)=@_;
-    $r->print('<script>popwin.close()</script>');
-    $r->rflush(); 
-}
-
- 
-# ------ Dump the Student's DB file and handling the data for statistics table 
-sub ExtractStudentData {
-    my ($cache,$name,$list,$Discuss,$r,$discriminant)=@_;
-    my $totalTries = 0;
-    my $totalAwarded = 0;
-    my $spent=0;
-    my $spent_yes=0;
-    my $TotDiscuss=0;
-    my $TotalOpend = 0;
-    my $ProbSolved = 0;
-    my $ProbTot = 0;
-    my $TotFirst = 0;
-    my $TimeTot = 0;
-    my $Discussed=0;
-    my $discrim='';
-    my $tempSequenceOrder=100;
-
-#$Apache::lonxml::debug=1;
-#&Apache::lonhomework::showhash(%$cache);
-#$Apache::lonxml::debug=0;
+    my ($headings,$r)=@_;
 
-    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
-	my $tempProblemOrder=100;
-        if($cache->{'ProblemStatisticsMaps'} ne 'All Maps'  &&
-           $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
-            next;
-        }
-	$tempSequenceOrder++;
-
-        foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
-            my $problem = $cache->{$problemID.':problem'};
-            my $LatestVersion = $cache->{$name.':version:'.$problem};
-	    # Output dashes for all the parts of this problem if there
-            # is no version information about the current problem.
-            #if(!$LatestVersion) {
-            #    foreach my $part (split(/\:/,$cache->{$sequence.':'.
-            #                                          $problemID.
-            #                                          ':parts'})) {
-            #        $codes    .= "-,";
-            #        $attempts .= "0,"; 
-            #    }
-            #    next;
-            #}
-
-            my %partData=undef;
-	    $partData{'count'}=0;
-            # Initialize part data, display skips correctly
-            # Skip refers to when a student made no submissions on that
-            # part/problem.
-            foreach my $part (split(/\:/,$cache->{$sequence.':'.
-                                                  $problemID.
-                                                  ':parts'})) {
-		$tempProblemOrder++;
-		$partData{'count'}++;
-                $partData{$part.':order'}=$tempProblemOrder;
-                $partData{$part.':tries'}=0;
-                $partData{$part.':code'}='-';
-            }
-
-            # Looping through all the versions of each part, starting with the
-            # oldest version.  Basically, it gets the most recent 
-            # set of grade data for each part.
-	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
-		foreach my $part (split(/\:/,$cache->{$sequence.':'.
-                                                      $problemID.
-                                                      ':parts'})) {
-
-                    if(!defined($cache->{$name.":$Version:$problem".
-                                               ":resource.$part.solved"})) {
-                        # No grade for this submission, so skip
-                        next;
-                    }
-
-                    my $tries=0;
-                    my $time=0;
-                    my $awarded=0;
-		    $Discussed=0;
-                    my $code='-';
-
-                    $awarded = $cache->{"$name:$Version:$problem:resource.".
-                                        "$part.awarded"};
-                    $partData{$part.':awarded'} = ($awarded) ? $awarded : 0;
-                    $totalAwarded += $awarded;
-
-                    $tries = $cache->{"$name:$Version:$problem".
-                                      ":resource.$part.tries"};
-                    $partData{$part.':tries'} = ($tries) ? $tries : 0;
-                    $partData{$part.':wrong'} = $partData{$part.':tries'};
-                    $totalTries += $tries;
-
-                    my $val = $cache->{$name.":$Version:$problem".
-                                       ":resource.$part.solved"};
-                    if    ($val eq 'correct_by_student')   {$code = 'C';} 
-                    elsif ($val eq 'correct_by_override')  {$code = 'O';}
-                    elsif ($val eq 'incorrect_attempted')  {$code = 'I';} 
-                    elsif ($val eq 'incorrect_by_override'){$code = 'I';}
-                    elsif ($val eq 'excused')              {$code = 'x';}
-                    $partData{$part.':code'}=$code;
-                    if($partData{$part.':wrong'} ne 0 && 
-                       ($code eq 'C' || $code eq 'O')) {
-                        $partData{$part.':wrong'}--;
-                    }
-                }
-            }
-
-            # Loop through all the parts for the current problem in the 
-            # correct order and prepare the output
-	    my $partCounter=0;
-            foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
-                                         ':parts'})) {
-		$partCounter++;
-                my $Yes = 0;
-                if($partData{$_.':code'} eq 'C' || 
-                   $partData{$_.':code'} eq 'O') {
-                    $Yes=1;
-                }
-                my $pOrder=$partData{$_.':order'};
-                my $ptr = $tempSequenceOrder.':'.$pOrder.':'.$problemID;
-
-                if($partData{'count'} > 1) {
-                    $ptr .= "*(part $_)";
-                }
-                $discrim .= '&';
-
-		my ($pr_no,$dod)=split('&',$ptr);
-#		my $DoDiff=$DoDiff->{$dod};
-#               $r->print('<br>'.$name.'---'.$ptr.'==='.$DoDiff);
-
-                my $Fac = ($partData{$_.':tries'}) ? 
-                    ($partData{$_.':awarded'}/$partData{$_.':tries'}) : 0;
-                my $DisF;
-                if($Fac > 0 &&  $Fac < 1) { 
-                    $DisF = sprintf( "%.4f", $Fac );
-                } else {
-                    $DisF = $Fac;
-                }
-
-                if ($Discuss->{"$name:$problem"}) {
-		    $TotDiscuss++;
-                    $Discussed=1;
-                }
-                my $time = $cache->{"$name:$LatestVersion:$problem:timestamp"};
-                $discrim .= $tempSequenceOrder.'@'.$pOrder.'='.$DisF.'+'.$Yes;
-                $ptr .= '&'.$partData{$_.':tries'}.
-                        '&'.$partData{$_.':wrong'}.
-                        '&'.$partData{$_.':code'};
-                push (@$list, $ptr."&$Discussed");
-#                $r->print('<br>'.$_.$name.'---'.$ptr);
-		
-####		if ($DoDiff>0.85) {
-
-                $TimeTot += $time;
-
-                if ($Yes==1 && $partData{$_.':tries'}==1) {
-		    $TotFirst++;
-                }
-#		my $Acts= $Activity->{$name.':'.$problem};
-#		if ($Acts) {
-#		    my $Pt=&ProcAct( $Acts, $time );
-		    #my ($spe,$beg) = split(/\+/,$Pt);
-#                    my $spe= $Pt;
-#		    if ($Yes==1) {$spent_yes += $spe;}
-#		    $spent += $spe;
-		    #$Beg += $beg;
-#                   $r->print('<br>'.$name.'---'.$problem.'---'.$spe);
-#		}
-		$TotalOpend++;
-		$ProbTot++;
-
-                $tempProblemOrder++;
-            }
-        }
-    }
-    my $pstr;
-    if($totalTries) {
-	my $DisFac = ($totalAwarded/$totalTries);
-	my $DisFactor = sprintf( "%.4f", $DisFac );
-        my $TS = sprintf( "%.2f", $spent );
-        my $TS_yes = sprintf( "%.2f", $spent_yes );
-	$pstr=$DisFactor.':'.$name.':'.$ProbTot.':'.$TotalOpend.':'.
-              $totalTries.':'.$ProbSolved.':'.$TotFirst.':'.
-              $TS_yes.':'.$TS.':'.$TotDiscuss;
-	(%$discriminant)->{$pstr}=$discrim;
+    my $Str='';
+    $Str .= '<tr>'."\n";
+    $Str .= '<th bgcolor="#ffffe6">P#</th>'."\n";
+    foreach(@$headings) {
+	$Str .= '<th bgcolor="#ffffe6">'.'<a href="/adm/statistics?reportSelected=';
+        $Str .= &Apache::lonnet::escape('Problem Statistics');
+        $Str .= '&ProblemStatisticsSort=';
+        $Str .= &Apache::lonnet::escape($_).'">'.$_.'</a>&nbsp</th>'."\n";
     }
-}
+    $Str .= "\n".'</tr>'."\n";    
 
-sub NumericSort {
-    $a <=> $b;
-}
-
-sub OrderedSort  {
-    if ($ENV{'form.order'} eq 'Descending') {
-	$b <=> $a;
-    } else { 
-	$a <=> $b;
-    }
+    return $Str;
 }
 
-
-
 sub BuildStatisticsTable {
-    my ($cache,$upper,$lower,$list,$headings,$students,$r,$color)=@_;
-    my $NoElements = scalar @$list;
-    my @list=sort(@$list);
+    my ($cache,$displayFormat,$data,$headings,$r,$color)=@_;
 
 #6666666
 #    my $file="/home/httpd/perl/tmp/183d.txt";
@@ -427,129 +154,40 @@
 ##777777
 ##    $Str .= &Classify($discriminantFactor, $students);
 
-    my $p_count = 0;
-    my $dummy;
-    my $p_val;
-    my $ResId;
     my %TempCache;
-    my $cIdx=0;
-
-    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
-        if($cache->{'ProblemStatisticsMaps'} ne 'All Maps'  &&
-           $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
-            next;
-        }
-        &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'}, 
-                                             $cache->{$sequence.':source'},
-                                             $cache->{$sequence.':title'}, 
-                                             $headings,$r);
-	my ($tar,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,
-                                                   $list[$cIdx]);
-        my ($SqOrd,$PrOrd,$Prob)=split(/\:/,$tar);
-	$sequence+=100;
-	while ($SqOrd==$sequence && $cIdx<$NoElements) {
-	    my %storestats=();
-	    my $pOrd=$PrOrd;
-	    my $Temp = $Prob;
-	    my $MxTries = 0;
-	    my $TotalTries = 0;
-	    my $YES = 0;
-	    my $Incorrect = 0;
-	    my $Override = 0;
-	    my $StdNo = 0;
-	    my $DiscNo=0;
-	    my @StdLst;
-	    while ($pOrd==$PrOrd && $cIdx<$NoElements)
-	    {
-		$cIdx++;
-		$StdNo++;
-		$StdLst[ $StdNo ] = $Tries;
-		$TotalTries += $Tries;
-		if ( $MxTries < $Tries ) { $MxTries = $Tries; } 
-		if ( $Code eq 'C' ){ $YES++; }
-		elsif( $Code eq 'I' ) { $Incorrect++; }
-		elsif( $Code eq 'O' ) { $Override++; }
-		elsif( $Code eq '-' ) { $StdNo--; }
-		($tar,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,
-                                                     $list[$cIdx]);
-	        ($SqOrd,$PrOrd,$Prob)=split(/\:/,$tar);
-	    }
-
-	    $p_count++;
-	    my $Dummy;
-	    ($ResId,$Dummy)=split(/\*/,$Temp);
-	    $Temp = '<a href="'.$cache->{$ResId.':source'}.
-                '" target="_blank">'.$cache->{$ResId.':title'}.$Dummy.'</a>';
-
-#	    my $urlres = $cache->{$sequence.':source'});
-#check with Gerd
-	    #symb of the problem (already decluttered and cleaned)
-	    my $urlres = $cache->{$ResId.':problem'};
-
-#------------------------ Compute the Average of Tries about one problem
-	    my $Average = ($StdNo) ? $TotalTries/$StdNo : 0;
-
-	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___timestamp'}=time;
-	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___stdno'}=$StdNo;
-	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___avetries'}=$Average;
-
-#-------------------------------- Compute percentage of Wrong tries
-	    my $Wrong = ( $StdNo ) ? 100 * ( $Incorrect / $StdNo ) : 0;
-
-#-------------------------------- Compute Standard Deviation
-	    my $StdDev = 0; 
-	    if ( $StdNo > 1 ) {
-		for ( my $n = 0; $n < $StdNo; $n++ ) {
-		    my $Dif = $StdLst[ $n ]-$Average;
-		    $StdDev += $Dif*$Dif;
-		} 
-		$StdDev /= ( $StdNo - 1 );
-		$StdDev = sqrt( $StdDev );
-	    }
-
-#-------------------------------- Compute Degree of Difficulty
-	    my $DoDiff = 0;
-	    if( $TotalTries > 0 ) {
-		$DoDiff = 1 - ( ( $YES + $Override ) / $TotalTries );
-#	    $DoDiff =  ($TotalTries)/($YES + $Override+ 0.1);	    
-	    }
-       
-	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___difficulty'}=$DoDiff;
-
-#-------------------------------- Compute the Skewness
-	    my $Skewness = 0;
-	    my $Sum = 0; 
-	    if ( $StdNo > 0 && $StdDev > 0 ) {
-		for ( my $n = 0; $n < $StdNo; $n++ ) {
-		    my $Dif = $StdLst[ $n ]-$Average;
-		    $Skewness += $Dif*$Dif*$Dif;
-		} 
-		$Skewness /= $StdNo;
-		$Skewness /= $StdDev*$StdDev*$StdDev;
-	    }
-
-#--------------------- Compute the Discrimination Factors
-            my ($Up1,$Up2)=split(/\:/,$upper->{$sequence.'@'.$pOrd});
-	    my ($Lw1,$Lw2)=split(/\:/,$lower->{$sequence.'@'.$pOrd});
-
-	    my $Dis1 = $Up1 - $Lw1;
-	    my $Dis2 = $Up2 - $Lw2;
-	    my $_D1 = sprintf("%.2f", $Dis1);
-	    my $_D2 = sprintf("%.2f", $Dis2);
-
-#-----------------  Some restition in presenting the float numbers
-	    my $Avg = sprintf( "%.2f", $Average );
-	    my $Wrng = sprintf( "%.1f", $Wrong );
-	    my $SD = sprintf( "%.1f", $StdDev );
-	    my $DoD = sprintf( "%.2f", $DoDiff );
-	    my $Sk = sprintf( "%.1f", $Skewness );
-	    my $join = $sequence.'@'.$pOrd.'&'.$Temp.'&'.$StdNo.'&'.
-                       $TotalTries.'&'.$MxTries.'&'.$Avg.'&'.
-                       $YES.'&'.$Override.'&'.$Wrng.'&'.$DoD.'&'.
-		       $SD.'&'.$Sk.'&'.$_D1.'&'.$_D2.'&'.
-                       $DiscNo.'&'.$Prob;
+    my $problems = $data->{'problemList'};
+    if($displayFormat ne 'Display CSV Format') {
+        $r->print('<table border="0"><tr><td bgcolor="#777777">'."\n");
+        $r->print('<table border="0" cellpadding="3">'."\n");
+        $r->print(&CreateProblemStatisticsTableHeading($headings, $r));
+    } else {
+        $r->print('<br>');
+    }
 
-	    $TempCache{'CacheTable:'.($p_count-1)}=$join;
+    my $count = 1;
+    foreach(@$problems) {
+        my ($sequence,$problem,$part)=split(':', $_);
+#        my $problemRef = '<a href="'.$cache->{$problem.':source'}.
+#                '" target="_blank">'.$cache->{$problem.':title'}.'</a>';
+
+        my $ref = $cache->{$problem.':title'};
+        my $title = $cache->{$problem.':title'};
+        my $source = 'source';
+        my $tableData = join('&', $ref, $title, $source,
+                         $data->{$_.':studentCount'},
+                         $data->{$_.':totalTries'},
+                         $data->{$_.':maxTries'},
+                         sprintf("%.2f", $data->{$_.':mean'}),
+                         $data->{$_.':correct'},
+                         $data->{$_.':correctByOverride'},
+                         sprintf("%.1f", $data->{$_.':percentWrong'}),
+                         sprintf("%.2f", $data->{$_.':degreeOfDifficulty'}),
+                         sprintf("%.1f", $data->{$_.':standardDeviation'}),
+                         sprintf("%.1f", $data->{$_.':skewness'}),
+                         sprintf("%.2f", $data->{$_.':discriminationFactor1'}),
+                         sprintf("%.2f", $data->{$_.':discriminationFactor2'}),
+                         0); # 0 is for discussion, need to figure out
+#        $TempCache{'CacheTable:'.$_}=$join;
 
 #6666666
 #	    $r->print('<br>'.$out.'&'.$DoD);
@@ -557,26 +195,28 @@
 #6666666
 
 #check with Gerd
-	    $urlres=~/^(\w+)\/(\w+)/;
-	    if ($StdNo) {
-		&Apache::lonnet::put('nohist_resevaldata',\%storestats,
-				     $1,$2);
-	    }
+#        $urlres=~/^(\w+)\/(\w+)/;
+#        if ($StdNo) {
+#            &Apache::lonnet::put('nohist_resevaldata',\%storestats,
+#                                 $1,$2);
+#        }
 #-------------------------------- Row of statistical table
-            &TableRow($cache,$join,$cIdx,($p_count-1),$r,$color,
-                      \%TempCache);
-	}
-	$TempCache{'ProblemCount'}=$p_count;
-	&CloseTable($cache,$r);
+        &TableRow($displayFormat,$tableData,$count,$r,$color);
+#        $GraphDat->{'GraphGif:'.($count-1)}=$DoD.':'.$Wrng;
+        $count++;
     }
-###    &Close_PrgWin();
+#    $TempCache{'ProblemCount'}=$count;
+    if($cache->{'DisplayFormat'} ne 'Display CSV Format') {
+        $r->print('</table>'."\n");
+    }
+    $r->print('</td></tr></table>');
 #6666666
 #    close( OUT );
 #666666
     return \%TempCache;
 }
 
-
+=pod
 sub CacheStatisticsTable {
     my ($state,$cache,$headings,$r,$color)=@_;
     my @list = (); 
@@ -608,10 +248,11 @@
 	    if ($cIdx==$p_count) {
 		return \%TempCache;
 	    }
-	    &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'}, 
+	    $r->print(&CreateProblemStatisticsTableHeading(
+                                             $cache->{'DisplayFormat'}, 
                                              $cache->{$sequence.':source'},
                                              $cache->{$sequence.':title'}, 
-                                             $headings,$r);
+                                             $headings,$r));
 
 	    my ($tar)=split(/\&/,$list[$cIdx]);
 	    $tar=~s/\+//eg;
@@ -629,10 +270,11 @@
 	}
     }
     else {
-        &CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'}, 
+        $r->print(&CreateProblemStatisticsTableHeading(
+                                             $cache->{'DisplayFormat'}, 
                                              'Sorted by: ',
 					     $headings->{$pos-1},
-                                             $headings,$r);
+                                             $headings,$r));
 	for ( my $nIndex = 0; $nIndex < $p_count; $nIndex++ ) {
 	    my($Pre, $Post) = split(/\+/,$list[$nIndex]);
 	    &TableRow($cache,$Post,$nIndex,$nIndex,$r,$color,\%TempCache);
@@ -642,19 +284,18 @@
 
     return \%TempCache;
 }
-
+=cut
 
 sub TableRow {
-    my ($cache,$Str,$Idx,$RealIdx,$r,$color,$GraphDat)=@_;
-    my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
+    my ($displayFormat,$Str,$RealIdx,$r,$color)=@_;
+    my($ref,$title,$source,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
        $Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$DiscNo,$Prob)=split(/\&/,$Str);	
     my $Ptr;
-    if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
-        my ($ResId,$Dummy)=split(/\*/,$Prob);
+    if($displayFormat eq 'Display CSV Format') {
         $Ptr="\n".'<br>'.
-             "\n".'"'.($RealIdx+1).'",'.
-             "\n".'"'.$cache->{$ResId.':title'}.$Dummy.'",'.
-             "\n".'"'.$cache->{$ResId.':source'}.'",'.
+             "\n".'"'.$RealIdx.'",'.
+             "\n".'"'.$title.'",'.
+             "\n".'"'.$source.'",'.
              "\n".'"'.$StdNo.'",'.
              "\n".'"'.$TotalTries.'",'.
              "\n".'"'.$MxTries.'",'.
@@ -672,8 +313,8 @@
         $r->print("\n".$Ptr);
     } else {
         $Ptr="\n".'<tr>'.
-             "\n".'<td>'.($RealIdx+1).'</td>'.
-             "\n".'<td>'.$Temp.'</td>'.
+             "\n".'<td bgcolor="#ffffe6">'.$RealIdx.'</td>'.
+             "\n".'<td bgcolor="#ffffe6">'.$ref.'</td>'.
              "\n".'<td bgcolor='.$color->{"yellow"}.'> '.$StdNo.'</td>'.
              "\n".'<td bgcolor='.$color->{"yellow"}.'>'.$TotalTries.'</td>'.
              "\n".'<td bgcolor='.$color->{"yellow"}.'>'.$MxTries.'</td>'.
@@ -689,9 +330,9 @@
              "\n".'<td bgcolor='.$color->{"yellow"}.'> '.$DiscNo.'</td>';
         $r->print("\n".$Ptr.'</tr>' );
     }
-    $GraphDat->{'GraphGif:'.$RealIdx}=$DoD.':'.$Wrng;
-}
 
+    return;
+}
 
 # For loading the colored table for display or un-colored for print
 sub setbgcolor {
@@ -740,16 +381,16 @@
     $Ptr = '<table border="0">';
     $Ptr .= '<tr><td>';
     $Ptr .= '<b>#Stdnts</b></td>';
-    $Ptr .= '<td>Total Number of Students opened the problem.';
+    $Ptr .= '<td>Total number of students attempted the problem.';
     $Ptr .= '</td></tr><tr><td>';
     $Ptr .= '<b>Tries</b></td>';
-    $Ptr .= '<td>Total Number of Tries for solving the problem.';
+    $Ptr .= '<td>Total number of tries for solving the problem.';
     $Ptr .= '</td></tr><tr><td>';
     $Ptr .= '<b>Mod</b></td>';
-    $Ptr .= '<td>Maximunm Number of Tries for solving the problem.';
+    $Ptr .= '<td>Largest number of tries for solving the problem by a student.';
     $Ptr .= '</td></tr><tr><td>';
     $Ptr .= '<b>Mean</b></td>';
-    $Ptr .= '<td>Average Number of the tries. [ Tries / #Stdnts ]';
+    $Ptr .= '<td>Average number of tries. [ Tries / #Stdnts ]';
     $Ptr .= '</td></tr><tr><td>';
     $Ptr .= '<b>#YES</b></td>';
     $Ptr .= '<td>Number of students solved the problem correctly.';
@@ -757,9 +398,9 @@
     $Ptr .= '<b>#yes</b></td>';
     $Ptr .= '<td>Number of students solved the problem by override.';
     $Ptr .= '</td></tr><tr><td>';
-    $Ptr .= '<b>%Wrng</b></td>';
-    $Ptr .= '<td>Percentage of students tried to solve the problem ';
-    $Ptr .= 'but still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
+    $Ptr .= '<b>%Wrong</b></td>';
+    $Ptr .= '<td>Percentage of students who tried to solve the problem ';
+    $Ptr .= 'but is still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
     $Ptr .= '</td></tr><tr><td>';
     $Ptr .= '<b>DoDiff</b></td>';
     $Ptr .= '<td>Degree of Difficulty of the problem.  ';
@@ -792,8 +433,184 @@
 }
 
 #------- Processing upperlist and lowerlist according to each problem
+
+sub ExtractStudentData {
+    my ($cache, $students)=@_;
+
+#$Apache::lonxml::debug=1;
+#&Apache::lonhomework::showhash(%$cache);
+#$Apache::lonxml::debug=0;
+
+    my @problemList=();
+    my %problemData;
+    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
+        if($cache->{'ProblemStatisticsMaps'} ne 'All Maps'  &&
+           $cache->{'ProblemStatisticsMaps'} ne $cache->{$sequence.':title'}) {
+            next;
+        }
+
+        foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
+            foreach my $part (split(/\:/,$cache->{$sequence.':'.
+                                                  $problemID.
+                                                  ':parts'})) {
+                my $id = $sequence.':'.$problemID.':'.$part;
+                push(@problemList, $id);
+                my $totalTries = 0;
+                my $totalAwarded = 0;
+                my $correct = 0;
+                my $correctByOverride = 0;
+                my $studentCount = 0;
+                my $maxTries = 0;
+                my $totalFirst = 0;
+                my @studentTries=();
+                foreach(@$students) {
+                    my $code = $cache->{"$_:$problemID:$part:code"};
+
+                    if(defined($cache->{$_.':error'}) || $code eq ' ' ||
+                       $cache->{"$_:$problemID:NoVersion"} eq 'true') {
+                        next;
+                    }
+
+                    $studentCount++;
+                    my $tries =  $cache->{"$_:$problemID:$part:tries"};
+                    if($maxTries < $tries) {
+                        $maxTries = $tries;
+                    }
+                    $totalTries += $tries;
+                    push(@studentTries, $tries);
+
+                    my $awarded = $cache->{"$_:$problemID:$part:awarded"};
+                    $totalAwarded += $awarded;
+
+                    if($code eq '*') {
+                        $correct++;
+                        if($tries == 1) {
+                            $totalFirst++;
+                        }
+                    } elsif($code eq '+') {
+                        $correctByOverride++;
+                    }
+                }
+
+                $problemData{$id.':sequenceTitle'} = 
+                    $cache->{$sequence.':title'};
+                $problemData{$id.':studentCount'} = $studentCount;
+                $problemData{$id.':totalTries'} = $totalTries;
+                $problemData{$id.':studentTries'} = \@studentTries;
+                $problemData{$id.':totalAwarded'} = $totalAwarded;
+                $problemData{$id.':correct'} = $correct;
+                $problemData{$id.':correctByOverride'} = $correctByOverride;
+                $problemData{$id.':wrong'} = $studentCount - 
+                                             ($correct + $correctByOverride);
+                $problemData{$id.':maxTries'} = $maxTries;
+                $problemData{$id.':totalFirst'} = $totalFirst;
+            }
+        }
+    }
+
+    $problemData{'problemList'} = \@problemList;
+#                $Discussed=0;
+#                if($Discuss->{"$name:$problem"}) {
+#		    $TotDiscuss++;
+#                    $Discussed=1;
+#                }
+
+    return \%problemData;
+}
+
+sub SortProblems {
+    my ($problemData,$sortBy,$ascend)=@_;
+
+    if($sortBy eq "Homework Sets Order") {
+        return;
+    }
+
+    my $data;
+
+    if   ($sortBy eq "#Stdnts") { $data = ':studentCount'; }
+    elsif($sortBy eq "Tries")   { $data = ':totalTries'; }
+    elsif($sortBy eq "Mod")     { $data = ':maxTries'; }
+    elsif($sortBy eq "Mean")    { $data = ':mean'; }
+    elsif($sortBy eq "#YES")    { $data = ':correct'; }
+    elsif($sortBy eq "#yes")    { $data = ':correctByOverride'; }
+    elsif($sortBy eq "%Wrng")   { $data = ':percentWrong'; }
+    elsif($sortBy eq "DoDiff")  { $data = ':degreeOfDifficulty'; }
+    elsif($sortBy eq "S.D.")    { $data = ':standardDeviation'; }
+    elsif($sortBy eq "Skew.")   { $data = ':skewness'; }
+    elsif($sortBy eq "D.F.1st") { $data = ':discriminantFactor1'; }
+    elsif($sortBy eq "D.F.2nd") { $data = ':discriminantFactor2'; }
+    elsif($sortBy eq "Disc.")   { $data = ''; }
+    else                        { return; }
+
+    my $problems = $problemData->{'problemList'};
+    my @orderedProblems = 
+        sort { $problemData->{$a.$data} <=> $problemData->{$b.$data} }
+             @$problems;
+    if($ascend eq 'Descending') {
+        @orderedProblems = reverse(@orderedProblems);
+    }
+
+    $problemData->{'problemList'} = \@orderedProblems;
+
+    return;
+}
+
+sub CalculateStatistics {
+    my ($data)=@_;
+
+    my $problems = $data->{'problemList'};
+    foreach(@$problems) {
+        # Mean
+        $data->{$_.':mean'} = ($data->{$_.':studentCount'}) ? 
+            ($data->{$_.':totalTries'} / $data->{$_.':studentCount'}) : 0;
+
+        # %Wrong
+        $data->{$_.':percentWrong'} = ($data->{$_.':studentCount'}) ?
+            (($data->{$_.':wrong'} / $data->{$_.':studentCount'}) * 100.0) : 
+            100.0;
+
+        # Degree of Difficulty
+        $data->{$_.':degreeOfDifficulty'} = ($data->{$_.':totalTries'}) ?
+            (1 - (($data->{$_.':correct'} + $data->{$_.':correctByOverride'}) /
+                  $data->{$_.':totalTries'})) : 0;
+
+        # Factor in mean
+        my $studentTries = $data->{$_.':studentTries'};
+        foreach(my $index=0; $index < scalar(@$studentTries); $index++) {
+            $studentTries->[$index] -= $data->{$_.':mean'};
+        }
+        my $sumSquared = 0;
+        my $sumCubed = 0;
+        foreach(@$studentTries) {
+            my $squared = ($_ * $_);
+            my $cubed = ($squared * $_);
+            $sumSquared += $squared;
+            $sumCubed += $cubed;
+        }
+
+        # Standard deviation
+        $data->{$_.':standardDeviation'} = ($data->{$_.':studentCount'} - 1) ?
+            ((sqrt($sumSquared)) / ($data->{$_.':studentCount'} - 1)) : 0;
+
+        # Skewness
+        my $standardDeviation = $data->{$_.':standardDeviation'};
+        $data->{$_.':skewness'} = ($data->{$_.':standardDeviation'}) ?
+            (((sqrt($sumSquared)) / $data->{$_.':studentCount'}) / 
+             ($standardDeviation * $standardDeviation * $standardDeviation)) :
+             0;
+
+        # Discrimination Factor 1
+        $data->{$_.':discriminationFactor1'} = 0;
+
+        # Discrimination Factor 2
+        $data->{$_.':discriminationFactor2'} = 0;
+    }
+
+    return;
+}
+
 sub ProcessDiscriminant {
-    my ($List,$r) = @_;
+    my ($List) = @_;
     my @sortedList = sort (@$List);
     my $Count = scalar @sortedList;
     my $Problem;
@@ -806,7 +623,7 @@
     my $nStudent=0;
     my %Proc=undef;
     while ($nIndex<$Count) {
-#        $r->print("<br> $nIndex) $sortedList[$nIndex]");
+#        $jr->print("<br> $nIndex) $sortedList[$nIndex]");
 	($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
 	@Dis=split(/\+/,$tmp);
 	my $Temp = $Problem;
@@ -819,7 +636,7 @@
 	    @Dis=split(/\+/,$tmp);
 	} while ( $Problem eq $Temp && $nIndex < $Count );
 	$Proc{$Temp}=($Sum1/$nStudent).':'.($Sum2/$nStudent);
-#        $r->print("<br> $nIndex) $Temp --> ($nStudent) $Proc{$Temp}");
+#        $jr->print("<br> $nIndex) $Temp --> ($nStudent) $Proc{$Temp}");
 	$Sum1=0;
 	$Sum2=0;
 	$nStudent=0;
@@ -830,7 +647,7 @@
 
 #------- Creating Discimination factor   
 sub Discriminant {
-    my ($discriminant,$r)=@_;
+    my ($discriminant)=@_;
     my @discriminantKeys=keys(%$discriminant);
     my $Count = scalar @discriminantKeys;
 
@@ -854,8 +671,8 @@
             }
         }
     }
-    my %DisUp =  &ProcessDiscriminant(\@UpList,$r);
-    my %DisLow = &ProcessDiscriminant(\@LowList,$r);
+    my %DisUp =  &ProcessDiscriminant(\@UpList);
+    my %DisLow = &ProcessDiscriminant(\@LowList);
 
     return (\%DisUp, \%DisLow);
 }   
Index: loncom/interface/statistics/lonstudentassessment.pm
diff -u loncom/interface/statistics/lonstudentassessment.pm:1.7 loncom/interface/statistics/lonstudentassessment.pm:1.8
--- loncom/interface/statistics/lonstudentassessment.pm:1.7	Mon Aug  5 16:53:38 2002
+++ loncom/interface/statistics/lonstudentassessment.pm	Mon Aug 12 20:37:18 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonstudentassessment.pm,v 1.7 2002/08/05 20:53:38 stredwic Exp $
+# $Id: lonstudentassessment.pm,v 1.8 2002/08/13 00:37:18 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -104,35 +104,59 @@
     my $selected=0;
     $r->print('<pre>'."\n");
     foreach (@$students) {
-        if($c->aborted()) {  return $Str; }
+        if($c->aborted()) { return $Str; }
         next if ($_ ne $selectedName && 
                  $selectedName ne 'All Students');
         $selected = 1;
-        my $courseData; 
-        my $downloadTime='';
-        if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
-            $downloadTime = $cache{$_.':lastDownloadTime'};
-            untie(%cache);
-        }
-        if($downloadTime eq 'Not downloaded') {
-            $courseData = 
-                &Apache::loncoursedata::DownloadCourseInformation($_, 
-                                                                  $courseID);
-            unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
-                next;
-            }
-            &Apache::loncoursedata::ProcessStudentData(\%cache, 
-                                                       $courseData, $_);
-            untie(%cache);
-        }
 
+        my @who = ($_);
+        next if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'true', 
+                                                             $cacheDB, 'true', 
+                                                             'false', $courseID,
+                                                             $r, $c) ne 'OK');
         next if($c->aborted());
 
         if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
+            my @before=();
+            my @after=();
+            my @updateColumn=();
+            my $foundUpdate = 0;
+            foreach(@$infoKeys) {
+                if(/updateTime/) {
+                    $foundUpdate=1;
+                    push(@updateColumn, $_);
+                    next;
+                }
+                if($foundUpdate) {
+                    push(@after, $_);
+                } else {
+                    push(@before, $_);
+                }
+            }
             my $displayString = 'DISPLAYDATA'.$spacing;
             $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
                                                          \%cache, $_,
-                                                         $infoKeys,
+                                                         \@before,
+                                                         $displayString,
+                                                         'preformatted'));
+
+            if($foundUpdate) {
+                $displayString = '';
+                $displayString .= '<a href="/adm/statistics?reportSelected=';
+                $displayString .= &Apache::lonnet::escape('Student Assessment');
+                $displayString .= '&download='.$_.'">';
+                $displayString .= 'DISPLAYDATA</a>'.$spacing;
+                $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
+                                                                   \%cache, $_,
+                                                                   \@updateColumn,
+                                                                   $displayString,
+                                                                   'preformatted'));
+            }
+
+            $displayString = 'DISPLAYDATA'.$spacing;
+            $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
+                                                         \%cache, $_,
+                                                         \@after,
                                                          $displayString,
                                                          'preformatted'));
             $r->print(&StudentReport(\%cache, $_, $spacing, $sequenceKeys));
@@ -214,7 +238,7 @@
                                                    $displayString,
                                                    'preformatted');
 
-    $displayString  = '<td align="left"><pre>DISPLAYDATA'.$spacing;
+    $displayString  = '<td align="left"><pre>DISPLAYDATAFORMATTING'.$spacing;
     $displayString .= '</pre></td>'."\n";
     $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
                                                    $sequenceKeys,
@@ -265,109 +289,42 @@
     my ($username,$domain)=split(':',$name);
 
     my $Str = '';
+    if(defined($cache->{$name.':error'})) {
+        return $Str;
+    }
     if($cache->{$name.':error'} =~ /course/) {
         $Str .= '<b><font color="blue">No course data for student </font>';
         $Str .= '<font color="red">'.$username.'.</font></b><br>';
         return $Str;
     }
 
-    my $Version;
-    my $problemsCorrect = 0;
-    my $totalProblems   = 0;
-    my $problemsSolved  = 0;
-    my $numberOfParts   = 0;
-#    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
     foreach my $sequence (@$showSequences) {
         my $characterCount=0;
         foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
             my $problem = $cache->{$problemID.':problem'};
-            my $LatestVersion = $cache->{$name.':version:'.$problem};
-
-            # Output dashes for all the parts of this problem if there
-            # is no version information about the current problem.
-            if(!$LatestVersion) {
-                foreach my $part (split(/\:/,$cache->{$sequence.':'.
-                                                      $problemID.
-                                                      ':parts'})) {
-                    $Str .= ' ';
-                    $totalProblems++;
-                    $characterCount++;
-                }
-                next;
-            }
-
-            my %partData=undef;
-            # Initialize part data, display skips correctly
-            # Skip refers to when a student made no submissions on that
-            # part/problem.
-            foreach my $part (split(/\:/,$cache->{$sequence.':'.
-                                                  $problemID.
-                                                  ':parts'})) {
-                $partData{$part.':tries'}=0;
-                $partData{$part.':code'}=' ';
-            }
-
-            # Looping through all the versions of each part, starting with the
-            # oldest version.  Basically, it gets the most recent 
-            # set of grade data for each part.
-	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
-                foreach my $part (split(/\:/,$cache->{$sequence.':'.
-                                                      $problemID.
-                                                      ':parts'})) {
-
-                    if(!defined($cache->{$name.":$Version:$problem".
-                                               ":resource.$part.solved"})) {
-                        # No grade for this submission, so skip
-                        next;
-                    }
-
-                    my $tries=0;
-                    my $code=' ';
-
-                    $tries = $cache->{$name.':'.$Version.':'.$problem.
-                                      ':resource.'.$part.'.tries'};
-                    $partData{$part.':tries'}=($tries) ? $tries : 0;
-
-                    my $val = $cache->{$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;
-                }
-            }
-
             # All grades (except for versionless parts) are displayed as links
             # to their submission record.  Loop through all the parts for the
             # current problem in the correct order and prepare the output links
-            $Str .= '<a href="/adm/grades?symb=';
-            $Str .= &Apache::lonnet::escape($problem);
-            $Str .= '&student='.$username.'&domain='.$domain;
-            $Str .= '&command=submission">'; 
             foreach(split(/\:/,$cache->{$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++;
+                if(defined($cache->{$name.':'.$problemID.':NoVersion'}) ||
+                   $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ') {
+                    $Str .= ' ';
+                    next;
                 }
+                $Str .= '<a href="/adm/grades?symb=';
+                $Str .= &Apache::lonnet::escape($problem);
+                $Str .= '&student='.$username.'&domain='.$domain;
+                $Str .= '&command=submission">'; 
+                my $code = $cache->{$name.':'.$problemID.':'.$_.':code'};
+                my $tries = $cache->{$name.':'.$problemID.':'.$_.':tries'};
+                if($code eq '*' && $tries < 10 && $tries ne '') {
+                    $code = $tries;
+                }
+                $Str .= $code;
+                $Str.='</a>';
             }
-            $Str.='</a>';
         }
 
         # Output the number of correct answers for the current sequence.
@@ -377,19 +334,17 @@
         $spacesNeeded -= 3;
         $Str .= (' 'x$spacesNeeded);
 
-	my $outputProblemsCorrect = sprintf( "%3d", $problemsCorrect );
+	my $outputProblemsCorrect = sprintf("%3d", $cache->{$name.':'.$sequence.
+                                                            ':problemsCorrect'});
 	$Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
-	$problemsSolved += $problemsCorrect;
-	$problemsCorrect=0;
-
         $Str .= $spacing;
     }
 
     # Output the total correct problems over the total number of problems.
     # I don't like this type of formatting, but it is a solution.  Need
     # a way to dynamically determine the space requirements.
-    my $outputProblemsSolved = sprintf( "%4d", $problemsSolved );
-    my $outputTotalProblems  = sprintf( "%4d", $totalProblems );
+    my $outputProblemsSolved = sprintf("%4d", $cache->{$name.':problemsSolved'});
+    my $outputTotalProblems  = sprintf("%4d", $cache->{$name.':totalProblems'});
     $Str .= '<font color="#000088">'.$outputProblemsSolved.
 	    ' / '.$outputTotalProblems.'</font>';
 

--stredwic1029199038--