--- loncom/interface/statistics/lonstudentassessment.pm 2003/06/11 15:04:55 1.57
+++ loncom/interface/statistics/lonstudentassessment.pm 2004/02/11 17:42:34 1.86
@@ -1,6 +1,6 @@
# The LearningOnline Network with CAPA
#
-# $Id: lonstudentassessment.pm,v 1.57 2003/06/11 15:04:55 matthew Exp $
+# $Id: lonstudentassessment.pm,v 1.86 2004/02/11 17:42:34 matthew Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -52,9 +52,12 @@ package Apache::lonstudentassessment;
use strict;
use Apache::lonstatistics;
use Apache::lonhtmlcommon;
+use Apache::loncommon();
use Apache::loncoursedata;
use Apache::lonnet; # for logging porpoises
+use Apache::lonlocal;
use Spreadsheet::WriteExcel;
+use Spreadsheet::WriteExcel::Utility();
#######################################################
#######################################################
@@ -138,8 +141,32 @@ Inputs:
#######################################################
sub BuildStudentAssessmentPage {
my ($r,$c)=@_;
+ #
undef($Statistics);
+ undef($show_links);
+ undef($output_mode);
+ undef($data);
+ undef($base);
+ undef($datadescription);
+ undef($single_student_mode);
+ #
+ my %Saveable_Parameters = ('Status' => 'scalar',
+ 'chartoutputmode' => 'scalar',
+ 'chartoutputdata' => 'scalar',
+ 'Section' => 'array',
+ 'StudentData' => 'array',
+ 'Maps' => 'array');
+ &Apache::loncommon::store_course_settings('chart',\%Saveable_Parameters);
+ &Apache::loncommon::restore_course_settings('chart',\%Saveable_Parameters);
+ #
+ &Apache::lonstatistics::PrepareClasslist();
+ #
+ $single_student_mode = 0;
$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
# This also parses the output mode selector
@@ -149,6 +176,7 @@ sub BuildStudentAssessmentPage {
$r->print(' ');
$r->rflush();
+ #
if (! exists($ENV{'form.notfirstrun'}) && ! $single_student_mode) {
return;
}
@@ -186,6 +214,9 @@ sub BuildStudentAssessmentPage {
# are immediately reflected in the chart.
&Apache::lonnet::clear_EXT_cache_status();
#
+ # Clean out loncoursedata's package data, just to be safe.
+ &Apache::loncoursedata::clear_internal_caches();
+ #
# Call the initialize routine selected above
$initialize->($r);
foreach my $student (@Students) {
@@ -288,12 +319,16 @@ sub CreateInterface {
# $Str .= &CreateLegend();
$Str .= '
'."\n";
$Str .= '';
- $Str .= 'Sections ';
- $Str .= 'Student Data ';
- $Str .= 'Enrollment Status ';
- $Str .= 'Sequences and Folders ';
- $Str .= 'Output Format ';
- $Str .= 'Output Data ';
+ $Str .= ''.&mt('Sections').' ';
+ $Str .= ''.&mt('Student Data ').' ';
+ $Str .= ''.&mt('Enrollment Status').' ';
+ $Str .= ''.&mt('Sequences and Folders').' ';
+ $Str .= ''.&mt('Output Format').' '.
+ &Apache::loncommon::help_open_topic("Chart_Output_Formats").
+ ' ';
+ $Str .= ''.&mt('Output Data').' '.
+ &Apache::loncommon::help_open_topic("Chart_Output_Data").
+ ' ';
$Str .= ' '."\n";
#
$Str .= ''."\n";
@@ -320,8 +355,16 @@ sub CreateInterface {
$Str .= &CreateAndParseOutputDataSelector();
$Str .= ' '."\n";
$Str .= '
'."\n";
- $Str .= ' ';
- $Str .= ' 'x8;
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
+ $Str .= ' 'x5;
+ $Str .= ' ';
return $Str;
}
@@ -379,7 +422,7 @@ my @OutputOptions =
sub OutputDescriptions {
my $Str = '';
- $Str .= "Output Modes \n";
+ $Str .= "Output Formats \n";
$Str .= "\n";
foreach my $outputmode (@OutputOptions) {
$Str .=" ".$outputmode->{'name'}." \n";
@@ -392,6 +435,8 @@ sub OutputDescriptions {
sub CreateAndParseOutputSelector {
my $Str = '';
my $elementname = 'chartoutputmode';
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+ [$elementname]);
#
# Format for output options is 'mode, restrictions';
my $selected = 'html, without links';
@@ -418,7 +463,7 @@ sub CreateAndParseOutputSelector {
foreach my $option (@OutputOptions) {
$Str .= "\n".' {'value'} eq $selected);
- $Str .= ">".$option->{'name'}."<\/option>";
+ $Str .= ">".&mt($option->{'name'})."<\/option>";
}
$Str .= "\n";
return $Str;
@@ -429,21 +474,7 @@ sub CreateAndParseOutputSelector {
##
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',
+ { name => 'Scores Summary',
base => 'scores',
value => 'sum and total',
shortdesc => 'Total Score and Maximum Possible for each '.
@@ -451,13 +482,27 @@ my @OutputDataOptions =
longdesc => 'The score of each student as well as the '.
' maximum possible on each Sequence or Folder.',
},
- { name => 'Scores Summary Table Only',
+ { name => 'Scores Per Problem',
base => 'scores',
- value => 'final table scores',
- shortdesc => 'Summary of Scores',
- longdesc => 'The average score on each sequence or folder for the '.
- 'selected students.',
+ 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 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',
@@ -466,29 +511,30 @@ my @OutputDataOptions =
},
{ 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.',
- },
+# { 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 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 .= "Output Data \n";
$Str .= "\n";
foreach my $option (@OutputDataOptions) {
$Str .= ' '.$option->{'name'}.' ';
@@ -525,7 +571,7 @@ sub CreateAndParseOutputDataSelector {
foreach my $option (@OutputDataOptions) {
$Str .= "\n".' {'value'} eq $data);
- $Str .= ">".$option->{'name'}."<\/option>";
+ $Str .= ">".&mt($option->{'name'})."<\/option>";
}
$Str .= "\n";
return $Str;
@@ -566,6 +612,7 @@ sub html_initialize {
$padding = ' 'x3;
$count = 0;
$nodata_count = 0;
+ undef(%prog_state);
#
$r->print("".$ENV{'course.'.$ENV{'request.course.id'}.'.description'}.
" ".localtime(time)." ");
@@ -738,22 +785,20 @@ sub StudentAverageTotal {
$total_ave += $ave;
my $max = $Statistics->{$seq->{'symb'}}->{'max'};
$total_max += $max;
- if ($ave == 0) {
- $ave = "0.00";
- }
- $ave .= ' ';
- $max .= ' ';
+ $ave = sprintf("%.2f",$ave);
$Str .= ''.$seq->{'title'}.' '.
- ''.$ave.' '.
- ''.$max.' '."\n";
+ ''.$ave.' '.
+ ''.$max.' '.' '."\n";
}
- $total_ave = int(100*$total_ave)/100; # only two digit
+ $total_ave = sprintf('%.2f',$total_ave); # only two digit
$Str .= "\n";
$Str .= ''."\n";
$Str .= 'Number of Students Average '.
"Maximum \n";
- $Str .= ''.($num_students-$nodata_count).' '.
- ''.$total_ave.' '.$total_max.' ';
+ $Str .= ''.
+ ''.($num_students-$nodata_count).' '.
+ ''.$total_ave.' '.' '.
+ ''.$total_max.' '.' ';
$Str .= "
\n";
return $Str;
}
@@ -814,10 +859,20 @@ my $cols_output;
my %prog_state; # progress window state
my $request_aborted;
+my $total_formula;
+
sub excel_initialize {
my ($r) = @_;
#
- $request_aborted = undef;
+ undef ($excel_sheet);
+ undef ($excel_workbook);
+ undef ($filename);
+ undef ($rows_output);
+ undef ($cols_output);
+ undef (%prog_state);
+ undef ($request_aborted);
+ undef ($total_formula);
+ #
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
@@ -852,7 +907,7 @@ You may consider reducing the number of
have selected.
LON-CAPA can produce CSV files of this data or Excel files of the
-summary data (Scores Sum or Scores Sum & Totals ).
+Scores Summary data.
END
$request_aborted = 1;
@@ -898,14 +953,25 @@ END
#
# Add a worksheet
my $sheetname = $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
- if (length($sheetname) > 31) {
- $sheetname = substr($sheetname,0,31);
- }
+ $sheetname = &Apache::loncommon::clean_excel_name($sheetname);
$excel_sheet = $excel_workbook->addworksheet($sheetname);
#
+ # Define some potentially useful formats
+ my $format;
+ $format->{'header'} = $excel_workbook->add_format(bold => 1,
+ bottom => 1,
+ align => 'center');
+ $format->{'bold'} = $excel_workbook->add_format(bold=>1);
+ $format->{'h1'} = $excel_workbook->add_format(bold=>1, size=>18);
+ $format->{'h2'} = $excel_workbook->add_format(bold=>1, size=>16);
+ $format->{'h3'} = $excel_workbook->add_format(bold=>1, size=>14);
+ $format->{'date'} = $excel_workbook->add_format(num_format=>
+ 'mmm d yyyy hh:mm AM/PM');
+ #
# Put the course description in the header
$excel_sheet->write($rows_output,$cols_output++,
- $ENV{'course.'.$ENV{'request.course.id'}.'.description'});
+ $ENV{'course.'.$ENV{'request.course.id'}.'.description'},
+ $format->{'h1'});
$cols_output += 3;
#
# Put a description of the sections listed
@@ -925,80 +991,133 @@ END
$sectionstring = "Section ".$Sections[0];
}
}
- $excel_sheet->write($rows_output,$cols_output++,$sectionstring);
+ $excel_sheet->write($rows_output,$cols_output++,$sectionstring,
+ $format->{'h3'});
$cols_output += scalar(@Sections);
#
# Put the date in there too
$excel_sheet->write($rows_output++,$cols_output++,
- 'Compiled on '.localtime(time));
+ 'Compiled on '.localtime(time),$format->{'h3'});
#
$cols_output = 0;
- $excel_sheet->write($rows_output++,$cols_output++,$datadescription);
+ $excel_sheet->write($rows_output++,$cols_output++,$datadescription,
+ $format->{'h3'});
#
if ($data eq 'tries' || $data eq 'scores') {
$rows_output++;
}
#
+ # Figure out the rows we need
+ my $sequence_name_row = $rows_output+1;
+ my $resource_name_row = $sequence_name_row+1;
+ my $maximum_data_row = $sequence_name_row+2;
+ my $first_data_row = $sequence_name_row+3;
+ #
# Add the student headers
$cols_output = 0;
foreach my $field (&get_student_fields_to_show()) {
- $excel_sheet->write($rows_output,$cols_output++,$field);
- }
- my $row_offset = 0;
- if ($data eq 'tries' || $data eq 'scores') {
- $row_offset = -1;
+ $excel_sheet->write($resource_name_row,$cols_output++,$field,
+ $format->{'bold'});
}
#
# Add the remaining column headers
+ my $total_formula_string = '=0';
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
- $excel_sheet->write($rows_output+$row_offset,
- $cols_output,$seq->{'title'});
+ $excel_sheet->write($sequence_name_row,,
+ $cols_output,$seq->{'title'},$format->{'h3'});
+ # Determine starting cell
+ $seq->{'Excel:startcell'}=
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$cols_output);
+ $seq->{'Excel:startcol'}=$cols_output;
if ($data eq 'tries' || $data eq 'scores') {
+ # Put the names of the problems and parts into the sheet
+ my $count = 0;
foreach my $res (@{$seq->{'contents'}}) {
- next if ($res->{'type'} ne 'assessment');
+ if ($res->{'type'} ne 'assessment' ||
+ ! exists($res->{'parts'}) ||
+ ref($res->{'parts'}) ne 'ARRAY' ||
+ scalar(@{$res->{'parts'}}) < 1) {
+ next;
+ }
if (scalar(@{$res->{'parts'}}) > 1) {
foreach my $part (@{$res->{'parts'}}) {
- $excel_sheet->write($rows_output,
+ $excel_sheet->write($resource_name_row,
$cols_output++,
- $res->{'title'}.' part '.$part);
+ $res->{'title'}.' part '.$part,
+ $format->{'bold'});
}
} else {
- $excel_sheet->write($rows_output,
+ $excel_sheet->write($resource_name_row,
$cols_output++,
- $res->{'title'});
+ $res->{'title'},$format->{'bold'});
}
+ $count++;
}
- $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+1,'maximum');
- $cols_output += 2;
+ # Determine ending cell
+ if ($count == 1) {
+ $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
+ $seq->{'Excel:endcol'} = $seq->{'Excel:startcol'};
+ } else {
+ $seq->{'Excel:endcell'} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$cols_output-1);
+ $seq->{'Excel:endcol'} = $cols_output-1;
+ }
+ # Create the formula for summing up this sequence
+ if (! exists($seq->{'Excel:endcell'}) ||
+ ! defined($seq->{'Excel:endcell'})) {
+ $seq->{'Excel:endcell'} = $seq->{'Excel:startcell'};
+ }
+ $seq->{'Excel:sum'}= $excel_sheet->store_formula
+ ('=SUM('.$seq->{'Excel:startcell'}.
+ ':'.$seq->{'Excel:endcell'}.')');
+ }
+ # Determine cell the score is held in
+ $seq->{'Excel:scorecell'} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$cols_output);
+ $seq->{'Excel:scorecol'}=$cols_output;
+ if ($data eq 'parts correct total') {
+ $excel_sheet->write($resource_name_row,$cols_output++,
+ 'parts correct',
+ $format->{'bold'});
} else {
- $cols_output++;
+ $excel_sheet->write($resource_name_row,$cols_output++,
+ 'score',
+ $format->{'bold'});
}
- }
- #
- # Bookkeeping
- if ($data eq 'sum and total' || $data eq 'parts correct total') {
- $rows_output += 2;
- } else {
- $rows_output += 1;
- }
+ #
+ $total_formula_string.='+'.
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$cols_output-1);
+ $excel_sheet->write($resource_name_row,$cols_output++,
+ 'maximum',
+ $format->{'bold'});
+ }
+ $excel_sheet->write($resource_name_row,$cols_output++,'Grand Total',
+ $format->{'bold'});
+ $total_formula = $excel_sheet->store_formula($total_formula_string);
#
# Output a row for MAX
$cols_output = 0;
foreach my $field (&get_student_fields_to_show()) {
if ($field eq 'username' || $field eq 'fullname' ||
$field eq 'id') {
- $excel_sheet->write($rows_output,$cols_output++,'Maximum');
+ $excel_sheet->write($maximum_data_row,$cols_output++,'Maximum',
+ $format->{'bold'});
} else {
- $excel_sheet->write($rows_output,$cols_output++,'');
+ $excel_sheet->write($maximum_data_row,$cols_output++,'');
}
}
#
# Add the maximums for each sequence or assessment
+ my %total_cell_translation;
+ my $grand_total = 0;
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ $total_cell_translation{$seq->{'Excel:scorecell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$seq->{'Excel:scorecol'});
my $weight;
my $max = 0;
foreach my $resource (@{$seq->{'contents'}}) {
@@ -1014,26 +1133,56 @@ END
}
}
if ($data eq 'scores') {
- $excel_sheet->write($rows_output,$cols_output++,$weight);
+ $excel_sheet->write($maximum_data_row,$cols_output++,$weight);
} elsif ($data eq 'tries') {
- $excel_sheet->write($rows_output,$cols_output++,'');
+ $excel_sheet->write($maximum_data_row,$cols_output++,'');
}
$max += $weight;
}
}
if (! ($data eq 'sum only' || $data eq 'parts correct')) {
- $excel_sheet->write($rows_output,$cols_output++,'');
+ $excel_sheet->write($maximum_data_row,$cols_output++,'');
}
- $excel_sheet->write($rows_output,$cols_output++,$max);
+ #
+ if ($data eq 'tries' || $data eq 'scores') {
+ my %replaceCells;
+ $replaceCells{$seq->{'Excel:startcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$seq->{'Excel:startcol'});
+ $replaceCells{$seq->{'Excel:endcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($maximum_data_row,$seq->{'Excel:endcol'});
+ $excel_sheet->repeat_formula($maximum_data_row,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells);
+ } else {
+ $excel_sheet->write($maximum_data_row,$cols_output++,
+ $max);
+ }
+ $grand_total+=$max;
+ }
+ if ($data eq 'tries' || $data eq 'scores') {
+ $excel_sheet->repeat_formula($maximum_data_row,$cols_output++,
+ $total_formula,undef,
+ %total_cell_translation);
+ } else {
+ $excel_sheet->write($maximum_data_row,$cols_output++,$grand_total);
}
- $rows_output++;
+ $rows_output = $first_data_row;
#
# Let the user know what we are doing
my $studentcount = scalar(@Apache::lonstatistics::Students);
- $r->print("Compiling Excel spreadsheet for ".
- $studentcount.' student');
- $r->print('s') if ($studentcount > 1);
- $r->print(" \n");
+ if ($ENV{'form.SelectedStudent'}) {
+ $studentcount = '1';
+ }
+ if ($studentcount > 1) {
+ $r->print(''.&mt('Compiling Excel spreadsheet for [_1] students',
+ $studentcount)." \n");
+ } else {
+ $r->print(''.
+ &mt('Compiling Excel spreadsheet for 1 student').
+ " \n");
+ }
$r->rflush();
#
# Initialize progress window
@@ -1041,6 +1190,8 @@ END
($r,'Excel File Compilation Status',
'Excel File Compilation Progress', $studentcount);
#
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
+ 'Processing first student');
return;
}
@@ -1067,7 +1218,14 @@ sub excel_outputstudent {
}
#
# Write out sequence scores and totals data
+ my %total_cell_translation;
foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ $cols_output = $seq->{'Excel:startcol'};
+ # Keep track of cells to translate in total cell
+ $total_cell_translation{$seq->{'Excel:scorecell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:scorecol'});
+ #
my ($performance,$performance_length,$score,$seq_max,$rawdata);
if ($base eq 'tries') {
($performance,$performance_length,$score,$seq_max,$rawdata) =
@@ -1082,7 +1240,25 @@ sub excel_outputstudent {
foreach my $value (@$rawdata) {
$excel_sheet->write($rows_output,$cols_output++,$value);
}
- $excel_sheet->write($rows_output,$cols_output++,$score);
+ # Write a formula for the sum of this sequence
+ my %replaceCells;
+ $replaceCells{$seq->{'Excel:startcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:startcol'});
+ $replaceCells{$seq->{'Excel:endcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$seq->{'Excel:endcol'});
+ # The undef is for the format
+ if (scalar(keys(%replaceCells)) == 1) {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells,%replaceCells);
+ } else {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $seq->{'Excel:sum'},undef,
+ %replaceCells);
+ }
+ #
$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') {
@@ -1093,6 +1269,10 @@ sub excel_outputstudent {
}
}
#
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $total_formula,undef,
+ %total_cell_translation);
+ #
# Bookkeeping
$rows_output++;
$cols_output=0;
@@ -1152,8 +1332,9 @@ sub csv_initialize{
my ($r) = @_;
#
# Clean up
- $filename = undef;
- $outputfile = undef;
+ undef($outputfile);
+ undef($filename);
+ undef($request_aborted);
undef(%prog_state);
#
# Deal with unimplemented requests
@@ -1357,43 +1538,56 @@ sub StudentTriesOnSequence {
$performance_length++;
my $symbol = ' '; # default to space
#
+ my $awarded = 0;
+ if (exists($resource_data->{'resource.'.$partnum.'.awarded'})) {
+ $awarded = $resource_data->{'resource.'.$partnum.'.awarded'};
+ $awarded = 0 if (! $awarded);
+ }
+ #
+ my $status = '';
if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {
- my $status = $resource_data->{'resource.'.$partnum.'.solved'};
- if ($status eq 'correct_by_override') {
- $symbol = '+';
- $sum++;
- } elsif ($status eq 'incorrect_by_override') {
- $symbol = '-';
- } elsif ($status eq 'ungraded_attempted') {
- $symbol = '#';
- } elsif ($status eq 'incorrect_attempted') {
- $symbol = '.';
- } elsif ($status eq 'excused') {
+ $status = $resource_data->{'resource.'.$partnum.'.solved'};
+ }
+ #
+ my $tries = 0;
+ if(exists($resource_data->{'resource.'.$partnum.'.tries'})) {
+ $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ }
+ #
+ if ($awarded > 0) {
+ # The student has gotten the problem correct to some degree
+ if ($status eq 'excused') {
$symbol = 'x';
$max--;
- } elsif ($status eq 'correct_by_student' &&
- exists($resource_data->{'resource.'.$partnum.'.tries'})){
- $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ } elsif ($status eq 'correct_by_override') {
+ $symbol = '+';
+ $sum++;
+ } elsif ($tries > 0) {
if ($tries > 9) {
$symbol = '*';
- } elsif ($tries > 0) {
- $symbol = $tries;
} else {
- $symbol = ' ';
+ $symbol = $tries;
}
$sum++;
- } elsif (exists($resource_data->{'resource.'.
- $partnum.'.tries'})){
- $symbol = '.';
} else {
- $symbol = ' ';
+ $symbol = '+';
+ $sum++;
}
} else {
- # Unsolved. Did they try?
- if (exists($resource_data->{'resource.'.$partnum.'.tries'})){
+ # The student has the problem incorrect or it is ungraded
+ if ($status eq 'excused') {
+ $symbol = 'x';
+ $max--;
+ } elsif ($status eq 'incorrect_by_override') {
+ $symbol = '-';
+ } elsif ($status eq 'ungraded_attempted') {
+ $symbol = '#';
+ } elsif ($status eq 'incorrect_attempted' ||
+ $tries > 0) {
$symbol = '.';
} else {
- $symbol = ' ';
+ # Problem is wrong and has not been attempted.
+ $symbol=' ';
}
}
#
@@ -1410,7 +1604,7 @@ sub StudentTriesOnSequence {
$symbol = ''.$symbol.' ';
}
$value .= $symbol;
@@ -1478,11 +1672,15 @@ sub StudentPerformanceOnSequence {
my $awarded = 0;
if (exists($resource_data->{'resource.'.$part.'.awarded'})) {
$awarded = $resource_data->{'resource.'.$part.'.awarded'};
+ $awarded = 0 if (! $awarded);
}
#
$partscore = $weight*$awarded;
$score += $partscore;
- $symbol = $weight;
+ $symbol = $partscore;
+ if (abs($symbol - sprintf("%.0f",$symbol)) < 0.001) {
+ $symbol = sprintf("%.0f",$symbol);
+ }
if (length($symbol) > 1) {
$symbol = '*';
}
@@ -1501,19 +1699,20 @@ sub StudentPerformanceOnSequence {
}
}
#
+ if (! defined($partscore)) {
+ $partscore = $symbol;
+ }
+ push (@ScoreData,$partscore);
+ #
if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
$symbol = ''.$symbol.' ';
}
- if (! defined($partscore)) {
- $partscore = $symbol;
- }
- push (@ScoreData,$partscore);
+ $Str .= $symbol;
}
- $Str .= $symbol;
}
return ($Str,$performance_length,$score,$max,\@ScoreData);
}