Diff for /loncom/interface/lonstatistics.pm between versions 1.3 and 1.38

version 1.3, 2002/02/06 16:38:04 version 1.38, 2002/08/01 20:49:06
Line 27 Line 27
 #  #
 # (Navigate problems for statistical reports  # (Navigate problems for statistical reports
 # YEAR=2001  # YEAR=2001
 # 5/05/01, 7/09/01, 7/25/01, 8/11/01,9/13/01, 9/26/01 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
 # 10/5/01, 10/9/01, 10/22/01, 10/26/01 Behrouz Minaei  # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
 # 11/1/01, 11/4/01, 11/16/01 Behrouz Minaei  
 # 12/14/01, 12/16/01, 12/18/01,12/20/01,12/31/01 Behrouz Minaei  
 # YEAR=2002  # YEAR=2002
 # 1/22/02,2/1/02 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; 
Line 41  use strict; Line 41  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::loncoursedata;
   use Apache::lonhtmlcommon;
   use Apache::lonproblemanalysis;
   use Apache::lonproblemstatistics;
   use Apache::lonstudentassessment;
   use Apache::lonchart;
 use HTML::TokeParser;  use HTML::TokeParser;
 use GDBM_File;  use GDBM_File;
 #use Benchmark;  
   
 # -------------------------------------------------------------- Module Globals  
 my %hash;  
 my %CachData;  
 my %GraphDat;  
 my %maps;  
 my @mapsort;  
 my %section;  
 my %StuBox;  
 my %DiscFac;  
 my $CurMap;  
 my $CurSec;  
 my $CurStu;  
 my @cols;  
 my @list;  
 my @students;  
 my $p_count;  
 my $Pos;  
 my $r;  
 my $OpSel1;  
 my $OpSel2;  
 my $OpSelDis1;  
 my $OpSelDis2;  
 my $CurDis=0;  
 my $OpSel3;  
 my $OpSel4;  
 my $GData;  
 my $cid;  
 my $firstres;  
 my $lastres;  
 my $DiscFlag=0;  
 my $HWN=0;  
   
 my %Header = (0,"Problem Title",1,"#Stdnts",2,"Tries",3,"Mod",  
               4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"S.D.",  
               9,"Skew.",10,"DoDiff",11,"Map");  
 #             9,"Skew.",10,"DoDiff",11,"Dis.F.",12,"Resourse URL");  
   
 sub NumericSort {            sub CheckFormElement {
     $a <=> $b;      my ($cache, $ENVName, $cacheName, $default)=@_;
 }  
   
 # ------ Create different Student Report       if(defined($ENV{'form.'.$ENVName})) {
 sub StudentReport {          $cache->{$cacheName} = $ENV{'form.'.$ENVName};
     my ($sname,$sdom)=@_;      } elsif(!defined($cache->{$cacheName})) {
     if ( $sname eq 'All Students' ) {          $cache->{$cacheName} = $default;
  $r->print( '<h3><font color=blue>WARNING:       }
                     Please select a student</font></h3>' );  
  return;      return;
     }  }
     my $shome=&Apache::lonnet::homeserver( $sname,$sdom );            
     my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname.':'.$cid,$shome );  sub ProcessFormData{
     my %result = ();      my ($cache)=@_;
     my $ResId;  
     my $Code;      $cache->{'reportKey'} = 'false';
     my $Tries;  
     my $TotalTries = 0;      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
     my $ParCr = 0;                                              ['sort','download',
     my $Wrongs;                                               'reportSelected',
     my %TempHash;                                               'StudentAssessmentStudent']);
     my $Version;      &CheckFormElement($cache, 'Status', 'Status', 'Active');
     my $LatestVersion;      &CheckFormElement($cache, 'postdata', 'reportSelected', 'Class list');
     my $PtrTry='';      &CheckFormElement($cache, 'reportSelected', 'reportSelected', 
     my $PtrCod='';                        'Class list');
     my $SetNo=0;      $cache->{'reportSelected'} = 
     my $Str = "\n".'<table border=2>'.          &Apache::lonnet::unescape($cache->{'reportSelected'});
               "\n".'<tr>'.      &CheckFormElement($cache, 'DownloadAll', 'DownloadAll', 'false');
               "\n".'<th> # </th>'.      &CheckFormElement($cache, 'sort', 'sort', 'fullname');
       "\n".'<th> Set Title </th>'.      &CheckFormElement($cache, 'download', 'download', 'false');
       "\n".'<th> Results </th>'.  
       "\n".'<th> Tries </th>'.      # student assessment
       "\n".'</tr>';      if(defined($ENV{'form.CreateStudentAssessment'}) ||
     unless ($reply=~/^error\:/) {         defined($ENV{'form.NextStudent'}) ||
         map {         defined($ENV{'form.PreviousStudent'})) {
             my ($name,$value)=split(/\=/,&Apache::lonnet::unescape($_));          $cache->{'reportSelected'} = 'Student Assessment';
             $result{$name}=$value;      }
         } split(/\&/,$reply);;      if(defined($ENV{'form.NextStudent'})) {
         foreach $ResId (@cols) {          $cache->{'StudentAssessmentMove'} = 'next';
     if ( !$ResId ) {      } elsif(defined($ENV{'form.PreviousStudent'})) {
  my $Set=&Apache::lonnet::declutter($hash{'map_id_'.$1});          $cache->{'StudentAssessmentMove'} = 'previous';
  if ( $Set ) {      } else {
     $SetNo++;          $cache->{'StudentAssessmentMove'} = 'selected';
     $Str .= "\n"."<tr>".      }
     "\n"."<td> $SetNo </td>".      &CheckFormElement($cache, 'StudentAssessmentStudent', 
                             "\n"."<td> $Set </td>".                        'StudentAssessmentStudent', 'All Students');
                             "\n"."<td> $PtrCod </td>".      $cache->{'StudentAssessmentStudent'} = 
                             "\n"."<td> $PtrTry</td>".          &Apache::lonnet::unescape($cache->{'StudentAssessmentStudent'});
                             "\n"."</tr>";      &CheckFormElement($cache, 'DefaultColumns', 'DefaultColumns', 'false');
  }  
  $PtrTry='';      if(defined($ENV{'form.Section'})) {
  $PtrCod='';          my @sectionsSelected = (ref($ENV{'form.Section'}) ?
  next;                                  @{$ENV{'form.Section'}} :
     }                                  ($ENV{'form.Section'}));
             $ResId=~/(\d+)\.(\d+)/;          $cache->{'sectionsSelected'} = join(':', @sectionsSelected);
             my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} );      } elsif(!defined($cache->{'sectionsSelected'})) {
             if ( $CurMap ne 'All Maps' ) {          $cache->{'sectionsSelected'} = $cache->{'sectionList'};
  my ( $ResMap, $NameMap ) = split(/\=/,$CurMap);      }
  if ( $Map ne $ResMap ) { next; }  
     }      # Problem analysis
     my $meta=$hash{'src_'.$ResId};      &CheckFormElement($cache, 'Interval', 'Interval', '1');
     my $PartNo = 0;  
     undef %TempHash;      # ProblemStatistcs
     map {      &CheckFormElement($cache, 'DisplayCSVFormat',
  if ($_=~/^stores\_(\d+)\_tries$/) {                        'DisplayFormat', 'Display Table Format');
                     my $Part=&Apache::lonnet::metadata($meta,$_.'.part');      &CheckFormElement($cache, 'ProblemStatisticsAscend',
     if ( $TempHash{"$Part"} eq '' ) {                         'ProblemStatisticsAscend', 'Ascending');
  $TempHash{"$Part"} = $Part;      &CheckFormElement($cache, 'ProblemStatisticsMaps', 
  $TempHash{$PartNo}=$Part;                        'ProblemStatisticsMaps', 'All Maps');
  $TempHash{"$Part.Code"} = '-';    
  $PartNo++;      # Search only form elements
     }      my @headingColumns=();
  }      my @sequenceColumns=();
             } split(/\,/,&Apache::lonnet::metadata($meta,'keys'));      my $foundColumn = 0;
       if(defined($ENV{'form.ReselectColumns'})) {
             my $Prob = $Map.'___'.$2.'___'.          my @reselected = (ref($ENV{'form.ReselectColumns'}) ? 
                        &Apache::lonnet::declutter( $hash{'src_'.$ResId} );                            @{$ENV{'form.ReselectColumns'}}
             $Code='U';                            : ($ENV{'form.ReselectColumns'}));
             $Tries = 0;          foreach (@reselected) {
             $Wrongs = 0;              if(/HeadingColumn/) {
      $LatestVersion = $result{"version:$Prob"};                         push(@headingColumns, $_);
                   $foundColumn = 1;
     if ( $LatestVersion ) {              } elsif(/SequenceColumn/) {
  for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {                  push(@sequenceColumns, $_);
     my $vkeys = $result{"$Version:keys:$Prob"};                  $foundColumn = 1;
     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();  
 }  
   
       $cache->{'reportKey'} = 'false';
 # ------------------------------------------- Prepare Statistics Table      if($cache->{'reportSelected'} eq 'Analyze') {
 sub PreStatTable {          $cache->{'reportKey'} = 'Analyze';
     my $CacheDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".      } elsif($cache->{'reportSelected'} eq 'DoDiffGraph') {
                   "_$ENV{'user.domain'}_$cid\_statistics.db";          $cache->{'reportKey'} = 'DoDiffGraph';
     my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".      } elsif($cache->{'reportSelected'} eq 'PercentWrongGraph') {
                   "_$ENV{'user.domain'}_$cid\_graph.db";          $cache->{'reportKey'} = 'PercentWrongGraph';
     my $CachDisFac = "/home/httpd/perl/tmp/$ENV{'user.name'}".      }
      "_$ENV{'user.domain'}_$cid\_DiscFactor.db";  
     $r->print('<br><input type="submit" name="sort" value="Recalculate Statistics" />');      if(defined($ENV{'form.DoDiffGraph'})) {
           $cache->{'reportSelected'} = 'DoDiffGraph';
     my $Ptr = '';          $cache->{'reportKey'} = 'DoDiffGraph';
       } elsif(defined($ENV{'form.PercentWrongGraph'})) {
     $Ptr .= '<br><b> Sorting Type: &nbsp; </b>'."\n".          $cache->{'reportSelected'} = 'PercentWrongGraph';
             '<select name="order"> <option '.$OpSel1.' >Ascending</option>'."\n".          $cache->{'reportKey'} = 'PercentWrongGraph';
     '<option '.$OpSel2.'>Descending</option> </select> '."\n";      }
     $Ptr .= '&nbsp;&nbsp;&nbsp;';  
     $Ptr .= '<input type="submit" name="sort" value="DoDiff Graph" />'."\n";      foreach (keys(%ENV)) {
     $Ptr .= '&nbsp;&nbsp;&nbsp;';          if(/form\.Analyze/) {
     $Ptr .= '<input type="submit" name="sort" value="%Wrong Graph" />'."\n";              $cache->{'reportSelected'} = 'Analyze';
               $cache->{'reportKey'} = 'Analyze';
     $Ptr .= '<pre>'.              my $data;
     '  #Stdnts: Total Number of Students opened the problem.<br>'.               (undef, $data)=split(':::', $_);
     '  Tries  : Total Number of Tries for solving the problem.<br>'.               $cache->{'AnalyzeInfo'}=$data;
     '  Mod    : Maximunm Number of Tries for solving the problem.<br>'.           } elsif(/form\.HeadingColumn/) {
     '  Mean   : Average Number of the tries. [ Tries / #Stdns ]<br>'.              my $value = $_;
     '  #YES   : Number of students solved the problem correctly.<br>'.               $value =~ s/form\.//;
     '  #yes   : Number of students solved the problem by override.<br>'.              push(@headingColumns, $value);
     '  %Wrng  : Percentage of students tried to solve the problem but'.              $foundColumn=1;
     ' still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]<br>'.          } elsif(/form\.SequenceColumn/) {
     '  S.D.   : Standard Deviation of the tries.'.              my $value = $_;
     '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1)'.              $value =~ s/form\.//;
     ' where Xi is every student\'s tries ]<br>'.              push(@sequenceColumns, $value);
     '  Skew.  : Skewness of the students tries.'.              $foundColumn=1;
     ' [ (sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3) ]<br>'.          }
 #    '  DoDiff : Degree of Difficulty of the problem. [ Tries/(#YES+#yes+0.1) ]<br>'.  
     '  DoDiff : Degree of Difficulty of the problem. [ 1 - ((#YES+#yes) / Tries) ]<br>'.  
 #    '  Dis.F. : Discrimination Factor. [ Sum of Partial Credits Awarded / Total Number of Tries in %27 upper and lower students]</b>'.  
             '</pre>';  
   
     $r->print($Ptr);  
     $r->rflush();  
         
     my $Result = "\n".'<table border=2>';  
     $Result .= '<tr><th>P#</th>'."\n";  
     for ( my $nIdx=0; $nIdx < 12; $nIdx++ ) {   
  $Result .= '<th>'.'<input type="submit" name="sort" value="'.  
                    $Header{$nIdx}.'" />'.'</th>'."\n";  
     }      }
     $Result .= "\n".'</tr>'."\n";      
     $r->print( $Result );  
     $r->rflush();  
   
     if ((-e "$CacheDB")&&($ENV{'form.sort'} ne 'Recalculate Statistics')) {      if($foundColumn) {
  if (tie(%CachData,'GDBM_File',"$CacheDB",&GDBM_READER,0640)) {          $cache->{'HeadingsFound'} = join(':', @headingColumns);
     tie(%GraphDat,'GDBM_File',$GraphDB,&GDBM_WRCREAT,0640);          $cache->{'SequencesFound'} = join(':', @sequenceColumns);;
     &Cache_Statistics();  
         }  
         else {  
     $r->print("Unable to tie hash to db file");  
         }  
     }      }
     else {      if(!defined($cache->{'HeadingsFound'}) || 
  if (tie(%CachData,'GDBM_File',$CacheDB,&GDBM_WRCREAT,0640)) {         $cache->{'DefaultColumns'} ne 'false') {
     tie(%DiscFac,'GDBM_File',$CachDisFac,&GDBM_WRCREAT,0640);          $cache->{'HeadingsFound'}='HeadingColumnFull Name';
     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");  
         }  
     }      }
     #$r->print('Total instances of the problems : '.($p_count*($#students+1)));      if(!defined($cache->{'SequencesFound'}) ||
          $cache->{'DefaultColumns'} ne 'false') {
     untie(%CachData);          $cache->{'SequencesFound'}='All Sequences';
     untie(%GraphDat);      }
     untie(%DiscFac);      $cache->{'DefaultColumns'} = 'false';
   
     $r->print("\n".'</table>'."\n");      return;
     $r->rflush();          
 }  }
   
   =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.
   
 # ------------------------------------- Find the section of student in a course  =over 4
   
 sub usection {  Input: $students, $CacheData
     my ($udom,$unam,$courseid)=@_;  
     $courseid=~s/\_/\//g;  $students: A array pointer to a list of students (username:domain)
     $courseid=~s/^(\w)/\/$1/;  
     map {  $CacheData: A pointer to the hash tied to the cached data
         my ($key,$value)=split(/\=/,$_);  
         $key=&Apache::lonnet::unescape($key);  Output: \@order
         if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {  
             my $section=$1;  @order: An ordered list of students (username:domain)
             if ($key eq $courseid.'_st') { $section=''; }  
     my ($dummy,$end,$start)=split(/\_/,&Apache::lonnet::unescape($value));  =back
             $section=($section) ? $section : '(none)';  
             $section=(int($section)) ? int($section) : $section;  =cut
 #            $r->print($unam.'...'.$section.'<br>');  
     return $section;  sub SortStudents {
       my ($cache)=@_;
   
       my @students = split(':::',$cache->{'NamesOfStudents'});
       my @sorted1Students=();
       foreach (@students) {
           if($cache->{'Status'} eq 'Any' || 
              $cache->{$_.':Status'} eq $cache->{'Status'}) {
               push(@sorted1Students, $_);
         }          }
     } split(/\&/,&Apache::lonnet::reply('dump:'.$udom.':'.$unam.':roles',      }
                         &Apache::lonnet::homeserver($unam,$udom)));  
     return '';      my $sortBy = '';
       if(defined($cache->{'sort'})) {
           $sortBy = ':'.$cache->{'sort'};
       }
       my @order = sort { $cache->{$a.$sortBy} cmp $cache->{$b.$sortBy} ||
                          $cache->{$a.':fullname'} cmp $cache->{$b.':fullname'} } 
                   @sorted1Students;
   
       return \@order;
 }  }
   
   =pod
   
   =item &SpaceColumns()
   
 # ------ Dump the Student's DB file and handling the data for statistics table   Determines the width of all the columns in the chart.  It is based on
   the max of the data for that column and its header.
   
 sub ExtractStudentData {  =over 4
     my ($student,$coid)=@_;  
     my ($sname,$sdom) = split( /\:/, $student );  Input: $students, $studentInformation, $headings, $ChartDB
     my $shome=&Apache::lonnet::homeserver( $sname,$sdom );            
     my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname.':'.$coid,$shome );  $students: An array pointer to a list of students (username:domain)
     my %result = ();  
     my $ResId;  $studentInformatin: The type of data for the student information.  It is
     my $Dis = '';  used as part of the key in $CacheData.
     my $Code;  
     my $Tries;  $headings: The name of the student information columns.
     my $ParCr;  
     my $TotalTries = 0;  $ChartDB: The name of the cache database which is opened for read/write.
     my $TotalOpend = 0;  
     my $ProbSolved = 0;  Output: None - All data stored in cache.
     my $ProbTot = 0;  
     my $TimeTot = 0;  =back
     my $TotParCr = 0;  
     my $Wrongs;  =cut
     my %TempHash;  
     my $Version;  sub SpaceColumns {
     my $LatestVersion;      my ($students,$studentInformation,$headings,$cache)=@_;
     my $SecLimit;  
     my $MapLimit;      # Initialize Lengths
     unless ($reply=~/^error\:/) {      for(my $index=0; $index<(scalar @$headings); $index++) {
         map {          my @titleLength=split(//,$headings->[$index]);
             my ($name,$value)=split(/\=/,&Apache::lonnet::unescape($_));          $cache->{$studentInformation->[$index].':columnWidth'}=
             $result{$name}=$value;              scalar @titleLength;
 #$r->print($name.'='.$value.'<br>');      }
         } split(/\&/,$reply);  
         foreach $ResId (@cols) {      foreach my $name (@$students) {
     if ( !$ResId ) { next; }          foreach (@$studentInformation) {
             $ResId=~/(\d+)\.(\d+)/;              my @dataLength=split(//,$cache->{$name.':'.$_});
             my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} );              my $length=(scalar @dataLength);
             if ( $CurMap ne 'All Maps' ) {              if($length > $cache->{$_.':columnWidth'}) {
  my ( $ResMap, $NameMap ) = split(/\=/,$CurMap);                  $cache->{$_.':columnWidth'}=$length;
  if ( $Map ne $ResMap ) { next; }  
     }  
     my $meta=$hash{'src_'.$ResId};  
     my $PartNo = 0;  
     $Dis .= ':';  
     undef %TempHash;  
     map {  
  if ($_=~/^stores\_(\d+)\_tries$/) {  
                     my $Part=&Apache::lonnet::metadata($meta,$_.'.part');  
     if ( $TempHash{"$Part"} eq '' ) {   
  $TempHash{"$Part"} = $Part;  
  $TempHash{$PartNo}=$Part;  
  $TempHash{"$Part.Code"} = 'U';    
  $PartNo++;  
     }  
  }  
             } split(/\,/,&Apache::lonnet::metadata($meta,'keys'));  
   
             my $Prob = $Map.'___'.$2.'___'.  
                        &Apache::lonnet::declutter( $hash{'src_'.$ResId} );  
             $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"};  
 #$r->print($Version.'---'.$Prob.'==='.$Time.'<br>');  
     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}";  
     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 .= $ptr.'*'.$ResId.'='.$DisF.'+'.$Yes;  
     $ptr .= "*$ResId:$TempHash{$part.'.Tries'}".  
             ":$TempHash{$part.'.Wrongs'}".  
                             ":$TempHash{$part.'.Code'}";      
 #$r->print($sname.' -- '.$ptr.'--- timestamp='.$TempHash{"$part.Time"}.'<br>');  
     push (@list, $ptr);  
     $TotalOpend++;  
     $ProbTot++;  
  }  
             }              }
     else {   
  for(my $n=0; $n<$PartNo; $n++) {  
     push (@list, "$hash{'title_'.$ResId}*$ResId:0:0:U");  
     $ProbTot++;   
  }  
     }  
         }          }
  if ( $TotalTries ) {  
     my $DisFac = ( $TotalTries ) ? ($TotParCr/$TotalTries) : 0;  
 #    my $DisFactor = int(sprintf( "%.4f", $DisFac ) * 100);  
     my $DisFactor = sprintf( "%.4f", $DisFac );  
     my $time;  
     if ($ProbSolved){  
  $time = int(($TimeTot/$ProbSolved)/10000000);  
     }  
     $DiscFac{($DisFactor.':'.$sname.':'.$ProbTot.':'.$TotalOpend.':'.  
                       $TotalTries.':'.$ProbSolved.':'.$time)}=$Dis;  
 #$r->print($DisFactor.$sname.'<br> --- Dis= '.$Dis.'<br>');  
  }  
     }      }
     #$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;
     $rid=~/(\d+)\.(\d+)/;      if(defined($ENV{'form.Recalculate'})) {
     $maps{&Apache::lonnet::declutter($hash{'map_id_'.$1})}='';#$hash{'title_'.$rid};           $isRecalculate=1;
     unless ($beenhere=~/\&$rid\&/) {      }
        $beenhere.=$rid.'&';   
        if (defined($hash{'is_map_'.$rid})) {      my $isCached = &Apache::loncoursedata::TestCacheData($cacheDB, 
    my $cmap=$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}};                                                           $isRecalculate);
            if ( $cmap eq 'sequence' || $cmap eq 'page' ) {       if($isCached < 0) {
                $cols[$#cols+1]=0;          return "Unable to tie hash to db file.";
        $HWN++;      }
                $mapsort[$HWN]=$rid.$hash{'title_'.$rid};   
                #$maps{&Apache::lonnet::declutter($hash{'src_'.$rid})}=       # Download class list information if not using cached data
                #      $hash{'title_'.$rid};       my %cache;
            }      unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT(),0640)) {
            if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&          return "Unable to tie hash to db file.";
                (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) {      }
               my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};  
       if(!$isCached) {
                 &tracetable($hash{'map_start_'.$hash{'src_'.$rid}},          my $processTopResourceMapReturn=
                 '&'.$frid.'&');              &Apache::loncoursedata::ProcessTopResourceMap(\%cache, $c, $r);
           if($processTopResourceMapReturn ne 'OK') {
               if ($hash{'src_'.$frid}) {              untie(%cache);
                  if ($hash{'src_'.$frid}=~              return $processTopResourceMapReturn;
                                  /\.(problem|exam|quiz|assess|survey|form)$/) {          }
      $cols[$#cols+1]=$frid;      }
      $mapsort[$HWN] .= '&'.$frid;  
                  }      if($c->aborted()) {
       }          untie(%cache);
    }          return 'aborted'; 
        } else {      }
           if ($hash{'src_'.$rid}) {  
              if ($hash{'src_'.$rid}=~      my $classlist=&Apache::loncoursedata::DownloadClasslist($courseID,
                                  /\.(problem|exam|quiz|assess|survey|form)$/) {                                                  $cache{'ClasslistTimestamp'},
          $cols[$#cols+1]=$rid;                                                  $c);
  $mapsort[$HWN] .= '&'.$rid;      foreach (keys(%$classlist)) {
              }          if(/^(con_lost|error|no_such_host)/i) {
           }              untie(%cache);
        }              return "Error getting student data.";
        if (defined($hash{'to_'.$rid})) {          }
           map {      }
               &tracetable($hash{'goesto_'.$_},$beenhere);  
           } split(/\,/,$hash{'to_'.$rid});      if($c->aborted()) {
        }          untie(%cache);
           return 'aborted'; 
       }
   
       # Active is a temporary solution, remember to change
       Apache::loncoursedata::ProcessClasslist(\%cache,$classlist,$courseID,$c);
       if($c->aborted()) {
           untie(%cache);
           return 'aborted'; 
       }
   
       &ProcessFormData(\%cache);
       my $students = &SortStudents(\%cache);
       &SpaceColumns($students, $studentInformation, $headings, \%cache);
       $cache{'updateTime:columnWidth'}=24;
   
       if($cache{'download'} ne 'false') {
           my $who = $cache{'download'};
           my $courseData = 
               &Apache::loncoursedata::DownloadCourseInformation(
                                                $who, $courseID, 
                                                $cache{$who.':lastDownloadTime'});
           &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, $who);
           $cache{'download'} = 'false';
       } elsif($cache{'DownloadAll'} ne 'false') {
           my @allStudents;
           if($cache{'DownloadAll'} eq 'sorted') {
               @allStudents = @$students;
           } else {
               @allStudents = split(':::', $cache{'NamesOfStudents'});
           }
           foreach (@allStudents) {
               my $courseData = 
                   &Apache::loncoursedata::DownloadCourseInformation(
                                                $_, $courseID, 
                                                $cache{$_.':lastDownloadTime'});
               &Apache::loncoursedata::ProcessStudentData(\%cache, $courseData, 
                                                          $_);
               if($c->aborted()) {
                   untie(%cache);
                   return 'aborted'; 
               }
           }
           $cache{'DownloadAll'} = 'false';
     }      }
 }  
   
 sub MySort {                if($c->aborted()) {
     if ( $Pos > 0 && $Pos < 11 ) {          untie(%cache);
  if ($ENV{'form.order'} eq 'Descending') {$b <=> $a;}          return 'aborted'; 
  else { $a <=> $b; }  
     }  
     else {  
  if ($ENV{'form.order'} eq 'Descending') {$b cmp $a;}  
  else { $a cmp $b; }  
     }      }
   
       untie(%cache);
   
       return ('OK', $students);
 }  }
   
 sub Build_Statistics {  
   # Create progress
   sub Create_PrgWin {
       my ($r)=@_;
     $r->print(<<ENDPOP);      $r->print(<<ENDPOP);
 <script>      <script>
     popwin=open('','popwin','width=400,height=100');      popwin=open('','popwin','width=400,height=100');
     popwin.document.writeln('<html><body bgcolor="#8cee8c">'+      popwin.document.writeln('<html><body bgcolor="#88DDFF">'+
       '<title>LON-CAPA Statistics</title>'+        '<title>LON-CAPA Statistics</title>'+
       '<h4>Computation Progress</h4>'+        '<h4>Computation Progress</h4>'+
       '<form name=popremain>'+        '<form name=popremain>'+
       '<input type=text size=35 name=remaining value=Starting></form>'+        '<input type=text size=35 name=remaining value=Starting></form>'+
       '</body></html>');        '</body></html>');
     popwin.document.close();      popwin.document.close();
 </script>      </script>
 ENDPOP  ENDPOP
   
     $r->rflush();      $r->rflush();
 # ---------------------------- Gathering the Data of students' tries  
     my $index;  
     for ($index=0;$index<=$#students;$index++) {  
 #----------- update progress  
         $r->print('<script>popwin.document.popremain.remaining.value="'.  
                   'Computing '.($index+1).'/'.($#students+1).': '.  
                   $students[$index].'";</script>');  
         $r->rflush();  
   
         &ExtractStudentData($students[$index],$cid);  
     }  
 #--------------------- close Progress Line  
     $r->print('<script>popwin.close()</script>');  
     $r->rflush();   
 # -------------------- sorting the Data  
     @list = sort(@list);  
     $OpSel2='';  
     $OpSel1='selected';  
       
     $p_count = 0;   
     my $nIdx = 0;  
     my $dummy;   
     my $p_val;  
     my $ResId;  
     my $NoElements = $#list + 1;  
 #-------------------------------- loop for data representation  
     while ( $nIdx < $NoElements ) {  
         my %storestats=();  
  my ($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;   
  do {  
     $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--; }  
     ($Prob,$Tries,$Wrongs,$Code)=split(/\:/,$list[$nIdx]);  
  } while ( $Prob eq $Temp && $nIdx < $NoElements );  
   
  $p_count++;  
   
  ($Temp,$ResId)=split(/\*/,$Temp);  
   
         $Temp = '<a href="'.$hash{'src_'.$ResId}.'" target="_blank">'.$Temp.'</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;  
  }  
 #-----------------  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 );  
       
  $CachData{($p_count-1)}=$Temp.':'.$StdNo.':'.$TotalTries.':'.  
                                 $MxTries.':'.$Avg.':'.$YES.':'.  
                                 $Override.':'.$Wrng.':'.$SD.':'.  
                                 $Sk.':'.$DoD.':'.$Map.':'.$Prob;  
   
         $urlres=~/^(\w+)\/(\w+)/;  
         if ($StdNo) {   
            &Apache::lonnet::put('resevaldata',\%storestats,$1,$2);   
         }  
   
 #-------------------------------- Row of statistical table  
         if ( $DiscFlag == 0 ) {  
     $r->print( "\n".'<tr>'.  
                "\n".'<td>'.$p_count.'</td>'.  
                "\n".'<td>'.$Temp.'</td>'.  
                "\n".'<td>'.$StdNo.'</td>'.  
                "\n".'<td>'.$TotalTries.'</td>'.  
                "\n".'<td>'.$MxTries.'</td>'.  
                "\n".'<td>'.$Avg.'</td>'.  
                "\n".'<td>'.$YES.'</td>'.  
                "\n".'<td>'.$Override.'</td>'.  
                "\n".'<td>'.$Wrng.'</td>'.  
                "\n".'<td>'.$SD.'</td>'.  
                "\n".'<td>'.$Sk.'</td>'.  
                "\n".'<td>'.$DoD.'</td>'.  
                "\n".'<td>'.$Map.'</td>'.  
                        "\n".'</tr>' );  
     $GraphDat{$nIdx}=$DoD.':'.$Wrng;  
  }   
     }  
 }  }
   
   # update progress
 sub Cache_Statistics {  sub Update_PrgWin {
     my @list = ();      my ($totalStudents,$index,$name,$r)=@_;
     my $Useful;      $r->print('<script>popwin.document.popremain.remaining.value="'.
     my $UnUseful;                'Computing '.$index.'/'.$totalStudents.': '.
     my %myHeader = reverse( %Header );                $name.'";</script>');
     $Pos = $myHeader{$ENV{'form.sort'}};      $r->rflush();
     $p_count = 0;  
   
     foreach my $key( keys %CachData) {   
  my @Temp=split(/\:/,$CachData{$key});  
  if ( $Pos == 0 || $Pos == 11 ) {  
     ($UnUseful,$Useful)=split(/\>/,$Temp[$Pos]);  
  }  
  else {  
     $Useful = $Temp[$Pos];  
  }     
  $list[$p_count]=$Useful.'&'.$CachData{$key};  
         $p_count++;  
     }  
   
     @list = sort MySort (@list);  
   
     for ( my $nIdx = 0; $nIdx < $p_count; $nIdx++ ) {  
  my( $Pre, $Post ) = split(/\&/,$list[$nIdx]);   
  my ($Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,  
             $Override,$Wrng,$SD,$Sk,$DoD,$res,$Prob)=split(/\:/,$Post);  
  $r->print( "\n".'<tr>'.  
                "\n".'<td>'.($nIdx+1).'</td>'.  
                "\n".'<td  bgcolor="#FFFFFF">'.$Temp.'</td>'.  
                "\n".'<td>'.$StdNo.'</td>'.  
                "\n".'<td>'.$TotalTries.'</td>'.  
                "\n".'<td>'.$MxTries.'</td>'.  
                "\n".'<td>'.$Avg.'</td>'.  
                "\n".'<td>'.$YES.'</td>'.  
                "\n".'<td>'.$Override.'</td>'.  
                "\n".'<td>'.$Wrng.'</td>'.  
                "\n".'<td>'.$SD.'</td>'.  
                "\n".'<td>'.$Sk.'</td>'.  
                "\n".'<td>'.$DoD.'</td>'.  
                "\n".'<td>'.$res.'</td>'.  
                "\n".'</tr>' );  
  $GraphDat{$nIdx}=$DoD.':'.$Wrng;  
     }   
 }  
   
 # ------------------------------------------- Prepare data for Graphical chart  
   
 sub GetGraphData {  
     my $Tag = shift;  
     my $Col;  
     my $data='';  
     my $count = 0;  
     my $Max = 0;  
     my $cid=$ENV{'request.course.id'};  
     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 ( $Tag eq 'DoDiff Graph' ) {  
  $Tag = 'Degree-of-Difficulty';  
  $Col = 0;  
     }  
     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");  
  }  
     }  
 }  }
   
   # close Progress Line
 sub initial {  sub Close_PrgWin {
 # --------------------------------- Initialize the global varaibles      my ($r)=@_;
   undef @students;      $r->print('<script>popwin.close()</script>');
   undef @cols;      $r->rflush(); 
   undef %maps;  
   undef %section;  
   undef %StuBox;  
   undef @list;  
   undef %CachData;  
   undef %GraphDat;  
   undef %DiscFac;  
   undef $CurMap;  
   undef $CurSec;  
   undef $CurStu;  
   undef $p_count;  
   undef $Pos;  
   undef $GData;  
 }  }
   
   
 sub ClassList {  sub BuildClasslist {
       my ($cacheDB,$students,$studentInformation,$headings)=@_;
     &GetStatus();  
   
     $cid=$ENV{'request.course.id'};      my %cache;
     my $chome=$ENV{'course.'.$cid.'.home'};      unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
     my ($cdom,$cnum)=split(/\_/,$cid);          return '<html><body>Unable to tie database.</body></html>';
 # ----------------------- 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'}};      my $Str='';
     if (($firstres) && ($lastres)) {      $Str .= '<table border="0"><tr><td bgcolor="#777777">'."\n";
 # ----------------------------------------------------------------- Render page      $Str .= '<table border="0" cellpadding="3"><tr bgcolor="#e6ffff">'."\n";
  my $classlst=&Apache::lonnet::reply  
                  ('dump:'.$cdom.':'.$cnum.':classlist',$chome);      my $displayString = '<td align="left"><a href="/adm/statistics?';
  my $StudNo = 0;      $displayString .= 'sort=LINKDATA">DISPLAYDATA&nbsp</a></td>'."\n";
  unless ($classlst=~/^error\:/) {      $Str .= &Apache::lonhtmlcommon::CreateHeadings(\%cache, $studentInformation,
     foreach (sort split(/\&/,$classlst)) {                                                     $headings, $displayString);
  my ($name,$value)=split(/\=/,$_);      $Str .= '</tr>'."\n";
  my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value));      my $alternate=0;
  $name=&Apache::lonnet::unescape($name);      foreach (@$students) {
  my ($sname,$sdom)=split(/\:/,$name);          my ($username, $domain) = split(':', $_);
  my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid);          if($alternate) {
                 if ($ssec==-1) {next;}              $Str .= '<tr bgcolor="#ffffe6">';
  $ssec=($ssec) ? $ssec : '(none)';          } else {
  $ssec=(int($ssec)) ? int($ssec) : $ssec;              $Str .= '<tr bgcolor="#ffffc6">';
  #$r->print($sname.'...'.$ssec.'<br>');          }
  $section{$ssec}=$ssec;          $alternate = ($alternate + 1) % 2;
  if ($CurSec eq 'All Sections' || $ssec eq $CurSec) {          foreach my $data (@$studentInformation) {
     $students[$StudNo]=$name;              $Str .= '<td>';
     $StuBox{$sname}=$ssec;              if($data eq 'fullname') {
  }                  $Str .= '<a href="/adm/statistics?reportSelected=';
  $StudNo++;                  $Str .= &Apache::lonnet::escape('Student Assessment');
     }                  $Str .= '&StudentAssessmentStudent=';
  }                  $Str .= &Apache::lonnet::escape($cache{$_.':'.$data}).'">';
  else {                  $Str .= $cache{$_.':'.$data}.'&nbsp';
     $r->print('<h1>Could not access course data</h1>');                  $Str .= '</a>';
  }               } elsif($data eq 'updateTime') {
         $r->print("Total number of students : ".($#students+1));                  $Str .= '<a href="/adm/statistics?reportSelected=';
         $r->rflush();                  $Str .= &Apache::lonnet::escape('Class list');
 # --------------- Find all assessments and put them into some linear-like order                  $Str .= '&download='.$_.'">';
  &tracetable($firstres,'&'.$lastres.'&');                  $Str .= $cache{$_.':'.$data}.'&nbsp';
                   $Str .= '&nbsp</a>';
 #my $c=0;              } else {
 #foreach(@mapsort) {                  $Str .= $cache{$_.':'.$data}.'&nbsp';
 #    $c++;              }
 #    $r->print('<br>'.$mapsort[$c]);  
 #}  
 #$r->print('<br> Count = '.$c);  
   
     }  
   
 # ------------------------------------------------------------- End render page               $Str .= '</td>'."\n";
     else {          }
  $r->print('<h3>Undefined course sequence</h3>');  
     }      }
     &MapSecOptions();  
 }  
   
       $Str .= '</tr>'."\n";
       $Str .= '</table></td></tr></table>'."\n";
   
 sub Menu {      untie(%cache);
     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"/>';#General Statistics"/>';  
     $Ptr .= '<br><br>';  
     $Ptr .= '<input type=submit name=sort value="Student Assessment"/>';  
     $Ptr .= '<br><br>';  
 #    $Ptr .= '<input type=submit name=sort value=Discrimination>';#"Problem Evaluation"/>';  
     $Ptr .= '</h3>';  
     $r->print( $Ptr );  
       }  
  else {  
     &initial();  
     &ClassList();  
     if ( $content eq 'Discrimination' || #'Problem Evaluation' ||  
                  $content eq 'Recalculate Discrimintion Factor' ) {  
  &CreateDiscFac();  
     }  
     elsif ( $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 {      return $Str;
     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";       
     }  
     $Ptr .= '</select>';  
     $Ptr .= '<br><input type="submit" name="sort" value="Create Student Report" />';  
     $r->print( $Ptr );  
     $r->rflush();  
 }  }
   
 sub GetStatus {  sub CreateMainMenu {
       my ($status, $reports)=@_;
     $OpSelDis1='';  
     $OpSelDis2='';      my $Str = '';
     $OpSel1='';  
     $OpSel2='';      $Str .= '<table border="0"><tbody><tr>'."\n";
     $OpSel3='';      $Str .= '<td></td><td></td>'."\n";
     $OpSel4='';      $Str .= '<td align="center"><b>Analysis Reports:</b></td>'."\n";
       $Str .= '<td align="center"><b>Student Status:</b></td></tr>'."\n";
 #    if ( $ENV{'form.DisType'} eq 'Total Number of Correct Answers' ) {       $Str .= '<tr>'."\n";
 # $OpSelDis1='selected';       $Str .= '<td align="center"><input type="submit" name="Refresh" ';
 # $CurDis=0;      $Str .= 'value="Refresh" /></td>'."\n";
 #    }      $Str .= '<td align="center"><input type="submit" name="DownloadAll" ';
 #    else { $OpSel2 = 'selected'; $CurDis = 1;}      $Str .= 'value="Update All Student Data" /></td>'."\n";
       $Str .= '<td align="center">';
     if ( $ENV{'form.order'} eq 'Descending' ) { $OpSel2='selected'; }      $Str .= '<select name="reportSelected" onchange="document.';
     else { $OpSel1 = 'selected'; }      $Str .= 'Statistics.submit()">'."\n";
     $CurMap = $ENV{'form.maps'};  
     if ( $CurMap eq '' ) {       foreach (sort(keys(%$reports))) {
  $CurMap = 'All Maps';          next if($_ eq 'reportSelected');
  $OpSel3 = 'selected';          $Str .= '<option name="'.$_.'"';
     }          if($reports->{'reportSelected'} eq $reports->{$_}) {
     $CurSec = $ENV{'form.section'};              $Str .= ' selected=""';
     if ( $CurSec eq '' ) {           }
  $CurSec = 'All Sections';          $Str .= '>'.$reports->{$_}.'</option>'."\n";
         $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',
                      '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";
   
       my ($returnValue, $students) = &PrepareData($c, $cacheDB, 
                                                   \@studentInformation, 
                                                   \@headings,$r);
       if($returnValue ne 'OK') {
           $r->print('<html><body>'.$returnValue."\n".'</body></html>');
           return OK;
       }
   
       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'} = 'Problem Analysis';
           }
   
 sub MapSecOptions {          $r->print(&Apache::lonhtmlcommon::Title('LON-CAPA Statistics'));
 # ----------------------------------- Loading the Maps Combobox          $r->print('<form name="Statistics" ');
     my $Ptr = '<br>';          $r->print('method="post" action="/adm/statistics">');
     $Ptr .= '<br><input type="submit" name="sort" value="Return to Menu" />';          $r->print(&CreateMainMenu($cache{'Status'}, \%reports));
     $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 'Problem Analysis') {
     '<option '.$OpSel4.'>All Sections</option>';                                       $r->print(
     foreach my $key ( sort keys %section ) {                          &Apache::lonproblemanalysis::BuildProblemAnalysisPage($cacheDB));
  $Ptr .= '<option';      } elsif($GoToPage eq 'Student Assessment') {
         if ($CurSec eq $key) {$Ptr .= ' selected';}               $r->print(
  $Ptr .= '>'.$key."</option>"."\n";                   &Apache::lonstudentassessment::BuildStudentAssessmentPage($cacheDB,
                                                             $students,
                                                             $courseID,
                                                             'Statistics',
                                                             \@headings,
                                                             $spacing,
                                                             \@studentInformation,
                                                             $r, $c));
       } elsif($GoToPage eq 'Analyze') {
           $r->print(&Apache::lonproblemanalysis::BuildAnalyzePage($cacheDB, 
                                                                   $students, 
                                                                   $courseID,$r));
       } elsif($GoToPage eq 'DoDiffGraph') {
           &Apache::lonproblemstatistics::BuildDiffGraph($r);
       } elsif($GoToPage eq 'PercentWrongGraph') {
           &Apache::lonproblemstatistics::BuildWrongGraph($r);
       } elsif($GoToPage eq 'Class list') {
           $r->print(&BuildClasslist($cacheDB, $students, \@studentInformation,
                                     \@headings));
     }      }
     $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;      unless(&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
   
  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;   
  }  
     }  
     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;
       }
   
       unless($ENV{'request.course.fn'}) {
    my $requrl=$r->uri;
           $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
         return HTTP_NOT_ACCEPTABLE;           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.3  
changed lines
  Added in v.1.38


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>