--- loncom/homework/grades.pm	2022/02/09 23:21:11	1.788
+++ loncom/homework/grades.pm	2024/07/01 20:22:34	1.794
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.788 2022/02/09 23:21:11 raeburn Exp $
+# $Id: grades.pm,v 1.794 2024/07/01 20:22:34 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2206,7 +2206,7 @@ sub files_exist {
         my ($uname,$udom,$fullname) = split(/:/,$student);
         my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},
 					      $udom,$uname);
-        my ($string,$timestamp)= &get_last_submission(\%record);
+        my ($string)= &get_last_submission(\%record);
         foreach my $submission (@$string) {
             my ($partid,$respid) =
 		($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/);
@@ -2558,169 +2558,12 @@ sub submission {
     #             (3) All transactions (by date)
     #             (4) The whole record (with detailed information for all transactions)
 
-    my ($string,$timestamp)= &get_last_submission(\%record,$is_tool);
-
-    my $lastsubonly;
-
-    if ($$timestamp eq '') {
-        $lastsubonly.='<div class="LC_grade_submissions_body">'.$$string[0].'</div>'; 
-    } elsif ($is_tool) {
-        $lastsubonly =
-            '<div class="LC_grade_submissions_body">'
-           .'<b>'.&mt('Date Grade Passed Back:').'</b> '.$$timestamp."</div>\n";
-    } else {
-        $lastsubonly =
-            '<div class="LC_grade_submissions_body">'
-           .'<b>'.&mt('Date Submitted:').'</b> '.$$timestamp."\n";
-
-	my %seenparts;
-	my @part_response_id = &flatten_responseType($responseType);
-	foreach my $part (@part_response_id) {
-	    my ($partid,$respid) = @{ $part };
-	    my $display_part=&get_display_part($partid,$symb);
-	    if ($env{"form.$uname:$udom:$partid:submitted_by"}) {
-		if (exists($seenparts{$partid})) { next; }
-		$seenparts{$partid}=1;
-                $request->print(
-                    '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
-                    ' <b>'.&mt('Collaborative submission by: [_1]',
-                               '<a href="javascript:viewSubmitter(\''.
-                               $env{"form.$uname:$udom:$partid:submitted_by"}.
-                               '\');" target="_self">'.
-                               $$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a>').
-                    '<br />');
-		next;
-	    }
-	    my $responsetype = $responseType->{$partid}->{$respid};
-	    if (!exists($record{"resource.$partid.$respid.submission"})) {
-                $lastsubonly.="\n".'<div class="LC_grade_submission_part">'.
-                    '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
-                    ' <span class="LC_internal_info">'.
-                    '('.&mt('Response ID: [_1]',$respid).')'.
-                    '</span>&nbsp; &nbsp;'.
-	       	    '<span class="LC_warning">'.&mt('Nothing submitted - no attempts.').'</span><br /><br /></div>';
-		next;
-	    }
-	    foreach my $submission (@$string) {
-		my ($partid,$respid) = ($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/);
-		if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; }
-		my ($ressub,$hide,$draft,$subval) = split(/:/,$submission,4);
-		# 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,$symb,$subval);
-		    if ($osim) {
-			$osim=int($osim*100.0);
-                        if ($hide eq 'anon') {
-                            $similar='<hr /><span class="LC_warning">'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'<br />'.
-                                     &mt('As the current submission is for an anonymous survey, no other details are available.').'</span><hr />';
-                        } else {
-			    $similar='<hr />';
-                            if ($essayurl eq 'lib/templates/simpleproblem.problem') {
-                                $similar .= '<h3><span class="LC_warning">'.
-                                            &mt('Essay is [_1]% similar to an essay by [_2]',
-                                                $osim,
-                                                &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
-                                            '</span></h3>';
-                            } else {
-                                my %old_course_desc;
-                                if ($ocrsid ne '') {
-                                    if (ref($coursedesc_by_cid{$ocrsid}) eq 'HASH') {
-                                        %old_course_desc = %{$coursedesc_by_cid{$ocrsid}};
-                                    } else {
-                                        my $args;
-                                        if ($ocrsid ne $env{'request.course.id'}) {
-                                            $args = {'one_time' => 1};
-                                        }
-                                        %old_course_desc =
-                                            &Apache::lonnet::coursedescription($ocrsid,$args);
-                                        $coursedesc_by_cid{$ocrsid} = \%old_course_desc;
-                                    }
-                                    $similar .=
-                                        '<h3><span class="LC_warning">'.
-                                        &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])',
-                                            $osim,
-                                            &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')',
-                                            $old_course_desc{'description'},
-                                            $old_course_desc{'num'},
-                                            $old_course_desc{'domain'}).
-                                        '</span></h3>';
-                                } else {
-                                    $similar .=
-                                        '<h3><span class="LC_warning">'.
-                                        &mt('Essay is [_1]% similar to an essay by [_2] in an unknown course',
-                                            $osim,
-                                            &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
-                                        '</span></h3>';
-                                }
-                            }
-                            $similar .= '<blockquote><i>'.
-                                        &keywords_highlight($oessay).
-                                        '</i></blockquote><hr />';
-                        }
-	            }
-		}
-		my $order=&get_order($partid,$respid,$symb,$uname,$udom,
-                                     undef,$type,$trial,$rndseed);
-                if (($env{'form.lastSub'} eq 'lastonly') ||
-                    ($env{'form.lastSub'} eq 'datesub')  ||
-                    ($env{'form.lastSub'} =~ /^(last|all)$/)) {
-		    my $display_part=&get_display_part($partid,$symb);
-                    $lastsubonly.='<div class="LC_grade_submission_part">'.
-                        '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
-                        ' <span class="LC_internal_info">'.
-                        '('.&mt('Response ID: [_1]',$respid).')'.
-                        '</span>&nbsp; &nbsp;';
-		    my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
-		    if (@$files) {
-                        if ($hide eq 'anon') {
-                            $lastsubonly.='<br />'.&mt('[quant,_1,file] uploaded to this anonymous survey',scalar(@{$files}));
-                        } else {
-                            $lastsubonly.='<br /><br />'.'<b>'.&mt('Submitted Files:').'</b>'
-                                        .'<br /><span class="LC_warning">';
-                            if(@$files == 1) {
-                                $lastsubonly .= &mt('Like all files provided by users, this file may contain viruses!');
-                            } else {
-                                $lastsubonly .= &mt('Like all files provided by users, these files may contain viruses!');
-                            }
-                            $lastsubonly .= '</span>';
-                            foreach my $file (@$files) {
-                                &Apache::lonnet::allowuploaded('/adm/grades',$file);
-                                $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border="0" alt="" /> '.$file.'</a>';
-                            }
-                        }
-			$lastsubonly.='<br />';
-                    }
-                    if ($hide eq 'anon') {
-                        $lastsubonly.='<br /><b>'.&mt('Anonymous Survey').'</b>'; 
-                    } else {
-                        $lastsubonly.='<br /><b>'.&mt('Submitted Answer:').' </b>';
-                        if ($draft) {
-                            $lastsubonly.= ' <span class="LC_warning">'.&mt('Draft Copy').'</span>';
-                        }
-                        $subval =
-			    &cleanRecord($subval,$responsetype,$symb,$partid,
-					 $respid,\%record,$order,undef,$uname,$udom,$type,$trial,$rndseed);
-                        if ($responsetype eq 'essay') {
-                            $subval =~ s{\n}{<br />}g;
-                        }
-                        $lastsubonly.=$subval."\n";
-                    }
-                    if ($similar) {$lastsubonly.="<br /><br />$similar\n";}
-		    $lastsubonly.='</div>';
-		}
-            }
-	}
-	$lastsubonly.='</div>'."\n"; # End: LC_grade_submissions_body
-    }
+    my ($lastsubonly,$partinfo) =
+        &show_last_submission($uname,$udom,$symb,$essayurl,$responseType,$env{'form.lastSub'},
+                              $is_tool,$fullname,\%record,\%coursedesc_by_cid);
+    $request->print($partinfo);
     $request->print($lastsubonly);
