Diff for /loncom/interface/statistics/lonstudentassessment.pm between versions 1.47 and 1.55

version 1.47, 2003/05/13 15:00:42 version 1.55, 2003/06/10 19:19:57
Line 85  my $Statistics; Line 85  my $Statistics;
   
 =item $show 'all', 'totals', or 'scores' determines how much data is output  =item $show 'all', 'totals', or 'scores' determines how much data is output
   
   =item $data  determines what performance data is shown
   
   =item $datadescription A short description of the output data selected.
   
   =item $base 'tries' or 'scores' determines the base of the performance shown
   
   =item $single_student_mode evaluates to true if we are showing only one
   student.
   
 =cut  =cut
   
 #######################################################  #######################################################
 #######################################################  #######################################################
 my $show_links;  my $show_links;
 my $output_mode;  my $output_mode;
 my $show;  my $data;
   my $base;
   my $datadescription;
   my $single_student_mode;
   
 #######################################################  #######################################################
 #######################################################  #######################################################
Line 127  Inputs: Line 139  Inputs:
 sub BuildStudentAssessmentPage {  sub BuildStudentAssessmentPage {
     my ($r,$c)=@_;      my ($r,$c)=@_;
     undef($Statistics);      undef($Statistics);
       $single_student_mode = 1 if ($ENV{'form.SelectedStudent'});
     #      #
     # Print out the HTML headers for the interface      # Print out the HTML headers for the interface
     #    This also parses the output mode selector      #    This also parses the output mode selector
     #    This step must always be done.      #    This step must *always* be done.
     $r->print(&CreateInterface());      $r->print(&CreateInterface());
     $r->print('<input type="hidden" name="notfirstrun" value="true" />');      $r->print('<input type="hidden" name="notfirstrun" value="true" />');
       $r->print('<input type="hidden" name="sort" value="'.
                 $ENV{'form.sort'}.'" />');
     $r->rflush();      $r->rflush();
     if (! exists($ENV{'form.notfirstrun'})) {      if (! exists($ENV{'form.notfirstrun'}) && ! $single_student_mode) {
         $r->print(<<ENDMSG);  
 <p>  
 <font size="+1">  
 Please make your selections in the boxes above and hit   
 the button marked &quot;Update&nbsp;Display&quot;.  
 </font>  
 </p>  
 ENDMSG  
 #        $r->print(&OutputDescriptions());  
         return;          return;
     }      }
     #      #
     #  
     my $initialize     = \&html_initialize;      my $initialize     = \&html_initialize;
     my $output_student = \&html_outputstudent;      my $output_student = \&html_outputstudent;
     my $finish         = \&html_finish;      my $finish         = \&html_finish;
Line 156  ENDMSG Line 161  ENDMSG
         $initialize     = \&excel_initialize;          $initialize     = \&excel_initialize;
         $output_student = \&excel_outputstudent;          $output_student = \&excel_outputstudent;
         $finish         = \&excel_finish;          $finish         = \&excel_finish;
     } elsif ($output_mode eq 'multi-sheet excel') {  
         $initialize     = \&multi_sheet_excel_initialize;  
         $output_student = \&multi_sheet_excel_outputstudent;  
         $finish         = \&multi_sheet_excel_finish;  
     } elsif ($output_mode eq 'csv') {      } elsif ($output_mode eq 'csv') {
         $initialize     = \&csv_initialize;          $initialize     = \&csv_initialize;
         $output_student = \&csv_outputstudent;          $output_student = \&csv_outputstudent;
Line 168  ENDMSG Line 169  ENDMSG
     #      #
     if($c->aborted()) {  return ; }      if($c->aborted()) {  return ; }
     #      #
       # Determine which students we want to look at
       my @Students;
       if ($single_student_mode) {
           @Students = (&Apache::lonstatistics::current_student());
           $r->print(&next_and_previous_buttons());
           $r->rflush();
       } else {
           @Students = @Apache::lonstatistics::Students;
       }
       #
     # Call the initialize routine selected above      # Call the initialize routine selected above
     $initialize->($r);      $initialize->($r);
     foreach my $student (@Apache::lonstatistics::Students) {      foreach my $student (@Students) {
         if($c->aborted()) {           if($c->aborted()) { 
             $finish->($r);              $finish->($r);
             return ;               return ; 
Line 186  ENDMSG Line 197  ENDMSG
   
 #######################################################  #######################################################
 #######################################################  #######################################################
   sub next_and_previous_buttons {
       my $Str = '';
       $Str .= '<input type="hidden" name="SelectedStudent" value="'.
           $ENV{'form.SelectedStudent'}.'" />';
       #
       # Build the previous student link
       my $previous = &Apache::lonstatistics::previous_student();
       my $previousbutton = '';
       if (defined($previous)) {
           my $sname = $previous->{'username'}.':'.$previous->{'domain'};
           $previousbutton .= '<input type="button" value="'.
               'Previous Student ('.
               $previous->{'username'}.'@'.$previous->{'domain'}.')'.
               '" onclick="document.Statistics.SelectedStudent.value='.
               "'".$sname."'".';'.
               'document.Statistics.submit();" />';
       } else {
           $previousbutton .= '<input type="button" value="'.
               'Previous student (none)'.'" />';
       }
       #
       # Build the next student link
       my $next = &Apache::lonstatistics::next_student();
       my $nextbutton = '';
       if (defined($next)) {
           my $sname = $next->{'username'}.':'.$next->{'domain'};
           $nextbutton .= '<input type="button" value="'.
               'Next Student ('.
               $next->{'username'}.'@'.$next->{'domain'}.')'.
               '" onclick="document.Statistics.SelectedStudent.value='.
               "'".$sname."'".';'.
               'document.Statistics.submit();" />';
       } else {
           $nextbutton .= '<input type="button" value="'.
               'Next student (none)'.'" />';
       }
       #
       # Build the 'all students' button
       my $all = '';
       $all .= '<input type="button" value="All Students" '.
               '" onclick="document.Statistics.SelectedStudent.value='.
               "''".';'.'document.Statistics.submit();" />';
       $Str .= $previousbutton.('&nbsp;'x5).$all.('&nbsp;'x5).$nextbutton;
       return $Str;
   }
   
   #######################################################
   #######################################################
   
 sub get_student_fields_to_show {  sub get_student_fields_to_show {
     my @to_show = @Apache::lonstatistics::SelectedStudentData;      my @to_show = @Apache::lonstatistics::SelectedStudentData;
Line 227  sub CreateInterface { Line 286  sub CreateInterface {
     $Str .= '<td align="center"><b>Enrollment Status</b></td>';      $Str .= '<td align="center"><b>Enrollment Status</b></td>';
     $Str .= '<td align="center"><b>Sequences and Folders</b></td>';      $Str .= '<td align="center"><b>Sequences and Folders</b></td>';
     $Str .= '<td align="center"><b>Output Format</b></td>';      $Str .= '<td align="center"><b>Output Format</b></td>';
       $Str .= '<td align="center"><b>Output Data</b></td>';
     $Str .= '</tr>'."\n";      $Str .= '</tr>'."\n";
     #      #
     $Str .= '<tr><td align="center">'."\n";      $Str .= '<tr><td align="center">'."\n";
Line 249  sub CreateInterface { Line 309  sub CreateInterface {
                                               $only_seq_with_assessments);                                                $only_seq_with_assessments);
     $Str .= '</td><td>'."\n";      $Str .= '</td><td>'."\n";
     $Str .= &CreateAndParseOutputSelector();      $Str .= &CreateAndParseOutputSelector();
       $Str .= '</td><td>'."\n";
       $Str .= &CreateAndParseOutputDataSelector();
     $Str .= '</td></tr>'."\n";      $Str .= '</td></tr>'."\n";
     $Str .= '</table>'."\n";      $Str .= '</table>'."\n";
       $Str .= '<input type="submit" value="Generate Chart" />';
       $Str .= '&nbsp;'x8;
     return $Str;      return $Str;
 }  }
   
Line 271  my @OutputOptions = Line 335  my @OutputOptions =
        description => 'Output HTML with each symbol linked to the problem '.         description => 'Output HTML with each symbol linked to the problem '.
    'which generated it.',     'which generated it.',
        mode => 'html',         mode => 'html',
        show => 'all',  
        show_links => 'yes',         show_links => 'yes',
        },         },
      { name  => 'HTML, with all links',       { name  => 'HTML, with all links',
Line 280  my @OutputOptions = Line 343  my @OutputOptions =
    'which generated it.  '.     'which generated it.  '.
            'This includes links for unattempted problems.',             'This includes links for unattempted problems.',
        mode => 'html',         mode => 'html',
        show => 'all',  
        show_links => 'all',         show_links => 'all',
        },         },
      { name  => 'HTML, without links',       { name  => 'HTML, without links',
Line 289  my @OutputOptions = Line 351  my @OutputOptions =
    ' web page is greatly reduced.  If your browser crashes on the '.     ' web page is greatly reduced.  If your browser crashes on the '.
    'full display, try this.',     'full display, try this.',
        mode => 'html',         mode => 'html',
        show => 'all',  
        show_links => 'no',         show_links => 'no',
            },             },
      { name  => 'HTML, scores only',       { name  => 'Excel',
        value => 'html, scores only',         value => 'excel',
        description => 'Output HTML, only showing the total number of correct'.         description => 'Output an Excel file (compatable with Excel 95).',
    ' problems (or problem parts) and not the maximum possible for '.  
    'each student',  
        mode => 'html',  
        show => 'scores',  
        show_links => 'no',  
            },  
      { name  => 'HTML, totals',  
        value => 'html, totals',  
        description => 'Output HTML, but only the summary statistics for each'.  
    ' sequence selected for each student.',  
        mode => 'html',  
        show => 'totals',  
        show_links => 'no',  
        },  
      { name  => 'HTML, summary table only',  
        value => 'html summary table only',  
        description => 'Output HTML, but only the final summary table for '.  
            'all students across all sequences.',  
        mode => 'html',  
        show => 'final table',  
        show_links => 'no',  
        },  
      { name  => 'Excel, scores only',  
        value => 'excel, scores only',  
        description => 'Output an Excel file (compatable with Excel 95), '.  
    'with a single column for each sequence showing the students '.  
    'score.',  
        mode => 'excel',         mode => 'excel',
        show => 'scores',  
        show_links => 'no',  
            },  
      { name  => 'Excel, totals',  
        value => 'excel, totals',  
        description => 'Output an Excel file (compatable with Excel 95), '.  
    'with two columns for each sequence, the students score on the '.  
    'sequence and the students maximum possible on the sequence',  
        mode => 'excel',  
        show => 'totals',  
        show_links => 'no',  
            },  
      { name  => 'multi-sheet Excel',  
        value => 'multi-sheet excel',  
        description => 'Output an Excel file (compatable with Excel 95), '.  
    'with a seperate worksheet for each sequence you have selected '.  
            'the data for each problem part '.  
            '(number of tries, status, points awarded) will be listed.',  
        mode => 'multi-sheet excel',  
        show => 'totals',  
        show_links => 'no',  
            },  
      { name  => 'multi-sheet Excel, by section',  
        value => 'multi-sheet excel, by section',  
        description => 'Output an Excel file (compatable with Excel 95), '.  
    'with a seperate worksheet for each sequence you have selected '.  
            'the data for each problem part '.  
            '(number of tries, status, points awarded) will be listed.  '.  
            'There will be one Excel workbook for each section selected.',  
        mode => 'multi-sheet excel',  
        show => 'by section',  
        show_links => 'no',         show_links => 'no',
            },     },
      { name  => 'CSV, everything',  #     { name  => 'multi-sheet Excel',
        value => 'csv, everything',  #       value => 'multi-sheet excel',
        description => '',  #       description => 'Output an Excel file (compatable with Excel 95), '.
   #   'with a seperate worksheet for each sequence you have selected '.
   #           'the data for each problem part '.
   #           '(number of tries, status, points awarded) will be listed.',
   #       mode => 'multi-sheet excel',
   #       show_links => 'no',
   #           },
   #     { name  => 'multi-sheet Excel, by section',
   #       value => 'multi-sheet excel, by section',
   #       description => 'Output an Excel file (compatable with Excel 95), '.
   #   'with a seperate worksheet for each sequence you have selected '.
   #           'the data for each problem part '.
   #           '(number of tries, status, points awarded) will be listed.  '.
   #           'There will be one Excel workbook for each section selected.',
   #       mode => 'multi-sheet excel',
   #       show_links => 'no',
   #           },
        { name  => 'CSV',
          value => 'csv',
          description => 'Output a comma seperated values file suitable for '.
              'import into a spreadsheet.',
        mode => 'csv',         mode => 'csv',
        show => 'all',  
        show_links => 'no',  
            },  
      { name  => 'CSV, scores only',  
        value => 'csv, scores only',  
        description => '',  
        mode => 'csv',  
        show => 'scores',  
        show_links => 'no',  
            },  
      { name  => 'CSV, totals',  
        value => 'csv, totals',  
        description => '',  
        mode => 'csv',  
        show => 'totals',  
        show_links => 'no',         show_links => 'no',
            },             },
      );       );
Line 396  sub CreateAndParseOutputSelector { Line 404  sub CreateAndParseOutputSelector {
     my $elementname = 'chartoutputmode';      my $elementname = 'chartoutputmode';
     #      #
     # Format for output options is 'mode, restrictions';      # Format for output options is 'mode, restrictions';
     my $selected = 'html, with links';      my $selected = 'html, without links';
     if (exists($ENV{'form.'.$elementname})) {      if (exists($ENV{'form.'.$elementname})) {
         if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {          if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
             $selected = $ENV{'form.'.$elementname}->[0];              $selected = $ENV{'form.'.$elementname}->[0];
Line 408  sub CreateAndParseOutputSelector { Line 416  sub CreateAndParseOutputSelector {
     # Set package variables describing output mode      # Set package variables describing output mode
     $show_links  = 'no';      $show_links  = 'no';
     $output_mode = 'html';      $output_mode = 'html';
     $show        = 'all';  
     foreach my $option (@OutputOptions) {      foreach my $option (@OutputOptions) {
         next if ($option->{'value'} ne $selected);          next if ($option->{'value'} ne $selected);
         $output_mode = $option->{'mode'};          $output_mode = $option->{'mode'};
         $show        = $option->{'show'};  
         $show_links  = $option->{'show_links'};          $show_links  = $option->{'show_links'};
     }      }
   
Line 428  sub CreateAndParseOutputSelector { Line 434  sub CreateAndParseOutputSelector {
     return $Str;      return $Str;
 }  }
   
   ##
   ## Data selector stuff
   ##
   my @OutputDataOptions =
       ( { name  =>'Tries',
           base  =>'tries',
           value => 'tries',
           shortdesc => 'Number of Tries before success on each Problem Part',
           longdesc =>'The number of tries before success on each problem part.',
           },
         { name  =>'Parts Correct',
           base  =>'tries',
           value => 'parts correct',
           shortdesc => 'Number of Problem Parts completed successfully.',
           longdesc => 'The Number of Problem Parts completed successfully.',
           },
         { name  =>'Parts Correct & Maximums',
           base  =>'tries',
           value => 'parts correct total',
           shortdesc => 'Number of Problem Parts completed successfully.',
           longdesc => 'The Number of Problem Parts completed successfully and '.
               'the maximum possible for each student',
           },
         { name  => 'Scores',
           base  => 'scores',
           value => 'scores',
           shortdesc => 'Score on each Problem Part',
           longdesc =>'The students score on each problem part, computed as'.
               'the part weight * part awarded',
           },
         { name  => 'Scores Sum',
           base  => 'scores',
           value => 'sum only',
           shortdesc => 'Sum of Scores on each Problem Part',
           longdesc =>'The total of the scores of the student on each problem'.
               ' part in the sequences or folders selected.',
           },
         { name  => 'Scores Sum & Maximums',
           base  => 'scores',
           value => 'sum and total',
           shortdesc => 'Total Score and Maximum Possible for each '.
               'Sequence or Folder',
           longdesc => 'The total of the scores of the student on each problem'.
               ' and the maximum possible for that student on each Sequence or '.
               ' Folder.',
           },
         { name  => 'Summary Table (Scores)',
           base  => 'scores',
           value => 'final table scores',
           shortdesc => 'Summary of Scores',
           longdesc  => '',
           },
         { name  => 'Summary Table (Parts)',
           base  => 'tries',
           value => 'final table parts',
           shortdesc => 'Summary of Parts Correct',
           longdesc  => '',
           }
         );
   
   sub CreateAndParseOutputDataSelector {
       my $Str = '';
       my $elementname = 'chartoutputdata';
       #
       my $selected = 'scores';
       if (exists($ENV{'form.'.$elementname})) {
           if (ref($ENV{'form.'.$elementname} eq 'ARRAY')) {
               $selected = $ENV{'form.'.$elementname}->[0];
           } else {
               $selected = $ENV{'form.'.$elementname};
           }
       }
       #
       $data = 'scores';
       foreach my $option (@OutputDataOptions) {
           if ($option->{'value'} eq $selected) {
               $data = $option->{'value'};
               $base = $option->{'base'};
               $datadescription = $option->{'shortdesc'};
           }
       }
       #
       # Build the form element
       $Str = qq/<select size="5" name="$elementname">/;
       foreach my $option (@OutputDataOptions) {
           $Str .= "\n".'    <option value="'.$option->{'value'}.'"';
           $Str .= " selected " if ($option->{'value'} eq $data);
           $Str .= ">".$option->{'name'}."<\/option>";
       }
       $Str .= "\n</select>";
       return $Str;
   
   }
   
 #######################################################  #######################################################
 #######################################################  #######################################################
   
Line 466  sub html_initialize { Line 566  sub html_initialize {
     $r->print("<h3>".$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.      $r->print("<h3>".$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
               "&nbsp;&nbsp;".localtime(time)."</h3>");                "&nbsp;&nbsp;".localtime(time)."</h3>");
   
       if ($data !~ /^final table/) {
           $r->print("<h3>".$datadescription."</h3>");        
       }
     #      #
     # Set up progress window for 'final table' display only      # Set up progress window for 'final table' display only
     if ($show eq 'final table') {      if ($data =~ /^final table/) {
         my $studentcount = scalar(@Apache::lonstatistics::Students);           my $studentcount = scalar(@Apache::lonstatistics::Students); 
         %prog_state=&Apache::lonhtmlcommon::Create_PrgWin          %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
             ($r,'Summary Table Status',              ($r,'Summary Table Status',
Line 490  sub html_initialize { Line 593  sub html_initialize {
         my $width = $sequence->{'width'};          my $width = $sequence->{'width'};
         $Str .= $title.' 'x($width-$base).$padding;          $Str .= $title.' 'x($width-$base).$padding;
     }      }
     $Str .= "total (of shown problems)</pre>\n";      $Str .= "total</pre>\n";
     $Str .= "<pre>";      $Str .= "<pre>";
     #      #
     # Check for suppression of output      # Check for suppression of output
     if ($show eq 'final table') {      if ($data =~ /^final table/) {
         $Str = '';          $Str = '';
     }      }
     $r->print($Str);      $r->print($Str);
Line 506  sub html_outputstudent { Line 609  sub html_outputstudent {
     my ($r,$student) = @_;      my ($r,$student) = @_;
     my $Str = '';      my $Str = '';
     #      #
     if($count++ % 5 == 0 && $count > 0) {      if($count++ % 5 == 0 && $count > 0 && $data !~ /^final table/) {
         $r->print("</pre><pre>");          $r->print("</pre><pre>");
     }      }
     # First, the @StudentData fields need to be listed      # First, the @StudentData fields need to be listed
Line 527  sub html_outputstudent { Line 630  sub html_outputstudent {
     }      }
     if (scalar(@tmp) < 1) {      if (scalar(@tmp) < 1) {
         $nodata_count++;          $nodata_count++;
         return if ($show eq 'final table');          return if ($data =~ /^final table/);
         $Str .= '<font color="blue">No Course Data</font>'."\n";          $Str .= '<font color="blue">No Course Data</font>'."\n";
         $r->print($Str);          $r->print($Str);
         $r->rflush();          $r->rflush();
Line 538  sub html_outputstudent { Line 641  sub html_outputstudent {
     my $studentstats;      my $studentstats;
     my $PerformanceStr = '';      my $PerformanceStr = '';
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
         my ($performance,$score,$seq_max) =          my ($performance,$performance_length,$score,$seq_max,$rawdata);
             &StudentPerformanceOnSequence($student,\%StudentsData,          if ($base eq 'tries') {
                                           $seq,$show_links);              ($performance,$performance_length,$score,$seq_max,$rawdata) =
         my $ratio = $score.'/'.$seq_max;                  &StudentTriesOnSequence($student,\%StudentsData,
                                           $seq,$show_links);
           } else {
               ($performance,$performance_length,$score,$seq_max,$rawdata) =
                   &StudentPerformanceOnSequence($student,\%StudentsData,
                                                 $seq,$show_links);
           }
           my $ratio = sprintf("%3d",$score).'/'.sprintf("%3d",$seq_max);
         #          #
         if ($show eq 'totals') {          if ($data eq 'sum and total' || $data eq 'parts correct total') {
             $performance = ' 'x(length($seq_max)-length($score)).$ratio;              $performance  = $ratio;
             $performance .= ' 'x($seq->{'width'}-length($performance));              $performance .= ' 'x($seq->{'width'}-length($ratio));
         } elsif ($show eq 'scores') {          } elsif ($data eq 'sum only' || $data eq 'parts correct') {
             $performance = $score;              $performance  = $score;
             $performance .= ' 'x($seq->{'width'}-length($performance));              $performance .= ' 'x($seq->{'width'}-length($score));
         } else {          } else {
             # Pad with extra spaces              # Pad with extra spaces
             $performance .= ' 'x($seq->{'width'}-$seq_max-              $performance .= ' 'x($seq->{'width'}-$performance_length-
                                  length($ratio)                                   length($ratio)
                                  ).$ratio;                                   ).$ratio;
         }          }
Line 566  sub html_outputstudent { Line 676  sub html_outputstudent {
     my ($score,$max) = (0,0);      my ($score,$max) = (0,0);
     while (my ($symb,$seq_stats) = each (%{$studentstats})) {      while (my ($symb,$seq_stats) = each (%{$studentstats})) {
         $Statistics->{$symb}->{'score'} += $seq_stats->{'score'};          $Statistics->{$symb}->{'score'} += $seq_stats->{'score'};
         $Statistics->{$symb}->{'max'}   += $seq_stats->{'max'};          if ($Statistics->{$symb}->{'max'} < $seq_stats->{'max'}) {
               $Statistics->{$symb}->{'max'} = $seq_stats->{'max'};
           }
         $score += $seq_stats->{'score'};          $score += $seq_stats->{'score'};
         $max   += $seq_stats->{'max'};          $max   += $seq_stats->{'max'};
     }      }
Line 574  sub html_outputstudent { Line 686  sub html_outputstudent {
     $Str .= " \n";      $Str .= " \n";
     #      #
     # Check for suppressed output and update the progress window if so...      # Check for suppressed output and update the progress window if so...
     if ($show eq 'final table') {      if ($data =~ /^final table/) {
         $Str = '';          $Str = '';
         &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,          &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
                                                  'last student');                                                   'last student');
Line 590  sub html_finish { Line 702  sub html_finish {
     my ($r) = @_;      my ($r) = @_;
     #      #
     # Check for suppressed output and close the progress window if so      # Check for suppressed output and close the progress window if so
     if ($show eq 'final table') {      if ($data =~ /^final table/) {
         &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);          &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
     } else {      } else {
         $r->print("</pre>\n");           $r->print("</pre>\n"); 
     }      }
     $r->print(&StudentAverageTotal());      if ($single_student_mode) {
           $r->print(&SingleStudentTotal());
       } else {
           $r->print(&StudentAverageTotal());
       }
     $r->rflush();      $r->rflush();
     return;      return;
 }  }
Line 616  sub StudentAverageTotal { Line 732  sub StudentAverageTotal {
             $ave = 0;              $ave = 0;
         }          }
         $total_ave += $ave;          $total_ave += $ave;
         my $max = $seq->{'num_assess_parts'};          my $max = $Statistics->{$seq->{'symb'}}->{'max'};
         $total_max += $max;          $total_max += $max;
         if ($ave == 0) {          if ($ave == 0) {
             $ave = "0.00";              $ave = "0.00";
Line 638  sub StudentAverageTotal { Line 754  sub StudentAverageTotal {
     return $Str;      return $Str;
 }  }
   
   sub SingleStudentTotal {
       my $student = &Apache::lonstatistics::current_student();
       my $Str = "<h3>Summary table for ".$student->{'fullname'}." ".
           $student->{'username'}.'@'.$student->{'domain'}."</h3>\n";
       $Str .= '<table border=2 cellspacing="1">'."\n";
       $Str .= 
           "<tr><th>Sequence or Folder</th><th>Score</th><th>Maximum</th></tr>\n";
       my $total = 0;
       my $total_max = 0;
       foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
           my $value = $Statistics->{$seq->{'symb'}}->{'score'};
           my $max = $Statistics->{$seq->{'symb'}}->{'max'};
           $Str .= '<tr><td>'.$seq->{'title'}.'</td>'.
               '<td align="right">'.$value.'</td>'.
                   '<td align="right">'.$max.'</td></tr>'."\n";
           $total += $value;
           $total_max +=$max;
       }
       $Str .= '<tr><td><b>Total</b></td>'.
           '<td align="right">'.$total.'</td>'.
           '<td align="right">'.$total_max."</td></tr>\n";
       $Str .= "</table>\n";
       return $Str;
   }
   
 }  }
   
 #######################################################  #######################################################
Line 681  sub multi_sheet_excel_initialize { Line 822  sub multi_sheet_excel_initialize {
     if ($size_estimate > $max_size) { # try to stay under 5 megs      if ($size_estimate > $max_size) { # try to stay under 5 megs
         $num_workbooks += int($size_estimate / $max_size);          $num_workbooks += int($size_estimate / $max_size);
     }      }
     if ($show eq 'by section') {  #    if ($data eq ) {
         if (@Apache::lonstatistics::SelectedSections > 1 &&   #        if (@Apache::lonstatistics::SelectedSections > 1 && 
             $Apache::lonstatistics::SelectedSections[0] ne 'all') {  #            $Apache::lonstatistics::SelectedSections[0] ne 'all') {
             $num_workbooks = scalar(@Apache::lonstatistics::SelectedSections);  #            $num_workbooks = scalar(@Apache::lonstatistics::SelectedSections);
         } else {  #        } else {
             # @Apache::lonstatistics::Sections contains 'all' as well.  #            # @Apache::lonstatistics::Sections contains 'all' as well.
             $num_workbooks = scalar(@Apache::lonstatistics::Sections) - 1;  #            $num_workbooks = scalar(@Apache::lonstatistics::Sections) - 1;
         }  #        }
     }  #    }
           
     $r->print("Maximum allowed size: ".$max_size." bytes<br />");      $r->print("Maximum allowed size: ".$max_size." bytes<br />");
     $r->print("Number of students: ".$num_students."<br />");      $r->print("Number of students: ".$num_students."<br />");
Line 739  my $rows_output; Line 880  my $rows_output;
 my $cols_output;  my $cols_output;
   
 my %prog_state; # progress window state  my %prog_state; # progress window state
   my $request_aborted;
   
 sub excel_initialize {  sub excel_initialize {
     my ($r) = @_;      my ($r) = @_;
     #      #
       $request_aborted = undef;
       my $total_columns = scalar(&get_student_fields_to_show());
       foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
           # Add 2 because we need a 'sum' and 'total' column for each
           $total_columns += $seq->{'num_assess_parts'}+2;
       }
       if ($data eq 'tries' && $total_columns > 255) {
           $r->print(<<END);
   <h2>Unable to Complete Request</h2>
   <p>
   LON-CAPA is unable to produce your Excel spreadsheet because your selections
   will result in more than 255 columns.  Excel allows only 255 columns in a
   spreadsheet.
   </p><p>
   You may consider reducing the number of <b>Sequences or Folders</b> you
   have selected.  
   </p><p>
   LON-CAPA can produce <b>CSV</b> files of this data or Excel files of the
   summary data (<b>Parts Correct</b> or <b>Parts Correct & Totals</b>).
   </p>
   END
          $request_aborted = 1;
       }
       if ($data eq 'scores' && $total_columns > 255) {
           $r->print(<<END);
   <h2>Unable to Complete Request</h2>
   <p>
   LON-CAPA is unable to produce your Excel spreadsheet because your selections
   will result in more than 255 columns.  Excel allows only 255 columns in a
   spreadsheet.
   </p><p>
   You may consider reducing the number of <b>Sequences or Folders</b> you
   have selected.  
   </p><p>
   LON-CAPA can produce <b>CSV</b> files of this data or Excel files of the
   summary data (<b>Scores Sum</b> or <b>Scores Sum & Totals</b>).
   </p>
   END
          $request_aborted = 1;
       }
       if ($data =~ /^final table/) {
           $r->print(<<END);
   <h2>Unable to Complete Request</h2>
   <p>
   The <b>Summary Table (Scores)</b> option is not available for non-HTML output.
   </p>
   END
          $request_aborted = 1;
       }
       return if ($request_aborted);
       #
     $filename = '/prtspool/'.      $filename = '/prtspool/'.
         $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.          $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
             time.'_'.rand(1000000000).'.xls';              time.'_'.rand(1000000000).'.xls';
Line 804  sub excel_initialize { Line 997  sub excel_initialize {
     $cols_output += scalar(@Sections);      $cols_output += scalar(@Sections);
     #      #
     # Put the date in there too      # Put the date in there too
     $excel_sheet->write($rows_output,$cols_output++,      $excel_sheet->write($rows_output++,$cols_output++,
                         'Compiled on '.localtime(time));                          'Compiled on '.localtime(time));
     #      #
     $rows_output++;      $cols_output = 0;
       $excel_sheet->write($rows_output++,$cols_output++,$datadescription);
       #
       if ($data eq 'tries' || $data eq 'scores') {
           $rows_output++;
       }
     #      #
     # Add the student headers      # Add the student headers
     $cols_output = 0;      $cols_output = 0;
     foreach my $field (&get_student_fields_to_show()) {      foreach my $field (&get_student_fields_to_show()) {
         $excel_sheet->write($rows_output,$cols_output++,$field);          $excel_sheet->write($rows_output,$cols_output++,$field);
     }      }
       my $row_offset = 0;
       if ($data eq 'tries' || $data eq 'scores') {
           $row_offset = -1;
       }
     #      #
     # Add the Sequence Headers      # Add the remaining column headers
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
         $excel_sheet->write($rows_output,$cols_output,$seq->{'title'});          $excel_sheet->write($rows_output+$row_offset,
         if ($show eq 'totals') {                              $cols_output,$seq->{'title'});
           if ($data eq 'tries' || $data eq 'scores') {
               foreach my $res (@{$seq->{'contents'}}) {
                   next if ($res->{'type'} ne 'assessment');
                   if (scalar(@{$res->{'parts'}}) > 1) {
                       foreach my $part (@{$res->{'parts'}}) {
                           $excel_sheet->write($rows_output,
                                               $cols_output++,
                                               $res->{'title'}.' part '.$part);
                       }
                   } else {
                       $excel_sheet->write($rows_output,
                                           $cols_output++,
                                           $res->{'title'});
                   }
               }
               $excel_sheet->write($rows_output,$cols_output++,'score');
               $excel_sheet->write($rows_output,$cols_output++,'maximum');
           } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
             $excel_sheet->write($rows_output+1,$cols_output,'score');              $excel_sheet->write($rows_output+1,$cols_output,'score');
             $excel_sheet->write($rows_output+1,$cols_output+1,'maximum');              $excel_sheet->write($rows_output+1,$cols_output+1,'maximum');
             $cols_output += 2;              $cols_output += 2;
Line 828  sub excel_initialize { Line 1048  sub excel_initialize {
     }      }
     #      #
     # Bookkeeping      # Bookkeeping
     if ($show eq 'totals') {      if ($data eq 'sum and total' || $data eq 'parts correct total') {
         $rows_output += 2;          $rows_output += 2;
     } else {      } else {
         $rows_output += 1;          $rows_output += 1;
     }      }
     #      #
     # Output a row for MAX      # Output a row for MAX
     if ($show ne 'totals') {      $cols_output = 0;
         $cols_output = 0;      foreach my $field (&get_student_fields_to_show()) {
         foreach my $field (&get_student_fields_to_show()) {          if ($field eq 'username' || $field eq 'fullname' || 
             if ($field eq 'username' || $field eq 'fullname' ||               $field eq 'id') {
                 $field eq 'id') {              $excel_sheet->write($rows_output,$cols_output++,'Maximum');
                 $excel_sheet->write($rows_output,$cols_output++,'Maximum');          } else {
             } else {              $excel_sheet->write($rows_output,$cols_output++,'');
                 $excel_sheet->write($rows_output,$cols_output++,'');  
             }  
         }          }
         #      }
         # Add the Sequence Headers      #
         foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      # Add the maximums for each sequence or assessment
             $excel_sheet->write($rows_output,$cols_output++,      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
                                 $seq->{'num_assess_parts'});          my $weight;
           my $max = 0;
           foreach my $resource (@{$seq->{'contents'}}) {
               next if ($resource->{'type'} ne 'assessment');
               foreach my $part (@{$resource->{'parts'}}) {
                   $weight = 1;
                   if ($base eq 'scores') {
                       $weight = &Apache::lonnet::EXT
                           ('resource.'.$part.'.weight',$resource->{'symb'},
                            undef,undef,undef);
                       if (!defined($weight) || ($weight eq '')) { 
                           $weight=1;
                       }
                   }
                   if ($data eq 'scores') {
                       $excel_sheet->write($rows_output,$cols_output++,$weight);
                   } elsif ($data eq 'tries') {
                       $excel_sheet->write($rows_output,$cols_output++,'');
                   }
                   $max += $weight;
               }
           } 
           if (! ($data eq 'sum only' || $data eq 'parts correct')) {
               $excel_sheet->write($rows_output,$cols_output++,'');
         }          }
         $rows_output++;          $excel_sheet->write($rows_output,$cols_output++,$max);
     }      }
       $rows_output++;
     #      #
     # Let the user know what we are doing      # Let the user know what we are doing
     my $studentcount = scalar(@Apache::lonstatistics::Students);       my $studentcount = scalar(@Apache::lonstatistics::Students); 
Line 872  sub excel_initialize { Line 1114  sub excel_initialize {
   
 sub excel_outputstudent {  sub excel_outputstudent {
     my ($r,$student) = @_;      my ($r,$student) = @_;
       return if ($request_aborted);
     return if (! defined($excel_sheet));      return if (! defined($excel_sheet));
     $cols_output=0;      $cols_output=0;
     #      #
Line 893  sub excel_outputstudent { Line 1136  sub excel_outputstudent {
     #      #
     # Write out sequence scores and totals data      # Write out sequence scores and totals data
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
         my ($performance,$score,$seq_max) =          my ($performance,$performance_length,$score,$seq_max,$rawdata);
             &StudentPerformanceOnSequence($student,\%StudentsData,          if ($base eq 'tries') {
                                           $seq,'no');              ($performance,$performance_length,$score,$seq_max,$rawdata) =
         if ($show eq 'totals' || $show eq 'scores') {                  &StudentTriesOnSequence($student,\%StudentsData,
                                           $seq,'no');
           } else {
               ($performance,$performance_length,$score,$seq_max,$rawdata) =
                   &StudentPerformanceOnSequence($student,\%StudentsData,
                                                 $seq,'no');
           }
           if ($data eq 'tries' || $data eq 'scores') {
               foreach my $value (@$rawdata) {
                   $excel_sheet->write($rows_output,$cols_output++,$value);
               }
               $excel_sheet->write($rows_output,$cols_output++,$score);
               $excel_sheet->write($rows_output,$cols_output++,$seq_max);
           } elsif ($data eq 'sum and total' || $data eq 'sum only' || 
               $data eq 'parts correct' || $data eq 'parts correct total') {
             $excel_sheet->write($rows_output,$cols_output++,$score);              $excel_sheet->write($rows_output,$cols_output++,$score);
         }          }
         if ($show eq 'totals') {          if ($data eq 'sum and total' || $data eq 'parts correct total') {
             $excel_sheet->write($rows_output,$cols_output++,$seq_max);              $excel_sheet->write($rows_output,$cols_output++,$seq_max);
         }          }
     }      }
Line 915  sub excel_outputstudent { Line 1172  sub excel_outputstudent {
   
 sub excel_finish {  sub excel_finish {
     my ($r) = @_;      my ($r) = @_;
       return if ($request_aborted);
     return if (! defined($excel_sheet));      return if (! defined($excel_sheet));
     #      #
     # Write the excel file      # Write the excel file
Line 955  sub excel_finish { Line 1213  sub excel_finish {
   
 my $outputfile;  my $outputfile;
 my $filename;  my $filename;
   my $request_aborted;
 my %prog_state; # progress window state  my %prog_state; # progress window state
   
 sub csv_initialize{  sub csv_initialize{
Line 966  sub csv_initialize{ Line 1224  sub csv_initialize{
     $outputfile = undef;      $outputfile = undef;
     undef(%prog_state);      undef(%prog_state);
     #      #
       # Deal with unimplemented requests
       $request_aborted = undef;
       if ($data =~ /final table/) {
           $r->print(<<END);
   <h2>Unable to Complete Request</h2>
   <p>
   The <b>Summary Table (Scores)</b> option is not available for non-HTML output.
   </p>
   END
          $request_aborted = 1;
       }
       return if ($request_aborted);
   
       #
     # Open a file      # Open a file
     $filename = '/prtspool/'.      $filename = '/prtspool/'.
         $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.          $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
Line 983  sub csv_initialize{ Line 1255  sub csv_initialize{
     print $outputfile '"'.&Apache::loncommon::csv_translate($description).'",'.      print $outputfile '"'.&Apache::loncommon::csv_translate($description).'",'.
         '"'.&Apache::loncommon::csv_translate(scalar(localtime(time))).'"'.          '"'.&Apache::loncommon::csv_translate(scalar(localtime(time))).'"'.
             "\n";              "\n";
   
     #      #
     # Print out the headings      # Print out the headings
     my $Str = '';      my $Str = '';
     my $Str2 = undef;      my $Str2 = undef;
     foreach my $field (&get_student_fields_to_show()) {      foreach my $field (&get_student_fields_to_show()) {
         if ($show eq 'scores') {          if ($data eq 'sum only') {
             $Str .= '"'.&Apache::loncommon::csv_translate($field).'",';              $Str .= '"'.&Apache::loncommon::csv_translate($field).'",';
         } elsif ($show eq 'totals') {          } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
             $Str .= '"",'; # first row empty on the student fields              $Str .= '"",'; # first row empty on the student fields
             $Str2 .= '"'.&Apache::loncommon::csv_translate($field).'",';              $Str2 .= '"'.&Apache::loncommon::csv_translate($field).'",';
         } elsif ($show eq 'all') {          } elsif ($data eq 'scores' || $data eq 'tries' || 
             $Str .= '"'.&Apache::loncommon::csv_translate($field).'",';                   $data eq 'parts correct') {
               $Str  .= '"",';
               $Str2 .= '"'.&Apache::loncommon::csv_translate($field).'",';
         }          }
     }      }
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
         if ($show eq 'scores') {          if ($data eq 'sum only' || $data eq 'parts correct') {
             $Str .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).              $Str .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
                 '",';                  '",';
         } elsif ($show eq 'totals') {          } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
             $Str  .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).              $Str  .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
                 '","",';                  '","",';
             $Str2 .= '"score","total possible",';              $Str2 .= '"score","total possible",';
         } elsif ($show eq 'all') {          } elsif ($data eq 'scores' || $data eq 'tries') {
             $Str  .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).              $Str  .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
                 '",';                  '",';
             $Str .= '"",'x($seq->{'num_assess_parts'}-1);              $Str .= '"",'x($seq->{'num_assess_parts'}-1+2);
             $Str .= '"score","total possible",';              foreach my $res (@{$seq->{'contents'}}) {
                   next if ($res->{'type'} ne 'assessment');
                   foreach my $part (@{$res->{'parts'}}) {
                       $Str2 .= '"'.&Apache::loncommon::csv_translate($res->{'title'}.', Part '.$part).'",';
                   }
               }
               $Str2 .= '"score","total possible",';
         }          }
     }      }
     chop($Str);      chop($Str);
Line 1032  sub csv_initialize{ Line 1311  sub csv_initialize{
   
 sub csv_outputstudent {  sub csv_outputstudent {
     my ($r,$student) = @_;      my ($r,$student) = @_;
       return if ($request_aborted);
     return if (! defined($outputfile));      return if (! defined($outputfile));
     my $Str = '';      my $Str = '';
     #      #
Line 1053  sub csv_outputstudent { Line 1333  sub csv_outputstudent {
     #      #
     # Output performance data      # Output performance data
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {      foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
         my ($performance,$score,$seq_max) =          my ($performance,$performance_length,$score,$seq_max,$rawdata);
             &StudentPerformanceOnSequence($student,\%StudentsData,          if ($base eq 'tries') {
                                           $seq,'no');              ($performance,$performance_length,$score,$seq_max,$rawdata) =
         if ($show eq 'scores') {                  &StudentTriesOnSequence($student,\%StudentsData,
                                           $seq,'no');
           } else {
               ($performance,$performance_length,$score,$seq_max,$rawdata) =
                   &StudentPerformanceOnSequence($student,\%StudentsData,
                                                 $seq,'no');
           }
           if ($data eq 'sum only' || $data eq 'parts correct') {
             $Str .= '"'.$score.'",';              $Str .= '"'.$score.'",';
         } elsif ($show eq 'totals') {          } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
             $Str  .= '"'.$score.'","'.$seq_max.'",';              $Str  .= '"'.$score.'","'.$seq_max.'",';
         } elsif ($show eq 'all') {          } elsif ($data eq 'scores' || $data eq 'tries') {
             $Str .= '"'.join('","',(split(//,$performance),$score,$seq_max)).              $Str .= '"'.join('","',(@$rawdata,$score,$seq_max)).'",';
                 '",';  
         }          }
     }      }
     chop($Str);      chop($Str);
Line 1076  sub csv_outputstudent { Line 1362  sub csv_outputstudent {
   
 sub csv_finish {  sub csv_finish {
     my ($r) = @_;      my ($r) = @_;
       return if ($request_aborted);
     return if (! defined($outputfile));      return if (! defined($outputfile));
     close($outputfile);      close($outputfile);
     #      #
Line 1100  sub csv_finish { Line 1387  sub csv_finish {
   
 =pod  =pod
   
 =item &StudentPerformanceOnSequence()  =item &StudentTriesOnSequence()
   
 Inputs:  Inputs:
   
Line 1120  Inputs: Line 1407  Inputs:
   
 #######################################################  #######################################################
 #######################################################  #######################################################
 sub StudentPerformanceOnSequence {  sub StudentTriesOnSequence {
     my ($student,$studentdata,$seq,$links) = @_;      my ($student,$studentdata,$seq,$links) = @_;
     $links = 'no' if (! defined($links));      $links = 'no' if (! defined($links));
     my $Str = '';      my $Str = '';
     my ($sum,$max) = (0,0);      my ($sum,$max) = (0,0);
       my $performance_length = 0;
       my @TriesData = ();
       my $tries;
     foreach my $resource (@{$seq->{'contents'}}) {      foreach my $resource (@{$seq->{'contents'}}) {
         next if ($resource->{'type'} ne 'assessment');          next if ($resource->{'type'} ne 'assessment');
         my $resource_data = $studentdata->{$resource->{'symb'}};          my $resource_data = $studentdata->{$resource->{'symb'}};
         my $value = '';          my $value = '';
         foreach my $partnum (@{$resource->{'parts'}}) {          foreach my $partnum (@{$resource->{'parts'}}) {
               $tries = undef;
             $max++;              $max++;
               $performance_length++;
             my $symbol = ' '; # default to space              my $symbol = ' '; # default to space
             #              #
             if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {              if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {
Line 1149  sub StudentPerformanceOnSequence { Line 1441  sub StudentPerformanceOnSequence {
                     $max--;                      $max--;
                 } elsif ($status eq 'correct_by_student' &&                  } elsif ($status eq 'correct_by_student' &&
                     exists($resource_data->{'resource.'.$partnum.'.tries'})){                      exists($resource_data->{'resource.'.$partnum.'.tries'})){
                     my $num = $resource_data->{'resource.'.$partnum.'.tries'};                      $tries = $resource_data->{'resource.'.$partnum.'.tries'};
                     if ($num > 9) {                      if ($tries > 9) {
                         $symbol = '*';                          $symbol = '*';
                     } elsif ($num > 0) {                      } elsif ($tries > 0) {
                         $symbol = $num;                          $symbol = $tries;
                     } else {                      } else {
                         $symbol = ' ';                          $symbol = ' ';
                     }                      }
Line 1173  sub StudentPerformanceOnSequence { Line 1465  sub StudentPerformanceOnSequence {
                 }                  }
             }              }
             #              #
               if (! defined($tries)) {
                   $tries = $symbol;
               }
               push (@TriesData,$tries);
               #
             if ( ($links eq 'yes' && $symbol ne ' ') ||              if ( ($links eq 'yes' && $symbol ne ' ') ||
                  ($links eq 'all')) {                   ($links eq 'all')) {
                   if (length($symbol) > 1) {
                       &Apache::lonnet::logthis('length of symbol "'.$symbol.'" > 1');
                   }
                 $symbol = '<a href="/adm/grades'.                  $symbol = '<a href="/adm/grades'.
                     '?symb='.&Apache::lonnet::escape($resource->{'symb'}).                      '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
                         '&student='.$student->{'username'}.                          '&student='.$student->{'username'}.
Line 1185  sub StudentPerformanceOnSequence { Line 1485  sub StudentPerformanceOnSequence {
         }          }
         $Str .= $value;          $Str .= $value;
     }      }
     return ($Str,$sum,$max);      if ($seq->{'randompick'}) {
           $max = $seq->{'randompick'};
       }
       return ($Str,$performance_length,$sum,$max,\@TriesData);
   }
   
   #######################################################
   #######################################################
   
   =pod
   
   =item &StudentPerformanceOnSequence()
   
   Inputs:
   
   =over 4
   
   =item $student
   
   =item $studentdata Hash ref to all student data
   
   =item $seq Hash ref, the sequence we are working on
   
   =item $links if defined we will output links to each resource.
   
   =back
   
   =cut
   
   #######################################################
   #######################################################
   sub StudentPerformanceOnSequence {
       my ($student,$studentdata,$seq,$links) = @_;
       $links = 'no' if (! defined($links));
       my $Str = ''; # final result string
       my ($score,$max) = (0,0);
       my $performance_length = 0;
       my $symbol;
       my @ScoreData = ();
       my $partscore;
       foreach my $resource (@{$seq->{'contents'}}) {
           next if ($resource->{'type'} ne 'assessment');
           my $resource_data = $studentdata->{$resource->{'symb'}};
           foreach my $part (@{$resource->{'parts'}}) {
               $partscore = undef;
               my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
                                                 $resource->{'symb'},
                                                 $student->{'domain'},
                                                 $student->{'username'},
                                                 $student->{'section'});
               if (!defined($weight) || ($weight eq '')) { 
                   $weight=1;
               }
               #
               $max += $weight; # see the 'excused' branch below...
               $performance_length++; # one character per part
               $symbol = ' '; # default to space
               #
               my $awarded = 0;
               if (exists($resource_data->{'resource.'.$part.'.awarded'})) {
                   $awarded = $resource_data->{'resource.'.$part.'.awarded'};
               }
               #
               $partscore = $weight*$awarded;
               $score += $partscore;
               $symbol = $weight; 
               if (length($symbol) > 1) {
                   $symbol = '*';
               }
               if (exists($resource_data->{'resource.'.$part.'.solved'})) {
                   my $status = $resource_data->{'resource.'.$part.'.solved'};
                   if ($status eq 'excused') {
                       $symbol = 'x';
                       $max -= $weight; # Do not count 'excused' problems.
                   }
               } else {
                   # Unsolved.  Did they try?
                   if (exists($resource_data->{'resource.'.$part.'.tries'})){
                       $symbol = '.';
                   } else {
                       $symbol = ' ';
                   }
               }
               #
               if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
                   $symbol = '<a href="/adm/grades'.
                       '?symb='.&Apache::lonnet::escape($resource->{'symb'}).
                       '&student='.$student->{'username'}.
                       '&domain='.$student->{'domain'}.
                       '&command=submission">'.$symbol.'</a>';
               }
               if (! defined($partscore)) {
                   $partscore = $symbol;
               }
               push (@ScoreData,$partscore);
           }
           $Str .= $symbol;
       }
       return ($Str,$performance_length,$score,$max,\@ScoreData);
 }  }
   
 #######################################################  #######################################################

Removed from v.1.47  
changed lines
  Added in v.1.55


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