Skip to content
Snippets Groups Projects
Commit 1746d2aa authored by Astor Bizard's avatar Astor Bizard :dog2:
Browse files

Fixed previous submissions list display bug when files are too large to compute diff graph.

parent 88e374a0
No related branches found
No related tags found
No related merge requests found
...@@ -128,6 +128,7 @@ $string ['gradeoptions'] = 'Grade options'; ...@@ -128,6 +128,7 @@ $string ['gradeoptions'] = 'Grade options';
$string ['grader'] = "Evaluator"; $string ['grader'] = "Evaluator";
$string ['gradercomments'] = 'Assessment report'; $string ['gradercomments'] = 'Assessment report';
$string ['graderemoved'] = 'The grade has been removed'; $string ['graderemoved'] = 'The grade has been removed';
$string ['graphcomputationfailed'] = 'This graph data could not be computed.<br>The files data may be too large.';
$string ['groupwork'] = 'Group work'; $string ['groupwork'] = 'Group work';
$string ['inconsistentgroup'] = 'You are not member of only one group (0 o >1)'; $string ['inconsistentgroup'] = 'You are not member of only one group (0 o >1)';
$string ['incorrect_file_name'] = 'Incorrect file name'; $string ['incorrect_file_name'] = 'Incorrect file name';
......
...@@ -406,7 +406,7 @@ class vpl_diff { ...@@ -406,7 +406,7 @@ class vpl_diff {
return $n1 + $n2; return $n1 + $n2;
} }
$queue = array_fill(0, $n1 + $n2 + 1, array()); $queue = array_fill(0, $n1 + $n2 + 1, array());
$done = array_fill(0, $n1 + 1, array_fill(0, $n2 + 1, false)); $done = array_fill(0, $n1 + 1, array());
$z = new stdClass(); $z = new stdClass();
$z->i1 = 0; $z->i1 = 0;
$z->i2 = 0; $z->i2 = 0;
...@@ -422,7 +422,7 @@ class vpl_diff { ...@@ -422,7 +422,7 @@ class vpl_diff {
$z = array_pop($queue[$priority]); $z = array_pop($queue[$priority]);
$i1 = $z->i1; $i1 = $z->i1;
$i2 = $z->i2; $i2 = $z->i2;
if ($done[$i1][$i2]) { if (isset($done[$i1][$i2])) {
continue; continue;
} else { } else {
$done[$i1][$i2] = true; $done[$i1][$i2] = true;
...@@ -472,31 +472,112 @@ class vpl_diff { ...@@ -472,31 +472,112 @@ class vpl_diff {
* Computes diff between two files. * Computes diff between two files.
* @param string $filedata1 * @param string $filedata1
* @param string $filedata2 * @param string $filedata2
* @param int $timelimit The maximum amount of time to spend on this computation (in milliseconds).
* If provided and the time limit is exceeded, an exception will be thrown.
* @return int The diff in number of chars. * @return int The diff in number of chars.
*/ */
static public function compute_filediff($filedata1, $filedata2) { static public function compute_filediff($filedata1, $filedata2, $timelimit=0) {
if (strlen($filedata1) == 0 || strlen($filedata2) == 0) { if (strlen($filedata1) == 0 || strlen($filedata2) == 0) {
return strlen($filedata1) + strlen($filedata2); return strlen($filedata1) + strlen($filedata2);
} }
$starttime = microtime(true);
$lines1 = explode("\n", $filedata1); $lines1 = explode("\n", $filedata1);
$lines2 = explode("\n", $filedata2); $lines2 = explode("\n", $filedata2);
$linesdiff = self::calculatediff($lines1, $lines2, false); $n1 = count($lines1);
$totaldiff = 0; $n2 = count($lines2);
foreach ($linesdiff as $diff) { $queue = array_fill(0, $n1 + $n2 + 1, array());
switch ($diff->type) { $prev = array_fill(0, $n1 + 1, array());
case '=' : $z = new stdClass();
break; $z->i1 = 0;
case '<' : $z->i2 = 0;
$totaldiff += strlen( $lines1[$diff->ln1 - 1] ) + 1; $z->d = 0;
break; $z->prev = 0;
case '>' : $queue[0][] = $z;
$totaldiff += strlen( $lines2[$diff->ln2 - 1] ) + 1; $priority = 0;
break;
default : // A-star search of shortest diff.
$totaldiff += self::compute_linediff( $lines1[$diff->ln1 - 1], $lines2[$diff->ln2 - 1] ); while (true) {
break; if ($timelimit > 0 && microtime(true)-$starttime > $timelimit/1000) {
// Time out.
throw new Exception();
}
while (count($queue[$priority]) == 0) {
$priority++;
}
$z = array_pop($queue[$priority]);
$i1 = $z->i1;
$i2 = $z->i2;
if (isset($prev[$i1][$i2])) {
continue;
} else {
$prev[$i1][$i2] = $z->prev;
}
// Identical substring: 0 distance.
while ($i1 < $n1 && $i2 < $n2 && $lines1[$i1] == $lines2[$i2]) {
$i1++;
$i2++;
}
if ($i1 == $n1 && $i2 == $n2) {
// Found shortest diff amongst lines.
// Backtrack to compute total diff as a sum of lines diff.
$totaldiff = 0;
while ($i1 > 0 && $i2 > 0) {
if (!isset($prev[$i1][$i2])) {
$i1--;
$i2--;
} else {
switch ($prev[$i1][$i2]) {
case 1 :
$totaldiff += strlen( $lines1[$i1-1] ) + 1;
$i1--;
break;
case 2 :
$totaldiff += strlen( $lines2[$i2-1] ) + 1;
$i2--;
break;
case 3 :
$totaldiff += self::compute_linediff( $lines1[$i1 - 1], $lines2[$i2 - 1] );
case 0 :
$i1--;
$i2--;
break;
}
}
}
return $totaldiff;
}
// Line addition in file1.
if ($i1 < $n1) {
$z1 = new stdClass();
$z1->i1 = $i1 + 1;
$z1->i2 = $i2;
$z1->d = $z->d + 1;
$z1->prev = 1;
$queue[$z1->d + abs(($n1 - $z1->i1) - ($n2 - $z1->i2))][] = $z1;
}
// Line addition in file2.
if ($i2 < $n2) {
$z2 = new stdClass();
$z2->i1 = $i1;
$z2->i2 = $i2 + 1;
$z2->d = $z->d + 1;
$z2->prev = 2;
$queue[$z2->d + abs(($n1 - $z2->i1) - ($n2 - $z2->i2))][] = $z2;
}
// Line change.
if ($i1 < $n1 && $i2 < $n2) {
$z3 = new stdClass();
$z3->i1 = $i1 + 1;
$z3->i2 = $i2 + 1;
$z3->d = $z->d + 1;
$z3->prev = 3;
$queue[$z3->d + abs(($n1 - $z3->i1) - ($n2 - $z3->i2))][] = $z3;
} }
} }
return $totaldiff;
} }
} }
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
display: inline-block; display: inline-block;
} }
.path-mod-vpl.pagelayout-incourse .chart-area.nograph {
text-align: center;
vertical-align: top;
top: 2em;
position: relative;
}
.path-mod-vpl.pagelayout-incourse .chart-area.nograph b {
font-size: .9em;
}
.path-mod-vpl .chart-area canvas { .path-mod-vpl .chart-area canvas {
width: 100%; width: 100%;
height: 100%; height: 100%;
......
...@@ -133,55 +133,62 @@ class vpl_grapher { ...@@ -133,55 +133,62 @@ class vpl_grapher {
if (count( $this->submissions ) == 0 || $this->userid === null) { if (count( $this->submissions ) == 0 || $this->userid === null) {
return; return;
} }
$submissionslist = array_reverse( $this->submissions ); try {
$title = $this->username . ' - ';
if ($diff) {
$title .= get_string( 'filesdiffevolution', VPL );
} else {
$title .= get_string( 'filessizeevolution', VPL );
}
$interval = self::compute_xaxis_legend_interval(count( $submissionslist ), 20); $submissionslist = array_reverse( $this->submissions );
$interval = self::compute_xaxis_legend_interval(count( $submissionslist ), 20);
$i = 1; $i = 1;
$subsn = array(); $subsn = array();
$series = array(); $series = array();
$names = array(); $names = array();
$totalseries = array(); $totalseries = array();
if ($diff) { if ($diff) {
$reqfiles = $this->vpl->get_fgm('required')->getAllFiles(); $reqfiles = $this->vpl->get_fgm('required')->getAllFiles();
} }
foreach ($submissionslist as $subinstance) { foreach ($submissionslist as $subinstance) {
$submission = new mod_vpl_submission( $this->vpl, $subinstance ); $submission = new mod_vpl_submission( $this->vpl, $subinstance );
$files = $submission->get_submitted_files(); $files = $submission->get_submitted_files();
$total = 0; $total = 0;
foreach ($files as $name => $data) { foreach ($files as $name => $data) {
if (!isset($series[$name])) { if (!isset($series[$name])) {
$names[] = $name; $names[] = $name;
$series[$name] = array_fill(0, $i - 1, null); $series[$name] = array_fill(0, $i - 1, null);
}
if ($diff && isset($reqfiles[$name])) {
$value = vpl_diff::compute_filediff($reqfiles[$name], $data, 500);
} else {
$value = strlen( $data );
}
$series[$name][] = $value;
$total += $value;
} }
if ($diff && isset($reqfiles[$name])) { foreach ($series as &$serie) {
$value = vpl_diff::compute_filediff($reqfiles[$name], $data); if (count($serie) < $i) {
} else { $serie[] = null;
$value = strlen( $data ); }
} }
$series[$name][] = $value; $totalseries[] = $total;
$total += $value; $subsn[] = $i % $interval == 0 ? $i : '';
$i++;
} }
foreach ($series as &$serie) { if ($diff && count($names) > 1) {
if (count($serie) < $i) { $names[] = get_string('total');
$serie[] = null; $series[get_string('total')] = $totalseries;
}
} }
$totalseries[] = $total; self::draw( $title, get_string( 'submissions', VPL ) , get_string( "sizeb" ), $subsn, $series, $names );
$subsn[] = $i % $interval == 0 ? $i : ''; } catch (Exception $e) {
$i++; echo '<span class="chart-area nograph">';
} echo '<b>' . $title . '</b><br>';
if ($diff && count($names) > 1) { echo get_string('graphcomputationfailed', VPL);
$names[] = get_string('total'); echo '</span>';
$series[get_string('total')] = $totalseries;
}
$title = $this->username . ' - ';
if ($diff) {
$title .= get_string( 'filesdiffevolution', VPL );
} else {
$title .= get_string( 'filessizeevolution', VPL );
} }
self::draw( $title, get_string( 'submissions', VPL ) , get_string( "sizeb" ), $subsn, $series, $names );
} }
static protected function new_working_period($workduration, &$firstwork, $intervals) { static protected function new_working_period($workduration, &$firstwork, $intervals) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment