--- loncom/homework/grades.pm 2012/05/02 14:01:32 1.596.2.12.2.1 +++ loncom/homework/grades.pm 2012/08/09 23:25:48 1.596.2.13 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.596.2.12.2.1 2012/05/02 14:01:32 raeburn Exp $ +# $Id: grades.pm,v 1.596.2.13 2012/08/09 23:25:48 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,6 +52,7 @@ use POSIX qw(floor); my %perm=(); +my %old_essays=(); # These variables are used to recover from ssi errors @@ -260,6 +261,7 @@ sub showResourceInfo { sub reset_caches { &reset_analyze_cache(); &reset_perm(); + &reset_old_essays(); } { @@ -272,7 +274,7 @@ sub reset_caches { } sub get_analyze { - my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed,$bubbles_per_row)=@_; + my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed)=@_; my $key = "$symb\0$uname\0$udom"; if ($type eq 'randomizetry') { if ($trial ne '') { @@ -306,9 +308,6 @@ sub reset_caches { 'grade_courseid' => $env{'request.course.id'}, 'grade_username' => $uname, 'grade_noincrement' => $no_increment); - if ($bubbles_per_row ne '') { - $form{'bubbles_per_row'} = $bubbles_per_row; - } if ($type eq 'randomizetry') { $form{'grade_questiontype'} = $type; if ($rndseed ne '') { @@ -349,7 +348,7 @@ sub reset_caches { } sub scantron_partids_tograde { - my ($resource,$cid,$uname,$udom,$check_for_randomlist,$bubbles_per_row) = @_; + my ($resource,$cid,$uname,$udom,$check_for_randomlist) = @_; my (%analysis,@parts); if (ref($resource)) { my $symb = $resource->symb(); @@ -357,9 +356,7 @@ sub reset_caches { if ($check_for_randomlist) { $add_to_form = { 'check_parts_withrandomlist' => 1,}; } - my $analyze = - &get_analyze($symb,$uname,$udom,undef,$add_to_form, - undef,undef,undef,$bubbles_per_row); + my $analyze = &get_analyze($symb,$uname,$udom,undef,$add_to_form); if (ref($analyze) eq 'HASH') { %analysis = %{$analyze}; } @@ -743,7 +740,11 @@ sub compute_points { # sub most_similar { - my ($uname,$udom,$uessay,$old_essays)=@_; + my ($uname,$udom,$symb,$uessay)=@_; + + unless ($symb) { return ''; } + + unless (ref($old_essays{$symb}) eq 'HASH') { return ''; } # ignore spaces and punctuation @@ -760,11 +761,11 @@ sub most_similar { my $scrsid=''; my $sessay=''; # go through all essays ... - foreach my $tkey (keys(%$old_essays)) { + foreach my $tkey (keys(%{$old_essays{$symb}})) { my ($tname,$tdom,$tcrsid)=map {&unescape($_)} (split(/\./,$tkey)); # ... except the same student next if (($tname eq $uname) && ($tdom eq $udom)); - my $tessay=$old_essays->{$tkey}; + my $tessay=$old_essays{$symb}{$tkey}; $tessay=~s/\W+/ /gs; # String similarity gives up if not even limit my $tsimilar=&String::Similarity::similarity($uessay,$tessay,$limit); @@ -774,7 +775,7 @@ sub most_similar { $sname=$tname; $sdom=$tdom; $scrsid=$tcrsid; - $sessay=$old_essays->{$tkey}; + $sessay=$old_essays{$symb}{$tkey}; } } if ($limit>0.6) { @@ -1830,6 +1831,7 @@ sub gradeBox { $line.=''."\n"; + #&mt('Part:[_1]Points:[_2]or[_3]',$display_part,$radio,$line); $result .= ''.$display_part.''.$radio.''.&mt('or').''.$line.''; $result.=&Apache::loncommon::end_data_table_row(); @@ -2013,7 +2015,6 @@ sub submission { '" src="'.$request->dir_config('lonIconsURL'). '/check.gif" height="16" border="0" />'; - my %old_essays; # header info if ($counter == 0) { &sub_page_js($request); @@ -2129,7 +2130,7 @@ KEYWORDS my ($adom,$aname,$apath)=($essayurl=~/^($LONCAPA::domain_re)\/($LONCAPA::username_re)\/(.*)$/); $apath=&escape($apath); $apath=~s/\W/\_/gs; - %old_essays=&Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); + &init_old_essays($symb,$apath,$adom,$aname); } } @@ -2266,7 +2267,7 @@ KEYWORDS } if($env{'form.checkPlag'}){ my ($oname,$odom,$ocrsid,$oessay,$osim)= - &most_similar($uname,$udom,$subval,\%old_essays); + &most_similar($uname,$udom,$symb,$subval); if ($osim) { $osim=int($osim*100.0); my %old_course_desc = @@ -5566,8 +5567,6 @@ sub scantron_selectphase { LastName - column that the last name starts in LastNameLength - number of columns that the last name spans - BubblesPerRow - number of bubbles available in each row used to - bubble an answer. (If not specified, 10 assumed). =cut @@ -5598,7 +5597,6 @@ sub get_scantron_config { $config{'FirstNamelength'}=$config[14]; $config{'LastName'}=$config[15]; $config{'LastNamelength'}=$config[16]; - $config{'BubblesPerRow'}=$config[17]; last; } return %config; @@ -6522,8 +6520,7 @@ sub scantron_validate_file { #get the student pick code ready $r->print(&Apache::loncommon::studentbrowser_javascript()); my $nav_error; - my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); - my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config); + my $max_bubble=&scantron_get_maxbubble(\$nav_error); if ($nav_error) { $r->print(&navmap_errormsg()); return ''; @@ -6976,7 +6973,7 @@ sub scantron_validate_ID { my ($scanlines,$scan_data)=&scantron_getfile(); my $nav_error; - &scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the bubble_lines.. array. + &scantron_get_maxbubble(\$nav_error); # parse needs the bubble_lines.. array. if ($nav_error) { $r->print(&navmap_errormsg()); return(1,$currentphase); @@ -7389,19 +7386,7 @@ sub scantron_bubble_selector { my $max=$$scan_config{'Qlength'}; my $scmode=$$scan_config{'Qon'}; - if ($scmode eq 'number' || $scmode eq 'letter') { - if (($$scan_config{'BubblesPerRow'} =~ /^\d+$/) && - ($$scan_config{'BubblesPerRow'} > 0)) { - $max=$$scan_config{'BubblesPerRow'}; - if (($scmode eq 'number') && ($max > 10)) { - $max = 10; - } elsif (($scmode eq 'letter') && $max > 26) { - $max = 26; - } - } else { - $max = 10; - } - } + if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; } my @alphabet=('A'..'Z'); $r->print(&Apache::loncommon::start_data_table(). @@ -7556,7 +7541,7 @@ sub scantron_validate_CODE { my %allcodes=&get_codes(); my $nav_error; - &scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the lines per response array. + &scantron_get_maxbubble(\$nav_error); # parse needs the lines per response array. if ($nav_error) { $r->print(&navmap_errormsg()); return(1,$currentphase); @@ -7615,7 +7600,7 @@ sub scantron_validate_doublebubble { my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); my $nav_error; - &scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the bubble line array. + &scantron_get_maxbubble(\$nav_error); # parse needs the bubble line array. if ($nav_error) { $r->print(&navmap_errormsg()); return(1,$currentphase); @@ -7637,7 +7622,7 @@ sub scantron_validate_doublebubble { sub scantron_get_maxbubble { - my ($nav_error,$scantron_config) = @_; + my ($nav_error) = @_; if (defined($env{'form.scantron_maxbubble'}) && $env{'form.scantron_maxbubble'}) { &restore_bubble_lines(); @@ -7656,7 +7641,6 @@ sub scantron_get_maxbubble { } my $map=$navmap->getResourceByUrl($sequence); my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); - my $bubbles_per_row = &bubblesheet_bubbles_per_row($scantron_config); &Apache::lonxml::clear_problem_counter(); @@ -7672,8 +7656,7 @@ sub scantron_get_maxbubble { my $response_number = 0; my $bubble_line = 0; foreach my $resource (@resources) { - my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname, - $udom,$bubbles_per_row); + my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,$udom); if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) { foreach my $part_id (@{$parts}) { my $lines; @@ -7702,10 +7685,9 @@ sub scantron_get_maxbubble { if (ref($analysis->{$part_id.'.shown'}) eq 'ARRAY') { $numshown = scalar(@{$analysis->{$part_id.'.shown'}}); } - my $bubbles_per_row = - &bubblesheet_bubbles_per_row($scantron_config); - my $inner_bubble_lines = int($numbub/$bubbles_per_row); - if (($numbub % $bubbles_per_row) != 0) { + my $bubbles_per_line = 10; + my $inner_bubble_lines = int($numbub/$bubbles_per_line); + if (($numbub % $bubbles_per_line) != 0) { $inner_bubble_lines++; } for (my $i=0; $i<$numshown; $i++) { @@ -7716,7 +7698,7 @@ sub scantron_get_maxbubble { $lines = $numshown * $inner_bubble_lines; } else { $lines = $analysis->{"$part_id.bubble_lines"}; - } + } $first_bubble_line{$response_number} = $bubble_line; $bubble_lines_per_response{$response_number} = $lines; @@ -7737,18 +7719,6 @@ sub scantron_get_maxbubble { return $env{'form.scantron_maxbubble'}; } -sub bubblesheet_bubbles_per_row { - my ($scantron_config) = @_; - my $bubbles_per_row; - if (ref($scantron_config) eq 'HASH') { - $bubbles_per_row = $scantron_config->{'BubblesPerRow'}; - } - if ((!$bubbles_per_row) || ($bubbles_per_row < 1)) { - $bubbles_per_row = 10; - } - return $bubbles_per_row; -} - sub scantron_validate_missingbubbles { my ($r,$currentphase) = @_; #get student info @@ -7759,7 +7729,7 @@ sub scantron_validate_missingbubbles { my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); my $nav_error; - my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config); + my $max_bubble=&scantron_get_maxbubble(\$nav_error); if ($nav_error) { return(1,$currentphase); } @@ -7842,8 +7812,7 @@ sub scantron_process_students { } my ($analysis,$parts) = &scantron_partids_tograde($resource,$env{'request.course.id'}, - $env{'user.name'},$env{'user.domain'}, - 1,$bubbles_per_row); + $env{'user.name'},$env{'user.domain'},1); $grader_partids_by_symb{$ressymb} = $parts; if (ref($analysis) eq 'HASH') { if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') { @@ -7881,7 +7850,7 @@ SCANTRONFORM my $started; my $nav_error; - &scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse. + &scantron_get_maxbubble(\$nav_error); # Need the bubble lines array to parse. if ($nav_error) { $r->print(&navmap_errormsg()); return ''; @@ -7938,8 +7907,7 @@ SCANTRONFORM if ((exists($grader_randomlists_by_symb{$ressymb})) || (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) { my ($analysis,$parts) = - &scantron_partids_tograde($resource,$env{'request.course.id'}, - $uname,$udom,undef,$bubbles_per_row); + &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom); $partids_by_symb{$ressymb} = $parts; } else { $partids_by_symb{$ressymb} = $grader_partids_by_symb{$ressymb}; @@ -7968,8 +7936,7 @@ SCANTRONFORM } if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode, - \@resources,\%partids_by_symb, - $bubbles_per_row) eq 'ssi_error') { + \@resources,\%partids_by_symb) eq 'ssi_error') { $ssi_error = 0; # So end of handler error message does not trigger. $r->print(""); &ssi_print_error($r); @@ -7997,8 +7964,7 @@ SCANTRONFORM if ($studentrecord ne $studentdata) { &Apache::lonxml::clear_problem_counter(); if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode, - \@resources,\%partids_by_symb, - $bubbles_per_row) eq 'ssi_error') { + \@resources,\%partids_by_symb) eq 'ssi_error') { $ssi_error = 0; # So end of handler error message does not trigger. $r->print(""); &ssi_print_error($r); @@ -8070,8 +8036,7 @@ sub graders_resources_pass { my $ressymb = $resource->symb(); my ($analysis,$parts) = &scantron_partids_tograde($resource,$env{'request.course.id'}, - $env{'user.name'},$env{'user.domain'}, - 1,$bubbles_per_row); + $env{'user.name'},$env{'user.domain'},1); $grader_partids_by_symb->{$ressymb} = $parts; if (ref($analysis) eq 'HASH') { if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') { @@ -8085,7 +8050,7 @@ sub graders_resources_pass { } sub grade_student_bubbles { - my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts,$bubbles_per_row) = @_; + my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts) = @_; if (ref($resources) eq 'ARRAY') { my $count = 0; foreach my $resource (@{$resources}) { @@ -8098,9 +8063,6 @@ sub grade_student_bubbles { 'grade_symb' => $ressymb, 'CODE' => $scancode ); - if ($bubbles_per_row ne '') { - $form{'bubbles_per_row'} = $bubbles_per_row; - } if (ref($parts) eq 'HASH') { if (ref($parts->{$ressymb}) eq 'ARRAY') { foreach my $part (@{$parts->{$ressymb}}) { @@ -8411,7 +8373,7 @@ sub checkscantron_results { 'inline',undef,'checkscantron'); my ($username,$domain,$started); my $nav_error; - &scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse. + &scantron_get_maxbubble(\$nav_error); # Need the bubble lines array to parse. if ($nav_error) { $r->print(&navmap_errormsg()); return ''; @@ -8461,9 +8423,7 @@ sub checkscantron_results { if ((exists($grader_randomlists_by_symb{$ressymb})) || (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) { (my $analysis,$parts) = - &scantron_partids_tograde($resource,$env{'request.course.id'}, - $username,$domain,undef, - $bubbles_per_row); + &scantron_partids_tograde($resource,$env{'request.course.id'},$username,$domain); } else { $parts = $grader_partids_by_symb{$ressymb}; } @@ -9009,6 +8969,21 @@ sub init_perm { } } +sub init_old_essays { + my ($symb,$apath,$adom,$aname) = @_; + if ($symb ne '') { + my %essays = &Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); + if (keys(%essays) > 0) { + $old_essays{$symb} = \%essays; + } + } + return; +} + +sub reset_old_essays { + undef(%old_essays); +} + sub gather_clicker_ids { my %clicker_ids; @@ -9811,8 +9786,6 @@ ssi_with_retries() calling routine should trap the error condition and display the warning found in &navmap_errormsg(). - $scantron_config - Reference to bubblesheet format configuration hash. - Returns the maximum number of bubble lines that are expected to occur. Does this by walking the selected sequence rendering the resource and then checking &Apache::lonxml::get_problem_counter()