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

stredwic lon-capa-cvs@mail.lon-capa.org
Wed, 17 Jul 2002 12:53:00 -0000


This is a MIME encoded message

--stredwic1026910380
Content-Type: text/plain

stredwic		Wed Jul 17 08:53:00 2002 EDT

  Modified files:              
    /loncom/interface	lonstatistics.pm 
  Log:
  Anyone currently working on lonstatistics and relying on the global variables
  like %hash, will have some intergration changes to make.  I will be happy to
  help.  The key is most of the data is now stored in the cache database.  Also
  look to loncoursedata.pm to see the key names.
  
  Merged the use of loncoursedata.pm for gathering student course data.  Also
  using the cache data instead of the global variables.  The process is about
  75% complete.  Student Assessment and Problem Analysis pages both work the
  same as before the changes.  Except for a couple of interface changes I made.
  Now there is a new student and previous student buttons on the student assessment
  page for cycling through the student list.  Changed all students to no student
  selected because all students would not display anything anyways.  May add back
  a all students which will display all students.  Removed the section selection
  from only the student assessment page.  I may add this back.  The problem 
  analysis->analyze page was already having the problem with the broken graph.gif.
  The first fix for redhat 7.3 users was to download and install the lonbarcode.
  The next fix will have to fix the posting data.  Currently it is not reading
  the information from ssi back correctly thus the post data is missing and
  no rendering of the graph.  This problem will be further explored.
  
  The problem statistics page is about halfway done.  The interface is up, but
  you will get no data.  The will be remedied over the next few days.  I wanted
  to submit because I was going to work a new scheme for downloading student
  course data.
  
  
--stredwic1026910380
Content-Type: text/plain
Content-Disposition: attachment; filename="stredwic-20020717085300.txt"

Index: loncom/interface/lonstatistics.pm
diff -u loncom/interface/lonstatistics.pm:1.26 loncom/interface/lonstatistics.pm:1.27
--- loncom/interface/lonstatistics.pm:1.26	Fri May 31 12:02:11 2002
+++ loncom/interface/lonstatistics.pm	Wed Jul 17 08:53:00 2002
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # (Publication Handler
 #
-# $Id: lonstatistics.pm,v 1.26 2002/05/31 16:02:11 minaeibi Exp $
+# $Id: lonstatistics.pm,v 1.27 2002/07/17 12:53:00 stredwic Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -42,6 +42,7 @@
 use Apache::lonnet();
 use Apache::lonhomework;
 use Apache::loncommon;
+use Apache::loncoursedata;
 use HTML::TokeParser;
 use GDBM_File;
 
@@ -49,45 +50,16 @@
 my %hash;
 my %CachData;
 my %GraphDat;
-my %OpResp;
-my %maps;
 my %mapsort;
-my %section;
-my %StuBox;
-my %DiscFac;
-my %DisUp;
-my %DisLow;
-my $UpCnt;
-my $CurMap;
-my $CurSec;
-my $CurStu;
-my @cols;
-my @list;
-my @students;
-my $p_count;
 my $Pos;
 my $r;
-my $OpSel1;
-my $OpSel2;
-my $OpSel3;
-my $OpSel4;
 my $GData;
-my $cid;
-my $firstres;
-my $lastres;
-my $DiscFlag;
-my $HWN;
-my $P_Order;
 my %color;
 my %foil_to_concept;
 my @Concepts;
 my %ConceptData;
-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");
 my %Answer = ();
 
-
 sub Activity {
     my $file="/home/minaeibi/activity.log";
     my $userid='adamsde1';
@@ -133,26 +105,29 @@
 #    }
 }
 
-
+#---- Analyze Web Page ---------------------------------------------------
 
 sub InitAnalysis {
-    my ($rid, $student)=@_;
-    my ($uname,$udom)=split(/\:/,$student);
-    $rid=~/(\d+)\.(\d+)/;
-    my $symb=&Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'.
-	     &Apache::lonnet::declutter($hash{'src_'.$rid});
-    my $URI = $hash{'src_'.$rid};
-    my $Answ=&Apache::lonnet::ssi($URI,('grade_target' => 'analyze',
-                                  'grade_username' => $uname,
-                                  'grade_domain' => $udom,
-                                  'grade_courseid' => $cid,
-                                  'grade_symb' => $symb));
-#    my $Answ=&Apache::lonnet::ssi($URI,('grade_target' => 'analyze'));
+    my ($uri,$part,$problem,$student,$courseID)=@_;
+    my ($username,$userdomain)=split(/\:/,$student);
 
-    (my $garbage,$Answ)=split(/_HASH_REF__/,$Answ,2);
+    # Render the student's view of the problem.  $Answ is the problem 
+    # Stringafied
+    my $Answ=&Apache::lonnet::ssi($uri,('grade_target'   => 'analyze',
+                                        'grade_username' => $username,
+                                        'grade_domain'   => $userdomain,
+                                        'grade_courseid' => $courseID,
+                                        'grade_symb'     => $problem));
+#    my $Answ=&Apache::lonnet::ssi($uri,('grade_target' => 'analyze'));
+
+#    (undef,$Answ)=split(/_HASH_REF__/,$Answ,2);
     %Answer=();
     %Answer=&Apache::lonnet::str2hash($Answ);
 
+#    foreach (sort(keys(%Answer))) {
+#        $r->print($_.'  '.$Answer{$_}.'<br>');
+#    }
+
     my $parts='';
     foreach my $elm (@{$Answer{"parts"}}) {
 	$parts.="$elm,";
@@ -171,69 +146,72 @@
 	    #$ConceptData{$foil} = $Answer{"$parts.foil.value.$foil"};
 	}
     }
-    return $symb;
-}
 
