{"id":452,"date":"2025-02-17T00:39:56","date_gmt":"2025-02-16T22:39:56","guid":{"rendered":"https:\/\/fabianvinke.com\/?page_id=452"},"modified":"2025-02-17T00:45:18","modified_gmt":"2025-02-16T22:45:18","slug":"jetpunk","status":"publish","type":"page","link":"https:\/\/fabianvinke.com\/architektur\/jetpunk\/","title":{"rendered":"Jetpunk"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Quiz Platform<\/title>\n<style>\nhtml, body {\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  font-family: Arial, sans-serif;\n}\n#page-container {\n  display: flex;\n  flex-direction: column;\n  min-height: 100vh;\n}\n#content-wrap {\n  flex: 1;\n}\nheader {\n  background: #2980b9;\n  color: #fff;\n  padding: 10px 20px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n}\nheader nav a {\n  color: #fff;\n  margin: 0 10px;\n  text-decoration: none;\n}\nheader .search {\n  display: flex;\n  align-items: center;\n}\nheader .search input {\n  padding: 5px;\n  border: none;\n  border-radius: 3px;\n}\n#user-info {\n  margin-left: 10px;\n  font-weight: bold;\n}\n.container {\n  max-width: 1200px;\n  margin: auto;\n  padding: 20px;\n}\n.hidden {\n  display: none;\n}\n.quiz-list {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n  gap: 20px;\n}\n.quiz-card {\n  background: #fff;\n  padding: 15px;\n  border-radius: 5px;\n  box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n  position: relative;\n  cursor: pointer;\n}\n.quiz-card:hover {\n  box-shadow: 0 4px 10px rgba(0,0,0,0.2);\n}\n.quiz-card .delete-btn {\n  position: absolute;\n  top: 10px;\n  right: 10px;\n  background: #e74c3c;\n  border: none;\n  color: #fff;\n  padding: 5px 10px;\n  border-radius: 3px;\n  cursor: pointer;\n}\n#play-top-bar {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  background: #d9edf7;\n  padding: 10px;\n  border-radius: 4px;\n  margin-bottom: 10px;\n  color: #333;\n}\n#timer-display {\n  font-weight: bold;\n  margin-right: 10px;\n  min-width: 50px;\n  text-align: center;\n}\n#give-up {\n  background: #3498db;\n  border: none;\n  color: #fff;\n  padding: 6px 12px;\n  border-radius: 3px;\n  cursor: pointer;\n  margin-right: 10px;\n}\n#answer-input {\n  flex: 1;\n  padding: 8px;\n  border: 1px solid #ccc;\n  border-radius: 3px;\n  margin: 0 10px;\n}\n#found-counter {\n  min-width: 120px;\n  text-align: right;\n  font-weight: bold;\n}\n.quiz-table {\n  width: 100%;\n  border-collapse: collapse;\n  border: 2px solid #000;\n}\n.quiz-table th, .quiz-table td {\n  border: 1px solid #000;\n  padding: 8px;\n  vertical-align: top;\n}\n.correct-highlight {\n  background: lightgreen !important;\n}\nfooter {\n  background: #2980b9;\n  color: #fff;\n  text-align: center;\n  padding: 20px;\n  margin-top: auto;\n}\n#login-section, #register-section {\n  max-width: 400px;\n  margin: 20px auto;\n  background: #fff;\n  border-radius: 5px;\n  box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n  padding: 20px;\n}\n#login-section h2, #register-section h2 {\n  margin-top: 0;\n}\n#login-section input, #register-section input {\n  width: 100%;\n  margin-bottom: 10px;\n  padding: 8px;\n  box-sizing: border-box;\n}\n#login-btn, #register-btn {\n  background: #3498db;\n  color: #fff;\n  border: none;\n  padding: 8px 12px;\n  cursor: pointer;\n  border-radius: 3px;\n}\n#logout-btn {\n  background: #e74c3c;\n  color: #fff;\n  border: none;\n  padding: 8px 12px;\n  cursor: pointer;\n  border-radius: 3px;\n}\n#category-section {\n  margin-bottom: 20px;\n}\n#category-section select {\n  width: 200px;\n  padding: 5px;\n}\n.import-area {\n  margin-top: 20px;\n  background: #fff;\n  padding: 15px;\n  border-radius: 5px;\n  box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n}\n.import-area textarea {\n  width: 100%;\n  height: 100px;\n  margin-bottom: 10px;\n}\n@media(max-width: 768px) {\n  header {\n    flex-direction: column;\n    align-items: flex-start;\n  }\n  header .search {\n    margin-top: 10px;\n  }\n  #play-top-bar {\n    flex-direction: column;\n    align-items: flex-start;\n    gap: 10px;\n  }\n  #found-counter {\n    text-align: left;\n  }\n}\n<\/style>\n<\/head>\n<body>\n<div id=\"page-container\">\n  <header>\n    <div style=\"display:flex;align-items:center;\">\n      <h1 style=\"margin:0;padding:0;\">Quiz Platform<\/h1>\n      <div id=\"user-info\" class=\"hidden\"><\/div>\n    <\/div>\n    <nav>\n      <a href=\"#\" id=\"nav-home\">Home<\/a>\n      <a href=\"#\" id=\"nav-categories\">Categories<\/a>\n      <a href=\"#\" id=\"nav-create\">Create Quiz<\/a>\n      <a href=\"#\" id=\"nav-login\">Login<\/a>\n      <a href=\"#\" id=\"nav-register\">Register<\/a>\n      <button id=\"logout-btn\" class=\"hidden\">Logout<\/button>\n    <\/nav>\n    <div class=\"search\">\n      <input type=\"text\" id=\"search-input\" placeholder=\"Search quizzes\">\n    <\/div>\n  <\/header>\n  <div id=\"content-wrap\">\n    <div class=\"container\">\n      <div id=\"login-section\" class=\"hidden\">\n        <h2>Login<\/h2>\n        <input type=\"text\" id=\"login-username\" placeholder=\"Username\">\n        <input type=\"password\" id=\"login-password\" placeholder=\"Password\">\n        <button id=\"login-btn\">Login<\/button>\n      <\/div>\n      <div id=\"register-section\" class=\"hidden\">\n        <h2>Register<\/h2>\n        <input type=\"text\" id=\"register-username\" placeholder=\"Username\">\n        <input type=\"password\" id=\"register-password\" placeholder=\"Password\">\n        <button id=\"register-btn\">Register<\/button>\n      <\/div>\n      <div id=\"category-filter-section\" class=\"hidden\">\n        <h2>Filter by Category<\/h2>\n        <select id=\"category-filter-select\">\n          <option value=\"\">All Categories<\/option>\n        <\/select>\n      <\/div>\n      <div id=\"home-section\">\n        <h2>Available Quizzes<\/h2>\n        <button id=\"random-quiz\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;\">\n          Random Quiz\n        <\/button>\n        <div class=\"quiz-list\" id=\"quiz-list\"><\/div>\n      <\/div>\n      <div id=\"play-section\" class=\"hidden\">\n        <button id=\"back-to-home\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;margin-bottom:10px;\">\n          Back\n        <\/button>\n        <h2 id=\"quiz-title\"><\/h2>\n        <p id=\"quiz-description\"><\/p>\n        <div id=\"quiz-content\" class=\"hidden\">\n          <div id=\"play-top-bar\">\n            <div style=\"display:flex;align-items:center;\">\n              <span id=\"timer-display\"><\/span>\n              <button id=\"give-up\">Give Up?<\/button>\n            <\/div>\n            <input type=\"text\" id=\"answer-input\" placeholder=\"Type your answers here...\">\n            <div id=\"found-counter\"><\/div>\n          <\/div>\n          <table class=\"quiz-table\" id=\"quiz-table\"><\/table>\n        <\/div>\n        <div id=\"quiz-result\" class=\"hidden\"><\/div>\n      <\/div>\n      <div id=\"create-section\" class=\"hidden\">\n        <button id=\"back-from-create\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;margin-bottom:10px;\">\n          Back\n        <\/button>\n        <h2>Create Quiz<\/h2>\n        <input type=\"text\" id=\"new-quiz-title\" placeholder=\"Quiz Title\" required><br><br>\n        <textarea id=\"new-quiz-description\" placeholder=\"Quiz Description\" required style=\"width:100%;height:60px;\"><\/textarea><br><br>\n        <div id=\"category-section\">\n          <label>Categories (comma separated):<\/label><br>\n          <input type=\"text\" id=\"new-quiz-categories\" placeholder=\"e.g. Geography, Math\" style=\"width:100%;\">\n        <\/div>\n        <br>\n        <div id=\"questions-container\"><\/div>\n        <button type=\"button\" id=\"add-question\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;\">\n          Add Question\n        <\/button>\n        <br><br>\n        <div class=\"import-area\">\n          <h4>Import Questions from Text (format: Question:Answer on each line)<\/h4>\n          <textarea id=\"import-text\"><\/textarea>\n          <button id=\"import-text-btn\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;\">Import Text<\/button>\n          <h4>Import from CSV file (Question,Answer on each row)<\/h4>\n          <input type=\"file\" id=\"csv-file\">\n          <button id=\"import-csv-btn\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;\">Import CSV<\/button>\n        <\/div>\n        <br>\n        <button type=\"submit\" id=\"save-quiz-btn\" style=\"background:#3498db;color:#fff;border:none;padding:8px 12px;border-radius:3px;cursor:pointer;\">\n          Save Quiz\n        <\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n  <footer>\n    <div>\n      <a href=\"#\" style=\"color:#fff;\">About<\/a> |\n      <a href=\"#\" style=\"color:#fff;\">Contact<\/a> |\n      <a href=\"#\" style=\"color:#fff;\">Terms of Service<\/a>\n    <\/div>\n  <\/footer>\n<\/div>\n<script>\nlet quizzes = [];\nlet users = [];\nlet currentQuiz = null;\nlet solvedCount = 0;\nlet currentTimer = null;\nlet currentUser = null;\n\nif(localStorage.getItem('quizzes')){\n  quizzes = JSON.parse(localStorage.getItem('quizzes'));\n} else {\n  quizzes = [];\n  localStorage.setItem('quizzes', JSON.stringify(quizzes));\n}\nif(localStorage.getItem('users')){\n  users = JSON.parse(localStorage.getItem('users'));\n} else {\n  users = [];\n  localStorage.setItem('users', JSON.stringify(users));\n}\nif(localStorage.getItem('loggedInUser')){\n  currentUser = localStorage.getItem('loggedInUser');\n  updateUIForLoggedInUser();\n}\n\nfunction updateUIForLoggedInUser(){\n  const userInfo = document.getElementById('user-info');\n  const logoutBtn = document.getElementById('logout-btn');\n  if(currentUser){\n    let userObj = getUserObject(currentUser);\n    if(userObj){\n      userInfo.innerText = \"Welcome, \" + userObj.username + \" | Score: \" + (userObj.score || 0);\n      userInfo.classList.remove('hidden');\n      logoutBtn.classList.remove('hidden');\n      document.getElementById('nav-login').classList.add('hidden');\n      document.getElementById('nav-register').classList.add('hidden');\n    }\n  } else {\n    userInfo.classList.add('hidden');\n    logoutBtn.classList.add('hidden');\n    document.getElementById('nav-login').classList.remove('hidden');\n    document.getElementById('nav-register').classList.remove('hidden');\n  }\n}\n\nfunction getUserObject(username){\n  return users.find(u => u.username === username);\n}\n\ndocument.getElementById('logout-btn').addEventListener('click', ()=>{\n  currentUser = null;\n  localStorage.removeItem('loggedInUser');\n  updateUIForLoggedInUser();\n  showHome();\n});\n\nfunction renderQuizList(filter=\"\", categoryFilter=\"\"){\n  const quizListDiv = document.getElementById('quiz-list');\n  quizListDiv.innerHTML = \"\";\n  let filteredQuizzes = quizzes.filter(q => q.title.toLowerCase().includes(filter.toLowerCase()));\n  if(categoryFilter){\n    filteredQuizzes = filteredQuizzes.filter(q => q.categories && q.categories.includes(categoryFilter));\n  }\n  filteredQuizzes.forEach(q => {\n    const card = document.createElement('div');\n    card.className = \"quiz-card\";\n    card.innerHTML = `\n      <h3>${q.title}<\/h3>\n      <p>${q.description}<\/p>\n      <p style=\"font-style:italic;font-size:0.9em;\">Created by: ${q.creator || \"Unknown\"}<\/p>\n    `;\n    card.onclick = () => { startPlayQuiz(q.id); };\n    const delBtn = document.createElement('button');\n    delBtn.className = \"delete-btn\";\n    delBtn.innerText = \"Delete\";\n    delBtn.onclick = (e) => {\n      e.stopPropagation();\n      if(!currentUser){\n        alert(\"You must be logged in to delete quizzes.\");\n        return;\n      }\n      let userObj = getUserObject(currentUser);\n      if(!userObj) return;\n      \/\/ Only allow deletion if user is the creator or an admin (not implemented but you can adapt)\n      if(q.creator !== currentUser){\n        alert(\"You are not the creator of this quiz.\");\n        return;\n      }\n      if(confirm(\"Are you sure you want to delete this quiz?\")){\n        quizzes = quizzes.filter(quiz => quiz.id !== q.id);\n        localStorage.setItem('quizzes', JSON.stringify(quizzes));\n        renderQuizList();\n      }\n    };\n    card.appendChild(delBtn);\n    quizListDiv.appendChild(card);\n  });\n}\n\nrenderQuizList();\ndocument.getElementById('search-input').addEventListener('input', (e)=>{\n  const categoryFilter = document.getElementById('category-filter-select') ? document.getElementById('category-filter-select').value : \"\";\n  renderQuizList(e.target.value, categoryFilter);\n});\n\ndocument.getElementById('nav-home').addEventListener('click', showHome);\ndocument.getElementById('nav-categories').addEventListener('click', showCategoryFilter);\ndocument.getElementById('nav-create').addEventListener('click', showCreateQuiz);\ndocument.getElementById('nav-login').addEventListener('click', showLogin);\ndocument.getElementById('nav-register').addEventListener('click', showRegister);\n\nfunction showHome(){\n  hideAllSections();\n  document.getElementById('home-section').classList.remove('hidden');\n  document.getElementById('category-filter-section').classList.add('hidden');\n}\n\nfunction showCategoryFilter(){\n  hideAllSections();\n  document.getElementById('home-section').classList.remove('hidden');\n  document.getElementById('category-filter-section').classList.remove('hidden');\n  populateCategoryFilter();\n}\n\nfunction showCreateQuiz(){\n  hideAllSections();\n  if(!currentUser){\n    alert(\"You must be logged in to create a quiz.\");\n    showLogin();\n    return;\n  }\n  document.getElementById('create-section').classList.remove('hidden');\n}\n\nfunction showLogin(){\n  hideAllSections();\n  document.getElementById('login-section').classList.remove('hidden');\n}\n\nfunction showRegister(){\n  hideAllSections();\n  document.getElementById('register-section').classList.remove('hidden');\n}\n\nfunction hideAllSections(){\n  document.getElementById('home-section').classList.add('hidden');\n  document.getElementById('play-section').classList.add('hidden');\n  document.getElementById('create-section').classList.add('hidden');\n  document.getElementById('login-section').classList.add('hidden');\n  document.getElementById('register-section').classList.add('hidden');\n  document.getElementById('category-filter-section').classList.add('hidden');\n}\n\ndocument.getElementById('random-quiz').addEventListener('click', ()=>{\n  if(quizzes.length > 0){\n    const randomIndex = Math.floor(Math.random()*quizzes.length);\n    startPlayQuiz(quizzes[randomIndex].id);\n  }\n});\n\ndocument.getElementById('back-to-home').addEventListener('click', ()=>{\n  clearInterval(currentTimer);\n  showHome();\n});\n\nlet startTime = 0;\nfunction startPlayQuiz(id){\n  hideAllSections();\n  document.getElementById('play-section').classList.remove('hidden');\n  currentQuiz = quizzes.find(q=> q.id === id);\n  solvedCount = 0;\n  document.getElementById('quiz-title').innerText = currentQuiz.title;\n  document.getElementById('quiz-description').innerText = currentQuiz.description;\n  const quizTable = document.getElementById('quiz-table');\n  quizTable.innerHTML = \"\";\n\n  const headerRow = document.createElement('tr');\n  const hintHeader = document.createElement('th');\n  hintHeader.innerText = \"Hint\";\n  const answerHeader = document.createElement('th');\n  answerHeader.innerText = \"Answer\";\n  headerRow.appendChild(hintHeader);\n  headerRow.appendChild(answerHeader);\n  quizTable.appendChild(headerRow);\n\n  currentQuiz.questions.forEach((q,i)=>{\n    const row = document.createElement('tr');\n    const hintCell = document.createElement('td');\n    hintCell.innerText = q.hint;\n    const answerCell = document.createElement('td');\n    answerCell.dataset.correct = q.answer.toLowerCase();\n    answerCell.dataset.solved = \"false\";\n    row.appendChild(hintCell);\n    row.appendChild(answerCell);\n    quizTable.appendChild(row);\n  });\n\n  document.getElementById('found-counter').innerText = \"0 \/ \" + currentQuiz.questions.length + \" found\";\n  document.getElementById('quiz-result').classList.add('hidden');\n  document.getElementById('quiz-content').classList.remove('hidden');\n  document.getElementById('answer-input').value = \"\";\n  document.getElementById('timer-display').innerText = \"\";\n  clearInterval(currentTimer);\n\n  \/\/ Check if user has completed quiz before\n  if(currentUser){\n    let userObj = getUserObject(currentUser);\n    if(userObj && userObj.completedQuizzes && userObj.completedQuizzes[currentQuiz.id]){\n      let bestTime = userObj.completedQuizzes[currentQuiz.id].bestTime;\n      if(bestTime !== undefined){\n        alert(\"You have completed this quiz before! Your best time was: \" + bestTime + \" seconds.\");\n      }\n    }\n  }\n\n  startTime = Date.now();\n  startTimer(120, document.getElementById('timer-display'), function(){\n    giveUpQuiz();\n  });\n}\n\nfunction startTimer(duration, display, callback){\n  let timer = duration, minutes, seconds;\n  currentTimer = setInterval(function(){\n    minutes = parseInt(timer\/60,10);\n    seconds = parseInt(timer%60,10);\n    minutes = minutes < 10 ? \"0\" + minutes : minutes;\n    seconds = seconds < 10 ? \"0\" + seconds : seconds;\n    display.textContent = minutes + \":\" + seconds;\n    if(--timer < 0){\n      clearInterval(currentTimer);\n      callback();\n    }\n  }, 1000);\n}\n\ndocument.getElementById('give-up').addEventListener('click', ()=>{\n  clearInterval(currentTimer);\n  giveUpQuiz();\n});\n\nfunction giveUpQuiz(){\n  const rows = document.querySelectorAll('#quiz-table tr');\n  let i = 0;\n  rows.forEach(row=>{\n    if(i>0){\n      const cells = row.querySelectorAll('td');\n      const answerCell = cells[1];\n      if(answerCell.dataset.solved === \"false\"){\n        answerCell.innerText = answerCell.dataset.correct;\n        answerCell.style.backgroundColor = \"#f8d7da\";\n      }\n    }\n    i++;\n  });\n  showResults();\n}\n\nfunction showResults(){\n  const resultDiv = document.getElementById('quiz-result');\n  resultDiv.classList.remove('hidden');\n  resultDiv.innerHTML = \"Score: \" + solvedCount + \" \/ \" + currentQuiz.questions.length +\n    \" (\" + Math.round((solvedCount\/currentQuiz.questions.length)*100) + \"%)\";\n  \/\/ If user is logged in, update best time, user score, etc.\n  if(currentUser){\n    let userObj = getUserObject(currentUser);\n    if(userObj){\n      let timeTaken = Math.floor((Date.now() - startTime)\/1000);\n      if(!userObj.completedQuizzes) userObj.completedQuizzes = {};\n      if(!userObj.completedQuizzes[currentQuiz.id]){\n        userObj.completedQuizzes[currentQuiz.id] = { times: [], bestTime: null };\n      }\n      userObj.completedQuizzes[currentQuiz.id].times.push(timeTaken);\n      if(userObj.completedQuizzes[currentQuiz.id].bestTime === null || timeTaken < userObj.completedQuizzes[currentQuiz.id].bestTime){\n        userObj.completedQuizzes[currentQuiz.id].bestTime = timeTaken;\n      }\n      \/\/ Update user score\n      let points = solvedCount;\n      userObj.score = (userObj.score || 0) + points;\n      updateUser(userObj);\n      updateUIForLoggedInUser();\n    }\n  }\n}\n\ndocument.getElementById('answer-input').addEventListener('input', function(){\n  const guess = this.value.trim().toLowerCase();\n  if(!guess) return;\n  const rows = document.querySelectorAll('#quiz-table tr');\n  let i = 0;\n  let foundMatch = false;\n  rows.forEach(row=>{\n    if(i>0){\n      const cells = row.querySelectorAll('td');\n      const answerCell = cells[1];\n      if(answerCell.dataset.solved === \"false\" && guess === answerCell.dataset.correct){\n        answerCell.innerText = answerCell.dataset.correct;\n        answerCell.dataset.solved = \"true\";\n        solvedCount++;\n        answerCell.classList.add('correct-highlight');\n        setTimeout(()=>{ answerCell.classList.remove('correct-highlight'); }, 1000);\n        foundMatch = true;\n      }\n    }\n    i++;\n  });\n  if(foundMatch){\n    this.value = \"\";\n    document.getElementById('found-counter').innerText = solvedCount + \" \/ \" + currentQuiz.questions.length + \" found\";\n    if(solvedCount === currentQuiz.questions.length){\n      clearInterval(currentTimer);\n      showResults();\n    }\n  }\n});\n\nfunction updateUser(userObj){\n  let index = users.findIndex(u => u.username === userObj.username);\n  if(index !== -1){\n    users[index] = userObj;\n    localStorage.setItem('users', JSON.stringify(users));\n  }\n}\n\ndocument.getElementById('add-question').addEventListener('click', function(){\n  const container = document.getElementById('questions-container');\n  const div = document.createElement('div');\n  div.innerHTML = '<input type=\"text\" placeholder=\"Question Hint\" required style=\"margin-right:5px;\">'\n                + '<input type=\"text\" placeholder=\"Correct Answer\" required><br><br>';\n  container.appendChild(div);\n});\n\ndocument.getElementById('import-text-btn').addEventListener('click', function(){\n  const importText = document.getElementById('import-text').value.trim();\n  if(!importText) return;\n  const container = document.getElementById('questions-container');\n  const lines = importText.split('\\n');\n  lines.forEach(line=>{\n    const parts = line.split(':');\n    if(parts.length === 2){\n      const question = parts[0].trim();\n      const answer = parts[1].trim();\n      const div = document.createElement('div');\n      div.innerHTML = `<input type=\"text\" placeholder=\"Question Hint\" value=\"${question}\" required style=\"margin-right:5px;\">`\n                    + `<input type=\"text\" placeholder=\"Correct Answer\" value=\"${answer}\" required><br><br>`;\n      container.appendChild(div);\n    }\n  });\n  document.getElementById('import-text').value = \"\";\n});\n\ndocument.getElementById('import-csv-btn').addEventListener('click', function(){\n  const fileInput = document.getElementById('csv-file');\n  if(fileInput.files.length === 0) return;\n  const file = fileInput.files[0];\n  const reader = new FileReader();\n  reader.onload = function(e){\n    const text = e.target.result;\n    const lines = text.split('\\n');\n    const container = document.getElementById('questions-container');\n    lines.forEach(line=>{\n      const parts = line.split(',');\n      if(parts.length >= 2){\n        const question = parts[0].trim();\n        const answer = parts[1].trim();\n        const div = document.createElement('div');\n        div.innerHTML = `<input type=\"text\" placeholder=\"Question Hint\" value=\"${question}\" required style=\"margin-right:5px;\">`\n                      + `<input type=\"text\" placeholder=\"Correct Answer\" value=\"${answer}\" required><br><br>`;\n        container.appendChild(div);\n      }\n    });\n    fileInput.value = \"\";\n  };\n  reader.readAsText(file);\n});\n\ndocument.getElementById('save-quiz-btn').addEventListener('click', function(){\n  const title = document.getElementById('new-quiz-title').value.trim();\n  const description = document.getElementById('new-quiz-description').value.trim();\n  const categoriesInput = document.getElementById('new-quiz-categories').value.trim();\n  if(!title || !description){\n    alert(\"Title and Description are required.\");\n    return;\n  }\n  const questionsDiv = document.getElementById('questions-container');\n  const questionElements = questionsDiv.querySelectorAll('div');\n  const questions = [];\n  questionElements.forEach(div=>{\n    const inputs = div.querySelectorAll('input');\n    if(inputs[0].value.trim() && inputs[1].value.trim()){\n      questions.push({hint: inputs[0].value.trim(), answer: inputs[1].value.trim()});\n    }\n  });\n  if(questions.length === 0){\n    alert(\"Please add at least one question.\");\n    return;\n  }\n  let categories = [];\n  if(categoriesInput){\n    categories = categoriesInput.split(',').map(c => c.trim()).filter(c => c !== \"\");\n  }\n  const newQuiz = {\n    id: Date.now(),\n    title,\n    description,\n    questions,\n    categories,\n    creator: currentUser\n  };\n  quizzes.push(newQuiz);\n  localStorage.setItem('quizzes', JSON.stringify(quizzes));\n\n  if(currentUser){\n    let userObj = getUserObject(currentUser);\n    if(userObj){\n      if(!userObj.createdQuizzes) userObj.createdQuizzes = [];\n      userObj.createdQuizzes.push(newQuiz.id);\n      updateUser(userObj);\n    }\n  }\n\n  document.getElementById('new-quiz-title').value = \"\";\n  document.getElementById('new-quiz-description').value = \"\";\n  document.getElementById('new-quiz-categories').value = \"\";\n  questionsDiv.innerHTML = \"\";\n  alert(\"Quiz created successfully.\");\n  renderQuizList();\n  showHome();\n});\n\ndocument.getElementById('login-btn').addEventListener('click', function(){\n  const username = document.getElementById('login-username').value.trim();\n  const password = document.getElementById('login-password').value.trim();\n  if(!username || !password) {\n    alert(\"Please enter username and password.\");\n    return;\n  }\n  let userObj = getUserObject(username);\n  if(!userObj){\n    alert(\"User not found.\");\n    return;\n  }\n  if(userObj.password !== password){\n    alert(\"Incorrect password.\");\n    return;\n  }\n  currentUser = username;\n  localStorage.setItem('loggedInUser', currentUser);\n  document.getElementById('login-username').value = \"\";\n  document.getElementById('login-password').value = \"\";\n  updateUIForLoggedInUser();\n  showHome();\n});\n\ndocument.getElementById('register-btn').addEventListener('click', function(){\n  const username = document.getElementById('register-username').value.trim();\n  const password = document.getElementById('register-password').value.trim();\n  if(!username || !password){\n    alert(\"Please enter username and password.\");\n    return;\n  }\n  let userObj = getUserObject(username);\n  if(userObj){\n    alert(\"Username already exists.\");\n    return;\n  }\n  let newUser = {\n    username,\n    password,\n    createdQuizzes: [],\n    completedQuizzes: {},\n    score: 0\n  };\n  users.push(newUser);\n  localStorage.setItem('users', JSON.stringify(users));\n  currentUser = username;\n  localStorage.setItem('loggedInUser', currentUser);\n  document.getElementById('register-username').value = \"\";\n  document.getElementById('register-password').value = \"\";\n  updateUIForLoggedInUser();\n  showHome();\n});\n\nfunction populateCategoryFilter(){\n  const categorySelect = document.getElementById('category-filter-select');\n  categorySelect.innerHTML = `<option value=\"\">All Categories<\/option>`;\n  let allCategories = [];\n  quizzes.forEach(q=>{\n    if(q.categories && q.categories.length){\n      q.categories.forEach(cat=>{\n        if(!allCategories.includes(cat)) allCategories.push(cat);\n      });\n    }\n  });\n  allCategories.forEach(cat=>{\n    const opt = document.createElement('option');\n    opt.value = cat;\n    opt.textContent = cat;\n    categorySelect.appendChild(opt);\n  });\n}\n\ndocument.getElementById('category-filter-select').addEventListener('change', function(){\n  const filterVal = document.getElementById('search-input').value;\n  renderQuizList(filterVal, this.value);\n});\n\nfunction showRegisterSection(){\n  hideAllSections();\n  document.getElementById('register-section').classList.remove('hidden');\n}\nfunction showLoginSection(){\n  hideAllSections();\n  document.getElementById('login-section').classList.remove('hidden');\n}\n\nrenderQuizList();\n<\/script>\n<\/body>\n\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quiz Platform Quiz Platform Home Categories Create Quiz Login Register Logout Login Login Register Register Filter by Category All Categories Available Quizzes Random Quiz Back Give Up? Back Create Quiz [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"class_list":["post-452","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Jetpunk - Fabian Vinke<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fabianvinke.com\/jetpunk\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Jetpunk - Fabian Vinke\" \/>\n<meta property=\"og:description\" content=\"Quiz Platform Quiz Platform Home Categories Create Quiz Login Register Logout Login Login Register Register Filter by Category All Categories Available Quizzes Random Quiz Back Give Up? Back Create Quiz [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fabianvinke.com\/jetpunk\/\" \/>\n<meta property=\"og:site_name\" content=\"Fabian Vinke\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-16T22:45:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"2048\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data1\" content=\"1\u00a0Minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/jetpunk\\\/\",\"url\":\"https:\\\/\\\/fabianvinke.com\\\/jetpunk\\\/\",\"name\":\"Jetpunk - Fabian Vinke\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/#website\"},\"datePublished\":\"2025-02-16T22:39:56+00:00\",\"dateModified\":\"2025-02-16T22:45:18+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/jetpunk\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/fabianvinke.com\\\/jetpunk\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/jetpunk\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Jetpunk\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/#website\",\"url\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/\",\"name\":\"Fabian Vinke\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/#\\\/schema\\\/person\\\/2816b7d60577ce6d8efde484ce234610\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/fabianvinke.com\\\/architektur\\\/#\\\/schema\\\/person\\\/2816b7d60577ce6d8efde484ce234610\",\"name\":\"Fabian\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/i0.wp.com\\\/fabianvinke.com\\\/architektur\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/logo_fv_gold.png?fit=2048%2C2048&ssl=1\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/fabianvinke.com\\\/architektur\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/logo_fv_gold.png?fit=2048%2C2048&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/fabianvinke.com\\\/architektur\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/logo_fv_gold.png?fit=2048%2C2048&ssl=1\",\"width\":2048,\"height\":2048,\"caption\":\"Fabian\"},\"logo\":{\"@id\":\"https:\\\/\\\/i0.wp.com\\\/fabianvinke.com\\\/architektur\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/logo_fv_gold.png?fit=2048%2C2048&ssl=1\"},\"sameAs\":[\"https:\\\/\\\/fabianvinke.com\\\/architektur\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Jetpunk - Fabian Vinke","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fabianvinke.com\/jetpunk\/","og_locale":"de_DE","og_type":"article","og_title":"Jetpunk - Fabian Vinke","og_description":"Quiz Platform Quiz Platform Home Categories Create Quiz Login Register Logout Login Login Register Register Filter by Category All Categories Available Quizzes Random Quiz Back Give Up? Back Create Quiz [&hellip;]","og_url":"https:\/\/fabianvinke.com\/jetpunk\/","og_site_name":"Fabian Vinke","article_modified_time":"2025-02-16T22:45:18+00:00","og_image":[{"width":2048,"height":2048,"url":"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Gesch\u00e4tzte Lesezeit":"1\u00a0Minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/fabianvinke.com\/jetpunk\/","url":"https:\/\/fabianvinke.com\/jetpunk\/","name":"Jetpunk - Fabian Vinke","isPartOf":{"@id":"https:\/\/fabianvinke.com\/architektur\/#website"},"datePublished":"2025-02-16T22:39:56+00:00","dateModified":"2025-02-16T22:45:18+00:00","breadcrumb":{"@id":"https:\/\/fabianvinke.com\/jetpunk\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fabianvinke.com\/jetpunk\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fabianvinke.com\/jetpunk\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fabianvinke.com\/architektur\/"},{"@type":"ListItem","position":2,"name":"Jetpunk"}]},{"@type":"WebSite","@id":"https:\/\/fabianvinke.com\/architektur\/#website","url":"https:\/\/fabianvinke.com\/architektur\/","name":"Fabian Vinke","description":"","publisher":{"@id":"https:\/\/fabianvinke.com\/architektur\/#\/schema\/person\/2816b7d60577ce6d8efde484ce234610"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fabianvinke.com\/architektur\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":["Person","Organization"],"@id":"https:\/\/fabianvinke.com\/architektur\/#\/schema\/person\/2816b7d60577ce6d8efde484ce234610","name":"Fabian","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1","url":"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1","contentUrl":"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1","width":2048,"height":2048,"caption":"Fabian"},"logo":{"@id":"https:\/\/i0.wp.com\/fabianvinke.com\/architektur\/wp-content\/uploads\/2024\/04\/logo_fv_gold.png?fit=2048%2C2048&ssl=1"},"sameAs":["https:\/\/fabianvinke.com\/architektur"]}]}},"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/pages\/452","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/comments?post=452"}],"version-history":[{"count":2,"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/pages\/452\/revisions"}],"predecessor-version":[{"id":455,"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/pages\/452\/revisions\/455"}],"wp:attachment":[{"href":"https:\/\/fabianvinke.com\/architektur\/wp-json\/wp\/v2\/media?parent=452"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}