--- loncom/homework/grades.pm 2010/10/22 15:29:57 1.638 +++ loncom/homework/grades.pm 2011/02/07 19:16:28 1.645 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.638 2010/10/22 15:29:57 www Exp $ +# $Id: grades.pm,v 1.645 2011/02/07 19:16:28 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -44,6 +44,7 @@ use Apache::Constants qw(:common); use Apache::lonlocal; use Apache::lonenc; use Apache::lonstathelpers; +use Apache::lonquickgrades; use String::Similarity; use LONCAPA; @@ -212,8 +213,13 @@ sub reset_caches { } sub get_analyze { - my ($symb,$uname,$udom,$no_increment,$add_to_hash)=@_; + 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 '') { + $key .= "\0".$trial; + } + } if (exists($analyze_cache{$key})) { my $getupdate = 0; if (ref($add_to_hash) eq 'HASH') { @@ -241,9 +247,15 @@ sub reset_caches { 'grade_courseid' => $env{'request.course.id'}, 'grade_username' => $uname, 'grade_noincrement' => $no_increment); + if ($type eq 'randomizetry') { + $form{'grade_questiontype'} = $type; + if ($rndseed ne '') { + $form{'grade_rndseed'} = $rndseed; + } + } if (ref($add_to_hash)) { %form = (%form,%{$add_to_hash}); - } + } my $subresult=&ssi_with_retries($url, $ssi_retries,%form); (undef,$subresult)=split(/_HASH_REF__/,$subresult,2); my %analyze=&Apache::lonnet::str2hash($subresult); @@ -256,15 +268,15 @@ sub reset_caches { } sub get_order { - my ($partid,$respid,$symb,$uname,$udom,$no_increment)=@_; - my $analyze = &get_analyze($symb,$uname,$udom,$no_increment); + my ($partid,$respid,$symb,$uname,$udom,$no_increment,$type,$trial,$rndseed)=@_; + my $analyze = &get_analyze($symb,$uname,$udom,$no_increment,undef,$type,$trial,$rndseed); return $analyze->{"$partid.$respid.shown"}; } sub get_radiobutton_correct_foil { - my ($partid,$respid,$symb,$uname,$udom)=@_; - my $analyze = &get_analyze($symb,$uname,$udom); - my $foils = &get_order($partid,$respid,$symb,$uname,$udom); + my ($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed)=@_; + my $analyze = &get_analyze($symb,$uname,$udom,undef,undef,$type,$trial,$rndseed); + my $foils = &get_order($partid,$respid,$symb,$uname,$udom,undef,$type,$trial,$rndseed); if (ref($foils) eq 'ARRAY') { foreach my $foil (@{$foils}) { if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') { @@ -306,7 +318,7 @@ sub reset_caches { # response types only. sub cleanRecord { my ($answer,$response,$symb,$partid,$respid,$record,$order,$version, - $uname,$udom) = @_; + $uname,$udom,$type,$trial,$rndseed) = @_; my $grayFont = ''; if ($response =~ /^(option|rank)$/) { my %answer=&Apache::lonnet::str2hash($answer); @@ -350,7 +362,7 @@ sub cleanRecord { my %answer=&Apache::lonnet::str2hash($answer); my ($toprow,$bottomrow); my $correct = - &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom); + &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed); foreach my $foil (@$order) { if (exists($answer{$foil})) { if ($foil eq $correct) { @@ -2132,6 +2144,12 @@ KEYWORDS my ($ressub,$hide,$subval) = split(/:/,$submission,3); # Similarity check my $similar=''; + my ($type,$trial,$rndseed); + if ($hide eq 'rand') { + $type = 'randomizetry'; + $trial = $record{"resource.$partid.tries"}; + $rndseed = $record{"resource.$partid.rndseed"}; + } if($env{'form.checkPlag'}){ my ($oname,$odom,$ocrsid,$oessay,$osim)= &most_similar($uname,$udom,$subval,\%old_essays); @@ -2141,7 +2159,7 @@ KEYWORDS &Apache::lonnet::coursedescription($ocrsid, {'one_time' => 1}); - if ($hide) { + if ($hide eq 'anon') { $similar='
'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'
'. &mt('As the current submission is for an anonymous survey, no other details are available.').'