+    return;
+}
 
 sub Interval {
-    my ($rid,$part,$symb)=@_;
-    my $Int=$ConceptData{"Interval"};
-    my $due = &Apache::lonnet::EXT('resource.$part.duedate',$symb)+1;
-    my $opn = &Apache::lonnet::EXT('resource.$part.opendate',$symb);
-    my $add=int(($due-$opn)/$Int);
-    $ConceptData{"Int.0"}=$opn;
-    for (my $i=1;$i<$Int;$i++) {
-	$ConceptData{"Int.$i"}=$opn+$i*$add;
+    my ($part,$symb)=@_;
+    my $interval=$ConceptData{"Interval"};
+    my $due  = &Apache::lonnet::EXT('resource.'.$part.'.duedate',$symb)+1;
+    my $open = &Apache::lonnet::EXT('resource.'.$part.'.opendate',$symb);
+    my $add=int(($due-$open)/$interval);
+    $ConceptData{'Interval.0'}=$open;
+    for (my $i=1;$i<$interval;$i++) {
+	$ConceptData{'Interval.'.$i}=$open+$i*$add;
     }
-    $ConceptData{"Int.$Int"}=$due;     
-    for (my $i=0;$i<$Int;$i++) {
+    $ConceptData{'Interval.'.$interval}=$due;     
+    for (my $i=0;$i<$interval;$i++) {
 	for (my $n=0; $n<=$#Concepts; $n++ ) {
 	    my $tmp=$Concepts[$n];
-	    $ConceptData{"$tmp.$i.true"}=0;
-	    $ConceptData{"$tmp.$i.false"}=0;
+	    $ConceptData{$tmp.'.'.$i.'.true'}=0;
+	    $ConceptData{$tmp.'.'.$i.'.false'}=0;
 	}
     }
 }
 
-
 sub ShowOpGraph {
-    my ($InpStr, $Int_No)=@_;
-    my ($rid,$part)=split(/\:/,substr($InpStr,8));
-    $ConceptData{"Interval"}=$Int_No;
+    my ($cache, $students, $courseID)=@_;
+    my $uri      = $cache->{'AnalyzeURI'};
+    my $part     = $cache->{'AnalyzePart'};
+    my $problem  = $cache->{'AnalyzeProblem'};
+    my $title    = $cache->{'AnalyzeProblem'};
+    my $interval = $cache->{'Interval'};
+    $ConceptData{"Interval"} = $interval;
+
     #Initialize the option response true answers
-    my $symb=&InitAnalysis($rid,$students[0]);
+    &InitAnalysis($uri, $part, $problem, $students->[0],$courseID);
+
     #compute the intervals
-    &Interval($rid,$part,$symb);
-    my $URI = $hash{'src_'.$rid};
-    my $Src = $hash{'title_'.$rid};
-    $Src =~ s/\ /"_"/eg;
-    $r->print('<br><b>'.$URI.'</b>');
+    &Interval($part,$problem);
+
+    $title =~ s/\ /"_"/eg;
+    $r->print('<br><b>'.$uri.'</b>');
     $r->rflush();
     
     #Java script Progress window
     &Create_PrgWin();
-    &Update_PrgWin("Starting to analyze problem");
-    for (my $index=0;$index<=$#students;$index++) {
-	&Update_PrgWin($index);
-	&OpStatus($rid,$students[$index]);
+    &Update_PrgWin("Starting to analyze problem",0,0,'');
+    for(my $index=0; $index<(scalar @$students); $index++) {
+	&Update_PrgWin(scalar @$students, $index+1, $students->[$index]);
+	&OpStatus($problem, $students->[$index], $courseID);
     }
     &Close_PrgWin();
 
     $r->print('<br>');
-    for (my $k=0; $k<$Int_No; $k++ ) {
-	&DrawGraph($k,$Src);
+    for(my $k=0; $k<$interval; $k++ ) {
+	&DrawGraph($k,$title);
     }
-    for (my $k=0; $k<$Int_No; $k++ ) {
+    for(my $k=0; $k<$interval; $k++ ) {
 	&DrawTable($k);
     }
 #$Apache::lonxml::debug=1;
 #&Apache::lonhomework::showhash(%ConceptData);
 #$Apache::lonxml::debug=0;
-    my $Answ=&Apache::lonnet::ssi($URI);
+    my $Answ=&Apache::lonnet::ssi($uri);
     $r->print("<br><b>Here you can see the Problem:</b><br>$Answ");
 }
 
-
 sub DrawTable {
     my $k=shift;
     my $Max=0;
@@ -288,85 +266,43 @@
 
 
 sub DrawGraph {
-    my ($k,$Src)=@_;
+    my ($currentInterval,$title)=@_;
     my $Max=0;
     my @data1;
     my @data2;
 
     # Adjust Data and find the Max 
-    for (my $n=0; $n<=$#Concepts; $n++ ) {
+    for(my $n=0; $n<=$#Concepts; $n++ ) {
 	my $tmp=$Concepts[$n];
-	$data1[$n]=$ConceptData{"$tmp.$k.true"};
-	$data2[$n]=$ConceptData{"$tmp.$k.false"};
+	$data1[$n]=$ConceptData{$tmp.'.'.$currentInterval.'.true'};
+	$data2[$n]=$ConceptData{$tmp.'.'.$currentInterval.'.false'};
 	my $Sum=$data1[$n]+$data2[$n];
-	if ( $Max<$Sum ) {$Max=$Sum;}
+	if($Max < $Sum) { $Max = $Sum; }
     }
-    for (my $n=0; $n<=$#Concepts; $n++ ) {
-	if ($data1[$n]+$data2[$n]<$Max) {
+    for(my $n=0; $n<=$#Concepts; $n++) {
+	if($data1[$n]+$data2[$n]<$Max) {
 	    $data2[$n]+=$Max-($data1[$n]+$data2[$n]);
 	}
     }
-    my $P_No = $#data1+1;
+    my $P_No = scalar @data1;
 
-    if ( $Max > 1 ) { 
+    if($Max > 1) { 
 	$Max += (10 - $Max % 10);
 	$Max = int($Max);
-    } else { $Max = 1; }
+    } else { 
+        $Max = 1;
+    }
 
-    my $Titr=($ConceptData{'Interval'}>1) ? $Src.'_interval_'.($k+1) : $Src;
+    my $Titr=($ConceptData{'Interval'}>1) ? 
+        $title.'_interval_'.($currentInterval+1) : $title;
 #    $GData=$Titr.'&Concepts'.'&'.'Answers'.'&'.$Max.'&'.$P_No.'&'.$data1.'&'.$data2;
-    $GData="$Titr&Concepts&Answers&$Max&$P_No&".
-           (join(',',@data1)).'&'.(join(',',@data2));
+    $GData  = $Titr.'&Concepts&Answers&'.$Max.'&'.$P_No.'&';
+    $GData .= (join(',',@data1)).'&'.(join(',',@data2));
 
     $r->print('<IMG src="/cgi-bin/graph.gif?'.$GData.'" border=1/>');
 }
 
 
-sub AnalyzeProblem {
-    # selecting the number of intervals
-    my $OpSel='';
-    my $CurInt = $ENV{'form.interval'};
-    if ($CurInt eq '') {$CurMap = '1';}
-    my $Ptr = '<br><b>Select number of intervals</b>'."\n".
-       	      '<select name="interval">'."\n";                     	     	     
-    for (my $n=1;$n<=7;$n++) {	          
-	$Ptr .= '<option';
-        if ($CurInt eq $n) {$Ptr .= ' selected';}     
-	$Ptr .= '>'.$n."</option>"."\n";	     
-    }
-    $Ptr .= '</select>'."\n";
-    $r->print( $Ptr );
-
-    #the table of option response problems
-    $r->print('<br><b> Option Response Problems in this course:</b><br><br>');
-    my $Str = "\n".'<table border=2>'.
-              "\n".'<tr>'.
-              "\n".'<th> # </th>'.
-	      "\n".'<th> Problem Title </th>'.
-	      "\n".'<th> Resource </th>'.
-	      "\n".'<th> Address </th>'.
-	      "\n".'</tr>';
-
-     my $P_No=1;
-     foreach (sort keys %OpResp) {
-	 my ($rid,$part)=split(/\:/,$OpResp{$_});
-	 my $Temp = '<a href="'.$hash{'src_'.$rid}.
-                    '" target="_blank">'.$hash{'title_'.$rid}.'</a>';
-	 $Str .= "\n"."<tr>".
-	         "\n"."<td> $P_No </td>".
-                 "\n"."<td bgcolor=".$color{"green"}."> ".$Temp." </td>".
-                 "\n"."<td bgcolor=".$color{"yellow"}."> ".$hash{'src_'.$rid}." </td>".
-	         "\n"."<td> ".'<input type="submit" name="sort" value="'.'Analyze_'.$rid.'" />'.'</td>'.
-                 "\n"."</tr>";
-	 $P_No++;
-     }
-     $Str .= "\n".'</table>';
-     $Str .= "\n".'</form>';
-     $r->print($Str);
-     $r->rflush();	
-}
-
-
 sub Decide {
     #deciding the true or false answer belongs to each interval
     my ($type,$foil,$time)=@_; 
@@ -379,13 +315,11 @@
 
 #restore the student submissions and finding the result
 sub OpStatus {
-    my ($rid,$student)=@_;
-    my ($uname,$udom)=split(/\:/,$student);
+    my ($problem, $student, $courseID)=@_;
+    my ($username,$userdomain)=split(/':'/,$student);
     my $code='U';
-    $rid=~/(\d+)\.(\d+)/;
-    my $symb=&Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'.
-	     &Apache::lonnet::declutter($hash{'src_'.$rid});
-    my %reshash=&Apache::lonnet::restore($symb,$cid,$udom,$uname);
+    my %reshash=&Apache::lonnet::restore($problem, $courseID, $userdomain, 
+                                         $username);
     my @True = ();
     my @False = ();
     my $flag=0;
@@ -422,604 +356,245 @@
     }
 }
 
+#---- END Analyze Web Page ----------------------------------------------
+
+#---- Problem Statistics Web Page ---------------------------------------
 
 #------- Processing upperlist and lowerlist according to each problem
-sub ProcessDisc {
-    my @List = @_;
-    @List = sort (@List);
-    my $Count = $#List+1;
-    my $Prb;
+sub ProcessDiscriminant {
+    my ($List) = @_;
+    my @sortedList = sort (@$List);
+    my $Count = scalar @sortedList;
+    my $Problem;
     my @Dis;
     my $Slvd=0;
     my $tmp;
     my $Sum1=0;
     my $Sum2=0;
-    my $nIdx=0;
-    my $nStud=0;
-    my %Proc;
-    undef %Proc;
-    while ($nIdx<$Count) {
-	($Prb,$tmp)=split(/\=/,$List[$nIdx]);
+    my $nIndex=0;
+    my $nStudent=0;
+    my %Proc=undef;
+    while ($nIndex<$Count) {
+	($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
 	@Dis=split(/\+/,$tmp);
-	my $Temp = $Prb;
+	my $Temp = $Problem;
 	do {
-	    $nIdx++;
-	    $nStud++;
+	    $nIndex++;
+	    $nStudent++;
 	    $Sum1 += $Dis[0];
 	    $Sum2 += $Dis[1];
-	    ($Prb,$tmp)=split(/\=/,$List[$nIdx]);
+	    ($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
 	    @Dis=split(/\+/,$tmp);
-	} while ( $Prb eq $Temp && $nIdx < $Count );
-#	$Proc{$Temp}=($Sum1/$nStud).':'.$nStud;
-	$Proc{$Temp}=($Sum1/$nStud).':'.($Sum2/$nStud);
-#       $r->print("$nIdx) $Temp --> ($nStud) $Proc{$Temp} <br>");
+	} while ( $Problem eq $Temp && $nIndex < $Count );
+#	$Proc{$Temp}=($Sum1/$nStudent).':'.$nStudent;
+	$Proc{$Temp}=($Sum1/$nStudent).':'.($Sum2/$nStudent);
+#       $r->print("$nIndex) $Temp --> ($nStudent) $Proc{$Temp} <br>");
 	$Sum1=0;
 	$Sum2=0;
-	$nStud=0;
+	$nStudent=0;
     }
+
     return %Proc;
 }
 
 
 #------- Creating Discimination factor   
 sub Discriminant {
-    my $Count=0;
-    foreach (keys(%DiscFac)){ 
-	$Count++;
-    }
-    $UpCnt = int(0.27*$Count);
+    my ($discriminantFactor)=@_;
+    my @discriminantKeys=keys(%$discriminantFactor);
+    my $Count = scalar @discriminantKeys;
+
+    my $UpCnt = int(0.27*$Count);
     my $low=0;
     my $up=$Count-$UpCnt;
     my @UpList=();
     my @LowList=();
+
     $Count=0;
-    foreach my $key (sort(keys(%DiscFac))){ 
+    foreach my $key (sort(@discriminantKeys)) { 
 	$Count++;    
-        #$r->print("<br>$Count) $key = $DiscFac{$key}");
-	if ($low < $UpCnt || $Count > $up) {
-	    $low++;
-	    my $str=$DiscFac{$key};
-	    foreach(split(/\:/,$str)){
-		if ($_) {
-		    if ($low<$UpCnt){push(@LowList,$_);}
-		    else {push(@UpList,$_);}
-		}
-	    }
-	}
+	if($low < $UpCnt || $Count > $up) {
+            $low++;
+            my $str=$discriminantFactor->{$key};
+            foreach(split(/\:/,$str)){
+                if($_) {
+                    if($low<$UpCnt) { push(@LowList,$_); }
+                    else            { push(@UpList,$_);  }
+                }
+            }
+        }
     }
-    %DisUp=&ProcessDisc(@UpList);
-    %DisLow=&ProcessDisc(@LowList);
+    my %DisUp =  &ProcessDiscriminant(\@UpList);
+    my %DisLow = &ProcessDiscriminant(\@LowList);
+
+    return (\%DisUp, \%DisLow);
 }
 
-   
 sub NumericSort {          
     $a <=> $b;
 }
 
-# ------ Create different Student Report 
-sub StudentReport {
-    my ($sname,$sdom)=@_;
-    if ( $sname eq 'All Students' ) {
-	$r->print( '<h3><font color=blue>WARNING: 
-                    Please select a student</font></h3>' );
+sub CreateProblemStatisticsTableHeading {
+    my ($displayFormat,$sequenceSource,$sequenceTitle,$headings)=@_;
+    if($displayFormat eq 'Display CSV Format') {
+        $r->print('<br>"'.$sequenceTitle.'","');
+        $r->print($sequenceSource.'"');
 	return;
     }
-    my %result = &Apache::lonnet::dump($cid,$sdom,$sname);
-    my $ResId;
-    my $PrOrd;
-    my $Code;
-    my $Tries;
-    my $TotalTries = 0;
-    my $ParCr = 0;
-    my $Wrongs;
-    my %TempHash;
-    my $Version;
-    my $LatestVersion;
-    my $PtrTry='';
-    my $PtrCod='';
-    my $SetNo=0;
-    my $Str = "\n".'<table border=2>'.
-              "\n".'<tr>'.
-              "\n".'<th> # </th>'.
-	      "\n".'<th> Set Title </th>'.
-	      "\n".'<th> Results </th>'.
-	      "\n".'<th> Tries </th>'.
-	      "\n".'</tr>';
-    my ($temp)=keys(%result);
-    unless ($temp=~/^(con_lost|error|no_such_host)/i) {
-        foreach my $CurCol (@cols) {
-	    if (!$CurCol){
-		my $Set=&Apache::lonnet::declutter($hash{'map_id_'.$1});
-		if ( $Set ) {
-		    $SetNo++;
-		    $Str .= "\n"."<tr>".
-			    "\n"."<td> $SetNo </td>".
-                            "\n"."<td> $Set </td>".
-                            "\n"."<td> $PtrCod </td>".
-                            "\n"."<td> $PtrTry</td>".
-                            "\n"."</tr>";
-		}
-		$PtrTry='';
-		$PtrCod='';
-		next; 
-	    }
-	    ($PrOrd,$ResId)=split(/\:/,$CurCol);
-            $ResId=~/(\d+)\.(\d+)/;
-            my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} );
-            if ( $CurMap ne 'All Maps' ) {
-		my ( $ResMap, $NameMap ) = split(/\=/,$CurMap);
-		if ( $Map ne $ResMap ) { next; }
-	    }
-	    my $meta=$hash{'src_'.$ResId};
-	    my $PartNo = 0;
-	    undef %TempHash;
-	    foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))){
-		if ($_=~/^stores\_(\w+)\_tries$/) {
-                    my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
-		    if ( $TempHash{"$Part"} eq '' ) { 
-			$TempHash{"$Part"} = $Part;
-			$TempHash{$PartNo}=$Part;
-			$TempHash{"$Part.Code"} = '-';  
-			$TempHash{"$Part.PrOrd"} = $PrOrd+$PartNo;  
-			$PartNo++;
-		    }
-		}
-            }
 
-            my $Prob = $Map.'___'.$2.'___'.
-                       &Apache::lonnet::declutter( $hash{'src_'.$ResId} );
-            $Code='U';
-            $Tries = 0;
-            $Wrongs = 0;
-  	    $LatestVersion = $result{"version:$Prob"};
-	    if ( $LatestVersion ) {
-		for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {
-		    my $vkeys = $result{"$Version:keys:$Prob"};
-		    my @keys = split(/\:/,$vkeys);		
-  
-		    foreach my $Key (@keys) {		  
-			if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {
-			    my $Part = $1;
-			    $Tries = $result{"$Version:$Prob:resource.$Part.tries"};
-			    $TempHash{"$Part.Tries"} = ($Tries) ? $Tries : 0; 
-			    $TotalTries += $Tries;
-			    my $Val = $result{"$Version:$Prob:resource.$Part.solved"};
-			    if ( $Val eq 'correct_by_student' )
-                                { $Wrongs = $Tries - 1; $Code = 'Y'; } 
-			    elsif ( $Val eq 'correct_by_override' )
-                                { $Wrongs = $Tries - 1; $Code = 'y'; }                        
-			    elsif ( $Val eq 'incorrect_attempted' || 
-                                $Val eq 'incorrect_by_override' )
-		                { $Wrongs = $Tries; $Code = 'N'; }
-			    $TempHash{"$Part.Code"} = $Code;
-			    $TempHash{"$Part.Wrongs"} = $Wrongs;
-			}
-     		    }
-                }
-		for ( my $n = 0; $n < $PartNo; $n++ ) {		  
-		    my $part = $TempHash{$n};
-		    if ($PtrTry ne '') {$PtrTry .= ',';}
-		    $PtrTry .= "$TempHash{$part.'.Tries'}";
-                    $PtrCod .= "$TempHash{$part.'.Code'}";    
-		}
-            }
-	    else { 
-		for(my $n=0; $n<$PartNo; $n++) { 
-		    if ($PtrTry ne '') {$PtrTry .= ',';}
-		    $PtrTry .= "0";
-                    $PtrCod .= "-"; 
-		}
-	    }
-        }
-    }
-    $Str .= "\n".'</table>';
-    $r->print($Str);
-    $r->rflush();
-}
+    $r->print('<br><a href="'.$sequenceSource.
+              '" target="_blank">'.$sequenceTitle.'</a>');
 
-sub CreateTable {
-    my ($Hd, $Hid)=@_;
-    if ($ENV{'form.showcsv'}) { 
-	if ( $Hd == 1 ) {
-	    $r->print('<br>"'.$hash{'title_'.$Hid}.'","'.$hash{'src_'.$Hid}.'"');
-	}
-	return;
-    }
-    my $ColNo=0;
-    foreach (keys(%Header)){ 
-	$ColNo++;
-    } 
-    if ( $Hd == 1 ) {
-	$r->print('<br><a href="'.$hash{'src_'.$Hid}.
-                  '" target="_blank">'.$hash{'title_'.$Hid}.'</a>');
-    }
-    my $Result = "\n".'<table border=2>';
-    $Result .= '<tr><th>P#</th>'."\n";
-    for ( my $nIdx=0; $nIdx < $ColNo; $nIdx++ ) { 
-	$Result .= '<th>'.'<input type="submit" name="sort" value="'.
-                   $Header{$nIdx}.'" />'.'</th>'."\n";
+    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->print($Result);
     $r->rflush();
 }
 
 sub CloseTable {
-    if ($ENV{'form.showcsv'}) {
+    my ($cache)=@_;
+    if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
 	return;
     }    
     $r->print("\n".'</table>'."\n");
     $r->rflush();
 }
- 
-# ------------------------------------------- Prepare Statistics Table
-sub PreStatTable {
 
-    my $CacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
-                  "_$ENV{'user.domain'}_$cid\_statistics.db";
-    my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
-                  "_$ENV{'user.domain'}_$cid\_graph.db";
-    my $OpSel11='';
-    my $OpSel12='';
-    my $OpSel13='';
-    my $Status = $ENV{'form.status'};
-    if ( $Status eq 'Any' ) { $OpSel13='selected'; }
-    elsif ($Status eq 'Expired' ) { $OpSel12 = 'selected'; }
-    else { $OpSel11 = 'selected'; }
-
-    my $Ptr = '';
-    $Ptr .= '<br><b> Student Status: &nbsp; </b>'."\n".
-            '<select name="status">'. 
-            '<option '.$OpSel11.' >Active</option>'."\n".
-            '<option '.$OpSel12.' >Expired</option>'."\n".
-	    '<option '.$OpSel13.' >Any</option> </select> '."\n";
-    $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type=submit name=sort value="Recalculate Statistics"/>'."\n";
-
-    $Ptr .= '<br><b> Sorting Type: &nbsp; </b>'."\n".
-            '<select name="order"> <option '.$OpSel1.' >Ascending</option>'."\n".
-	    '<option '.$OpSel2.'>Descending</option> </select> '."\n";
-    $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type="submit" name="sort" value="DoDiff Graph" />'."\n";
-    $Ptr .= '&nbsp;&nbsp;&nbsp;';
-    $Ptr .= '<input type="submit" name="sort" value="%Wrong Graph" />'."\n";
-
-    $Ptr .= '<pre>'.
-    '<b>  #Stdnts</b>: Total Number of Students opened the problem.<br>'. 
-    '<b>  Tries  </b>: Total Number of Tries for solving the problem.<br>'. 
-    '<b>  Mod    </b>: Maximunm Number of Tries for solving the problem.<br>'. 
-    '<b>  Mean   </b>: Average Number of the tries. [ Tries / #Stdnts ]<br>'.
-    '<b>  #YES   </b>: Number of students solved the problem correctly.<br>'. 
-    '<b>  #yes   </b>: Number of students solved the problem by override.<br>'.
-    '<b>  %Wrng  </b>: Percentage of students tried to solve the problem but'.
-    ' still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]<br>'.
-#    '  DoDiff : Degree of Difficulty of the problem. [ Tries/(#YES+#yes+0.1) ]<br>'. Kashy formula
-    '<b>  DoDiff </b>: Degree of Difficulty of the problem. [ 1 - ((#YES+#yes) / Tries) ]<br>'. #Gerd formula
-    '<b>  S.D.  </b> : Standard Deviation of the tries.'.
-    '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1)'.
-    ' where Xi denotes every student\'s tries ]<br>'.
-    '<b>  Skew.  </b>: Skewness of the students tries.'.
-	' [ (sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3) ]<br>'.
-    '<b>  Dis.F. </b>: Discrimination Factor: A Standard for '.
-	'evaluating the problem according to a Criterion<br>'.
-	'<b>           [Applied Criterion in %27 Upper Students - '.
-	'Applied the same Criterion in %27 Lower Students]</b><br>'.
-    '<b>           1st Criterion</b> for Sorting the Students: '.
-	'<b>Sum of Partial Credit Awarded / Total Number of Tries</b><br>'.
-    '<b>           2nd Criterion</b> for Sorting the Students: '.
-	'<b>Total number of Correct Answers / Total Number of Tries</b>'.	
-            '</pre>';
-
-    $r->print($Ptr);
-    
-    $r->print('Output CSV format: <input type=checkbox name=showcsv onClick="submit()"');
-    if ($ENV{'form.showcsv'}) { $r->print(' checked'); }
-    $r->print('>');
-
-    $r->rflush();	
-
-    if ((-e "$CacheDB")&&($ENV{'form.sort'} ne 'Recalculate Statistics')) {
-	if (tie(%CachData,'GDBM_File',"$CacheDB",&GDBM_READER,0640)) {
-	    tie(%GraphDat,'GDBM_File',$GraphDB,&GDBM_WRCREAT,0640);
-	    &Cache_Statistics();
-        }
-        else {
-	    $r->print("Unable to tie hash to db file");
-        }
-    }
-    else {
-	if (tie(%CachData,'GDBM_File',$CacheDB,&GDBM_WRCREAT,0640)) {
-	    tie(%GraphDat,'GDBM_File',$GraphDB,&GDBM_WRCREAT,0640);
-	    foreach (keys %DiscFac) {delete $CachData{$_};}
-	    foreach (keys %CachData) {delete $CachData{$_};}
-	    $DiscFlag=0;
-	    &Build_Statistics();
-	}
-        else {
-	    $r->print("Unable to tie hash to db file");
+# ------ Dump the Student's DB file and handling the data for statistics table 
+sub ExtractStudentData {
+    my ($cache,$name)=@_;
+    my %discriminantFactor;
+    my @list=();
+
+    my $totalTries = 0;
+    my $totalAwarded = 0;
+    my $tempProblemOrder=0;
+    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
+        if($cache->{'ProblemStatisticsMap'} ne 'All Maps'  &&
+           $cache->{'ProblemStatisticsMap'} ne $cache->{$sequence.':title'}) {
+            next;
         }
-    }
-
-#    $r->print('Total instances of the problems : '.($p_count*($#students+1)));
-    untie(%CachData);
-    untie(%GraphDat);
-}
 
+        my $Dis = '';
+        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;
+            # 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'}='-';
+            }
 
-# ------------------------------------- Find the section of student in a course
-
-sub usection {
-    my ($udom,$unam,$courseid,$ActiveFlag)=@_;
-    $courseid=~s/\_/\//g;
-    $courseid=~s/^(\w)/\/$1/;
-
-    my %result=&Apache::lonnet::dump('roles',$udom,$unam);
-    my ($checkForResult)=keys(%result);
-    if ($checkForResult=~/^(con_lost|error|no_such_host)/i) {
-	return -1;
-    }
-    foreach my $key (keys (%result)) {
-	my $value=$result{$key};
-        if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
-            my $section=$1;
-            if ($key eq $courseid.'_st') { $section=''; }
-	    my ($dummy,$end,$start)=split(/\_/,$value);
-	    if ( $ActiveFlag ne 'Any' ) {
-		my $now=time;
-		my $notactive=0;
-		if ($start) {
-		    if ($now<$start) { $notactive=1; }
-		}
-		if ($end) {
-		    if ($now>$end) { $notactive=1; }
-		}
-		if ((($ActiveFlag eq 'Expired') && $notactive == 1) || 
-                    (($ActiveFlag eq 'Active') && $notactive == 0 ) ) {
-		    return $section;
-		}
-		else { return '-1'; } 
-	    }
-	    return $section;
-        }
-    }
-    return '-1';
-}
+            # 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;
+                    my $code='U';
+
+                    $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
+            foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
+                                         ':parts'})) {
+                my $Yes = 0;
+                if($partData{$_.':code'} eq 'C' || 
+                   $partData{$_.':code'} eq 'O') {
+                    $Yes=1;
+                }
+                #my $ptr = "$hash{'title_'.$ResId}";
+                my $ptr = $tempProblemOrder.'&'.$problemID;
 
-# ------ Dump the Student's DB file and handling the data for statistics table 
-sub ExtractStudentData {
-    my $student=shift;
-    my ($sname,$sdom) = split( /\:/, $student );
-    my %result = &Apache::lonnet::dump($cid,$sdom,$sname);
-    my $ResId;
-    my $PrOrd;
-    my $Dis = '';
-    my $Code;
-    my $Tries;
-    my $ParCr;
-    my $TotalTries = 0;
-    my $TotalOpend = 0;
-    my $ProbSolved = 0;
-    my $ProbTot = 0;
-    my $TimeTot = 0;
-    my $TotParCr = 0;
-    my $Wrongs;
-    my %TempHash;
-    my $Version; 
-    my $LatestVersion;
-    my $SecLimit;
-    my $MapLimit;
-    my ($temp)=keys(%result);
-    unless ($temp=~/^(con_lost|error|no_such_host)/i) {
-        foreach my $CurCol(@cols) {
-	    ($PrOrd,$ResId)=split(/\:/,$CurCol);
-	    if ( !$CurCol ) { next; }
-            $ResId=~/(\d+)\.(\d+)/;
-	    my $MapId=$1;
-	    my $PrbId=$2;
-            my $MapOrg = $hash{'map_id_'.$MapId};
-            my $Map = &Apache::lonnet::declutter($MapOrg);
-            if ( $CurMap ne 'All Maps' ) {
-		my ( $ResMap, $NameMap ) = split(/\=/,$CurMap);
-		if ( $Map ne $ResMap ) { next; }
-	    }
-	    my $meta=$hash{'src_'.$ResId};
-	    my $PartNo = 0;
-	    $Dis .= ':';
-	    undef %TempHash;
-
-	    foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) { 
-		if ($_=~/^stores\_(\w+)\_tries$/) {
-                    my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
-		    if ( $TempHash{"$Part"} eq '' ) { 
-			$TempHash{"$Part"} = $Part;
-			$TempHash{$PartNo}=$Part;
-			$TempHash{"$Part.Code"} = 'U';  
-			$TempHash{"$Part.PrOrd"} = $PrOrd+$PartNo;
-			$PartNo++;
-		    }
-                    #my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
-		}
-            }
-            &Apache::lonnet::declutter( $hash{'src_'.$ResId} );
-	    my $URI = $hash{'src_'.$ResId};
-            my $Prob = $Map.'___'.$PrbId.'___'.
-                       &Apache::lonnet::declutter($URI);
-            $Code='U';
-            $Tries = 0;
-	    $ParCr = 0;
-            $Wrongs = 0;
-  	    $LatestVersion = $result{"version:$Prob"};        
-	    if ( $LatestVersion ) {
-		for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {
-		    my $vkeys = $result{"$Version:keys:$Prob"};
-		    my @keys = split(/\:/,$vkeys);		
-		    foreach my $Key (@keys) {		  
-			if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {
-			    my $Part = $1;
-			    $Tries = $result{"$Version:$Prob:resource.$Part.tries"};
-			    $ParCr = $result{"$Version:$Prob:resource.$Part.awarded"};
-			    my $Time = $result{"$Version:$Prob:timestamp"};
-			    $TempHash{"$Part.Time"} = ($Time) ? $Time : 0;
-			    $TempHash{"$Part.Tries"} = ($Tries) ? $Tries : 0;
-			    $TempHash{"$Part.ParCr"} = ($ParCr) ? $ParCr : 0;        
-			    $TotalTries += $TempHash{"$Part.Tries"};
-			    $TotParCr += $TempHash{"$Part.ParCr"};
-			    my $Val = $result{"$Version:$Prob:resource.$Part.solved"};
-			    if ( $Val eq 'correct_by_student' )
-                               { $Wrongs = $Tries - 1; $Code = 'C'; } 
-			    elsif ( $Val eq 'correct_by_override' )
-                               { $Wrongs = $Tries - 1; $Code = 'O'; }                        
-			    elsif ( $Val eq 'incorrect_attempted' || 
-                                $Val eq 'incorrect_by_override' )
-		               { $Wrongs = $Tries; $Code = 'I'; }
-			    $TempHash{"$Part.Code"} = $Code;
-			    $TempHash{"$Part.Wrongs"} = $Wrongs;
-			}
-     		    }
-                } 
-		for ( my $n = 0; $n < $PartNo; $n++ ) {		  
-		    my $part = $TempHash{$n};
-		    my $Yes = 0;
-                    if ( $TempHash{$part.'.Code'} eq 'C' ||
-                         $TempHash{$part.'.Code'} eq 'O'  ) 
-		       {$ProbSolved++;$Yes=1;}		
-
- #		    my $ptr = "$hash{'title_'.$ResId}";
-		    my $ptr = $TempHash{$part.'.PrOrd'}.'&'.$ResId;
-
-		    if ( $PartNo > 1 ) {                
-			$ptr .= "*(part $part)";
-			$Dis .= '&';
-		    }
-		    my $Fac = ($TempHash{"$part.Tries"}) ? 
-                              ($TempHash{"$part.ParCr"}/$TempHash{"$part.Tries"}) : 0;
-		    my $DisF;
-		    if ( $Fac > 0 &&  $Fac < 1 ) { 
-			$DisF = sprintf( "%.4f", $Fac );
-		    }
-		    else {$DisF = $Fac;}
-#		    $DisF .= '+'.$TempHash{"$part.Time"};33333333
-		    $TimeTot += $TempHash{"$part.Time"};
-		    $Dis .= $TempHash{$part.'.PrOrd'}.'='.$DisF.'+'.$Yes;
-		    $ptr .= "&$TempHash{$part.'.Tries'}".
-		            "&$TempHash{$part.'.Wrongs'}".
-                            "&$TempHash{$part.'.Code'}";
-		    push (@list, $ptr);
-		    $TotalOpend++;
-		    $ProbTot++;
-		}
+                if($_ > 1) {
+                    $ptr .= "*(part $_)";
+                    $Dis .= '&';
+                }
+                my $Fac = ($partData{$_.':Tries'}) ? 
+                    ($partData{$_.':awarded'}/$partData{$_.':tries'}) : 0;
+                my $DisF;
+                if($Fac > 0 &&  $Fac < 1) { 
+                    $DisF = sprintf( "%.4f", $Fac );
+                } else {
+                    $DisF = $Fac;
+                }
+                $Dis .= $tempProblemOrder.'='.$DisF.'+'.$Yes;
+                $ptr .= '&'.$partData{$_.'.Tries'}.
+                        '&'.$partData{$_.'.Wrongs'}.
+                        '&'.$partData{$_.'.Code'};
+                push (@list, $ptr);
+                $tempProblemOrder++;
             }
-	    #else { 
-		#for(my $n=0; $n<$PartNo; $n++) {
-		#    push (@list, "$TempHash{'0'.'.PrOrd'}.':'.$ResId:0:0:U");
-		#    $ProbTot++; 
-		#}
-	    #}
         }
-	if ( $TotalTries ) {
-	    my $DisFac = ( $TotalTries ) ? ($TotParCr/$TotalTries) : 0;
+        if($totalTries) {
+	    my $DisFac = ($totalAwarded/$totalTries);
 	    my $DisFactor = sprintf( "%.4f", $DisFac );
-	    $DiscFac{$DisFactor}=$Dis;
-	    #my $time;
-	    #if ($ProbSolved){
-		#$time = int(($TimeTot/$ProbSolved)-10000000);
-	    #}
-	    #$DiscFac{($DisFactor.':'.$sname.':'.$ProbTot.':'.$TotalOpend.':'.
-            #          $TotalTries.':'.$ProbSolved.':'.$time)}=$Dis;
+	    $discriminantFactor{$DisFactor}=$Dis;
 	}
     }
-    #$r->print($sname.' PrCr= '.$TotParCr.' Slvd= '.$ProbSolved.' Tries='.$TotalTries.'<br>');
-}
-
 
-
-# ------------------------------------------------------------ Build page table
-sub tracetable {
-    my ($rid,$beenhere)=@_;
-    my $IsMap=0;
-    $rid=~/(\d+)\.(\d+)/;
-    $maps{&Apache::lonnet::declutter($hash{'map_id_'.$1})}='';#$hash{'title_'.$rid}; 
-    #$maps{$HWN}=$hash{'title_'.$rid}; 
-    unless ($beenhere=~/\&$rid\&/) {
-       $beenhere.=$rid.'&'; 
-       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;
-	       $P_Order++;
-	       $HWN=$P_Order;
-               $mapsort{$HWN} = $rid.':';
-	       $IsMap=1;
- 
-               #$maps{&Apache::lonnet::declutter($hash{'src_'.$rid})}= 
-               #      $hash{'title_'.$rid}; 
-           }
-           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.'&');
-
-	       $cols[$#cols+1]=($P_Order+1).':'.$frid;
-      
-	       my $meta=$hash{'src_'.$frid};
-	       my $PartNo = 0;
-	       my $Part;
-	#       if ($IsMap==0){
-               if ($meta) {
-		   if ($meta=~/\.(problem|exam|quiz|assess|survey|form)$/) {
-		       foreach (split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
-			   if ($_=~/^stores\_(\w+)\_tries$/) {
-			       $Part=&Apache::lonnet::metadata($meta,$_.'.part');
-			       $P_Order++;
-			       $mapsort{$HWN} .= '&'.$P_Order;
-			       $PartNo++;
-			       #$r->print('<br>'.$PartNo.'---'.$P_Order);
-			   }
-			   foreach my $K(split(/\,/,&Apache::lonnet::metadata($meta,'packages'))) {
-			       if ($K=~/^optionresponse\_($Part)\_(\w+)$/) {
-				   #$r->print('<br>'.$_.'...'.$P_Order.'---'.$Part);
-				   $OpResp{$P_Order}="$frid:$Part";
-			       } 
-			   }
-		       }
-		   }
-               }
-	   }
-	 #  }
-       } else {
-	   $cols[$#cols+1]=($P_Order+1).':'.$rid;
-	   my $meta=$hash{'src_'.$rid};
-	   my $PartNo = 0;
-	   if ($meta) {
-	       if ($meta=~/\.(problem|exam|quiz|assess|survey|form)$/) {
-		   foreach my $Key(split(/\,/,&Apache::lonnet::metadata($meta,'keys'))) {
-		       if ($Key=~/^stores\_(\w+)\_tries$/) {
-			   my $Part=&Apache::lonnet::metadata($meta,$Key.'.part');
-			   $P_Order++;
-			   $mapsort{$HWN} .= '&'.$P_Order;
-			   $PartNo++;
-			   foreach (split(/\,/,&Apache::lonnet::metadata($meta,'packages'))) {
-			       if ($_=~/^optionresponse\_($Part)\_(\w+)$/) {
-				   #$r->print('<br>'.$_.'...'.$P_Order.'---'.$Part);
-				   $OpResp{$P_Order}="$rid:$Part";;
-			       } 
-		   
-			   }
-
-		       }
-		   }
-	       }
-	   }       
-       }
-       if (defined($hash{'to_'.$rid})) {
-          foreach (split(/\,/,$hash{'to_'.$rid})){
-              &tracetable($hash{'goesto_'.$_},$beenhere);
-          }
-       }
-    }
+    return (\%discriminantFactor, \@list);
 }
 
 sub MySort {          
@@ -1033,73 +608,31 @@
     }
 }
 
-sub Create_PrgWin {
-#----------- Create progress
-    $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();
-}
-
-
-sub Update_PrgWin {
-#----------- update progress
-    my $index = shift;
-    $r->print('<script>popwin.document.popremain.remaining.value="'.
-              'Computing '.($index+1).'/'.($#students+1).': '.
-              $students[$index].'";</script>');
-    $r->rflush();
-}
+sub BuildStatisticsTable {
+    my ($cache,$discriminantFactor,$list,$headings)=@_;
 
-sub Close_PrgWin {
-#--------------------- close Progress Line
-    $r->print('<script>popwin.close()</script>');
-    $r->rflush(); 
-}
-
-sub Build_Statistics {
-    &Create_PrgWin();
-# ---------------------------- Gathering the Data of students' tries
-    for (my $index=0;$index<=$#students;$index++) {
-	&Update_PrgWin($index);
-        &ExtractStudentData($students[$index]);
-    }
-
-# -------------------- sorting the Data
-    $r->print('<script>popwin.document.popremain.remaining.value="'.
-              'Calculating Discrimination Factors...";</script>');
-
-    @list = sort (@list);
-
-    &Discriminant();
-
-    $OpSel2='';
-    $OpSel1='selected';
- 		   
-    $p_count = 0; 
-    my $nIdx = 0;
-    my $dummy; 
+    my $p_count = 0;
+    my $nIndex = 0;
+    my $dummy;
     my $p_val;
     my $ResId;
-    my $NoElements = $#list + 1;
-#-------------------------------- loop for data representation
-    foreach (sort keys %mapsort) {
+    my $NoElements = scalar @$list;
+
+    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
+        if($cache->{'ProblemStatisticsMap'} ne 'All Maps'  &&
+           $cache->{'ProblemStatisticsMap'} ne $cache->{$sequence.':title'}) {
+            next;
+        }
+
+	&CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'},
+                                             $cache->{$sequence.':source'}, 
+                                             $cache->{$sequence.':title'},
+                                             $headings);
 	my ($Hid,$pr)=split(/\:/,$mapsort{$_});
 	my @lpr=split(/\&/,$pr);
-	&CreateTable(1,$Hid);
 	for (my $i=1; $i<=$#lpr; $i++) {
 	    my %storestats=();
-	    my ($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\&/,$list[$nIdx]);
+	    my ($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\&/,$list->[$nIndex]);
 	    my $Temp = $Prob;
 	    my $MxTries = 0;
 	    my $TotalTries = 0;
@@ -1110,7 +643,7 @@
 	    my @StdLst;
 	    while ( $PrOrd == $lpr[$i] ) 
 	    {
-		$nIdx++;
+		$nIndex++;
 		$StdNo++;
 		$StdLst[ $StdNo ] = $Tries;
 		$TotalTries += $Tries;
@@ -1119,7 +652,7 @@
 		elsif( $Code eq 'I' ) { $Incorrect++; }
 		elsif( $Code eq 'O' ) { $Override++; }
 		elsif( $Code eq 'U' ) { $StdNo--; }
-		($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\&/,$list[$nIdx]);
+		($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\&/,$list->[$nIndex]);
 	    }	
 
 	    $p_count++;
@@ -1182,8 +715,8 @@
 	    }
 
 #--------------------- Compute the Discrimination Factors
-	    my ($Up1,$Up2)=split(/\:/,$DisUp{$lpr[$i]});
-	    my ($Lw1,$Lw2)=split(/\:/,$DisLow{$lpr[$i]});
+            my ($Up1,$Up2)=split(/\:/,':');#jason$DisUp->{$lpr[$i]});
+	    my ($Lw1,$Lw2)=split(/\:/,':');#jason$DisLow->{$lpr[$i]});
 	    my $Dis1 = $Up1 - $Lw1;
 	    my $Dis2 = $Up2 - $Lw2;
 	    my $_D1 = sprintf("%.2f", $Dis1);
@@ -1207,16 +740,16 @@
 		&Apache::lonnet::put('resevaldata',\%storestats,$1,$2); 
 	    }
 #-------------------------------- Row of statistical table
-	    if ( $DiscFlag == 0 ) {
-		&TableRow($join,$i,($p_count-1));
-	    } 
+            &TableRow($cache,$join,$i,($p_count-1));
 	}
-	&CloseTable();
+	&CloseTable($cache);
     }
     &Close_PrgWin();
 }
 
+=pod
 sub Cache_Statistics {
+    my ($cache)=@_;
     my @list = ();
     my $Useful;
     my $UnUseful;
@@ -1224,7 +757,7 @@
     my %myHeader = reverse( %Header );
     $Pos = $myHeader{$ENV{'form.sort'}};
     if ($Pos > 0) {$Pos++;}
-    $p_count = 0;
+    my $p_count = 0;
     foreach my $key( keys %CachData) { 
 	my @Temp=split(/\&/,$CachData{$key});
 	if ( $Pos == 0 ) {
@@ -1239,37 +772,37 @@
 
     @list = sort MySort (@list);
 
-    my $nIdx=0;
+    my $nIndex=0;
 
     if ( $Pos == 0 ) {
 	foreach (sort keys %mapsort) {
 	    my ($Hid,$pr)=split(/\:/,$mapsort{$_});
-	    &CreateTable(1,$Hid);
+	    &CreateProblemStatisticsTableHeading($cache,1,$Hid);
 	    my @lpr=split(/\&/,$pr);
 	    for (my $i=1; $i<=$#lpr; $i++) {
-		my($Pre, $Post) = split(/\@/,$list[$nIdx]); 
+		my($Pre, $Post) = split(/\@/,$list[$nIndex]); 
 		#$r->print('<br>'.$Pre.'---'.$Post);
-		&TableRow($Post,$i,$nIdx);
-		$nIdx++;
+		&TableRow($cache,$Post,$i,$nIndex);
+		$nIndex++;
 	    }
-	    &CloseTable();
+	    &CloseTable($cache);
 	}
     }
     else {
-	&CreateTable(0);
-	for ( my $nIdx = 0; $nIdx < $p_count; $nIdx++ ) {
-	    my($Pre, $Post) = split(/\@/,$list[$nIdx]); 
-	    &TableRow($Post,$nIdx,$nIdx);
+	&CreateProblemStatisticsTableHeading($cache,0);
+	for ( my $nIndex = 0; $nIndex < $p_count; $nIndex++ ) {
+	    my($Pre, $Post) = split(/\@/,$list[$nIndex]); 
+	    &TableRow($cache,$Post,$nIndex,$nIndex);
 	} 
-	&CloseTable();
+	&CloseTable($cache);
     }
 }
-
+=cut
 sub TableRow {
-    my ($Str,$Idx,$RealIdx)=@_;
+    my ($cache,$Str,$Idx,$RealIdx)=@_;
     my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
        $Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$Prob)=split(/\&/,$Str);	
-    if ($ENV{'form.showcsv'}) {
+    if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
         my ($ResId,$Dummy)=split(/\*/,$Prob);
         my $Ptr =  "\n".'<br>'.
                "\n".'"'.($RealIdx+1).'",'.
@@ -1288,8 +821,7 @@
                "\n".'"'.$_D1.'",'.
 	       "\n".'"'.$_D2.'"';
         $r->print("\n".$Ptr);
-    }
-    else{
+    } else {
         my $Ptr =  "\n".'<tr>'.
                "\n".'<td>'.($RealIdx+1).'</td>'.
           #     "\n".'<td>'.$PrOrd.$Temp.'</td>'.
@@ -1311,75 +843,716 @@
     $GraphDat{$RealIdx}=$DoD.':'.$Wrng;
 }
 
-# ------------------------------------------- Prepare data for Graphical chart
+sub StatusOptions {
+    my ($cache)=@_;
+
+    my $Status = $cache->{'Status'};
+    my $OpSel1 = '';
+    my $OpSel2 = '';
+    my $OpSel3 = '';
+
+    if($Status eq 'Any')         { $OpSel3 = ' selected'; }
+    elsif($Status eq 'Expired' ) { $OpSel2 = ' selected'; }
+    else                         { $OpSel1 = ' selected'; }
+
+    my $Ptr = '';
+    $Ptr .= '<tr><td align="right"><b>Student Status:</b></td>'."\n";
+    $Ptr .= '<td align="left"><select name="Status">';
+    $Ptr .= '<option'.$OpSel1.'>Active</option>'."\n";
+    $Ptr .= '<option'.$OpSel2.'>Expired</option>'."\n";
+    $Ptr .= '<option'.$OpSel3.'>Any</option>'."\n";
+    $Ptr .= '</select></td></tr>'."\n";
+
+    return $Ptr;
+}
+
+sub AscendOrderOptions {
+    my ($cache)=@_;
+
+    my $order = $cache->{'Ascend'};
+    my $OpSel1 = '';
+    my $OpSel2 = '';
+
+    if($order eq 'Ascending') {
+        $OpSel1 = ' selected';
+    } else {
+        $OpSel2 = ' selected';
+    }
+
+    my $Ptr = '';
+    $Ptr .= '<tr><td align="right"><b>Sorting Type:</b></td>'."\n";
+    $Ptr .= '<td align="left"><select name="Ascend">'."\n";
+    $Ptr .= '<option'.$OpSel1.'>Ascending</option>'."\n".
+	    '<option'.$OpSel2.'>Descending</option>'."\n";
+    $Ptr .= '</select></td></tr>'."\n";
+
+    return $Ptr;
+}
+
+sub ProblemStatisticsButtons {
+    my ($cache)=@_;
+
+    my $Ptr = '<tr><td></td><td align="left">';
+    $Ptr .= '<input type=submit name="ProblemStatisticsRecalculate" ';
+    $Ptr .= 'value="Recalculate Statistics"/>'."\n";
+    $Ptr .= '&nbsp;&nbsp;&nbsp;';
+    $Ptr .= '<input type="submit" name="DoDiffGraph" ';
+    $Ptr .= 'value="DoDiff Graph" />'."\n";
+    $Ptr .= '&nbsp;&nbsp;&nbsp;';
+    $Ptr .= '<input type="submit" name="PercentWrongGraph" ';
+    $Ptr .= 'value="%Wrong Graph" />'."\n";
+    $Ptr .= '&nbsp;&nbsp;&nbsp;';
+    $Ptr .= '<input type="submit" name="DisplayCSVFormat" ';
+    if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
+        $Ptr .= 'value="Display CSV Format" />'."\n";
+    } else {
+        $Ptr .= 'value="Display Table Format" />'."\n";
+    }
+    $Ptr .= '</td></tr>';
+
+    return $Ptr;
+}
+
+sub ProblemStatisticsLegend {
+    my $Ptr = '';
+    $Ptr = '<table border="0">';
+    $Ptr .= '<tr><td>';
+    $Ptr .= '<b>#Stdnts</b>:</td>';
+    $Ptr .= '<td>Total Number of Students opened the problem.';
+    $Ptr .= '</td></tr><tr><td>';
+    $Ptr .= '<b>Tries</b>:</td>';
+    $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></tr><tr><td>';
+    $Ptr .= '<b>Mean</b>:</td>';
+    $Ptr .= '<td>Average Number of the tries. [ Tries / #Stdnts ]';
+    $Ptr .= '</td></tr><tr><td>';
+    $Ptr .= '<b>#YES</b>:</td>';
+    $Ptr .= '<td>Number of students solved the problem correctly.';
+    $Ptr .= '</td></tr><tr><td>';
+    $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 .= '</td></tr><tr><td>';
+#    Kashy formula
+#    '<b>  DoDiff </b>: Degree of Difficulty of the problem.<br>'.
+#    '[ Tries/(#YES+#yes+0.1) ]<br>'.
+    #Gerd formula
+    $Ptr .= '<b>DoDiff</b>:</td>';
+    $Ptr .= '<td>Degree of Difficulty of the problem.  ';
+    $Ptr .= '[ 1 - ((#YES+#yes) / Tries) ]';
+    $Ptr .= '</td></tr><tr><td>';
+    $Ptr .= '<b>S.D.</b>:</td>';
+    $Ptr .= '<td>Standard Deviation of the tries.  ';
+    $Ptr .= '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1) ';
+    $Ptr .= 'where Xi denotes every student\'s tries ]';
+    $Ptr .= '</td></tr><tr><td>';
+    $Ptr .= '<b>Skew.</b>:</td>';
+    $Ptr .= '<td>Skewness of the students tries.';
+    $Ptr .= '[(sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3)]';
+    $Ptr .= '</td></tr><tr><td>';
+    $Ptr .= '<b>Dis.F.</b>:</td>';
+    $Ptr .= '<td>Discrimination Factor: A Standard for evaluating the ';
+    $Ptr .= 'problem according to a Criterion<br>';
+    $Ptr .= '<b>[Applied Criterion in %27 Upper Students - ';
+    $Ptr .= 'Applied the same Criterion in %27 Lower Students]</b><br>';
+    $Ptr .= '<b>1st Criterion</b> for Sorting the Students: ';
+    $Ptr .= '<b>Sum of Partial Credit Awarded / Total Number of Tries</b><br>';
+    $Ptr .= '<b>2nd Criterion</b> for Sorting the Students: ';
+    $Ptr .= '<b>Total number of Correct Answers / Total Number of Tries</b>';
+    $Ptr .= '</td></tr></table>';
+
+    return $Ptr;
+}
+
+#---- END Problem Statistics Web Page ----------------------------------------
+
+#---- Problem Statistics Graph Web Page --------------------------------------
 
 sub GetGraphData {
-    my $ylab = shift;
-    my $Col;
+    my ($whichGraph, $courseID)=@_;
+    my $Col=0;
+    my $graphTitle='';
     my $data='';
     my $count = 0;
     my $Max = 0;
-    my $cid=$ENV{'request.course.id'};
+    my $graphData='Graph data does not exist.';
     my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
-                  "_$ENV{'user.domain'}_$cid\_graph.db";
-    foreach (keys %GraphDat) {delete $GraphDat{$_};}
-    if (-e "$GraphDB") {
-	if (tie(%GraphDat,'GDBM_File',"$GraphDB",&GDBM_READER,0640)) {
-	    if ( $ylab eq 'DoDiff Graph' ) {
-		$ylab = 'Degree-of-Difficulty';
+                  "_$ENV{'user.domain'}_$courseID\_graph.db";
+    if(-e $GraphDB) {
+	if(tie(%GraphDat,'GDBM_File',"$GraphDB",&GDBM_READER,0640)) {
+	    if($whichGraph eq 'DiffGraph') {
+		$graphTitle = 'Degree-of-Difficulty';
 		$Col = 0;
-	    }
-	    else {
-		$ylab = 'Wrong-Percentage';
+	    } else {
+		$graphTitle = 'Wrong-Percentage';
 		$Col = 1;
 	    }
 	    foreach (sort NumericSort keys %GraphDat) { 
 		my @Temp=split(/\:/,$GraphDat{$_});
                 my $inf = $Temp[$Col]; 
-		if ( $Max < $inf ) {$Max = $inf;}
+		if($Max < $inf) {
+                    $Max = $inf;
+                }
 		$data .= $inf.',';
 		$count++;
 	    }
-	    if ( $Max > 1 ) { 
+	    if($Max > 1) { 
 		$Max += (10 - $Max % 10);
 		$Max = int($Max);
-	    }
-	    else { $Max = 1; }
+	    } else { 
+                $Max = 1;
+            }
             untie(%GraphDat);
-	    my $Course = $ENV{'course.'.$cid.'.description'};
+	    my $Course = $ENV{'course.'.$courseID.'.description'};
 	    $Course =~ s/\ /"_"/eg;
-	    $GData=$Course.'&'.'Problems'.'&'.$ylab.'&'.$Max.'&'.$count.'&'.$data;
+	    $graphData  = $Course.'&'.'Problems'.'&'.$graphTitle.'&'.$Max.'&';
+            $graphData .= $count.'&'.$data;
+	} else {
+	    $graphData = "Unable to tie hash to db file";
 	}
-	else {
-	    $r->print("Unable to tie hash to db file");
+    }
+
+    return $graphData;
+}
+
+#---- END Problem Statistics Graph Web Page ----------------------------------
+
+#---- Problem Analysis Web Page ----------------------------------------------
+
+sub IntervalOptions {
+    my ($cache)=@_;
+
+    my $interval = 1;
+    for(my $n=1; $n<=7; $n++) {
+        if($cache->{'Interval'} == $n) {
+            $interval = $n;
+        }
+    }
+
+    my $Ptr = '<br><b>Select number of intervals</b>'."\n".
+       	      '<select name="Interval">'."\n";
+    for(my $n=1; $n<=7;$ n++) {
+	$Ptr .= '<option';
+        if($interval == $n) {
+            $Ptr .= ' selected';
+        }
+	$Ptr .= '>'.$n."</option>"."\n";
+    }
+    $Ptr .= '</select>'."\n";
+
+    return $Ptr;
+}
+
+sub OptionResponseTable {
+    my ($cache)=@_;
+    my $Str = '';
+    $Str .= '<br><b> Option Response Problems in this course:</b>'."\n";
+    $Str .= '<br><br>'."\n";
+    $Str .= "<table border=2><tr><th> \# </th><th> Problem Title </th>";
+    $Str .= '<th> Resource </th><th> Analysis  </th></tr>'."\n";
+
+    my $number=1;
+    foreach (split(':::',$cache->{'OptionResponses'})) {
+        my ($uri,$title,$part,$problem)=split('::',$_);
+        my $Temp = '<a href="'.$uri.'" target="_blank">'.$title.'</a>';
+        $Str .= '<tr>';
+        $Str .= '<td> '.$number.' </td>';
+        $Str .= '<td bgcolor="'.$color{"green"}.'"> '.$Temp.' </td>';
+        $Str .= '<td bgcolor="'.$color{"yellow"}.'"> '.$uri.' </td>';
+        $Str .= '<td><input type="submit" name="Analyze:::'.$uri.':::';
+        $Str .= $title.':::'.$part.':::'.$problem.'" value="';
+        $Str .= 'Analyze" /></td></tr>'."\n";
+        $number++;
+    }
+    $Str .= '</table>'."\n";
+
+    return $Str;
+}
+
+#---- END Problem Analysis Web Page ------------------------------------------
+
+#---- Student Assessment Web Page --------------------------------------------
+
+sub MapOptions {
+    my ($cache, $page)=@_;
+    my $Ptr = '<tr>';
+    $Ptr .= '<td align="right"><b>Select Map</b></td>'."\n";
+    $Ptr .= '<td align="left"><select name="Maps">'."\n";
+
+    my $selected = 0;
+    foreach my $sequence (split(':',$cache->{'orderedSequences'})) {
+	$Ptr .= '<option';
+        if($cache->{$page.'Map'} eq $cache->{$sequence.':title'}) {
+            $Ptr .= ' selected';
+            $selected = 1;
+        }
+	$Ptr .= '>'.$cache->{$sequence.':title'}.'</option>'."\n";	     
+    }
+    $Ptr .= '<option';
+    if(!$selected) {
+        $Ptr .= ' selected';
+    }
+    $Ptr .= '>All Maps</option>'."\n";
+
+    $Ptr .= '</select></td></tr>'."\n";
+
+    return $Ptr;
+}
+
+sub StudentOptions {
+    my ($students, $selectedName)=@_;
+
+    my $Ptr ='<tr>';
+    $Ptr .= '<td align="right"><b>Select Student</b></td>'."\n";
+    $Ptr .= '<td align="left"><select name="Students">'."\n";
+
+    my $selected=0;
+    foreach (@$students) {
+        my ($name) = split(':',$_);
+	$Ptr .= '<option';
+	if($selectedName eq $name) {
+            $Ptr .= ' selected';
+            $selected = 1;
+        }
+        $Ptr .= '>'.$name.'</option>'."\n";	     
+    }
+
+    $Ptr .= '<option';
+    if(!$selected) {
+        $Ptr .= ' selected';
+    }
+    $Ptr .= '>No Student Selected</option>'."\n";
+
+    $Ptr .= '</select></td></tr>'."\n";
+
+    return $Ptr;
+}
+
+# ------ Create different Student Report 
+sub StudentReport {
+    my ($cache, $name)=@_;
+
+    my $Str = '';
+    if($cache->{$name.':error'} =~ /course/) {
+        my ($username)=split(':',$name);
+        $Str .= '<b><font color="blue">No course data for student </font>';
+        $Str .= '<font color="red">'.$username.'.</font></b><br>';
+        return $Str;
+    }
+
+    $Str .= "<table border=2><tr><th> \# </th><th> Set Title </th>";
+    $Str .= '<th> Results </th><th> Tries </th></tr>'."\n";
+
+    my $codes;
+    my $attempts;
+    foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
+        if($cache->{'StudentAssessmentMap'} ne 'All Maps'  &&
+           $cache->{'StudentAssessmentMap'} ne $cache->{$sequence.':title'}) {
+            next;
+        }
+
+        $Str .= '<tr><td>'.$sequence.'</td>';
+        $Str .= '<td>'.$cache->{$sequence.':title'}.'</td>';
+
+        $codes = '';
+        $attempts = '';
+        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;
+            # 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='U';
+
+                    $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 = 'Y';} 
+                    elsif ($val eq 'correct_by_override')  {$code = 'y';}
+                    elsif ($val eq 'incorrect_attempted')  {$code = 'N';} 
+                    elsif ($val eq 'incorrect_by_override'){$code = 'N';}
+                    elsif ($val eq 'excused')              {$code = 'x';}
+                    $partData{$part.':code'}=$code;
+                }
+            }
+
+            # Loop through all the parts for the current problem in the 
+            # correct order and prepare the output
+            foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
+                                         ':parts'})) {
+                $codes    .= $partData{$_.':code'}.',';
+                $attempts .= $partData{$_.':tries'}.','; 
+            }
+        }
+        $codes    =~ s/,$//;
+        $attempts =~ s/,$//;
+        $Str .= '<td>'.$codes.'</td>';
+        $Str .= '<td>'.$attempts.'</td>';
+        $Str .= '</tr>'."\n";
+    }
+
+    $Str .= '</table>'."\n";
+
+    return $Str;
+}
+
+#---- END Student Assessment Web Page ----------------------------------------
+
+#---- Menu Web Page ----------------------------------------------------------
+
+sub Title {
+    my ($downloadTime)=@_;
+
+    my $Ptr = '';
+
+    $Ptr .= '<html><head><title>LON-CAPA Statistics</title></head>'."\n";
+    $Ptr .= '<body bgcolor="#FFFFFF">'."\n";
+    $Ptr .= '<script>window.focus(); window.width=500;window.height=500;';
+    $Ptr .= '</script>'."\n";
+    $Ptr .= '<img align=right src=/adm/lonIcons/lonlogos.gif>'."\n";
+    $Ptr .= '<h1> Course : "';
+    $Ptr .= $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+    $Ptr .= '"</h1>'."\n";
+    $Ptr .= '<h3>'.$downloadTime.'</h3>';
+
+    return $Ptr;
+}
+
+sub CreateMenuForm {
+    my ($cache)=@_;
+    my $Ptr = '<table border="0">';
+    $Ptr .= '<tr><td><input type="submit" name="ProblemStatistics" ';
+    $Ptr .= 'value="Problem Stats"/>';
+    $Ptr .= '</td></tr>'."\n";
+
+    if(defined($cache->{'OptionResponses'})) {
+        $Ptr .= '<tr><td><input type="submit" name="ProblemAnalysis" ';
+        $Ptr .= 'value="Problem Analysis"/>';
+        $Ptr .= '</td></tr>'."\n";
+    }
+
+    $Ptr .= '<tr><td><input type="submit" name="StudentAssessment" ';
+    $Ptr .= 'value="Student Assessment"/>';
+    $Ptr .= '</td></tr>'."\n";
+    #$Ptr .= '<input type="submit" name="ActivityLog" value="Activity Log"/>';
+
+    $Ptr .= '</table>'."\n";
+
+    return $Ptr;
+}
+
+#---- END Menu Web Page ------------------------------------------------------
+
+#---- HELPER FUNCTIONS -------------------------------------------------------
+
+sub CheckFormElement {
+    my ($cache, $ENVName, $cacheName, $default)=@_;
+
+    if(defined($ENV{'form.'.$ENVName})) {
+        $cache->{$cacheName} = $ENV{'form.'.$ENVName};
+    } elsif(!defined($cache->{$cacheName})) {
+        $cache->{$cacheName} = $default;
+    }
+
+    return;
+}
+
+sub ProcessFormData{
+    my ($cacheDB, $isCached)=@_;
+    my %cache;
+
+    if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) {
+        # Select page to display
+        if(defined($ENV{'form.ProblemStatistics'}) ||
+           defined($ENV{'form.ProblemStatisticsRecalculate'}) || 
+           defined($ENV{'form.DisplayCSVFormat'})) {
+            $cache{'GoToPage'} = 'ProblemStatistics';
+            &CheckFormElement(\%cache, 'DisplayCSVFormat',
+                              'DisplayFormat', 'Display Table Format');
+            &CheckFormElement(\%cache, 'Ascend','ProblemStatisticsAscend',
+                              'Ascending');
+            &CheckFormElement(\%cache, 'Maps', 'ProblemStatisticsMap', 
+                              'All Maps');
+        } elsif(defined($ENV{'form.ProblemAnalysis'})) {
+            $cache{'GoToPage'} = 'ProblemAnalysis';
+            &CheckFormElement(\%cache, 'Interval', 'Interval', '1');
+        } elsif(defined($ENV{'form.StudentAssessment'}) ||
+                defined($ENV{'form.CreateStudentAssessment'}) ||
+                defined($ENV{'form.NextStudent'}) ||
+                defined($ENV{'form.PreviousStudent'})) {
+            $cache{'GoToPage'} = 'StudentAssessment';
+            if(defined($ENV{'form.NextStudent'})) {
+                $cache{'StudentAssessmentMove'} = 'next';
+            } elsif(defined($ENV{'form.PreviousStudent'})) {
+                $cache{'StudentAssessmentMove'} = 'previous';
+            } else {
+                $cache{'StudentAssessmentMove'} = 'selected';
+            }
+            &CheckFormElement(\%cache, 'Maps', 'StudentAssessmentMap', 
+                              'All Maps');
+
+            &CheckFormElement(\%cache, 'Students', 'StudentAssessmentStudent', 
+                              'No Student Selected');
+        } elsif(defined($ENV{'form.DoDiffGraph'})) {
+            $cache{'GoToPage'} = 'DoDiffGraph';
+        } elsif(defined($ENV{'form.PercentWrongGraph'})) {
+            $cache{'GoToPage'} = 'PercentWrongGraph';
+        } elsif(defined($ENV{'form.ActivityLog'})) {
+            $cache{'GoToPage'} = 'ActivityLog';
+        } else {
+            $cache{'GoToPage'} = 'Menu';
+        }
+
+        &CheckFormElement(\%cache, 'Status', 'Status', 'Active');
+
+        foreach (keys(%ENV)) {
+            if(/form\.Analyze:::/) {
+                $cache{'GoToPage'} = 'Analyze';
+                my ($uri, $title, $part, $problem);
+                (undef, $uri, $title, $part, $problem)=split(':::', $_);
+                $cache{'AnalyzeURI'}     = $uri;
+                $cache{'AnalyzeTitle'}   = $title;
+                $cache{'AnalyzePart'}    = $part;
+                $cache{'AnalyzeProblem'} = $problem;
+
+                &CheckFormElement(\%cache, 'Interval', 'Interval', '1');
+            }
+        }
+    }
+
+    return;
+}
+
+=pod
+
+=item &SortStudents()
+
+Determines which students to display and in which order.  Which are 
+displayed are determined by their status(active/expired).  The order
+is determined by the sort button pressed (default to username).  The
+type of sorting is username, lastname, or section.
+
+=over 4
+
+Input: $students, $CacheData
+
+$students: A array pointer to a list of students (username:domain)
+
+$CacheData: A pointer to the hash tied to the cached data
+
+Output: \@order
+
+@order: An ordered list of students (username:domain)
+
+=back
+
+=cut
+
+sub SortStudents {
+    my ($students,$cache)=@_;
+
+    my @sorted1Students=();
+    foreach (@$students) {
+        push(@sorted1Students, $_);
+    }
+#        my ($end,$start)=split(/\:/,$cache->{$_.':date'});
+#        my $active=1;
+#        my $now=time;
+#        my $Status=$cache->{'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, $_);
+#        }
+#    }
+
+    my $Pos = $cache->{'form.ChartSort'};
+    my %sortData;
+    if($Pos eq 'Last Name') {
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$cache->{$sorted1Students[$index].':fullname'}}=
+		$sorted1Students[$index];
+	}
+    } elsif($Pos eq 'Section') {
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$cache->{$sorted1Students[$index].':section'}.
+		      $sorted1Students[$index]}=$sorted1Students[$index];
 	}
+    } else {
+	# Sort by user name
+	for(my $index=0; $index<scalar @sorted1Students; $index++) {
+	    $sortData{$sorted1Students[$index]}=$sorted1Students[$index];
+	}
+    }
+
+    my @order = ();
+    foreach my $key (sort(keys(%sortData))) {
+	push (@order,$sortData{$key});
     }
+
+    return \@order;
 }
 
+sub PrepareData {
+    my ($c, $cacheDB)=@_;
 
-sub initial {
-# --------------------------------- Initialize the global varaibles
-    undef @students;
-    undef @cols;
-    undef %maps;
-    undef %section;
-    undef %StuBox;
-    undef @list;
-    undef %CachData;
-    undef %GraphDat;
-    undef %DiscFac;
-    undef %OpResp;
-    undef %ConceptData;
-    undef $CurMap;
-    undef $CurSec;
-    undef $CurStu;
-    undef $p_count;
-    undef $Pos;
-    undef $GData;
-    $DiscFlag=0; 
-    $P_Order=100000;
-    $HWN=$P_Order;
-    &setbgcolor(0);
+    # Test for access to the cache data
+    my $isCached=0;
+    my $courseID=$ENV{'request.course.id'};
+    my $isRecalculate=0;
+    if(defined($ENV{'form.ProblemStatisticsRecalculate'}) ||
+       defined($ENV{'form.ChartRecalculate'})) {
+        $isRecalculate=1;
+    }
+
+    $isRecalculate=1;
+
+    $isCached=&Apache::loncoursedata::TestCacheData($cacheDB, $isRecalculate);
+    if($isCached < 0) {
+        return "Unable to tie hash to db file.";
+    }
+    &ProcessFormData($cacheDB, $isCached);
+
+    # Download class list information if not using cached data
+    my %cache;
+    my @students=();
+    if(!$isCached) {
+        unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) {
+            return "Unable to tie hash to db file.";
+        }
+
+        my $processTopResourceMapReturn=
+            &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c);
+        if($processTopResourceMapReturn ne 'OK') {
+            untie(%cache);
+            return $processTopResourceMapReturn;
+        }
+
+        if($c->aborted()) {
+            untie(%cache);
+            return 'aborted'; 
+        }
+
+        my $classlist=&Apache::loncoursedata::DownloadStudentNamePIDSection(
+                                                                   $courseID, 
+                                                                   $c);
+        my ($checkForError)=keys(%$classlist);
+        if($checkForError =~ /^(con_lost|error|no_such_host)/i ||
+           defined($classlist->{'error'})) {
+            untie(%cache);
+            return "Error getting student data.";
+        }
+
+        if($c->aborted()) {
+            untie(%cache);
+            return 'aborted'; 
+        }
+
+        # Active is a temporary solution, remember to change
+        @students=&Apache::loncoursedata::ProcessClassList(\%cache, 
+                                                           $classlist, 
+                                                           $courseID, 
+                                                           'Active', $c);
+
+        if($c->aborted()) {
+            untie(%cache);
+            return 'aborted'; 
+        }
+
+        untie(%cache);
+    } else {
+        if(!$c->aborted() && tie(%cache,'GDBM_File',$cacheDB,
+                                 &GDBM_READER,0640)) {
+            @students=split(/:::/,$cache{'NamesOfStudents'});
+        } else {
+            return 'aborted';
+        }
+    }
+
+    return ('OK', $isCached, \@students);
+}
+
+# Create progress
+sub Create_PrgWin {
+    $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->print('<script>popwin.document.popremain.remaining.value="'.
+              'Computing '.$index.'/'.$totalStudents.': '.
+              $name.'";</script>');
+    $r->rflush();
+}
+
+# close Progress Line
+sub Close_PrgWin {
+    $r->print('<script>popwin.close()</script>');
+    $r->rflush(); 
 }
 
 # For loading the colored table for display or un-colored for print