+
     if ($env{'form.lastSub'} eq 'datesub') {
         my ($parts,$handgrade,$responseType) = &response_type($symb,\$res_error);
 	$request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));
@@ -2844,6 +2687,186 @@ sub submission {
     return '';
 }
 
+sub show_last_submission {
+    my ($uname,$udom,$symb,$essayurl,$responseType,$viewtype,$is_tool,$fullname,
+        $record,$coursedesc_by_cid) = @_;
+    my ($string,$timestamp,$lastgradetime,$lastsubmittime) =
+        &get_last_submission($record,$is_tool);
+
+    my ($lastsubonly,$partinfo);
+    if ($timestamp eq '') {
+        $lastsubonly.='<div class="LC_grade_submissions_body">'.$string->[0].'</div>';
+    } elsif ($is_tool) {
+        $lastsubonly =
+            '<div class="LC_grade_submissions_body">'
+           .'<b>'.&mt('Date Grade Passed Back:').'</b> '.$timestamp."</div>\n";
+    } else {
+        my ($shownsubmdate,$showngradedate);
+        if ($lastsubmittime && $lastgradetime) {
+            $shownsubmdate = &Apache::lonlocal::locallocaltime($lastsubmittime);
+            if ($lastgradetime > $lastsubmittime) {
+                 $showngradedate = &Apache::lonlocal::locallocaltime($lastgradetime);
+             }
+        } else {
+            $shownsubmdate = $timestamp;
+        }
+        $lastsubonly =
+            '<div class="LC_grade_submissions_body">'
+           .'<b>'.&mt('Date Submitted:').'</b> '.$shownsubmdate."\n";
+        if ($showngradedate) {
+            $lastsubonly .= '<br /><b>'.&mt('Date Graded:').'</b> '.$showngradedate."\n";
+        }
+
+        my %seenparts;
+        my @part_response_id = &flatten_responseType($responseType);
+        foreach my $part (@part_response_id) {
+            my ($partid,$respid) = @{ $part };
+            my $display_part=&get_display_part($partid,$symb);
+            if ($env{"form.$uname:$udom:$partid:submitted_by"}) {
+                if (exists($seenparts{$partid})) { next; }
+                $seenparts{$partid}=1;
+                $partinfo .=
+                    '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
+                    ' <b>'.&mt('Collaborative submission by: [_1]',
+                               '<a href="javascript:viewSubmitter(\''.
+                               $env{"form.$uname:$udom:$partid:submitted_by"}.
+                               '\');" target="_self">'.
+                               $$fullname{$env{"form.$uname:$udom:$partid:submitted_by"}}.'</a>').
+                    '<br />';
+                next;
+            }
+            my $responsetype = $responseType->{$partid}->{$respid};
+            if (!exists($record->{"resource.$partid.$respid.submission"})) {
+                $lastsubonly.="\n".'<div class="LC_grade_submission_part">'.
+                    '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
+                    ' <span class="LC_internal_info">'.
+                    '('.&mt('Response ID: [_1]',$respid).')'.
+                    '</span>&nbsp; &nbsp;'.
+                    '<span class="LC_warning">'.&mt('Nothing submitted - no attempts.').'</span><br /><br /></div>';
+                next;
+            }
+            foreach my $submission (@$string) {
+                my ($partid,$respid) = ($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/);
+                if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; }
+                my ($ressub,$hide,$draft,$subval) = split(/:/,$submission,4);
+                # 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,$symb,$subval);
+                    if ($osim) {
+                        $osim=int($osim*100.0);
+                        if ($hide eq 'anon') {
+                            $similar='<hr /><span class="LC_warning">'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'<br />'.
+                                     &mt('As the current submission is for an anonymous survey, no other details are available.').'</span><hr />';
+                        } else {
+                            $similar='<hr />';
+                            if ($essayurl eq 'lib/templates/simpleproblem.problem') {
+                                $similar .= '<h3><span class="LC_warning">'.
+                                            &mt('Essay is [_1]% similar to an essay by [_2]',
+                                                $osim,
+                                                &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
+                                            '</span></h3>';
+                            } else {
+                                my %old_course_desc;
+                                if ($ocrsid ne '') {
+                                    if (ref($coursedesc_by_cid->{$ocrsid}) eq 'HASH') {
+                                        %old_course_desc = %{$coursedesc_by_cid->{$ocrsid}};
+                                    } else {
+                                        my $args;
+                                        if ($ocrsid ne $env{'request.course.id'}) {
+                                            $args = {'one_time' => 1};
+                                        }
+                                        %old_course_desc =
+                                            &Apache::lonnet::coursedescription($ocrsid,$args);
+                                        $coursedesc_by_cid->{$ocrsid} = \%old_course_desc;
+                                    }
+                                    $similar .=
+                                        '<h3><span class="LC_warning">'.
+                                        &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])',
+                                            $osim,
+                                            &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')',
+                                            $old_course_desc{'description'},
+                                            $old_course_desc{'num'},
+                                            $old_course_desc{'domain'}).
+                                        '</span></h3>';
+                                } else {
+                                    $similar .=
+                                        '<h3><span class="LC_warning">'.
+                                        &mt('Essay is [_1]% similar to an essay by [_2] in an unknown course',
+                                            $osim,
+                                            &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')').
+                                        '</span></h3>';
+                                }
+                            }
+                            $similar .= '<blockquote><i>'.
+                                        &keywords_highlight($oessay).
+                                        '</i></blockquote><hr />';
+                        }
+                    }
+                }
+                my $order=&get_order($partid,$respid,$symb,$uname,$udom,
+                                     undef,$type,$trial,$rndseed);
+                if (($viewtype eq 'lastonly') ||
+                    ($viewtype eq 'datesub')  ||
+                    ($viewtype =~ /^(last|all)$/)) {
+                    my $display_part=&get_display_part($partid,$symb);
+                    $lastsubonly.='<div class="LC_grade_submission_part">'.
+                        '<b>'.&mt('Part: [_1]',$display_part).'</b>'.
+                        ' <span class="LC_internal_info">'.
+                        '('.&mt('Response ID: [_1]',$respid).')'.
+                        '</span>&nbsp; &nbsp;';
+                    my $files=&get_submitted_files($udom,$uname,$partid,$respid,$record);
+                    if (@$files) {
+                        if ($hide eq 'anon') {
+                            $lastsubonly.='<br />'.&mt('[quant,_1,file] uploaded to this anonymous survey',scalar(@{$files}));
+                        } else {
+                            $lastsubonly.='<br /><br />'.'<b>'.&mt('Submitted Files:').'</b>'
+                                        .'<br /><span class="LC_warning">';
+                            if(@$files == 1) {
+                                $lastsubonly .= &mt('Like all files provided by users, this file may contain viruses!');
+                            } else {
+                                $lastsubonly .= &mt('Like all files provided by users, these files may contain viruses!');
+                            }
+                            $lastsubonly .= '</span>';
+                            foreach my $file (@$files) {
+                                &Apache::lonnet::allowuploaded('/adm/grades',$file);
+                                $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border="0" alt="" /> '.$file.'</a>';
+                            }
+                        }
+                        $lastsubonly.='<br />';
+                    }
+                    if ($hide eq 'anon') {
+                        $lastsubonly.='<br /><b>'.&mt('Anonymous Survey').'</b>';
+                    } else {
+                        $lastsubonly.='<br /><b>'.&mt('Submitted Answer:').' </b>';
+                        if ($draft) {
+                            $lastsubonly.= ' <span class="LC_warning">'.&mt('Draft Copy').'</span>';
+                        }
+                        $subval =
+                            &cleanRecord($subval,$responsetype,$symb,$partid,
+                                         $respid,$record,$order,undef,$uname,$udom,$type,$trial,$rndseed);
+                        if ($responsetype eq 'essay') {
+                            $subval =~ s{\n}{<br />}g;
+                        }
+                        $lastsubonly.=$subval."\n";
+                    }
+                    if ($similar) {$lastsubonly.="<br /><br />$similar\n";}
+                    $lastsubonly.='</div>';
+                }
+            }
+        }
+        $lastsubonly.='</div>'."\n"; # End: LC_grade_submissions_body
+    }
+    return ($lastsubonly,$partinfo);
+}
+
 sub check_collaborators {
     my ($symb,$uname,$udom,$record,$handgrade,$counter) = @_;
     my ($result,@col_fullnames);
@@ -2903,17 +2926,45 @@ sub check_collaborators {
 #--- Retrieve the last submission for all the parts
 sub get_last_submission {
     my ($returnhash,$is_tool)=@_;
-    my (@string,$timestamp,%lasthidden);
+    my (@string,$timestamp,$lastgradetime,$lastsubmittime);
     if ($$returnhash{'version'}) {
 	my %lasthash=();
-	my ($version);
+        my %prevsolved=();
+        my %solved=();
+	my $version;
 	for ($version=1;$version<=$$returnhash{'version'};$version++) {
+            my %handgraded = ();
 	    foreach my $key (sort(split(/\:/,
 					$$returnhash{$version.':keys'}))) {
 		$lasthash{$key}=$$returnhash{$version.':'.$key};
-		$timestamp = 
-		    &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'});
+                if ($key =~ /\.([^.]+)\.regrader$/) {
+                    $handgraded{$1} = 1;
+                } elsif ($key =~ /\.portfiles$/) {
+                    if (($$returnhash{$version.':'.$key} ne '') &&
+                        ($$returnhash{$version.':'.$key} !~ /\.\d+\.\w+$/)) {
+                        $lastsubmittime = $$returnhash{$version.':timestamp'};
+                    }
+                } elsif ($key =~ /\.submission$/) {
+                    if ($$returnhash{$version.':'.$key} ne '') {
+                        $lastsubmittime = $$returnhash{$version.':timestamp'};
+                    }
+                } elsif ($key =~ /\.([^.]+)\.solved$/) {
+                    $prevsolved{$1} = $solved{$1};
+                    $solved{$1} = $lasthash{$key};
+                }
+            }
+            foreach my $partid (keys(%handgraded)) {
+                if (($prevsolved{$partid} eq 'ungraded_attempted') &&
+                    (($solved{$partid} eq 'incorrect_by_override') ||
+                     ($solved{$partid} eq 'correct_by_override'))) {
+                    $lastgradetime = $$returnhash{$version.':timestamp'};
+                }
+                if ($solved{$partid} ne '') {
+                    $prevsolved{$partid} = $solved{$partid};
+                }
 	    }
+            $timestamp =
+                &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'});
 	}
         my (%typeparts,%randombytry);
         my $showsurv = 
@@ -2977,7 +3028,7 @@ sub get_last_submission {
 	$string[0] =
 	    '<span class="LC_warning">'.$msg.'</span>';
     }
-    return (\@string,\$timestamp);
+    return (\@string,$timestamp,$lastgradetime,$lastsubmittime);
 }
 
 #--- High light keywords, with style choosen by user.
@@ -3797,8 +3848,8 @@ sub version_portfiles {
             $$record{$key} = join(',',@versioned_portfiles);
             push(@returned_keys,$key);
         }
-    } 
-    return (@returned_keys);   
+    }
+    return (@returned_keys);
 }
 
 #--------------------------------------------------------------------------------------