'; } else { @@ -2158,7 +2176,8 @@ KEYWORDS } } } - my $order=&get_order($partid,$respid,$symb,$uname,$udom); + my $order=&get_order($partid,$respid,$symb,$uname,$udom, + undef,$type,$trial,$rndseed); if ($env{'form.lastSub'} eq 'lastonly' || ($env{'form.lastSub'} eq 'hdgrade' && $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) { @@ -2170,7 +2189,7 @@ KEYWORDS '
   '; my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record); if (@$files) { - if ($hide) { + if ($hide eq 'anon') { $lastsubonly.='
'.&mt('[quant,_1,file] uploaded to this anonymous survey',scalar(@{$files})); } else { $lastsubonly.='
'.&mt('Like all files provided by users, this file may contain viruses').'
'; @@ -2181,12 +2200,12 @@ KEYWORDS } $lastsubonly.='
'; } - if ($hide) { + if ($hide eq 'anon') { $lastsubonly.=''.&mt('Anonymous Survey').''; } else { $lastsubonly.=''.&mt('Submitted Answer:').' '. &cleanRecord($subval,$responsetype,$symb,$partid, - $respid,\%record,$order,undef,$uname,$udom); + $respid,\%record,$order,undef,$uname,$udom,$type,$trial,$rndseed); } if ($similar) {$lastsubonly.="