@@ -1399,321 +1572,326 @@
 	$color{"green"}="#DDFFDD";
 	$color{"purple"}="#FFDDFF";
     }
+
+    return;
 }
 
-#	my $CacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
-#                  "_$ENV{'user.domain'}_$cid\_classlist.db";
-#	if (-e "$CacheDB") {
-#	    if (tie(%students,'GDBM_File',"$CacheDB",&GDBM_READER,0640)) {
-#		&CachClassList();
-#	    }
-#            else {
-#	        $r->print("Unable to tie hash to db file");
-#            }
-#        }
-#        else {
-#	    if (tie(%students,'GDBM_File',$CacheDB,&GDBM_WRCREAT,0640)) {
-#	        &MakeClassList();
-#	    }
-#            else {
-#	        $r->print("Unable to tie hash to db file");
-#            }
-#        }
-#        untie(%students);
+sub initial {
+    undef %hash;
+    undef %CachData;
+    undef %GraphDat;
+    undef %ConceptData;
+    undef $Pos;
+    undef $GData;
+}
 
-sub ClassList {
+#---- END HELPER FUNCTIONS ---------------------------------------------------
 
-    &GetStatus();
+sub BuildProblemStatisticsPage {
+    my ($cacheDB, $students)=@_;
 
-    $cid=$ENV{'request.course.id'};
-    my ($cdom,$cnum)=split(/\_/,$cid);
-# ----------------------- Get first and last resource, see if there is anything
-    $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
-    $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
-    if (($firstres) && ($lastres)) {
-
-	my $StudNo = 0;
-	my $now=time;
-	my %classlist=&Apache::lonnet::dump('classlist',$cdom,$cnum);
-
-	my ($checkForError)=keys(%classlist);
-	if($checkForError=~/^(con_lost|error|no_such_host)/i) {
-	    $r->print('<h1>Could not access course data</h1>');
-	} else {
-	    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) {
-		    my $thisindex=$#students+1;
-		    $students[$thisindex]=$name;
-		    my ($sname,$sdom)=split(/\:/,$name);
-		    my $ssec=&usection($sdom,$sname,$cid,$Status);
-		    if ($ssec==-1 || $ssec eq 'adm' ) {next;}
-		    $ssec=($ssec) ? $ssec : '(none)';
-		    #$ssec=(int($ssec)) ? int($ssec) : $ssec;
-		    $section{$ssec}=$ssec;
-		    if ($CurSec eq 'All Sections' || $ssec eq $CurSec) {
-			$students[$StudNo]=$name;
-			$StuBox{$sname}=$sdom;
-		    }
-		    $StudNo++;
-		}
-	    }
-	}
+    my %cache;
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return;
+    }
+
+    my $Ptr = '';
+    $Ptr .= '<form name="ProblemStatisticsPage" method="post" ';
+    $Ptr .= 'action="/adm/statistics">'."\n";
+    $Ptr .= '<table border="0"><tbody>';
+    $Ptr .= '<tr><td></td><td align="left"><input type="submit" name="Menu" ';
+    $Ptr .= 'value="Return to Menu" /></td></tr>'."\n";
+    $r->print($Ptr);
 