@@ -9611,7 +9662,7 @@ END
                             my @lines = &Apache::lonnet::get_scantronformat_file();
                             my $count = 0;
                             foreach my $line (@lines) {
-                                next if ($line =~ /^#/);
+                                next if (($line =~ /^\#/) || ($line eq ''));
                                 $singleline = $line;
                                 $count ++;
                             }
@@ -9805,7 +9856,7 @@ sub validate_uploaded_scantron_file {
         my %unique_formats;
         my @formatlines = &Apache::lonnet::get_scantronformat_file();
         foreach my $line (@formatlines) {
-            chomp($line);
+            next if (($line =~ /^\#/) || ($line eq ''));
             my @config = split(/:/,$line);
             my $idstart = $config[5];
             my $idlength = $config[6];
@@ -11514,6 +11565,77 @@ sub select_problem {
     $r->print('<input type="submit" value="'.&mt('Next').' &rarr;" /></form>');
 }
 
+#----- display problem, answer, and submissions for a single student (no grading)
+
+sub view_as_user {
+    my ($symb,$vuname,$vudom,$hasperm) = @_;
+    my $plainname = &Apache::loncommon::plainname($vuname,$vudom,'lastname');
+    my $displayname = &nameUserString('',$plainname,$vuname,$vudom);
+    my $output = &Apache::loncommon::get_student_view($symb,$vuname,$vudom,
+                                                      $env{'request.course.id'},
+                                                      undef,{'disable_submit' => 1}).
+                 "\n\n".
+                 '<div class="LC_grade_show_user">'.
+                 '<h2>'.$displayname.'</h2>'.
+                 "\n".
+                 &Apache::loncommon::track_student_link('View recent activity',
+                                                        $vuname,$vudom,'check').' '.
+                 "\n";
+    if (&Apache::lonnet::allowed('opa',$env{'request.course.id'}) ||
+        (($env{'request.course.sec'} ne '') &&
+         &Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.$env{'request.course.sec'}))) {
+        $output .= &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
+                                               $vuname,$vudom,$symb,'check');
+    }
+    $output .= "\n";
+    my $companswer = &Apache::loncommon::get_student_answers($symb,$vuname,$vudom,
+                                                             $env{'request.course.id'});
+    $companswer=~s|<form(.*?)>||g;
+    $companswer=~s|</form>||g;
+    $companswer=~s|name="submit"|name="would_have_been_submit"|g;
+    $output .= '<div class="LC_Box">'.
+               '<h3 class="LC_hcell">'.&mt('Correct answer for[_1]',$displayname).'</h3>'.
+               $companswer.
+               '</div>'."\n";
+    my $is_tool = ($symb =~ /ext\.tool$/);
+    my ($essayurl,%coursedesc_by_cid);
+    (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb);
+    my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$vudom,$vuname);
+    my $res_error;
+    my ($partlist,$handgrade,$responseType,$numresp,$numessay) =
+        &response_type($symb,\$res_error);
+    my $fullname;
+    my $collabinfo;
+    if ($numessay) {
+        unless ($hasperm) {
+            &init_perm();
+        }
+        ($collabinfo,$fullname)=
+            &check_collaborators($symb,$vuname,$vudom,\%record,$handgrade,0);
+        unless ($hasperm) {
+            &reset_perm();
+        }
+    }
+    my $checkIcon = '<img alt="'.&mt('Check Mark').
+                    '" src="'.$Apache::lonnet::perlvar{'lonIconsURL'}.
+                    '/check.gif" height="16" border="0" />';
+    my ($lastsubonly,$partinfo) =
+        &show_last_submission($vuname,$vudom,$symb,$essayurl,$responseType,'datesub',
+                              '',$fullname,\%record,\%coursedesc_by_cid);
+    $output .= '<div class="LC_Box">'.
+               '<h3 class="LC_hcell">'.&mt('Submissions').'</h3>'."\n".$collabinfo."\n";
+    if (($numresp > $numessay) & !$is_tool) {
+        $output .='<p class="LC_info">'.
+                  &mt('Part(s) graded correct by the computer is marked with a [_1] symbol.',$checkIcon).
+                  "</p>\n";
+    }
+    $output .= $partinfo;
+    $output .= $lastsubonly;
+    $output .= &displaySubByDates($symb,\%record,$partlist,$responseType,$checkIcon,$vuname,$vudom);
+    $output .= '</div></div>'."\n";
+    return $output;
+}
+
 sub handler {
     my $request=$_[0];
     &reset_caches();