$similar\n";} $lastsubonly.=''; @@ -2385,35 +2404,51 @@ sub get_last_submission { &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'}); } } - my %typeparts; + my (%typeparts,%randombytry); my $showsurv = &Apache::lonnet::allowed('vas',$env{'request.course.id'}); foreach my $key (sort(keys(%lasthash))) { if ($key =~ /\.type$/) { if (($lasthash{$key} eq 'anonsurvey') || - ($lasthash{$key} eq 'anonsurveycred')) { + ($lasthash{$key} eq 'anonsurveycred') || + ($lasthash{$key} eq 'randomizetry')) { my ($ign,@parts) = split(/\./,$key); pop(@parts); - unless ($showsurv) { - my $id = join(',',@parts); - $typeparts{$ign.'.'.$id} = $lasthash{$key}; + my $id = join('.',@parts); + if ($lasthash{$key} eq 'randomizetry') { + $randombytry{$ign.'.'.$id} = $lasthash{$key}; + } else { + unless ($showsurv) { + $typeparts{$ign.'.'.$id} = $lasthash{$key}; + } } delete($lasthash{$key}); } } } my @hidden = keys(%typeparts); + my @randomize = keys(%randombytry); foreach my $key (keys(%lasthash)) { next if ($key !~ /\.submission$/); my $hide; if (@hidden) { foreach my $id (@hidden) { if ($key =~ /^\Q$id\E/) { - $hide = 1; + $hide = 'anon'; last; } } } + unless ($hide) { + if (@randomize) { + foreach my $id (@hidden) { + if ($key =~ /^\Q$id\E/) { + $hide = 'rand'; + last; + } + } + } + } my ($partid,$foo) = split(/submission$/,$key); my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ? 'Draft Copy ' : ''; @@ -4365,8 +4400,8 @@ sub displayPage { &Apache::loncommon::start_data_table_row(). ''.$prob. (scalar(@{$parts}) == 1 ? '' - : '
('.&mt('[_1] parts)', - scalar(@{$parts})) + : '
('.&mt('[_1]parts)', + scalar(@{$parts}).' ') ). ''; $studentTable.=''; @@ -4460,6 +4495,7 @@ sub displaySubByDates { my $interaction; my $no_increment = 1; + my %lastrndseed; for ($version=1;$version<=$$record{'version'};$version++) { my $timestamp = &Apache::lonlocal::locallocaltime($$record{$version.':timestamp'}); @@ -4477,9 +4513,9 @@ sub displaySubByDates { my @versionKeys = split(/\:/,$$record{$version.':keys'}); my @displaySub = (); foreach my $partid (@{$parts}) { - my $hidden; - if (($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurvey') || - ($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurveycred')) { + my ($hidden,$type); + $type = $$record{$version.':resource.'.$partid.'.type'}; + if (($type eq 'anonsurvey') || ($type eq 'anonsurveycred')) { $hidden = 1; } my @matchKey = ($isTask ? sort(grep /^resource\.\d+\.\Q$partid\E\.award$/,@versionKeys) @@ -4502,23 +4538,34 @@ sub displaySubByDates { if ($hidden) { $displaySub[0].= &mt('Anonymous Survey').''; } else { + my ($trial,$rndseed,$newvariation); + if ($type eq 'randomizetry') { + $trial = $$record{"$where.$partid.tries"}; + $rndseed = $$record{"$where.$partid.rndseed"}; + } if ($$record{"$where.$partid.tries"} eq '') { $displaySub[0].=&mt('Trial not counted'); } else { $displaySub[0].=&mt('Trial: [_1]', $$record{"$where.$partid.tries"}); + if ($rndseed || $lastrndseed{$partid}) { + if ($rndseed ne $lastrndseed{$partid}) { + $newvariation = ' ('.&mt('New variation this try').')'; + } + } + $lastrndseed{$partid} = $rndseed; } my $responseType=($isTask ? 'Task' : $responseType->{$partid}->{$responseId}); if (!exists($orders{$partid})) { $orders{$partid}={}; } - if (!exists($orders{$partid}->{$responseId})) { + if ((!exists($orders{$partid}->{$responseId})) || ($trial)) { $orders{$partid}->{$responseId}= &get_order($partid,$responseId,$symb,$uname,$udom, - $no_increment); + $no_increment,$type,$trial,$rndseed); } - $displaySub[0].=''; # /nobreak + $displaySub[0].=''.$newvariation.''; # /nobreak $displaySub[0].='  '. - &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).'
'; + &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom,$type,$trial,$rndseed).'
'; } } } @@ -4617,7 +4664,7 @@ sub updateGradeByPage { &Apache::loncommon::start_data_table_row(). ''.$prob. (scalar(@{$parts}) == 1 ? '' - : '
('.&mt('[quant,_1, part]',scalar(@{$parts})) + : '
('.&mt('[quant,_1,part]',scalar(@{$parts})) .')').''; $studentTable.=' '.$title.' '; @@ -6152,15 +6199,15 @@ sub scantron_do_warning { if ( $env{'form.selectpage'} eq '' || $env{'form.scantron_selectfile'} eq '' || $env{'form.scantron_format'} eq '' ) { - $r->print("

".&mt('You have forgetten to specify some information. Please go Back and try again.')."

"); + $r->print("

".&mt('You have forgotten to specify some information. Please go Back and try again.')."

"); if ( $env{'form.selectpage'} eq '') { $r->print('

'.&mt('You have not selected a Sequence to grade').'

'); } if ( $env{'form.scantron_selectfile'} eq '') { - $r->print('

'.&mt('You have not selected a file that contains the student\'s response data.').'

'); + $r->print('

'.&mt("You have not selected a file that contains the student's response data.").'

'); } if ( $env{'form.scantron_format'} eq '') { - $r->print('

'.&mt('You have not selected a the format of the student\'s response data.').'

'); + $r->print('

'.&mt("You have not selected the format of the student's response data.").'