-        $r->print("Total number of students : ".($#students+1));
-        $r->rflush();
-# --------------- Find all assessments and put them into some linear-like order
-	&tracetable($firstres,'&'.$lastres.'&');
-#    my $c=0;
-#    foreach (sort keys %mapsort) {
-#	$r->print('<br>'.$c.')'.$_.' ... '.$mapsort{$_});
-#	$c++;
+    $r->print(&MapOptions(\%cache, 'ProblemStatistics'));
+    $r->print(&StatusOptions());
+    $r->print(&AscendOrderOptions());
+    $r->print(&ProblemStatisticsButtons(\%cache));
+    $r->print('</table>');
+
+    $r->print(&ProblemStatisticsLegend());
+
+#    my $discriminantFactor;
+#    my $list;
+#    foreach (@$students) {
+#        ($discriminantFactor, $list) = &ExtractStudentData($_);
 #    }
-#	my $c=1;
-#	foreach (sort keys %OpResp) {
-#	    $r->print('<br>'.$c.')'.$_.' ... '.$OpResp{$_}.' ... '.$hash{'src_'.$OpResp{$_}});
-#	    $c++;
-#	}
 
-    }
+#    my ($upper, $lower) = &Discriminant($discriminantFactor);
+#    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");
+#    &BuildStatisticsTable(\%cache, $discriminantFactor, $list, \%Header);
 
-# ------------------------------------------------------------- End render page 
-    else {
-	$r->print('<h3>Undefined course sequence</h3>');
-    }
-}
+    $r->print('</form>');
 
