| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Secure TASK Submission</title> |
|
|
| |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.15.3/ace.js"></script> |
|
|
| <style> |
| .editor{height:400px;width:100%;font-size:16px} |
| .typewriter-cursor{display:inline-block;width:10px;height:20px;background:#000;animation:blink 1s step-end infinite} |
| @keyframes blink{from,to{background:transparent}50%{background:#000}} |
| .hidden{display:none} |
| .shake{animation:shake .5s} |
| @keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-5px)}40%,80%{transform:translateX(5px)}} |
| </style> |
| </head> |
| <body class="bg-gray-100 min-h-screen"> |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="bg-blue-600 text-white p-4 rounded-lg shadow-md mb-8"> |
| <div class="flex justify-between items-center"> |
| <h1 class="text-2xl font-bold">Secure TASK Submission</h1> |
| <div id="appMode" class="bg-blue-800 px-3 py-1 rounded-full text-sm">Student Mode</div> |
| </div> |
| </header> |
|
|
| |
| <div class="bg-white p-4 rounded-lg shadow-md mb-8"> |
| <div class="flex space-x-4"> |
| <button id="studentModeBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Student Mode</button> |
| <button id="teacherModeBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Teacher Mode</button> |
| </div> |
| </div> |
|
|
| |
| <div id="studentInterface" class="bg-white p-6 rounded-lg shadow-md"> |
| |
| <div id="studentInfoForm" class="mb-8"> |
| <h2 class="text-xl font-semibold mb-4">Student Information & Assignment Details</h2> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4"> |
| <div> |
| <label for="rollNumber" class="block text-sm font-medium text-gray-700 mb-1">Roll Number</label> |
| <input id="rollNumber" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div> |
| <label for="studentName" class="block text-sm font-medium text-gray-700 mb-1">Full Name</label> |
| <input id="studentName" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div class="grid grid-cols-2 gap-4"> |
| <div> |
| <label for="courseName" class="block text-sm font-medium text-gray-700 mb-1">Course Name</label> |
| <input id="courseName" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div> |
| <label for="assignmentNumber" class="block text-sm font-medium text-gray-700 mb-1">Assignment #</label> |
| <input id="assignmentNumber" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| </div> |
| </div> |
| </div> |
| <button id="startAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Start Assignment</button> |
| </div> |
|
|
| |
| <div id="assignmentArea" class="hidden"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-xl font-semibold">TASK Editor</h2> |
| <div class="flex items-center space-x-4"> |
| <div> |
| <label for="languageSelect" class="block text-sm font-medium text-gray-700 mb-1">Language</label> |
| <select id="languageSelect" class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| <option value="plaintext">Plain Text</option> |
| <option value="python">Python</option><option value="java">Java</option> |
| <option value="c_cpp">C/C++</option><option value="javascript">JavaScript</option> |
| <option value="html">HTML</option><option value="css">CSS</option> |
| </select> |
| </div> |
| <div class="text-sm bg-gray-200 px-3 py-1 rounded-full"> |
| <span id="charCount">0</span> characters typed |
| </div> |
| </div> |
| </div> |
|
|
| <div class="mb-4 p-4 bg-gray-100 rounded-md"> |
| <h3 class="font-medium mb-2">Assignment Instructions:</h3> |
| <p id="assignmentPrompt" class="text-gray-700">Type your assignment character by character. Copy-paste is not allowed. |
|
|
| </p> |
| </div> |
|
|
| <div class="relative"> |
| <div id="editor" class="editor border border-gray-300 rounded-md"></div> |
| <div id="typewriterOverlay" class="absolute inset-0 bg-white bg-opacity-90 flex items-center justify-center hidden"> |
| <div class="text-center p-8 max-w-lg"> |
| <h3 class="text-xl font-semibold mb-4">Typewriter Mode Active</h3> |
| <p class="mb-6">You must type your code character by character. Copy-paste is disabled to ensure academic integrity.</p> |
| <div class="bg-gray-200 p-4 rounded-md mb-6"> |
| <p class="font-mono text-lg"><span id="typedContent"></span><span class="typewriter-cursor"></span></p> |
| </div> |
| <button id="resumeTypingBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Continue Typing</button> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="mt-4 flex justify-between items-center"> |
| <div class="text-sm text-gray-600"><span id="lastSaved"></span></div> |
| <div class="space-x-2"> |
| <button id="submitAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Assignment</button> |
| <button id="saveDraftBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Save Draft</button> |
| </div> |
| </div> |
|
|
| |
| <div id="studentInfoDisplay" class="mt-6 p-4 bg-gray-100 rounded-md"> |
| <h3 class="font-medium mb-2">Submission Information</h3> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
| <div><p class="text-sm text-gray-600">Roll Number</p><p id="displayRollNumber" class="font-medium"></p></div> |
| <div><p class="text-sm text-gray-600">Full Name</p><p id="displayStudentName" class="font-medium"></p></div> |
| <div class="grid grid-cols-2 gap-4"> |
| <div><p class="text-sm text-gray-600">Course Name</p><p id="displayCourseName" class="font-medium"></p></div> |
| <div><p class="text-sm text-gray-600">Assignment #</p><p id="displayAssignmentNumber" class="font-medium"></p></div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="teacherInterface" class="bg-white p-6 rounded-lg shadow-md hidden"> |
| <h2 class="text-xl font-semibold mb-4">Teacher Dashboard</h2> |
|
|
| |
| <div class="mb-6"> |
| <label for="assignmentFile" class="block text-sm font-medium text-gray-700 mb-2">Upload Student Assignment</label> |
| <div class="flex items-center space-x-4"> |
| <input id="assignmentFile" type="file" accept=".json,.task" class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> |
| <button id="uploadAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Upload</button> |
| </div> |
| <p class="text-sm text-gray-500 mt-2">Only assignments created with this app can be viewed.</p> |
| </div> |
|
|
| |
| <div id="assignmentVerification" class="hidden p-4 border rounded-md mb-6"> |
| <div class="flex items-center mb-2"> |
| <span id="verificationIcon" class="text-2xl mr-2"></span> |
| <h3 id="verificationResult" class="font-semibold"></h3> |
| </div> |
| <p id="verificationDetails" class="text-sm"></p> |
| </div> |
|
|
| |
| <div id="assignmentViewer" class="hidden"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-medium">Assignment Submission</h3> |
| <div class="text-sm bg-gray-200 px-3 py-1 rounded-full"><span id="submissionCharCount">0</span> characters</div> |
| </div> |
|
|
| <div class="mb-4 p-4 bg-gray-100 rounded-md"> |
| <h4 class="font-medium mb-2">Student Information:</h4> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div><p class="text-sm text-gray-600">Roll Number</p><p id="submissionRollNumber" class="font-medium"></p></div> |
| <div><p class="text-sm text-gray-600">Full Name</p><p id="submissionStudentName" class="font-medium"></p></div> |
| <div><p class="text-sm text-gray-600">Course Name</p><p id="submissionCourseName" class="font-medium"></p></div> |
| <div><p class="text-sm text-gray-600">Assignment #</p><p id="submissionAssignmentNumber" class="font-medium"></p></div> |
| </div> |
| </div> |
|
|
| <div class="mb-4 p-4 bg-gray-100 rounded-md"> |
| <h4 class="font-medium mb-2">Assignment Instructions:</h4> |
| <p id="submissionPrompt" class="text-gray-700"></p> |
| </div> |
|
|
| <div class="border border-gray-300 rounded-md p-4 bg-white"> |
| <pre id="submissionContent" class="whitespace-pre-wrap font-mono text-sm"></pre> |
| </div> |
|
|
| <div class="mt-4 flex justify-end"> |
| <button id="downloadAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Submission</button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <script> |
| |
| const studentModeBtn = document.getElementById('studentModeBtn'); |
| const teacherModeBtn = document.getElementById('teacherModeBtn'); |
| const appMode = document.getElementById('appMode'); |
| const studentInterface= document.getElementById('studentInterface'); |
| const teacherInterface= document.getElementById('teacherInterface'); |
| |
| |
| const studentInfoForm = document.getElementById('studentInfoForm'); |
| const assignmentArea = document.getElementById('assignmentArea'); |
| const rollNumberInput = document.getElementById('rollNumber'); |
| const studentNameInput= document.getElementById('studentName'); |
| const courseNameInput = document.getElementById('courseName'); |
| const assignmentNumberInput = document.getElementById('assignmentNumber'); |
| const startAssignmentBtn = document.getElementById('startAssignmentBtn'); |
| |
| const displayRollNumber = document.getElementById('displayRollNumber'); |
| const displayStudentName = document.getElementById('displayStudentName'); |
| const displayCourseName = document.getElementById('displayCourseName'); |
| const displayAssignmentNumber = document.getElementById('displayAssignmentNumber'); |
| |
| const languageSelect = document.getElementById('languageSelect'); |
| const charCount = document.getElementById('charCount'); |
| const submitAssignmentBtn = document.getElementById('submitAssignmentBtn'); |
| const saveDraftBtn = document.getElementById('saveDraftBtn'); |
| const lastSaved = document.getElementById('lastSaved'); |
| |
| const typewriterOverlay= document.getElementById('typewriterOverlay'); |
| const typedContent = document.getElementById('typedContent'); |
| const resumeTypingBtn = document.getElementById('resumeTypingBtn'); |
| |
| |
| const assignmentFile = document.getElementById('assignmentFile'); |
| const uploadAssignmentBtn = document.getElementById('uploadAssignmentBtn'); |
| const assignmentVerification = document.getElementById('assignmentVerification'); |
| const verificationIcon = document.getElementById('verificationIcon'); |
| const verificationResult = document.getElementById('verificationResult'); |
| const verificationDetails = document.getElementById('verificationDetails'); |
| const assignmentViewer = document.getElementById('assignmentViewer'); |
| |
| const submissionRollNumber = document.getElementById('submissionRollNumber'); |
| const submissionStudentName = document.getElementById('submissionStudentName'); |
| const submissionCourseName = document.getElementById('submissionCourseName'); |
| const submissionAssignmentNumber= document.getElementById('submissionAssignmentNumber'); |
| const submissionPrompt = document.getElementById('submissionPrompt'); |
| const submissionContent = document.getElementById('submissionContent'); |
| const submissionCharCount = document.getElementById('submissionCharCount'); |
| const downloadAssignmentBtn = document.getElementById('downloadAssignmentBtn'); |
| |
| |
| let studentInfoLocked = false; |
| let editor; |
| let lastSaveTime = null; |
| let currentContent='', typedPosition=0, typingTimeout; |
| |
| |
| async function sha256(text){ |
| const data = new TextEncoder().encode(text); |
| const digest = await crypto.subtle.digest('SHA-256', data); |
| return [...new Uint8Array(digest)].map(b=>b.toString(16).padStart(2,'0')).join(''); |
| } |
| |
| |
| async function deriveKey(roll, name, ts){ |
| const seed = new TextEncoder().encode(`${roll}:${name}:${ts}`); |
| const hash = await crypto.subtle.digest('SHA-256', seed); |
| return crypto.subtle.importKey('raw', hash, 'AES-GCM', false, ['encrypt','decrypt']); |
| } |
| function strToUtf8(str){ return new TextEncoder().encode(str);} |
| function u8ToB64(u8){ |
| return btoa(String.fromCharCode(...u8)); |
| } |
| function b64ToU8(b64){ |
| return Uint8Array.from(atob(b64), c=>c.charCodeAt(0)); |
| } |
| |
| |
| async function encryptAssignment(obj){ |
| const key = await deriveKey(obj.rollNumber, obj.studentName, obj.timestamp); |
| const iv = crypto.getRandomValues(new Uint8Array(12)); |
| const ad = strToUtf8(`${obj.rollNumber}:${obj.timestamp}`); |
| |
| const plaintext = strToUtf8(JSON.stringify(obj)); |
| const cipherBuf = await crypto.subtle.encrypt({name:'AES-GCM',iv,additionalData:ad}, key, plaintext); |
| |
| return { |
| iv: u8ToB64(iv), |
| ad: u8ToB64(ad), |
| ct: u8ToB64(new Uint8Array(cipherBuf)), |
| meta:{ |
| rollNumber: obj.rollNumber, |
| studentName: obj.studentName, |
| timestamp: obj.timestamp, |
| alg:'AES-GCM-256' |
| } |
| }; |
| } |
| |
| |
| async function decryptAssignment(pkg){ |
| const iv = b64ToU8(pkg.iv); |
| const ad = b64ToU8(pkg.ad); |
| const ct = b64ToU8(pkg.ct); |
| const {rollNumber,studentName,timestamp}=pkg.meta; |
| |
| const key = await deriveKey(rollNumber, studentName, timestamp); |
| const plainBuf = await crypto.subtle.decrypt({name:'AES-GCM',iv,additionalData:ad}, key, ct); |
| return JSON.parse(new TextDecoder().decode(plainBuf)); |
| } |
| |
| |
| function initEditor(){ |
| editor = ace.edit('editor'); |
| editor.setTheme('ace/theme/chrome'); |
| editor.session.setMode('ace/mode/plain_text'); |
| editor.setOptions({fontSize:'14px',showPrintMargin:false,behavioursEnabled:true}); |
| |
| editor.commands.addCommand({ |
| name:'insertBraces',bindKey:{win:'{',mac:'{'},exec(ed){ed.insert('{}');ed.navigateLeft(1);} |
| }); |
| |
| editor.commands.bindKeys({'Ctrl-V':null,'Command-V':null,'Ctrl-C':null,'Command-C':null,'Ctrl-X':null,'Command-X':null}); |
| editor.session.on('change',()=>{ |
| if(!studentInfoLocked) return; |
| updateCharCount(); lastSaveTime=new Date(); updateLastSaved(); |
| }); |
| } |
| |
| |
| function init(){ |
| initEditor(); |
| |
| editor.container.addEventListener('keydown',e=>{ |
| if(!studentInfoLocked) return; |
| if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='v'){e.preventDefault();showTypewriterOverlay();} |
| }); |
| |
| studentModeBtn.onclick = ()=>{studentInterface.classList.remove('hidden');teacherInterface.classList.add('hidden');appMode.textContent='Student Mode';}; |
| teacherModeBtn.onclick = ()=>{studentInterface.classList.add('hidden');teacherInterface.classList.remove('hidden');appMode.textContent='Teacher Mode';}; |
| |
| startAssignmentBtn.onclick = ()=>{ |
| const roll=rollNumberInput.value.trim(), name=studentNameInput.value.trim(), |
| course=courseNameInput.value.trim(), num=assignmentNumberInput.value.trim(); |
| if(!roll||!name||!course||!num){alert('Please fill in all required fields');return;} |
| |
| studentInfoLocked=true; |
| displayRollNumber.textContent=roll; |
| displayStudentName.textContent=name; |
| displayCourseName.textContent=course; |
| displayAssignmentNumber.textContent=num; |
| studentInfoForm.classList.add('hidden'); assignmentArea.classList.remove('hidden'); editor.focus(); |
| }; |
| |
| languageSelect.onchange = ()=>{ |
| const map={python:'python',java:'java',c_cpp:'c_cpp',javascript:'javascript',html:'html',css:'css'}; |
| editor.session.setMode(`ace/mode/${map[languageSelect.value]||'plain_text'}`); |
| }; |
| |
| saveDraftBtn.onclick = ()=>{saveDraft();}; |
| submitAssignmentBtn.onclick = ()=>{submitAssignment();}; |
| resumeTypingBtn.onclick = ()=>{typewriterOverlay.classList.add('hidden');editor.focus();}; |
| |
| uploadAssignmentBtn.onclick = ()=>{verifyAssignment();}; |
| downloadAssignmentBtn.onclick = ()=>{downloadSubmission();}; |
| |
| setInterval(()=>{if(studentInfoLocked&&lastSaveTime){saveDraft();}},30000); |
| |
| updateCharCount(); updateLastSaved(); |
| } |
| |
| |
| function updateCharCount(){charCount.textContent=editor.getValue().length;} |
| function updateLastSaved(){ |
| lastSaved.textContent=lastSaveTime ? `Last saved: ${lastSaveTime.toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:true})}`:'Not saved yet'; |
| } |
| |
| |
| function showTypewriterOverlay(){ |
| currentContent=editor.getValue();typedPosition=0;typedContent.textContent=''; |
| typewriterOverlay.classList.remove('hidden'); |
| const warn=document.createElement('div');warn.className='text-red-500 font-medium mb-4';warn.textContent='You must type one character at a time!'; |
| typewriterOverlay.querySelector('.text-center').prepend(warn); typeNextCharacter(); |
| } |
| function typeNextCharacter(){if(typedPosition<currentContent.length){typedContent.textContent+=currentContent.charAt(typedPosition++);typingTimeout=setTimeout(typeNextCharacter,Math.random()*100+50);}} |
| |
| |
| async function saveDraft(){ |
| if(!studentInfoLocked) return; |
| const data = { |
| rollNumber:displayRollNumber.textContent, studentName:displayStudentName.textContent, |
| courseName:displayCourseName.textContent, assignmentNumber:displayAssignmentNumber.textContent, |
| language:languageSelect.value, content:editor.getValue(), |
| prompt:document.getElementById('assignmentPrompt').textContent, |
| timestamp:new Date().toISOString(), |
| hash:await sha256(editor.getValue()) |
| }; |
| localStorage.setItem('assignmentDraft',JSON.stringify(data)); |
| lastSaveTime=new Date();updateLastSaved(); |
| saveDraftBtn.textContent='Saved!';setTimeout(()=>{saveDraftBtn.textContent='Save Draft';},2000); |
| } |
| |
| |
| async function submitAssignment(){ |
| if(!studentInfoLocked) return; |
| |
| const payload = { |
| rollNumber:displayRollNumber.textContent, studentName:displayStudentName.textContent, |
| courseName:displayCourseName.textContent, assignmentNumber:displayAssignmentNumber.textContent, |
| language:languageSelect.value, content:editor.getValue(), |
| prompt:document.getElementById('assignmentPrompt').textContent, |
| timestamp:new Date().toISOString(), |
| hash:await sha256(editor.getValue()) |
| }; |
| |
| |
| const encryptedPkg = await encryptAssignment(payload); |
| const fileText = JSON.stringify(encryptedPkg); |
| |
| const blob = new Blob([fileText], {type:'application/octet-stream'}); |
| const url = URL.createObjectURL(blob); |
| const a = document.createElement('a'); |
| a.href=url; a.download=`assignment_${payload.rollNumber}.task`; document.body.appendChild(a); a.click(); |
| document.body.removeChild(a); URL.revokeObjectURL(url); |
| |
| localStorage.removeItem('assignmentDraft'); editor.setValue(''); updateCharCount(); |
| } |
| |
| |
| async function verifyAssignment(){ |
| const file=assignmentFile.files[0]; |
| if(!file){alert('Please select a file');return;} |
| |
| |
| if (!file.name.toLowerCase().endsWith('.task')) { |
| showVerificationResult(false, |
| 'Wrong file type – please upload a ".task" assignment file.'); |
| return; |
| } |
| const reader=new FileReader(); |
| reader.onload=async e=>{ |
| try{ |
| const encryptedPkg=JSON.parse(e.target.result); |
| const data = await decryptAssignment(encryptedPkg); |
| |
| |
| const required=['rollNumber','studentName','content','hash']; |
| if(required.some(k=>!data[k])){showVerificationResult(false,'Missing required fields');return;} |
| |
| const expectedHash=await sha256(data.content); |
| if(expectedHash!==data.hash){showVerificationResult(false,'Content hash mismatch');return;} |
| |
| showVerificationResult(true,'Valid encrypted submission'); displayAssignment(data); |
| }catch(err){ |
| showVerificationResult(false,'Decryption failed – file was modified or wrong key'); |
| } |
| }; |
| reader.readAsText(file); |
| } |
| |
| |
| function displayAssignment(d){ |
| submissionRollNumber.textContent=d.rollNumber; |
| submissionStudentName.textContent=d.studentName; |
| submissionCourseName.textContent=d.courseName||'N/A'; |
| submissionAssignmentNumber.textContent=d.assignmentNumber||'N/A'; |
| submissionPrompt.textContent=d.prompt; |
| submissionContent.textContent=d.content; |
| submissionCharCount.textContent=d.content.length; |
| |
| const map={python:'python',java:'java',c_cpp:'cpp',javascript:'javascript',html:'html',css:'css'}; |
| submissionContent.className=`whitespace-pre-wrap font-mono text-sm language-${map[d.language]||''}`; |
| assignmentViewer.classList.remove('hidden'); |
| } |
| |
| |
| function showVerificationResult(ok,msg){ |
| assignmentVerification.classList.remove('hidden'); |
| if(ok){ |
| verificationIcon.innerHTML='<i class="fas fa-check-circle text-green-500"></i>'; |
| verificationResult.textContent='Valid Submission'; |
| verificationResult.className='font-semibold text-green-600'; |
| }else{ |
| verificationIcon.innerHTML='<i class="fas fa-times-circle text-red-500"></i>'; |
| verificationResult.textContent='Invalid Submission'; |
| verificationResult.className='font-semibold text-red-600'; |
| assignmentViewer.classList.add('hidden'); |
| } |
| verificationDetails.textContent=msg; |
| } |
| |
| |
| async function downloadSubmission(){ |
| if(assignmentViewer.classList.contains('hidden')) return; |
| |
| |
| const data = { |
| rollNumber:submissionRollNumber.textContent, |
| studentName:submissionStudentName.textContent, |
| courseName:submissionCourseName.textContent, |
| assignmentNumber:submissionAssignmentNumber.textContent, |
| language:languageSelect.value, |
| content:submissionContent.textContent, |
| prompt:submissionPrompt.textContent, |
| timestamp:new Date().toISOString(), |
| hash:await sha256(submissionContent.textContent) |
| }; |
| |
| const encryptedPkg = await encryptAssignment(data); |
| const blob = new Blob([JSON.stringify(encryptedPkg)],{type:'application/octet-stream'}); |
| const url = URL.createObjectURL(blob); |
| const a=document.createElement('a'); |
| a.href=url; a.download=`assignment_${data.rollNumber}_checked.task`; |
| document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded',init); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Kast-KIIT/cms" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |
|
|