Diff for /loncom/interface/statistics/lonstudentassessment.pm between versions 1.50 and 1.62

version 1.50, 2003/05/29 21:41:10 version 1.62, 2003/06/23 16:06:11
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  =item $single_student_mode evaluates to true if we are showing only one
 student.  student.
   
Line 94  student. Line 100  student.
 #######################################################  #######################################################
 my $show_links;  my $show_links;
 my $output_mode;  my $output_mode;
 my $show;  my $data;
   my $base;
   my $datadescription;
 my $single_student_mode;  my $single_student_mode;
   
 #######################################################  #######################################################
Line 132  sub BuildStudentAssessmentPage { Line 140  sub BuildStudentAssessmentPage {
     my ($r,$c)=@_;      my ($r,$c)=@_;
     undef($Statistics);      undef($Statistics);
     $single_student_mode = 1 if ($ENV{'form.SelectedStudent'});      $single_student_mode = 1 if ($ENV{'form.SelectedStudent'});
       if ($ENV{'form.selectstudent'}) {
           &Apache::lonstatistics::DisplayClasslist($r);
           return;
       }
     #      #
     # 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="'.      $r->print('<input type="hidden" name="sort" value="'.
               $ENV{'form.sort'}.'" />');                $ENV{'form.sort'}.'" />');
     $r->rflush();      $r->rflush();
       #
     if (! exists($ENV{'form.notfirstrun'}) && ! $single_student_mode) {      if (! exists($ENV{'form.notfirstrun'}) && ! $single_student_mode) {
         $r->print(<<ENDMSG);  
 <p>  
 <font size="+2">  
 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 163  ENDMSG Line 166  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 185  ENDMSG Line 184  ENDMSG
         @Students = @Apache::lonstatistics::Students;          @Students = @Apache::lonstatistics::Students;
     }      }
     #      #
       # Perform generic initialization tasks
       #       Since we use lonnet::EXT to retrieve problem weights,
       #       to ensure current data we must clear the caches out.
       #       This makes sure that parameter changes at the student level
       #       are immediately reflected in the chart.
       &Apache::lonnet::clear_EXT_cache_status();
       #
     # Call the initialize routine selected above      # Call the initialize routine selected above
     $initialize->($r);      $initialize->($r);
     foreach my $student (@Students) {      foreach my $student (@Students) {
Line 291  sub CreateInterface { Line 297  sub CreateInterface {
     $Str .= '<td align="center"><b>Student Data</b></td>';      $Str .= '<td align="center"><b>Student Data</b></td>';
     $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>'.
           &Apache::loncommon::help_open_topic("Chart_Output_Formats").
           '</td>';
       $Str .= '<td align="center"><b>Output Data</b>'.
           &Apache::loncommon::help_open_topic("Chart_Output_Data").
           '</td>';
     $Str .= '</tr>'."\n";      $Str .= '</tr>'."\n";
     #      #
     $Str .= '<tr><td align="center">'."\n";      $Str .= '<tr><td align="center">'."\n";
Line 314  sub CreateInterface { Line 325  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;'x5;
       $Str .= '<input type="submit" name="selectstudent" '.
                                     'value="Select One Student" />';
       $Str .= '&nbsp;'x5;
       $Str .= '<input type="submit" name="ClearCache" value="Clear Caches" />';
       $Str .= '&nbsp;'x5;
       $Str .= '<br />';
     return $Str;      return $Str;
 }  }
   
Line 336  my @OutputOptions = Line 357  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 345  my @OutputOptions = Line 365  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 354  my @OutputOptions = Line 373  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',  
        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',         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',  
 #           },  
      { name  => 'CSV, everything',  
        value => 'csv, everything',  
        description => '',  
        mode => 'csv',  
        show => 'all',  
        show_links => 'no',  
            },  
      { name  => 'CSV, scores only',  
        value => 'csv, scores only',  
        description => '',  
        mode => 'csv',  
        show => 'scores',  
        show_links => 'no',         show_links => 'no',
            },     },
      { name  => 'CSV, totals',       { name  => 'CSV',
        value => 'csv, totals',         value => 'csv',
        description => '',         description => 'Output a comma seperated values file suitable for '.
              'import into a spreadsheet program.  Using this method as opposed '.
              'to Excel output allows you to organize your data before importing'.
              ' it into a spreadsheet program.',
        mode => 'csv',         mode => 'csv',
        show => 'totals',  
        show_links => 'no',         show_links => 'no',
            },             },
      );       );
   
 sub OutputDescriptions {  sub OutputDescriptions {
     my $Str = '';      my $Str = '';
     $Str .= "<h2>Output Modes</h2>\n";      $Str .= "<h2>Output Formats</h2>\n";
     $Str .= "<dl>\n";      $Str .= "<dl>\n";
     foreach my $outputmode (@OutputOptions) {      foreach my $outputmode (@OutputOptions) {
  $Str .="    <dt>".$outputmode->{'name'}."</dt>\n";   $Str .="    <dt>".$outputmode->{'name'}."</dt>\n";
Line 473  sub CreateAndParseOutputSelector { Line 421  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 493  sub CreateAndParseOutputSelector { Line 439  sub CreateAndParseOutputSelector {
     return $Str;      return $Str;
 }  }
   
   ##
   ## Data selector stuff
   ##
   my @OutputDataOptions =
       (
        { 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 score of each student as well as the '.
              ' maximum possible on each Sequence or Folder.',
          },
        { name  => 'Scores Summary Table Only',
          base  => 'scores',
          value => 'final table scores',
          shortdesc => 'Summary of Scores',
          longdesc  => 'The average score on each sequence or folder for the '.
              'selected students.',
          },
        { 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'.
              ' on each sequence or folder.',
          },
        { 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  => 'Parts Summary Table Only',
          base  => 'tries',
          value => 'final table parts',
          shortdesc => 'Summary of Parts Correct',
          longdesc  => 'A summary table of the average number of problem parts '.
              'students were able to get correct on each sequence.',
          },
        );
   
   sub HTMLifyOutputDataDescriptions {
       my $Str = '';
       $Str .= "<h2>Output Data</h2>\n";
       $Str .= "<dl>\n";
       foreach my $option (@OutputDataOptions) {
           $Str .= '    <dt>'.$option->{'name'}.'</dt>';
           $Str .= '<dd>'.$option->{'longdesc'}.'</dd>'."\n";
       }
       $Str .= "</dl>\n";
       return $Str;
   }
   
   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 531  sub html_initialize { Line 586  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 555  sub html_initialize { Line 613  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 571  sub html_outputstudent { Line 629  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 592  sub html_outputstudent { Line 650  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 603  sub html_outputstudent { Line 661  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 631  sub html_outputstudent { Line 696  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 639  sub html_outputstudent { Line 706  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 655  sub html_finish { Line 722  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"); 
Line 685  sub StudentAverageTotal { Line 752  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 709  sub StudentAverageTotal { Line 776  sub StudentAverageTotal {
   
 sub SingleStudentTotal {  sub SingleStudentTotal {
     my $student = &Apache::lonstatistics::current_student();      my $student = &Apache::lonstatistics::current_student();
     my $Str = "<h3>Summary Table For ".$student->{'username'}.'@'.      my $Str = "<h3>Summary table for ".$student->{'fullname'}." ".
         $student->{'domain'}."</h3>\n";          $student->{'username'}.'@'.$student->{'domain'}."</h3>\n";
     $Str .= '<table border=2 cellspacing="1">'."\n";      $Str .= '<table border=2 cellspacing="1">'."\n";
     $Str .=       $Str .= 
         "<tr><th>Sequence or Folder</th><th>Score</th><th>Maximum</th></tr>\n";          "<tr><th>Sequence or Folder</th><th>Score</th><th>Maximum</th></tr>\n";
Line 739  sub SingleStudentTotal { Line 806  sub SingleStudentTotal {
   
 =pod  =pod
   
 =head2 Multi-Sheet EXCEL subroutines  
   
 =item &multi_sheet_excel_initialize($r)  
   
 =item &multi_sheet_excel_outputstudent($r,$student)  
   
 =item &multi_sheet_excel_finish($r)  
   
 =cut  
   
 #######################################################  
 #######################################################  
 {  
   
 sub multi_sheet_excel_initialize {  
     my ($r)=@_;  
     $r->print("<h1>Not yet implemented</h1>");  
     #   
     # Estimate the size of the file.  We would like to have < 5 megs of data.  
     my $max_size = 5000000;  
     my $num_students  = scalar(@Apache::lonstatistics::Students);  
     my $num_sequences = 0;  
     my $num_data_per_part  = 2; # 'status' and 'numtries'  
     my $fields_per_student = scalar(&get_student_fields_to_show());  
     my $bytes_per_field    = 20; # Back of the envelope calculation  
     foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {  
         $num_sequences++ if ($seq->{'num_assess'} > 0);  
         $fields_per_student += $num_data_per_part * $seq->{'num_assess_parts'};  
     }  
     my $size_estimate = $fields_per_student*$num_students*$bytes_per_field;  
     #  
     # Compute number of workbooks  
     my $num_workbooks = 1;  
     if ($size_estimate > $max_size) { # try to stay under 5 megs  
         $num_workbooks += int($size_estimate / $max_size);  
     }  
     if ($show eq 'by section') {  
         if (@Apache::lonstatistics::SelectedSections > 1 &&   
             $Apache::lonstatistics::SelectedSections[0] ne 'all') {  
             $num_workbooks = scalar(@Apache::lonstatistics::SelectedSections);  
         } else {  
             # @Apache::lonstatistics::Sections contains 'all' as well.  
             $num_workbooks = scalar(@Apache::lonstatistics::Sections) - 1;  
         }  
     }  
       
     $r->print("Maximum allowed size: ".$max_size." bytes<br />");  
     $r->print("Number of students: ".$num_students."<br />");  
     $r->print("Number of fields per student: ".$fields_per_student."<br />");  
     $r->print("Total number of fields: ".($fields_per_student*$num_students).  
               "<br />");  
     $r->print("Bytes per field: ".$bytes_per_field." (estimated)"."<br />");  
     $r->print("Estimated size: ".$size_estimate." bytes<br />");  
     $r->print("Number of workbooks: ".$num_workbooks."<br />");  
     $r->rflush();  
     return;  
 }  
   
 sub multi_sheet_excel_outputstudent {  
     my ($r,$student) = @_;  
 }  
   
 sub multi_sheet_excel_finish {  
     my ($r) = @_;  
 }  
   
 }  
 #######################################################  
 #######################################################  
   
 =pod  
   
 =head2 EXCEL subroutines  =head2 EXCEL subroutines
   
 =item &excel_initialize($r)  =item &excel_initialize($r)
Line 833  my $rows_output; Line 828  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 898  sub excel_initialize { Line 945  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 922  sub excel_initialize { Line 996  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 961  sub excel_initialize { Line 1057  sub excel_initialize {
         ($r,'Excel File Compilation Status',          ($r,'Excel File Compilation Status',
          'Excel File Compilation Progress', $studentcount);           'Excel File Compilation Progress', $studentcount);
     #      #
       &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
                                             'Processing first student');
     return;      return;
 }  }
   
 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 987  sub excel_outputstudent { Line 1086  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 1009  sub excel_outputstudent { Line 1122  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 1049  sub excel_finish { Line 1163  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 1060  sub csv_initialize{ Line 1174  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 1077  sub csv_initialize{ Line 1205  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 1126  sub csv_initialize{ Line 1261  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 1147  sub csv_outputstudent { Line 1283  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 1170  sub csv_outputstudent { Line 1312  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 1194  sub csv_finish { Line 1337  sub csv_finish {
   
 =pod  =pod
   
 =item &StudentPerformanceOnSequence()  =item &StudentTriesOnSequence()
   
 Inputs:  Inputs:
   
Line 1214  Inputs: Line 1357  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 1243  sub StudentPerformanceOnSequence { Line 1391  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 1267  sub StudentPerformanceOnSequence { Line 1415  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) {                  if (length($symbol) > 1) {
Line 1282  sub StudentPerformanceOnSequence { Line 1435  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 (! defined($partscore)) {
                   $partscore = $symbol;
               }
               push (@ScoreData,$partscore);
               #
               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>';
               }
               $Str .= $symbol;
           }
       }
       return ($Str,$performance_length,$score,$max,\@ScoreData);
 }  }
   
 #######################################################  #######################################################

Removed from v.1.50  
changed lines
  Added in v.1.62


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