+    untie(%cache);
 
-sub Title {
-    $r->print('<html><head><title>LON-CAPA Statistics</title></head>');
-    $r->print('<body bgcolor="#FFFFFF">'.
-              '<script>window.focus(); window.width=500;window.height=500;</script>'.
-              '<img align=right src=/adm/lonIcons/lonlogos.gif>');
-# ---------------------------------------------------------------- Course title
-    $r->print('<h1> Course : "'.
-              $ENV{'course.'.$ENV{'request.course.id'}.
-              '.description'}.'"</h1><h2>'.localtime().'</h2>');
-# ------------------------------- This is going to take a while, produce output
-    $r->rflush();	
+    return;
 }
 
+sub BuildDiffGraph {
+    my ($courseID)=@_;
 
-sub CreateForm {
-    $r->print("\n".'<form name=stat method=post action="/adm/statistics" >');
-    my $content = $ENV{'form.sort'};
-    if (!($ENV{'form.showcsv'}) && 
-        ($content eq '' || $content eq 'Return to Menu')) {
-	my $Ptr = '<h3>';
-	$Ptr .= '<input type=submit name=sort value="Problem Stats"/>';
-	$Ptr .= '<br><br>';
-	$Ptr .= '<input type=submit name=sort value="Problem Analysis"/>';
-	$Ptr .= '<br><br>';
-	$Ptr .= '<input type=submit name=sort value="Student Assessment"/>';
-	$Ptr .= '</h3>';
-	#$Ptr .= '<input type=submit name=sort value="Activity Log"/>';
-	$r->print( $Ptr );
-    }
-    else {
-	&ClassList();
-	if ( $content eq 'Student Assessment' || 
-	     $content eq 'Create Student Report' ) {
-	    &MapSecOptions();
-	    &StudentOptions();
-	    &StudentReport($CurStu,$StuBox{"$CurStu"});
-	}
-	elsif ( $content eq 'Problem Analysis' ) {
-	    &AnalyzeProblem();
-	}
-	else {
-	    &MapSecOptions();
-	    &PreStatTable();
-	}
-    }
+    my $graphData = &GetGraphData('DiffGraph', $courseID);
+    $r->print('<IMG src="/cgi-bin/graph.gif?'.$graphData.'" />');
+
+    return;
 }
 
+sub BuildWrongGraph {
+    my ($courseID)=@_;
 
-sub Menu {
-    &initial();
-#    my $fn=$ENV{'request.course.fn'};
-#    $r->print( '<br>'.$fn.'<br>' );
+    my $graphData = &GetGraphData('WrongGraph', $courseID);
+    $r->print('<IMG src="/cgi-bin/graph.gif?'.$graphData.'" />');
 
-#    $Apache::lonxml::debug=1;
-#    &Apache::lonhomework::showhash(%ENV);
-#    $Apache::lonxml::debug=0;
-
-    &Title();
-    my $InpStr = $ENV{'form.sort'};
-    if ($InpStr eq 'Activity Log') {
-	&Activity();
-    }    
-    elsif ($InpStr=~/^Analyze\_/) {
-	&ClassList();
-	&ShowOpGraph($InpStr,$ENV{'form.interval'});
-    }
-    elsif ( $InpStr eq 'DoDiff Graph' || $InpStr eq '%Wrong Graph' ) {      
-	&GetGraphData($InpStr);
-    	$r->print('<IMG src="/cgi-bin/graph.gif?'.$GData.'" />');
-    }
-    else {
-	&CreateForm();
-	$r->print("\n".'</form>');
+    return;
+}
+
+sub BuildAnalyzePage {
+    my ($cacheDB, $students, $courseID)=@_;
+
+    my %cache;
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return;
     }
-    $r->print("\n".'</body>'.
-	      "\n".'</html>');
-    $r->rflush();
+
+    &ShowOpGraph(\%cache, $students, $courseID);
+
+    untie(%cache);
+
+    return;
 }
 
+sub BuildProblemAnalysisPage {
+    my ($cacheDB)=@_;
 
-sub StudentOptions {
-    my $OpSel5='';
-    $CurStu = $ENV{'form.student'};
-    if ( $CurStu eq '' ) { 
-        $CurStu = 'All Students';
-        $OpSel5 = 'selected';
-    }
-    my $Ptr ='';
-# ----------------------------------- Loading the Students Combobox
-    $Ptr .= '<br><b>Select Student</b>'."\n".
-       	    '<select name="student">'."\n". 
-	    '<option '.$OpSel5.'>All Students</option>';                     	     	     
-    foreach my $key ( sort keys %StuBox ) {	          
-	$Ptr .= '<option';
-	if ($CurStu eq $key) {$Ptr .= ' selected';}     
-        $Ptr .= '>'.$key."</option>\n";	     
+    my %cache;
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return;
     }
-    $Ptr .= '</select>';
-    $Ptr .= '<br><input type="submit" name="sort" value="Create Student Report" />';
-    $r->print( $Ptr );
-    $r->rflush();	
+
+    $r->print('<form name="ProblemAnalysisPage" method="post" ');
+    $r->print('action="/adm/statistics">'."\n");
+    $r->print('<tr><td></td><td align="left"><input type="submit" ');
+    $r->print('name="Menu" value="Return to Menu" /></td></tr>'."\n");
+    $r->print(&IntervalOptions());
+    $r->print(&OptionResponseTable(\%cache));
+    $r->print('</form>'."\n");
+
+    untie(%cache);
+
+    return;
 }
 
+sub BuildStudentAssessmentPage {
+    my ($cacheDB, $students, $courseID)=@_;
 
-sub GetStatus {
-    $OpSel1='';
-    $OpSel2='';
-    $OpSel3='';
-    $OpSel4='';
+    my %cache;
 
-    if ( $ENV{'form.order'} eq 'Descending' ) { $OpSel2='selected'; }
-    else { $OpSel1 = 'selected'; }
+    my $Ptr = '';
+    $Ptr .= '<form name="StudentAssessmentPage" method="post" ';
+    $Ptr .= 'action="/adm/statistics">'."\n";
+    $Ptr .= '<table border="0"><tbody>';
+    $Ptr .= '<tr><td></td><td align="left"><input type="submit" name="Menu" ';
+    $Ptr .= 'value="Return to Menu" /></td></tr>'."\n";
+    $r->print($Ptr);
 
-    my %myHeader = reverse( %Header );
-    $Pos = $myHeader{$ENV{'form.sort'}};
-    if ($Pos == 0) {
-	$OpSel1 = 'selected';
-	$ENV{'form.order'}='Ascendig';
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return;
     }
 
-    $CurMap = $ENV{'form.maps'};
-    if ( $CurMap eq '' ) { 
-	$CurMap = 'All Maps';
-	$OpSel3 = 'selected';
+    my $selectedName = $cache{'StudentAssessmentStudent'};
+    for(my $index=0; $index<(scalar @$students); $index++) {
+        my ($username) = split(':', $students->[$index]);
+        if($username eq $selectedName) {
+            if($cache{'StudentAssessmentMove'} eq 'next') {
+                if($index == ((scalar @$students) - 1)) {
+                    ($selectedName) = split(':',$students->[0]);
+                } else {
+                    ($selectedName) = split(':',$students->[$index+1]);
+                }
+            } elsif($cache{'StudentAssessmentMove'} eq 'previous') {
+                if($index == 0) {
+                    ($selectedName) = split(':',
+                                           $students->[(scalar @$students)-1]);
+                } else {
+                    ($selectedName)=split(':',$students->[$index-1]);
+                }
+            }
+            last;
+        }
     }
-    $CurSec = $ENV{'form.section'};
-    if ( $CurSec eq '' ) { 
-	$CurSec = 'All Sections';
-        $OpSel4 = 'selected';
+
+    $r->print(&MapOptions(\%cache, 'StudentAssessment'));
+    $r->print(&StudentOptions($students, $selectedName));
+
+    $Ptr  = '<tr><td></td><td align="left">';
+    $Ptr .= '<input type="submit" name="CreateStudentAssessment" ';
+    $Ptr .= 'value="Create Student Report" />';
+    $Ptr .= '&nbsp&nbsp&nbsp';
+    $Ptr .= '<input type="submit" name="PreviousStudent" ';
+    $Ptr .= 'value="Previous Student" />';
+    $Ptr .= '&nbsp&nbsp&nbsp';
+    $Ptr .= '<input type="submit" name="NextStudent" ';
+    $Ptr .= 'value="Next Student" />';
+    $Ptr .= '&nbsp&nbsp&nbsp';
+    $Ptr .= '</td></tr></tbody></table></form>'."\n";
+    $r->print($Ptr);
+
+    untie(%cache);
+
+    if($selectedName eq 'No Student Selected') {
+	$r->print('<h3><font color=blue>WARNING: ');
+        $r->print('Please select a student</font></h3>');
+        return;
     }
-}
 
+    my $name = '';
+    foreach (@$students) {
+        my ($currentName) = split(':',$_);
+        if($currentName eq $selectedName) {
+            $name = $_;
+            last;
+        }
+    }
+    if($name eq '') {
+        $r->print('<h3><font color=blue>ERROR: Unknown student selected.');
+        $r->print('</font></h3>');
+        return;
+    }
 
-sub MapSecOptions {
-# ----------------------------------- Loading the Maps Combobox
-    my $Ptr = '<br>';
-    $Ptr .= '<input type="submit" name="sort" value="Return to Menu" />';
-    $Ptr .= '<br><b> Select &nbsp; Map &nbsp; &nbsp; </b>'."\n".
-       	    '<select name="maps">'."\n". 
-	    '<option '.$OpSel3.'>All Maps</option>';                     	     	     
-    foreach my $key ( sort keys %maps ) {	          
-	$Ptr .= '<option';
-        if ($CurMap eq $key) {$Ptr .= ' selected';}	     
-	$Ptr .= '>'.$key."</option>\n";	     
+    my $courseData = 
+        &Apache::loncoursedata::DownloadStudentCourseInformation($name, 
+                                                                 $courseID);
+    if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) {
+        &Apache::loncoursedata::ProcessStudentData(\%cache, 
+                                                   $courseData, $name);
+        untie(%cache);
     }
-    $Ptr .= '</select>';
-    $Ptr .= '&nbsp;&nbsp;&nbsp;';
 
-# ----------------------------------- Loading the Sections Combobox
-    $Ptr .= '<br><b>Select Section</b>'."\n".
-       	    '<select name="section">'."\n". 
-	    '<option '.$OpSel4.'>All Sections</option>';                     	     	     
-    foreach my $key ( sort keys %section ) {	          
-	$Ptr .= '<option';
-        if ($CurSec eq $key) {$Ptr .= ' selected';}     
-	$Ptr .= '>'.$key."</option>"."\n";	     
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $Ptr .= 'Could not tie database.';
+        return $Ptr;
     }
-    $Ptr .= '</select>'."\n";
+    $r->print(&StudentReport(\%cache, $name));
+    untie(%cache);
 
-    $r->print( $Ptr );
-    $r->rflush();
+    return;
 }
 
+sub BuildMenu {
+    my ($cacheDB)=@_;
+
+    my %cache;
+    unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return;
+    }
+
+    $r->print('<form name="Menu" method="post" action="/adm/statistics" >');
+    $r->print(&CreateMenuForm(\%cache));
+    $r->print('</form>'."\n");
+
+    untie(%cache);
+
+    return;
+}
 
 # ================================================================ Main Handler
 
 sub handler {
     $r=shift;
+    &initial();
 
-    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');
-	    }
-	    $r->send_http_header;
-	    return OK;
-	}    
+    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;
-# ----------------------------------------------------------------- Tie db file
+        $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
+        return HTTP_NOT_ACCEPTABLE; 
+    }
 
-	undef %hash;
+    $r->content_type('text/html');
+    $r->send_http_header;
 
-	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
-		    $r->content_type('text/html');
-		    $r->send_http_header;
-		    &Menu();
-		}
-		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; 
-	}
+    my %cache;
+    my $courseID=$ENV{'request.course.id'};
+    my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
+                  "_$ENV{'user.domain'}_$courseID\_statistics.db";
+    my $c = $r->connection;
+
+    my ($returnValue, $isCached, $students) = &PrepareData($c, $cacheDB);
+    if($returnValue ne 'OK') {
+        $r->print('<html><body>'.$returnValue."\n".'</body></html>');
+        return OK;
+    }
+
+    my $downloadTime=0;
+    my $GoToPage;
+    if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
+        $students = &SortStudents($students, \%cache);
+        if(defined($cache{'time'})) {
+            $downloadTime=$cache{'time'};
+        } else {
+            $downloadTime=localtime();
+        }
+        if(!defined($cache{'GoToPage'})) {
+            $GoToPage = 'Menu';
+        } else {
+            $GoToPage = $cache{'GoToPage'};
+        }
+        untie(%cache);
+    } else {
+        $r->print('<html><body>Unable to tie database.</body></html>');
+        return OK;
     }
