dataProcess.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. export function processData () {
  2. const folderInput = document.querySelector("#folder");
  3. const header = [
  4. "submissionid",
  5. "file",
  6. "filesize",
  7. "timestamp",
  8. "humandate",
  9. "grade",
  10. "userid",
  11. "exerciseid",
  12. ];
  13. function generateSubCode (algorithmInIlm) {
  14. window.program_obj.functions = JSON.parse(algorithmInIlm).functions;
  15. window.program_obj.globals = JSON.parse(algorithmInIlm).globals;
  16. return window.ivprogCore.generateCode();
  17. }
  18. function prepareData (map, submission) {
  19. if (!submission) {
  20. return map;
  21. }
  22. const exercID = submission["exerciseid"];
  23. const studentID = submission["userid"];
  24. let exercMap = null;
  25. if (map.has(exercID)) {
  26. exercMap = map.get(exercID);
  27. } else {
  28. exercMap = new Map();
  29. map.set(exercID, exercMap);
  30. }
  31. if (exercMap.has(studentID)) {
  32. exercMap.get(studentID).push(submission);
  33. } else {
  34. exercMap.set(studentID, [submission]);
  35. }
  36. return map;
  37. }
  38. folderInput.addEventListener("change", async () => {
  39. const files = Array.from(folderInput.files);
  40. const idx = files.find((f) => f.name == "index.csv");
  41. const folderName = idx.webkitRelativePath.replace(idx.name, "");
  42. //console.debug(idx);
  43. //console.debug(folderName);
  44. const data = await idx.text();
  45. //console.debug(data);
  46. const csvEntries = data
  47. .split("\n")
  48. .slice(1)
  49. .filter((line) => line.length > 0)
  50. .map((line) => line.split(","))
  51. .map((vec) => {
  52. const obj = {};
  53. vec.forEach((val, i) => (obj[header[i]] = val));
  54. return obj;
  55. });
  56. //console.debug(csvEntries);
  57. const blockExercMap = csvEntries.reduce(prepareData, new Map());
  58. //console.log(Array.from(blockExercMatrix.entries()));
  59. const getFilePath = async function (submission) {
  60. const path = `${folderName}${submission["file"]}`;
  61. const file = files.find((f) => f.webkitRelativePath == path);
  62. const text = await file.text();
  63. return text;
  64. };
  65. const matrix = {};
  66. let counter = 0;
  67. blockExercMap.forEach((studentsMap, exercID) => {
  68. const column = [];
  69. studentsMap.forEach(async (submissions, studentID) => {
  70. submissions = submissions.sort((a, b) => {
  71. return parseInt(a["timestamp"]) - parseInt(b["timestamp"]);
  72. });
  73. counter++;
  74. submissions.forEach(async (submission, index, array) => {
  75. counter++;
  76. const student = {};
  77. student["grade"] = Math.max(0, parseFloat(submission["grade"]));
  78. student["timestamp"] = parseInt(submission["timestamp"]);
  79. student["student_id"] = studentID;
  80. student["TES"] = 0;
  81. student["DES"] = 0;
  82. student["D/T"] = 0;
  83. let previousCode = "";
  84. if (index > 0) {
  85. student["TES"] =
  86. parseInt(submission["timestamp"]) -
  87. parseInt(array[index - 1]["timestamp"]);
  88. const previousFile = await getFilePath(array[index - 1]);
  89. const previous = window.ivprogCore
  90. .prepareActivityToStudentHelper(previousFile)
  91. .getOrElse(1);
  92. if (previous == 1) {
  93. console.error(
  94. `A submission from ${studentID} to ${exercID} is invalid`
  95. );
  96. return;
  97. }
  98. previousCode = generateSubCode(previous.algorithmInIlm);
  99. }
  100. const currentFile = await getFilePath(submission);
  101. const current = window.ivprogCore
  102. .prepareActivityToStudentHelper(currentFile)
  103. .getOrElse(2);
  104. if (current == 2) {
  105. console.error(
  106. `A submission from ${studentID} to ${exercID} is invalid`
  107. );
  108. return;
  109. }
  110. const currentCode = generateSubCode(current.algorithmInIlm);
  111. if (previousCode === "") {
  112. const logs = JSON.parse(currentFile.split("::logs::")[1]);
  113. const event = logs[0];
  114. if (event == null) {
  115. // empty submission
  116. student["TES"] = 0;
  117. } else if (event.length === 4) {
  118. student["TES"] =
  119. parseInt(submission["timestamp"]) -
  120. Math.floor(parseInt(event[2]) / 1000);
  121. } else {
  122. student["TES"] =
  123. parseInt(submission["timestamp"]) -
  124. Math.floor(parseInt(event[1]) / 1000);
  125. }
  126. }
  127. student["DES"] = window.ivprogCore.levenshteinDistance(
  128. previousCode,
  129. currentCode
  130. );
  131. const ratio =
  132. student["TES"] === 0 ? 0 : student["DES"] / student["TES"];
  133. student["D/T"] = isNaN(ratio) ? 0 : ratio;
  134. column.push(student);
  135. counter--;
  136. });
  137. counter--;
  138. });
  139. matrix[exercID] = column;
  140. });
  141. function download (file, text) {
  142. //creating an invisible element
  143. const element = document.createElement("a");
  144. element.setAttribute(
  145. "href",
  146. "data:text/plain," + encodeURIComponent(text)
  147. );
  148. element.setAttribute("download", file);
  149. element.innerHTML = file;
  150. element.classList.add("ui", "primary", "button");
  151. // Above code is equivalent to
  152. // <a href="path of file" download="file name">
  153. document.querySelector("#downloads").appendChild(element);
  154. }
  155. function getExercHeader (id) {
  156. const props = ["TES", "DES", "grade", "D/T", "timestamp"];
  157. return props.reduce((acc, prop) => acc + `${id}_${prop},`, "");
  158. }
  159. const id = setInterval(() => {
  160. if (counter == 0) {
  161. clearInterval(id);
  162. for (const exercID in matrix) {
  163. let csv = "";
  164. let firstLine = "student_id,";
  165. firstLine += getExercHeader(exercID);
  166. for (const submission of matrix[exercID]) {
  167. csv += `${submission["student_id"]},`;
  168. csv += `${submission["TES"]},`;
  169. csv += `${submission["DES"]},`;
  170. csv += `${submission["grade"]},`;
  171. csv += `${submission["D/T"]},`;
  172. csv += `${submission["timestamp"]}`;
  173. csv += "\n";
  174. }
  175. download(`${exercID}.csv`, `${firstLine}\n${csv}`);
  176. }
  177. }
  178. }, 1000);
  179. });
  180. }