'); } } else { my $warning=&scantron_warning_screen('Grading: Validate Records'); @@ -8794,7 +8841,7 @@ sub process_clicker_file { if ($env{'form.gradingmechanism'} eq 'given') { $env{'form.givenanswer'}=~s/^\s*//gs; $env{'form.givenanswer'}=~s/\s*$//gs; - $env{'form.givenanswer'}=~s/[^a-zA-Z0-9\.\*\-]+/\,/g; + $env{'form.givenanswer'}=~s/[^a-zA-Z0-9\.\*\-\+]+/\,/g; $env{'form.givenanswer'}=uc($env{'form.givenanswer'}); my @answers=split(/\,/,$env{'form.givenanswer'}); $foundgiven=$#answers+1; @@ -8926,7 +8973,7 @@ ENDHEADER "\n".&mt("Username").":  ". "\n".&mt("Domain").": ". &Apache::loncommon::select_dom_form($env{'course.'.$env{'request.course.id'}.'.domain'},'udom'.$id).' '. - &Apache::loncommon::selectstudent_link('clickeranalysis','uname'.$id,'udom'.$id); + &Apache::loncommon::selectstudent_link('clickeranalysis','uname'.$id,'udom'.$id,0,$id); $unknown_count++; } } @@ -8972,6 +9019,7 @@ sub iclicker_eval { $id=~s/^[\#0]+//; for (my $i=0;$i<$number;$i++) { my $idx=3+$i*6; + $entries[$idx]=~s/[^a-zA-Z0-9\.\*\-\+]+//g; push(@idresponses,$entries[$idx]); } $$responses{$id}=join(',',@idresponses); @@ -9043,20 +9091,20 @@ sub assign_clicker_grades { $result.='
'. &mt('More than one correct result given for question "[_1]": [_2] versus [_3].', $env{'form.question:'.$i},$correct[$i],$input[$i]).''; - } elsif ($input[$i]) { + } elsif (($input[$i]) || ($input[$i] eq '0')) { $correct[$i]=$input[$i]; } } } } for (my $i=0;$i<$number;$i++) { - if (!$correct[$i]) { + if ((!$correct[$i]) && ($correct[$i] ne '0')) { $result.='
'. &mt('No correct result given for question "[_1]"!', $env{'form.question:'.$i}).''; } } - $result.='
'.&mt("Correct answer: [_1]",join(', ',map { ($_?$_:'-') } @correct)); + $result.='
'.&mt("Correct answer: [_1]",join(', ',map { ((($_) || ($_ eq '0'))?$_:'-') } @correct)); } # Start grading my $pcorrect=$env{'form.pcorrect'}; @@ -9089,17 +9137,29 @@ sub assign_clicker_grades { for (my $i=0;$i<$number;$i++) { if ($correct[$i] eq '-') { $realnumber--; - } elsif ($answer[$i]) { + } elsif (($answer[$i]) || ($answer[$i]=~/^[0\.]+$/)) { if ($gradingmechanism eq 'attendance') { $sum+=$pcorrect; } elsif ($correct[$i] eq '*') { $sum+=$pcorrect; } else { - if ($answer[$i] eq $correct[$i]) { - $sum+=$pcorrect; - } else { - $sum+=$pincorrect; +# We actually grade if correct or not + my $increment=$pincorrect; +# Special case: numerical answer "0" + if ($correct[$i] eq '0') { + if ($answer[$i]=~/^[0\.]+$/) { + $increment=$pcorrect; + } +# General numerical answer, both evaluate to something non-zero + } elsif ((1.0*$correct[$i]!=0) && (1.0*$answer[$i]!=0)) { + if (1.0*$correct[$i]==1.0*$answer[$i]) { + $increment=$pcorrect; + } +# Must be just alphanumeric + } elsif ($answer[$i] eq $correct[$i]) { + $increment=$pcorrect; } + $sum+=$increment; } } } @@ -9140,7 +9200,7 @@ sub startpage { unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"}); $r->print(&Apache::loncommon::start_page('Grading',undef, {'bread_crumbs' => $crumbs})); - $r->print('

'.$$crumbs[-1]{'text'}.'

'); + &Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading')); unless ($nodisplayflag) { $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag)); } @@ -9333,6 +9393,7 @@ sub handler { if ($ssi_error) { &ssi_print_error($request); } + &Apache::lonquickgrades::endGradeScreen($request); $request->print(&Apache::loncommon::end_page()); &reset_caches(); return '';