Diff for /loncom/interface/lonstatistics.pm between versions 1.14 and 1.55.2.1

version 1.14, 2002/03/26 18:11:32 version 1.55.2.1, 2003/01/13 20:34:24
Line 27 Line 27
 #  #
 # (Navigate problems for statistical reports  # (Navigate problems for statistical reports
 # YEAR=2001  # YEAR=2001
 # 5/05,7/09,7/25/01,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei  # 5/5,7/9,7/25/1,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei
 # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei  # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
 # YEAR=2002  # YEAR=2002
 # 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26 Behrouz Minaei  # 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26,4/7,5/6 Behrouz Minaei
   # 5/12,5/14,5/15,5/19,5/26,7/16,25/7,29/7  Behrouz Minaei
 #  #
 ###  ###
   
 package Apache::lonstatistics;   package Apache::lonstatistics;
   
 use strict;  use strict;
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
 use Apache::lonnet();  use Apache::lonnet();
 use Apache::lonhomework;  use Apache::lonhomework;
 use Apache::loncommon;  use Apache::loncommon;
   use Apache::loncoursedata;
   use Apache::lonhtmlcommon;
   use Apache::lonproblemanalysis;
   use Apache::lonproblemstatistics;
   use Apache::lonstudentassessment;
   use Apache::lonpercentage;
 use HTML::TokeParser;  use HTML::TokeParser;
 use GDBM_File;  use GDBM_File;
   
 # -------------------------------------------------------------- Module Globals  
 my %hash;  sub CheckFormElement {
 my %CachData;      my ($cache, $ENVName, $cacheName, $default)=@_;
 my %GraphDat;  
 my %OpResp;      if(defined($ENV{'form.'.$ENVName})) {
 my %maps;          $cache->{$cacheName} = $ENV{'form.'.$ENVName};
 my %mapsort;      } elsif(!defined($cache->{$cacheName})) {
 my %section;          $cache->{$cacheName} = $default;
 my %StuBox;      }
 my %DiscFac;  
 my %DisUp;      return;
 my %DisLow;  }
 my $UpCnt;  
 my $CurMap;  sub ProcessFormData{
 my $CurSec;      my ($cache)=@_;
 my $CurStu;  
 my @cols;      $cache->{'reportKey'} = 'false';
 my @list;  
 my @students;      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
 my $p_count;                                              ['sort','download',
 my $Pos;                                               'reportSelected',
 my $r;                                               'StudentAssessmentStudent',
 my $OpSel1;                                               'ProblemStatisticsSort']);
 my $OpSel2;      &CheckFormElement($cache, 'Status', 'Status', 'Active');
 my $OpSelDis1;      &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list');
 my $OpSelDis2;      &CheckFormElement($cache, 'reportSelected', 'reportSelected', 
 my $OpSel3;                        'Class list');
 my $OpSel4;      $cache->{'reportSelected'} = 
 my $GData;          &Apache::lonnet::unescape($cache->{'reportSelected'});
 my $cid;      &CheckFormElement($cache, 'DownloadAll', 'DownloadAll', 'false');
 my $firstres;      &CheckFormElement($cache, 'sort', 'sort', 'fullname');
 my $lastres;      &CheckFormElement($cache, 'download', 'download', 'false');
 my $DiscFlag;      &CheckFormElement($cache, 'StatisticsMaps', 
 my $HWN;                        'StatisticsMaps', 'All Maps');
 my $P_Order;      &CheckFormElement($cache, 'StatisticsProblemSelect',
 my %Header = (0,"Homework Sets Order",1,"#Stdnts",2,"Tries",3,"Mod",        'StatisticsProblemSelect', 'All Problems');
               4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"DoDiff",      &CheckFormElement($cache, 'StatisticsPartSelect',
               9,"S.D.",10,"Skew.",11,"D.F.1st",12,"D.F.2nd");#,13,"OpResp");        'StatisticsPartSelect', 'All Parts');
       if(defined($ENV{'form.Section'})) {
           my @sectionsSelected = (ref($ENV{'form.Section'}) ?
 #------- Processing upperlist and lowerlist according to each problem                                 @{$ENV{'form.Section'}} :
 sub ProcessDisc {                                  ($ENV{'form.Section'}));
     my @List = @_;          $cache->{'sectionsSelected'} = join(':', @sectionsSelected);
     @List = sort (@List);      } elsif(!defined($cache->{'sectionsSelected'})) {
     my $Count = $#List+1;          $cache->{'sectionsSelected'} = $cache->{'sectionList'};
     my $Prb;      }
     my @Dis;  
     my $Slvd=0;      # student assessment
     my $tmp;      if(defined($ENV{'form.CreateStudentAssessment'}) ||
     my $Sum1=0;         defined($ENV{'form.NextStudent'}) ||
     my $Sum2=0;         defined($ENV{'form.PreviousStudent'})) {
     my $nIdx=0;          $cache->{'reportSelected'} = 'Student Assessment';
     my $nStud=0;      }
     my %Proc;      if(defined($ENV{'form.NextStudent'})) {
     undef %Proc;          $cache->{'StudentAssessmentMove'} = 'next';
     while ($nIdx<$Count) {      } elsif(defined($ENV{'form.PreviousStudent'})) {
  ($Prb,$tmp)=split(/\=/,$List[$nIdx]);          $cache->{'StudentAssessmentMove'} = 'previous';
  @Dis=split(/\+/,$tmp);      } else {
  my $Temp = $Prb;          $cache->{'StudentAssessmentMove'} = 'selected';
  do {      }
     $nIdx++;      &CheckFormElement($cache, 'StudentAssessmentStudent', 
     $nStud++;                        'StudentAssessmentStudent', 'All Students');
     $Sum1 += $Dis[0];      $cache->{'StudentAssessmentStudent'} = 
     $Sum2 += $Dis[1];          &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'});
     ($Prb,$tmp)=split(/\=/,$List[$nIdx]);      &CheckFormElement($cache, 'DefaultColumns', 'DefaultColumns', 'false');
     @Dis=split(/\+/,$tmp);  
  } while ( $Prb eq $Temp && $nIdx < $Count );      # Problem analysis
 # $Proc{$Temp}=($Sum1/$nStud).':'.$nStud;      &CheckFormElement($cache, 'Interval', 'Interval', '1');
  $Proc{$Temp}=($Sum1/$nStud).':'.($Sum2/$nStud);  
 #        $r->print("$nIdx) $Temp --> ($nStud) $Proc{$Temp} <br>");      # ProblemStatistcs
  $Sum1=0;      &CheckFormElement($cache, 'DisplayCSVFormat',
  $Sum2=0;                        'DisplayFormat', 'Display Table Format');
  $nStud=0;      &CheckFormElement($cache, 'ProblemStatisticsAscend',
                         'ProblemStatisticsAscend', 'Ascending');
       &CheckFormElement($cache, 'ProblemStatisticsSort',
                         'ProblemStatisticsSort', 'Homework Sets Order');
       &CheckFormElement($cache, 'DisplayLegend', 'DisplayLegend', 
         'Hide Legend');
       &CheckFormElement($cache, 'SortProblems', 'SortProblems', 
                         'Sort Within Sequence');
   
       # Search only form elements
       my @headingColumns=();
       my @sequenceColumns=();
       my $foundColumn = 0;
       if(defined($ENV{'form.ReselectColumns'})) {
           my @reselected = (ref($ENV{'form.ReselectColumns'}) ? 
                             @{$ENV{'form.ReselectColumns'}}
                             : ($ENV{'form.ReselectColumns'}));
           foreach (@reselected) {
               if(/HeadingColumn/) {
                   push(@headingColumns, $_);
                   $foundColumn = 1;
               } elsif(/SequenceColumn/) {
                   push(@sequenceColumns, $_);
                   $foundColumn = 1;
               }
           }
     }      }
     return %Proc;  
 }  
   
       $cache->{'reportKey'} = 'false';
       if($cache->{'reportSelected'} eq 'Analyze') {
           $cache->{'reportKey'} = 'Analyze';
       } elsif($cache->{'reportSelected'} eq 'DoDiffGraph') {
           $cache->{'reportKey'} = 'DoDiffGraph';
       } elsif($cache->{'reportSelected'} eq 'PercentWrongGraph') {
           $cache->{'reportKey'} = 'PercentWrongGraph';
       }
   
       if(defined($ENV{'form.DoDiffGraph'})) {
           $cache->{'reportSelected'} = 'DoDiffGraph';
           $cache->{'reportKey'} = 'DoDiffGraph';
       } elsif(defined($ENV{'form.PercentWrongGraph'})) {
           $cache->{'reportSelected'} = 'PercentWrongGraph';
           $cache->{'reportKey'} = 'PercentWrongGraph';
       }
   
       foreach (keys(%ENV)) {
           if(/form\.Analyze/) {
               $cache->{'reportSelected'} = 'Analyze';
               $cache->{'reportKey'} = 'Analyze';
               my $data;
               (undef, $data)=split(':::', $_);
               $cache->{'AnalyzeInfo'}=$data;
           } elsif(/form\.HeadingColumn/) {
               my $value = $_;
               $value =~ s/form\.//;
               push(@headingColumns, $value);
               $foundColumn=1;
           } elsif(/form\.SequenceColumn/) {
               my $value = $_;
               $value =~ s/form\.//;
               push(@sequenceColumns, $value);
               $foundColumn=1;
           }
       }
   
 #------- Creating Discimination factor         if($foundColumn) {
 sub Discriminant {          $cache->{'HeadingsFound'} = join(':', @headingColumns);
     my $Count=0;          $cache->{'SequencesFound'} = join(':', @sequenceColumns);;
     foreach (keys(%DiscFac)){   
  $Count++;  
     }  
     $UpCnt = int(0.27*$Count);  
     my $low=0;  
     my $up=$Count-$UpCnt;  
     my @UpList=();  
     my @LowList=();  
     $Count=0;  
     foreach my $key (sort(keys(%DiscFac))){   
  $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,$_);}  
  }  
     }  
  }  
     }      }
     %DisUp=&ProcessDisc(@UpList);      if(!defined($cache->{'HeadingsFound'}) || 
     %DisLow=&ProcessDisc(@LowList);         $cache->{'DefaultColumns'} ne 'false') {
 }          $cache->{'HeadingsFound'}='HeadingColumnFull Name';
       }
       if(!defined($cache->{'SequencesFound'}) ||
          $cache->{'DefaultColumns'} ne 'false') {
           $cache->{'SequencesFound'}='All Sequences';
       }
       $cache->{'DefaultColumns'} = 'false';
   
          return;
 sub NumericSort {            
     $a <=> $b;  
 }  }
   
 # ------ Create different Student Report   =pod
 sub StudentReport {  
     my ($sname,$sdom)=@_;  
     if ( $sname eq 'All Students' ) {  
  $r->print( '<h3><font color=blue>WARNING:   
                     Please select a student</font></h3>' );  
  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=~/^error\:/) {  
         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.'___'.  =item &SortStudents()
                        &Apache::lonnet::declutter( $hash{'src_'.$ResId} );  
             $Code='U';  Determines which students to display and in which order.  Which are 
             $Tries = 0;  displayed are determined by their status(active/expired).  The order
             $Wrongs = 0;  is determined by the sort button pressed (default to username).  The
      $LatestVersion = $result{"version:$Prob"};  type of sorting is username, lastname, or section.
     if ( $LatestVersion ) {  
  for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {  =over 4
     my $vkeys = $result{"$Version:keys:$Prob"};  
     my @keys = split(/\:/,$vkeys);  Input: $students, $CacheData
     
     foreach my $Key (@keys) {    $students: A array pointer to a list of students (username:domain)
  if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {  
     my $Part = $1;  $CacheData: A pointer to the hash tied to the cached data
     $Tries = $result{"$Version:$Prob:resource.$Part.tries"};  
     $TempHash{"$Part.Tries"} = ($Tries) ? $Tries : 0;   Output: \@order
     $TotalTries += $Tries;  
     my $Val = $result{"$Version:$Prob:resource.$Part.solved"};  @order: An ordered list of students (username:domain)
     if ( $Val eq 'correct_by_student' )  
                                 { $Wrongs = $Tries - 1; $Code = 'Y'; }   =back
     elsif ( $Val eq 'correct_by_override' )  
                                 { $Wrongs = $Tries - 1; $Code = 'y'; }                          =cut
     elsif ( $Val eq 'incorrect_attempted' ||   
                                 $Val eq 'incorrect_by_override' )  sub SortStudents {
                 { $Wrongs = $Tries; $Code = 'N'; }      my ($cache)=@_;
     $TempHash{"$Part.Code"} = $Code;  
     $TempHash{"$Part.Wrongs"} = $Wrongs;      my @students = split(':::',$cache->{'NamesOfStudents'});
  }      my @sorted1Students=();
          }      foreach (@students) {
                 }          if($cache->{'Status'} eq 'Any' || 
  for ( my $n = 0; $n < $PartNo; $n++ ) {               $cache->{$_.':Status'} eq $cache->{'Status'}) {
     my $part = $TempHash{$n};              push(@sorted1Students, $_);
     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();  
 }  
   
 sub CreateTable {      my $sortBy = '';
     my $ColNo=0;      if(defined($cache->{'sort'})) {
     foreach (keys(%Header)){           $sortBy = ':'.$cache->{'sort'};
  $ColNo++;      } else {
     }           $sortBy = ':fullname';
     my ($Hd, $Hid)=@_;  
     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";  
     }      }
     $Result .= "\n".'</tr>'."\n";          my @order = sort { lc($cache->{$a.$sortBy}) cmp lc($cache->{$b.$sortBy}) ||
     $r->print( $Result );                         lc($cache->{$a.':fullname'}) cmp lc($cache->{$b.':fullname'}) } 
     $r->rflush();                  @sorted1Students;
 }  
   
 sub CloseTable {      return \@order;
     $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->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");  
         }  
     }  
   
 #33333  =pod
 #    my $c=0;  
 #    foreach (sort keys %OpResp) {  
 # $r->print('<br>'.$c.$_.' ====== '.$OpResp{$_});  
 # my $count=$#students+1;  
 # for (my $n=0;$n<1;$n++){  
 #    my ($sname,$sdom)=$students[$n];  
 #    my $Prob=$OpResp{$_};  
 ##my $userview=&Apache::lonnet::ssi($hash{'src_'.$ResId});  
 # $r->print('<br>'.$Prob.$sname.$sdom.$cid.  
 #  '<br>'.&Apache::loncommon::get_previous_attempt($Prob,$sname,$sdom,$cid));  
 # #$r->print('<br>'.$Prob.$sname. ' *** '.&Apache::lonnet::ssi($hash{'src_'.$Prob}));   
 # }  
 # $c++;  
 #    }  
   
     #$r->print('Total instances of the problems : '.($p_count*($#students+1)));  =item &SpaceColumns()
   
     untie(%CachData);  Determines the width of all the columns in the chart.  It is based on
     untie(%GraphDat);  the max of the data for that column and its header.
 }  
   
   =over 4
   
 # ------------------------------------- Find the section of student in a course  Input: $students, $studentInformation, $headings, $ChartDB
   
 sub usection {  $students: An array pointer to a list of students (username:domain)
     my ($udom,$unam,$courseid,$ActiveFlag)=@_;  
     $courseid=~s/\_/\//g;  
     $courseid=~s/^(\w)/\/$1/;  
     foreach (split(/\&/,&Apache::lonnet::reply('dump:'.  
              $udom.':'.$unam.':roles',  
              &Apache::lonnet::homeserver($unam,$udom)))){  
         my ($key,$value)=split(/\=/,$_);  
         $key=&Apache::lonnet::unescape($key);  
         if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {  
             my $section=$1;  
             if ($key eq $courseid.'_st') { $section=''; }  
     my ($dummy,$end,$start)=split(/\_/,&Apache::lonnet::unescape($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';  
 }  
   
   $studentInformatin: The type of data for the student information.  It is
   used as part of the key in $CacheData.
   
 # ------ Dump the Student's DB file and handling the data for statistics table   $headings: The name of the student information columns.
   
 sub ExtractStudentData {  $ChartDB: The name of the cache database which is opened for read/write.
     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=~/^error\:/) {  
         foreach my $CurCol(@cols) {  
     ($PrOrd,$ResId)=split(/\:/,$CurCol);  
     if ( !$CurCol ) { next; }  
             $ResId=~/(\d+)\.(\d+)/;  
     my $MapId=$1;  
     my $PrbId=$2;  
             my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$MapId} );  
             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');  
  }  
             }  
   
             my $Prob = $Map.'___'.$PrbId.'___'.  Output: None - All data stored in cache.
                        &Apache::lonnet::declutter( $hash{'src_'.$ResId} );  
             $Code='U';  =back
             $Tries = 0;  
     $ParCr = 0;  =cut
             $Wrongs = 0;  
      $LatestVersion = $result{"version:$Prob"};         sub SpaceColumns {
       my ($students,$studentInformation,$headings,$cache)=@_;
     if ( $LatestVersion ) {  
  for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {      # Initialize Lengths
     my $vkeys = $result{"$Version:keys:$Prob"};      for(my $index=0; $index<(scalar @$headings); $index++) {
     my @keys = split(/\:/,$vkeys);          my @titleLength=split(//,$headings->[$index]);
           $cache->{$studentInformation->[$index].':columnWidth'}=
     foreach my $Key (@keys) {                scalar @titleLength;
 #333333333      }
 # if ($OpResp{$PrOrd}) {  
 #    if (($Key=~/\.(\w+)\.submission$/)) {      foreach my $name (@$students) {
 # my $Resp = $result{"$Version:$Prob:$Key"};          foreach (@$studentInformation) {
 # $r->print('<br>'.$Prob.'<br>'.$sname.'<br>'.$PrOrd.'<br>'.$Key.'<br><b>'.$Resp.'</b>');               my @dataLength=split(//,$cache->{$name.':'.$_});
 # $r->rflush();              my $length=(scalar @dataLength);
 #              if($length > $cache->{$_.':columnWidth'}) {
 # my %submission=&Apache::lonnet::str2hash($Resp);                  $cache->{$_.':columnWidth'}=$length;
 #    my $cb=0;  
 #    foreach (sort keys %submission) {  
 # $r->print('<br>'.$cb.')'.$_.' ... '.$submission{$_});  
 # $cb++;  
 #    }  
 #    }    
 # }  
  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"};  
     $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++;  
  }  
             }              }
     #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;  
     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;  
  }  
     }      }
     #$r->print($sname.' PrCr= '.$TotParCr.' Slvd= '.$ProbSolved.' Tries='.$TotalTries.'<br>');  
       return;
 }  }
   
   sub PrepareData {
       my ($c, $cacheDB, $studentInformation, $headings,$r)=@_;
   
 # ------------------------------------------------------------ Build page table      # Test for access to the cache data
 sub tracetable {      my $courseID=$ENV{'request.course.id'};
     my ($rid,$beenhere)=@_;      my $isRecalculate=0;
     my $IsMap=0;      if(defined($ENV{'form.Recalculate'})) {
     $rid=~/(\d+)\.(\d+)/;          $isRecalculate=1;
     $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+1}=$frid;  
        }   
      
    }  
        }  
    }  
                }  
    }  
  #  }  
        } 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+1}=$rid;  
        }   
      
    }  
   
        }  
    }  
        }  
    }         
        }  
        if (defined($hash{'to_'.$rid})) {  
           foreach (split(/\,/,$hash{'to_'.$rid})){  
               &tracetable($hash{'goesto_'.$_},$beenhere);  
           }  
        }  
     }      }
 }  
   
 sub MySort {                my $isCached = &Apache::loncoursedata::TestCacheData($cacheDB,
     if ( $Pos > 0 ) {                                                           $isRecalculate);
  if ($ENV{'form.order'} eq 'Descending') {$b <=> $a;}      if($isCached < 0) {
  else { $a <=> $b; }          return "Unable to tie hash to db file.";
     }  
     else {  
  if ($ENV{'form.order'} eq 'Descending') {$b cmp $a;}  
  else { $a cmp $b; }  
     }      }
 }  
   
 sub Build_Statistics {      # Download class list information if not using cached data
     $r->print(<<ENDPOP);      my %cache;
     <script>      unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
     popwin=open('','popwin','width=400,height=100');          return "Unable to tie hash to db file.";
     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();  #    if(!$isCached) {
 # ---------------------------- Gathering the Data of students' tries          my $processTopResourceMapReturn=
     my $index;              &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c);
     for ($index=0;$index<=$#students;$index++) {          if($processTopResourceMapReturn ne 'OK') {
 #----------- update progress              untie(%cache);
         $r->print('<script>popwin.document.popremain.remaining.value="'.              return $processTopResourceMapReturn;
                   'Computing '.($index+1).'/'.($#students+1).': '.          }
                   $students[$index].'";</script>');   #   }
         $r->rflush();  
   
         &ExtractStudentData($students[$index]);      if($c->aborted()) {
           untie(%cache);
           return 'aborted'; 
     }      }
   
 # -------------------- sorting the Data      my $classlist=&Apache::loncoursedata::DownloadClasslist($courseID,
     $r->print('<script>popwin.document.popremain.remaining.value="'.                                                  $cache{'ClasslistTimestamp'},
               'Calculating Discrimination Factors...";</script>');                                                  $c);
       foreach (keys(%$classlist)) {
     @list = sort (@list);          if(/^(con_lost|error|no_such_host)/i) {
               untie(%cache);
               return "Error getting student data.";
     &Discriminant();          }
   
     $OpSel2='';  
     $OpSel1='selected';  
       
     $p_count = 0;   
     my $nIdx = 0;  
     my $dummy;   
     my $p_val;  
     my $ResId;  
     my $NoElements = $#list + 1;  
 #-------------------------------- loop for data representation  
     foreach (sort keys %mapsort) {  
  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 $Temp = $Prob;  
     my $MxTries = 0;  
     my $TotalTries = 0;  
     my $YES = 0;  
     my $Incorrect = 0;  
     my $Override = 0;  
     my $StdNo = 0;  
     my @StdLst;  
     while ( $PrOrd == $lpr[$i] )   
     {  
  $nIdx++;  
  $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 'U' ) { $StdNo--; }  
  ($PrOrd,$Prob,$Tries,$Wrongs,$Code)=split(/\&/,$list[$nIdx]);  
     }  
   
     $p_count++;  
     my $Dummy;  
     ($ResId,$Dummy)=split(/\*/,$Temp);  
   
     $Temp = '<a href="'.$hash{'src_'.$ResId}.  
                 '" target="_blank">'.$hash{'title_'.$ResId}.$Dummy.'</a>';  
       
     my $res = &Apache::lonnet::declutter($hash{'src_'.$ResId});  
     my $urlres=$res;  
   
     $ResId=~/(\d+)\.(\d+)/;  
     my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} );  
     $urlres=$Map;  
    
     $res = '<a href="'.$hash{'src_'.$ResId}.'">'.$res.'</a>';  
     #$Map = '<a href="'.$Map.'">'.$res.'</a>';  
   
 #------------------------ 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(/\:/,$DisUp{$lpr[$i]});  
     my ($Lw1,$Lw2)=split(/\:/,$DisLow{$lpr[$i]});  
     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 = $PrOrd.'&'.$Temp.'&'.$StdNo.'&'.  
                        $TotalTries.'&'.$MxTries.'&'.$Avg.'&'.  
                        $YES.'&'.$Override.'&'.$Wrng.'&'.$DoD.'&'.  
        $SD.'&'.$Sk.'&'.$_D1.'&'.$_D2.'&'.$Prob;  
     $CachData{($p_count-1)}=$join;  
   
     $urlres=~/^(\w+)\/(\w+)/;  
     if ($StdNo) {   
  &Apache::lonnet::put('resevaldata',\%storestats,$1,$2);   
     }  
 #-------------------------------- Row of statistical table  
     if ( $DiscFlag == 0 ) {  
  &TableRow($join,$i,($p_count-1));  
     }   
  }  
  &CloseTable();  
     }  
 #--------------------- close Progress Line  
     $r->print('<script>popwin.close()</script>');  
     $r->rflush();   
 }  
   
 sub Cache_Statistics {  
     my @list = ();  
     my $Useful;  
     my $UnUseful;  
     my %myHeader = reverse( %Header );  
     $Pos = $myHeader{$ENV{'form.sort'}};  
     if ($Pos > 0) {$Pos++;}  
     $p_count = 0;  
     foreach my $key( keys %CachData) {   
  my @Temp=split(/\&/,$CachData{$key});  
  if ( $Pos == 0 ) {  
     ($UnUseful,$Useful)=split(/\>/,$Temp[$Pos]);  
  }  
  else {  
     $Useful = $Temp[$Pos];  
  }     
  $list[$p_count]=$Useful.'@'.$CachData{$key};  
         $p_count++;  
     }  
   
     @list = sort MySort (@list);  
   
     my $nIdx=0;  
   
     if ( $Pos == 0 ) {  
  foreach (sort keys %mapsort) {  
     my ($Hid,$pr)=split(/\:/,$mapsort{$_});  
     &CreateTable(1,$Hid);  
     my @lpr=split(/\&/,$pr);  
     for (my $i=1; $i<=$#lpr; $i++) {  
  my($Pre, $Post) = split(/\@/,$list[$nIdx]);   
  #$r->print('<br>'.$Pre.'---'.$Post);  
  &TableRow($Post,$i,$nIdx);  
  $nIdx++;  
     }  
     &CloseTable();  
  }  
     }  
     else {  
  &CreateTable(0);  
  for ( my $nIdx = 0; $nIdx < $p_count; $nIdx++ ) {  
     my($Pre, $Post) = split(/\@/,$list[$nIdx]);   
     &TableRow($Post,$nIdx,$nIdx);  
  }   
  &CloseTable();  
     }      }
 }  
   
 sub TableRow {      if($c->aborted()) {
     my ($Str,$Idx,$RealIdx)=@_;          untie(%cache);
     my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,          return 'aborted'; 
        $Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$Prob)=split(/\&/,$Str);      }
     my $Ptr =  "\n".'<tr>'.  
                "\n".'<td>'.($RealIdx+1).'</td>'.      # Active is a temporary solution, remember to change
           #     "\n".'<td>'.$PrOrd.$Temp.'</td>'.      Apache::loncoursedata::ProcessClasslist(\%cache,$classlist,$courseID,$c);
                "\n".'<td>'.$Temp.'</td>'.      if($c->aborted()) {
                "\n".'<td bgcolor="#EEFFCC"> '.$StdNo.'</td>'.          untie(%cache);
                "\n".'<td bgcolor="#EEFFCC">'.$TotalTries.'</td>'.          return 'aborted'; 
                "\n".'<td bgcolor="#EEFFCC">'.$MxTries.'</td>'.      }
                "\n".'<td bgcolor="#DDFFFF">'.$Avg.'</td>'.  
                "\n".'<td bgcolor="#DDFFFF"> '.$YES.'</td>'.      &ProcessFormData(\%cache);
                "\n".'<td bgcolor="#DDFFFF"> '.$Override.'</td>'.      my $students = &SortStudents(\%cache);
                "\n".'<td bgcolor="#FFDDDD"> '.$Wrng.'</td>'.      &SpaceColumns($students, $studentInformation, $headings, \%cache);
                "\n".'<td bgcolor="#FFDDDD">'.$DoD.'</td>'.      $cache{'updateTime:columnWidth'}=24;
                "\n".'<td bgcolor="#DDFFDD"> '.$SD.'</td>'.  
                "\n".'<td bgcolor="#DDFFDD"> '.$Sk.'</td>'.      my $download = $cache{'download'};
                "\n".'<td bgcolor="#FFDDFF"> '.$_D1.'</td>'.      my $downloadAll = $cache{'DownloadAll'};
        "\n".'<td bgcolor="#FFDDFF"> '.$_D2.'</td>';      my @allStudents=();
 #    if( $OpResp{$PrOrd} ) {      if($download ne 'false') {
 # $Ptr.='<td>'.'<input type="submit" name="OpResp" value="'."View_$PrOrd".'" />'.'</td>';          $cache{'download'} = 'false';
 #    }         } elsif($downloadAll ne 'false') {
 #    else {          $cache{'DownloadAll'} = 'false';
 # $Ptr.='<td> -------- </td>';          if($downloadAll eq 'sorted') {
 #    }              @allStudents = @$students;
     $r->print("\n".$Ptr.'</tr>' );          } else {
     $GraphDat{$RealIdx}=$DoD.':'.$Wrng;              @allStudents = split(':::', $cache{'NamesOfStudents'});
 }          }
       }
   
 # ------------------------------------------- Prepare data for Graphical chart      untie(%cache);
   
 sub GetGraphData {      if($download ne 'false') {
     my $Tag = shift;          my @who = ($download);
     my $Col;          if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'false',
     my $data='';                                                               $cacheDB, 'true',
     my $count = 0;                                                               'false', $courseID,
     my $Max = 0;                                                               $r, $c) ne 'OK') {
     my $cid=$ENV{'request.course.id'};              return 'Stop at download individual';
     my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".          }
                   "_$ENV{'user.domain'}_$cid\_graph.db";      } elsif($downloadAll ne 'false') {
     foreach (keys %GraphDat) {delete $GraphDat{$_};}          if(&Apache::loncoursedata::DownloadStudentCourseData(\@allStudents,
     if (-e "$GraphDB") {                                                               'false',
  if (tie(%GraphDat,'GDBM_File',"$GraphDB",&GDBM_READER,0640)) {                                                               $cacheDB, 'true',
     if ( $Tag eq 'DoDiff Graph' ) {                                                               'true', $courseID,
  $Tag = 'Degree-of-Difficulty';                                                               $r, $c) ne 'OK') {
  $Col = 0;              return 'Stop at download all';
     }          }
     else {  
  $Tag = 'Wrong-Percentage';  
  $Col = 1;  
     }  
     foreach (sort NumericSort keys %GraphDat) {   
  my @Temp=split(/\:/,$GraphDat{$_});  
                 my $inf = $Temp[$Col];   
  if ( $Max < $inf ) {$Max = $inf;}  
  $data .= $inf.',';  
  $count++;  
     }  
             untie(%GraphDat);  
     my $Course = $ENV{'course.'.$cid.'.description'};  
     $Course =~ s/\ /"_"/eg;  
     $GData=$Course.'&'.$Tag.'&'.$Max.'&'.$count.'&'.$data;  
   
  }  
  else {  
     $r->print("Unable to tie hash to db file");  
  }  
     }      }
 }  
   
       return ('OK', $students);
 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 $CurMap;  
   undef $CurSec;  
   undef $CurStu;  
   undef $p_count;  
   undef $Pos;  
   undef $GData;  
   $DiscFlag=0;   
   $P_Order=100000;  
   $HWN=$P_Order;  
 }  }
   
   sub BuildClasslist {
       my ($cacheDB,$students,$studentInformation,$headings,$r)=@_;
   
 sub ClassList {      my %cache;
       unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
     &GetStatus();          return '<html><body>Unable to tie database.</body></html>';
       }
   
   #    my $Ptr = '';
   #    $Ptr .= '<table border="0"><tbody>';
   #    $Ptr .= '<tr><td align="right"><b>Select Sections</b>';
   #    $Ptr .= '</td>'."\n";
   #    $Ptr .= '<td align="left">'."\n";
   #    my @sectionsSelected = split(':',$cache{'sectionsSelected'});
   #    my @sections = split(':',$cache{'sectionList'});
   #    $Ptr .= &Apache::lonhtmlcommon::MultipleSectionSelect(\@sections,
   #                                                          \@sectionsSelected,
   #                                                          'Statistics');
   #    $Ptr .= '</td></tr></table><br>';
   #    $r->print($Ptr);
   #    $r->rflush();
   #    my %mySections = ();
   #    foreach (@sections) { $mySections{$_} = 'True'; }
   #    $r->print("<br>$cache{'sectionsSelected'}<br>");
   
       my $Str='';
       $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
       $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
   
       my $displayString = '<td align="left"><a href="/adm/statistics?';
       $displayString .= 'sort=LINKDATA">DISPLAYDATA&nbsp</a></td>'."\n";
       $Str .= &Apache::lonhtmlcommon::CreateHeadings(\%cache,
                                                      $studentInformation,
                                                      $headings, $displayString);
       $Str .= '</tr>'."\n";
   
       my $alternate=0;
       foreach (@$students) {
   #        if ($mySections{$cache{$_.':'.'section'}} ne 'True') {next;}
           my ($username, $domain) = split(':', $_);
           if($alternate) {
               $Str .= '<tr bgcolor="#ffffe6">';
           } else {
               $Str .= '<tr bgcolor="#ffffc6">';
           }
           $alternate = ($alternate + 1) % 2;
           foreach my $data (@$studentInformation) {
               $Str .= '<td>';
               if($data eq 'fullname') {
                   $Str .= '<a href="/adm/statistics?reportSelected=';
                   $Str .= &Apache::lonnet::escape('Student Assessment');
                   $Str .= '&StudentAssessmentStudent=';
                   $Str .= &Apache::lonnet::escape($cache{$_.':'.$data}).'">';
                   $Str .= $cache{$_.':'.$data}.'&nbsp';
                   $Str .= '</a>';
               } elsif($data eq 'updateTime') {
                   $Str .= '<a href="/adm/statistics?reportSelected=';
                   $Str .= &Apache::lonnet::escape('Class list');
                   $Str .= '&download='.$_.'">';
                   $Str .= $cache{$_.':'.$data}.'&nbsp';
                   $Str .= '&nbsp</a>';
               } else {
                   $Str .= $cache{$_.':'.$data}.'&nbsp';
               }
   
     $cid=$ENV{'request.course.id'};              $Str .= '</td>'."\n";
     my $chome=$ENV{'course.'.$cid.'.home'};          }
     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)) {  
 # ----------------------------------------------------------------- Render page  
  my $classlst=&Apache::lonnet::reply  
                  ('dump:'.$cdom.':'.$cnum.':classlist',$chome);  
  my $StudNo = 0;  
  my $now=time;  
  unless ($classlst=~/^error\:/) {  
     foreach (sort split(/\&/,$classlst)) {  
  my ($name,$value)=split(/\=/,$_);  
  my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value));  
  $name=&Apache::lonnet::unescape($name);  
  my ($sname,$sdom)=split(/\:/,$name);  
  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;  
     $name=&Apache::lonnet::unescape($name);  
     $students[$thisindex]=$name;  
     my ($sname,$sdom)=split(/\:/,$name);  
     #my %reply=&Apache::lonnet::idrget($sdom,$sname);  
     #my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname.  
     #         ':environment:lastname&generation&firstname&middlename',  
     #         &Apache::lonnet::homeserver($sname,$sdom));  
     my $ssec=&usection($sdom,$sname,$cid,$Status);  
     if ($ssec==-1) {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++;  
         }  
     }  
  }  
  else {  
     $r->print('<h1>Could not access course data</h1>');  
  }   
         $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++;  
 #    }  
     }      }
   
 # ------------------------------------------------------------- End render page       $Str .= '</tr>'."\n";
     else {      $Str .= '</table></td></tr></table>'."\n";
  $r->print('<h3>Undefined course sequence</h3>');      $r->print($Str);
     }      $r->rflush();
     &MapSecOptions();  
 }  
   
       untie(%cache);
   
 sub Menu {      return;
     my $InpStr = $ENV{'form.sort'};  
     if ( $InpStr eq 'DoDiff Graph' || $InpStr eq '%Wrong Graph' ) {        
  &GetGraphData($InpStr);  
     $r->print('<IMG src="/cgi-bin/graph.gif?'.$GData.'" />');  
     }  
     else {  
  $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();  
   
  $r->print("\n".'<form name=stat method=post action="/adm/statistics" >');  
   
  my $content = $ENV{'form.sort'};  
  if ($content eq '' || $content eq 'Return to Menu') {  
     my $Ptr = '<h3>';  
     $Ptr .= '<input type=submit name=sort value="Problem Evaluation"/>';  
     $Ptr .= '<br><br>';  
     $Ptr .= '<input type=submit name=sort value="Student Assessment"/>';  
     $Ptr .= '</h3>';  
     $r->print( $Ptr );  
       }  
  else {  
     &initial();  
     &ClassList();  
     if ( $content eq 'Student Assessment' ||   
                     $content eq 'Create Student Report' ) {  
  &StudentOptions();  
  &StudentReport($CurStu,$StuBox{"$CurStu"});  
     }  
     else {  
  &PreStatTable();  
     }  
  }  
  $r->print("\n".'</form>'.  
                   "\n".'</body>'.  
                   "\n".'</html>');  
  $r->rflush();  
     }  
 }  }
   
 sub StudentOptions {  sub CreateMainMenu {
     my $OpSel5='';      my ($status, $reports)=@_;
     $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";       
     }  
     $Ptr .= '</select>';  
     $Ptr .= '<br><input type="submit" name="sort" value="Create Student Report" />';  
     $r->print( $Ptr );  
     $r->rflush();  
 }  
   
 sub GetStatus {      my $Str = '';
     $OpSel1='';  
     $OpSel2='';      $Str .= '<table border="0"><tbody><tr>'."\n";
     $OpSel3='';      $Str .= '<td></td><td></td>'."\n";
     $OpSel4='';      $Str .= '<td align="center"><b>Select a Report</b></td>'."\n";
       $Str .= '<td align="center"><b>Student Status</b></td></tr>'."\n";
     if ( $ENV{'form.order'} eq 'Descending' ) { $OpSel2='selected'; }      $Str .= '<tr>'."\n";
     else { $OpSel1 = 'selected'; }      $Str .= '<td align="center"><input type="submit" name="Refresh" ';
       $Str .= 'value="Refresh" /></td>'."\n";
     my %myHeader = reverse( %Header );      $Str .= '<td align="center"><input type="submit" name="DownloadAll" ';
     $Pos = $myHeader{$ENV{'form.sort'}};      $Str .= 'value="Update All Student Data" /></td>'."\n";
     if ($Pos == 0) {      $Str .= '<td align="center">';
  $OpSel1 = 'selected';      $Str .= '<select name="reportSelected" onchange="document.';
  $ENV{'form.order'}='Ascendig';      $Str .= 'Statistics.submit()">'."\n";
     }  
       foreach (sort(keys(%$reports))) {
     $CurMap = $ENV{'form.maps'};          next if($_ eq 'reportSelected');
     if ( $CurMap eq '' ) {           $Str .= '<option name="'.$_.'"';
  $CurMap = 'All Maps';          if($reports->{'reportSelected'} eq $reports->{$_}) {
  $OpSel3 = 'selected';              $Str .= ' selected=""';
     }          }
     $CurSec = $ENV{'form.section'};          $Str .= '>'.$reports->{$_}.'</option>'."\n";
     if ( $CurSec eq '' ) {   
  $CurSec = 'All Sections';  
         $OpSel4 = 'selected';  
     }      }
 }      $Str .= '</select></td>'."\n";
   
       $Str .= '<td align="center">';
       $Str .= &Apache::lonhtmlcommon::StatusOptions($status, 'Statistics');
       $Str .= '</td>'."\n";
   
       $Str .= '</tr></tbody></table>'."\n";
       $Str .= '<hr>'."\n";
   
       return $Str;
   }
   
   sub BuildStatistics {
       my ($r)=@_;
   
       my $c = $r->connection;
       my @studentInformation=('fullname','section','id','domain','username',
                               'updateTime');
       my @headings=('Full Name', 'Section', 'PID', 'Domain', 'User Name',
                     'Last Updated');
       my $spacing = '   ';
   
       my %reports = ('classlist'          => 'Class list',
                      'problem_statistics' => 'Problem Statistics',
                      'student_assessment' => 'Student Assessment',
      'percentage'         => 'Correct-problems Plot',
   #                   'activitylog'        => 'Activity Log',
                      'reportSelected'     => 'Class list');
   
       my %cache;
       my $courseID=$ENV{'request.course.id'};
       my $cacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
                     "_$ENV{'user.domain'}_$courseID\_statistics.db";
   
       $r->print(&Apache::lonhtmlcommon::Title('Course Statistics and Charts'));
   
       my ($returnValue, $students) = &PrepareData($c, $cacheDB,
                                                   \@studentInformation,
                                                   \@headings,$r);
       if($returnValue ne 'OK') {
           $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)) {
           $GoToPage = $cache{'reportSelected'};
           $reports{'reportSelected'} = $cache{'reportSelected'};
           if(defined($cache{'reportKey'}) &&
              !exists($reports{$cache{'reportKey'}}) &&
              $cache{'reportKey'} ne 'false') {
               $reports{$cache{'reportKey'}} = $cache{'reportSelected'};
           }
   
           if(defined($cache{'OptionResponses'})) {
               $reports{'problem_analysis'} = 'Option Response Analysis';
           }
   
 sub MapSecOptions {          $r->print('<form name="Statistics" ');
 # ----------------------------------- Loading the Maps Combobox          $r->print('method="post" action="/adm/statistics">');
     my $Ptr = '<br>';          $r->print(&CreateMainMenu($cache{'Status'}, \%reports));
     $Ptr .= '<br><input type="submit" name="sort" value="Return to Menu" />';          $r->rflush();
     $Ptr .= '<br><b> Select &nbsp; Map &nbsp; &nbsp; </b>'."\n".          untie(%cache);
            '<select name="maps">'."\n".       } else {
     '<option '.$OpSel3.'>All Maps</option>';                                       $r->print('<html><body>Unable to tie database.</body></html>');
     foreach my $key ( sort keys %maps ) {                    return OK;
  $Ptr .= '<option';      }
         if ($CurMap eq $key) {$Ptr .= ' selected';}       
  $Ptr .= '>'.$key."</option>\n";           if($GoToPage eq 'Activity Log') {
     }          &Apache::lonproblemstatistics::Activity();
     $Ptr .= '</select>';      } elsif($GoToPage eq 'Problem Statistics') {
     $Ptr .= '&nbsp;&nbsp;&nbsp;';          &Apache::lonproblemstatistics::BuildProblemStatisticsPage($cacheDB,
                                                                     $students,
 # ----------------------------------- Loading the Sections Combobox                                                                    $courseID,
     $Ptr .= '<br><b>Select Section</b>'."\n".                                                                    $c,$r);
            '<select name="section">'."\n".       } elsif($GoToPage eq 'Option Response Analysis') {
     '<option '.$OpSel4.'>All Sections</option>';                                       &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB, $r);
     foreach my $key ( sort keys %section ) {                } elsif($GoToPage eq 'Student Assessment') {
  $Ptr .= '<option';          &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB,
         if ($CurSec eq $key) {$Ptr .= ' selected';}                                                                 $students,
  $Ptr .= '>'.$key."</option>"."\n";                                                                 $courseID,
                                                             'Statistics',
                                                             \@headings,
                                                             $spacing,
                                                             \@studentInformation,
                                                             $r, $c);
       } elsif($GoToPage eq 'Analyze') {
           &Apache::lonproblemanalysis::BuildAnalyzePage($cacheDB, $students,
                                                         $courseID, $r);
       } elsif($GoToPage eq 'DoDiffGraph' || $GoToPage eq 'PercentWrongGraph') {
           my $courseDescription = $ENV{'course.'.$courseID.'.description'};
           $courseDescription =~ s/\ /"_"/eg;
           &Apache::lonproblemstatistics::BuildGraphicChart($GoToPage, $cacheDB,
                                                            $courseDescription,
                                                            $students, $courseID,
                                                            $r, $c);
       } elsif($GoToPage eq 'Class list') {
           &BuildClasslist($cacheDB, $students, \@studentInformation,
                           \@headings, $r);
       } elsif($GoToPage eq 'Correct-problems Plot') {
    &Apache::lonpercentage::BuildPercentageGraph($cacheDB, $students,
        $courseID, $c, $r);
     }      }
     $Ptr .= '</select>'."\n";  
   
     $r->print( $Ptr );      $r->print('</form>'."\n");
       $r->print("\n".'</body>'."\n".'</html>');
     $r->rflush();      $r->rflush();
 }  
   
       return OK;
   }
   
 # ================================================================ Main Handler  # ================================================================ Main Handler
   
 sub handler {  sub handler {
     $r=shift;      my $r=shift;
   
     if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {  #    $jr = $r;
 # ------------------------------------------- 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;  
  }      
  my $requrl=$r->uri;  
 # ----------------------------------------------------------------- Tie db file  
   
  undef %hash;      my $loaderror=&Apache::lonnet::overloaderror($r);
       if ($loaderror) { return $loaderror; }
       $loaderror=
          &Apache::lonnet::overloaderror($r,
            $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
       if ($loaderror) { return $loaderror; }
   
  if ($ENV{'request.course.fn'}) {      unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
     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;   
  }  
     }  
     else {  
         $ENV{'user.error.msg'}=          $ENV{'user.error.msg'}=
         $r->uri.":vgr:0:0:Cannot view grades for complete course";          $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;
       }
   
         return HTTP_NOT_ACCEPTABLE;       unless($ENV{'request.course.fn'}) {
    my $requrl=$r->uri;
           $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
           return HTTP_NOT_ACCEPTABLE;
     }      }
   
       $r->content_type('text/html');
       $r->send_http_header;
   
       &BuildStatistics($r);
   
       return OK;
 }  }
 1;  1;
 __END__  __END__
   
   
   

Removed from v.1.14  
changed lines
  Added in v.1.55.2.1


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.