-    else {
-        $ENV{'user.error.msg'}=
-        $r->uri.":vgr:0:0:Cannot view grades for complete course";
 
-        return HTTP_NOT_ACCEPTABLE; 
+    &setbgcolor(0);
+    $r->print(&Title());
+
+    if($GoToPage eq 'ActivityLog') {
+        &Activity();
+    } elsif($GoToPage eq 'ProblemStatistics') {
+        &BuildProblemStatisticsPage($cacheDB, $students);
+    } elsif($GoToPage eq 'ProblemAnalysis') {
+        &BuildProblemAnalysisPage($cacheDB);
+    } elsif($GoToPage eq 'StudentAssessment') {
+        &BuildStudentAssessmentPage($cacheDB, $students, $courseID);
+    } elsif($GoToPage eq 'Analyze') {
+        &BuildAnalyzePage($cacheDB, $students, $courseID);
+    } elsif($GoToPage eq 'DoDiffGraph') {
+        &BuildDiffGraph($courseID);
+    } elsif($GoToPage eq 'PercentWrongGraph') {
+        &BuildWrongGraph($courseID);
+    } else {
+        &BuildMenu($cacheDB);
     }
+
+    $r->print("\n".'</body>'."\n".'</html>');
+    $r->rflush();
+
+    return OK;
 }
 1;
 __END__

--stredwic1026910380--