/* ui-quiz-bank.js — Built-in quiz question bank generation */ (function () { "use strict"; function toTitleCase(value) { const text = String(value || "").trim().toLowerCase(); if (!text) { return ""; } return text.charAt(0).toUpperCase() + text.slice(1); } function normalizeOption(value) { return String(value || "").trim(); } function normalizeKey(value) { return normalizeOption(value).toLowerCase(); } function toUniqueOptionList(values) { const seen = new Set(); const unique = []; (values || []).forEach((value) => { const formatted = normalizeOption(value); if (!formatted) { return; } const key = normalizeKey(formatted); if (seen.has(key)) { return; } seen.add(key); unique.push(formatted); }); return unique; } function resolveDifficultyValue(valueByDifficulty, difficulty = "normal") { if (valueByDifficulty == null) { return ""; } if (typeof valueByDifficulty !== "object" || Array.isArray(valueByDifficulty)) { return valueByDifficulty; } if (Object.prototype.hasOwnProperty.call(valueByDifficulty, difficulty)) { return valueByDifficulty[difficulty]; } if (Object.prototype.hasOwnProperty.call(valueByDifficulty, "normal")) { return valueByDifficulty.normal; } if (Object.prototype.hasOwnProperty.call(valueByDifficulty, "easy")) { return valueByDifficulty.easy; } if (Object.prototype.hasOwnProperty.call(valueByDifficulty, "hard")) { return valueByDifficulty.hard; } return ""; } function createQuestionTemplate(payload, poolValues) { const key = String(payload?.key || "").trim(); const promptByDifficulty = payload?.promptByDifficulty ?? payload?.prompt; const answerByDifficulty = payload?.answerByDifficulty ?? payload?.answer; const poolByDifficulty = poolValues; const categoryId = String(payload?.categoryId || "").trim(); const category = String(payload?.category || "Correspondence").trim(); const defaultPrompt = String(resolveDifficultyValue(promptByDifficulty, "normal") || "").trim(); const defaultAnswer = normalizeOption(resolveDifficultyValue(answerByDifficulty, "normal")); const defaultPool = toUniqueOptionList(resolveDifficultyValue(poolByDifficulty, "normal") || []); if (!key || !defaultPrompt || !defaultAnswer || !categoryId || !category) { return null; } if (!defaultPool.some((value) => normalizeKey(value) === normalizeKey(defaultAnswer))) { defaultPool.push(defaultAnswer); } const distractorCount = defaultPool.filter((value) => normalizeKey(value) !== normalizeKey(defaultAnswer)).length; if (distractorCount < 3) { return null; } return { key, categoryId, category, promptByDifficulty, answerByDifficulty, poolByDifficulty }; } function buildQuestionBank(referenceData, magickDataset, dynamicCategoryRegistry) { const grouped = magickDataset?.grouped || {}; const alphabets = grouped.alphabets || {}; const englishLetters = Array.isArray(alphabets?.english) ? alphabets.english : []; const hebrewLetters = Array.isArray(alphabets?.hebrew) ? alphabets.hebrew : []; const kabbalahTree = grouped?.kabbalah?.["kabbalah-tree"] || {}; const treePaths = Array.isArray(kabbalahTree?.paths) ? kabbalahTree.paths : []; const treeSephiroth = Array.isArray(kabbalahTree?.sephiroth) ? kabbalahTree.sephiroth : []; const sephirotById = grouped?.kabbalah?.sephirot && typeof grouped.kabbalah.sephirot === "object" ? grouped.kabbalah.sephirot : {}; const cube = grouped?.kabbalah?.cube && typeof grouped.kabbalah.cube === "object" ? grouped.kabbalah.cube : {}; const cubeWalls = Array.isArray(cube?.walls) ? cube.walls : []; const cubeEdges = Array.isArray(cube?.edges) ? cube.edges : []; const cubeCenter = cube?.center && typeof cube.center === "object" ? cube.center : null; const playingCardsData = grouped?.["playing-cards-52"]; const playingCards = Array.isArray(playingCardsData) ? playingCardsData : (Array.isArray(playingCardsData?.entries) ? playingCardsData.entries : []); const signs = Array.isArray(referenceData?.signs) ? referenceData.signs : []; const planetsById = referenceData?.planets && typeof referenceData.planets === "object" ? referenceData.planets : {}; const planets = Object.values(planetsById); const decansBySign = referenceData?.decansBySign && typeof referenceData.decansBySign === "object" ? referenceData.decansBySign : {}; const normalizeId = (value) => String(value || "").trim().toLowerCase(); const toRomanNumeral = (value) => { const numeric = Number(value); if (!Number.isFinite(numeric) || numeric <= 0) { return String(value || ""); } const intValue = Math.trunc(numeric); const lookup = [ [1000, "M"], [900, "CM"], [500, "D"], [400, "CD"], [100, "C"], [90, "XC"], [50, "L"], [40, "XL"], [10, "X"], [9, "IX"], [5, "V"], [4, "IV"], [1, "I"] ]; let current = intValue; let result = ""; lookup.forEach(([size, symbol]) => { while (current >= size) { result += symbol; current -= size; } }); return result || String(intValue); }; const labelFromId = (value) => { const id = String(value || "").trim(); if (!id) { return ""; } return id .replace(/[_-]+/g, " ") .replace(/\s+/g, " ") .trim() .split(" ") .map((part) => part ? part.charAt(0).toUpperCase() + part.slice(1) : "") .join(" "); }; const getPlanetLabelById = (planetId) => { const normalized = normalizeId(planetId); if (!normalized) { return ""; } const directPlanet = planetsById[normalized]; if (directPlanet?.name) { return directPlanet.name; } if (normalized === "primum-mobile") { return "Primum Mobile"; } if (normalized === "olam-yesodot") { return "Earth / Elements"; } return labelFromId(normalized); }; const hebrewById = new Map( hebrewLetters .filter((entry) => entry?.hebrewLetterId) .map((entry) => [normalizeId(entry.hebrewLetterId), entry]) ); const formatHebrewLetterLabel = (entry, fallbackId = "") => { if (entry?.name && entry?.char) { return `${entry.name} (${entry.char})`; } if (entry?.name) { return entry.name; } if (entry?.char) { return entry.char; } return labelFromId(fallbackId); }; const sephiraNameByNumber = new Map( treeSephiroth .filter((entry) => Number.isFinite(Number(entry?.number)) && entry?.name) .map((entry) => [Math.trunc(Number(entry.number)), String(entry.name)]) ); const sephiraNameById = new Map( treeSephiroth .filter((entry) => entry?.sephiraId && entry?.name) .map((entry) => [normalizeId(entry.sephiraId), String(entry.name)]) ); const getSephiraName = (numberValue, idValue) => { const numberKey = Number(numberValue); if (Number.isFinite(numberKey)) { const byNumber = sephiraNameByNumber.get(Math.trunc(numberKey)); if (byNumber) { return byNumber; } } const byId = sephiraNameById.get(normalizeId(idValue)); if (byId) { return byId; } if (Number.isFinite(numberKey)) { return `Sephira ${Math.trunc(numberKey)}`; } return labelFromId(idValue); }; const formatPathLetter = (path) => { const transliteration = String(path?.hebrewLetter?.transliteration || "").trim(); const glyph = String(path?.hebrewLetter?.char || "").trim(); if (transliteration && glyph) { return `${transliteration} (${glyph})`; } if (transliteration) { return transliteration; } if (glyph) { return glyph; } return ""; }; const flattenDecans = Object.values(decansBySign) .flatMap((entries) => (Array.isArray(entries) ? entries : [])); const signNameById = new Map( signs .filter((entry) => entry?.id && entry?.name) .map((entry) => [normalizeId(entry.id), String(entry.name)]) ); const formatDecanLabel = (decan) => { const signName = signNameById.get(normalizeId(decan?.signId)) || labelFromId(decan?.signId); const index = Number(decan?.index); if (!signName || !Number.isFinite(index)) { return ""; } return `${signName} Decan ${toRomanNumeral(index)}`; }; const bank = []; const englishGematriaPool = englishLetters .map((item) => (Number.isFinite(Number(item?.pythagorean)) ? String(item.pythagorean) : "")) .filter(Boolean); const hebrewNumerologyPool = hebrewLetters .map((item) => (Number.isFinite(Number(item?.numerology)) ? String(item.numerology) : "")) .filter(Boolean); const hebrewNameAndCharPool = hebrewLetters .filter((item) => item?.name && item?.char) .map((item) => `${item.name} (${item.char})`); const hebrewCharPool = hebrewLetters .map((item) => item?.char) .filter(Boolean); const planetNamePool = planets .map((planet) => planet?.name) .filter(Boolean); const planetWeekdayPool = planets .map((planet) => planet?.weekday) .filter(Boolean); const zodiacElementPool = signs .map((sign) => toTitleCase(sign?.element)) .filter(Boolean); const zodiacTarotPool = signs .map((sign) => sign?.tarot?.majorArcana) .filter(Boolean); const pathNumberPool = toUniqueOptionList( treePaths .map((path) => { const pathNo = Number(path?.pathNumber); return Number.isFinite(pathNo) ? String(Math.trunc(pathNo)) : ""; }) ); const pathLetterPool = toUniqueOptionList(treePaths.map((path) => formatPathLetter(path))); const pathTarotPool = toUniqueOptionList(treePaths.map((path) => normalizeOption(path?.tarot?.card))); const decanLabelPool = toUniqueOptionList(flattenDecans.map((decan) => formatDecanLabel(decan))); const decanRulerPool = toUniqueOptionList( flattenDecans.map((decan) => getPlanetLabelById(decan?.rulerPlanetId)) ); const cubeWallLabelPool = toUniqueOptionList( cubeWalls.map((wall) => `${String(wall?.name || labelFromId(wall?.id)).trim()} Wall`) ); const cubeEdgeLabelPool = toUniqueOptionList( cubeEdges.map((edge) => `${String(edge?.name || labelFromId(edge?.id)).trim()} Edge`) ); const cubeLocationPool = toUniqueOptionList([ ...cubeWallLabelPool, ...cubeEdgeLabelPool, "Center" ]); const cubeHebrewLetterPool = toUniqueOptionList([ ...cubeWalls.map((wall) => { const hebrew = hebrewById.get(normalizeId(wall?.hebrewLetterId)); return formatHebrewLetterLabel(hebrew, wall?.hebrewLetterId); }), ...cubeEdges.map((edge) => { const hebrew = hebrewById.get(normalizeId(edge?.hebrewLetterId)); return formatHebrewLetterLabel(hebrew, edge?.hebrewLetterId); }), formatHebrewLetterLabel(hebrewById.get(normalizeId(cubeCenter?.hebrewLetterId)), cubeCenter?.hebrewLetterId) ]); const playingTarotPool = toUniqueOptionList( playingCards.map((entry) => normalizeOption(entry?.tarotCard)) ); englishLetters.forEach((entry) => { if (!entry?.letter || !Number.isFinite(Number(entry?.pythagorean))) { return; } const template = createQuestionTemplate( { key: `english-gematria:${entry.letter}`, categoryId: "english-gematria", category: "English Gematria", promptByDifficulty: `${entry.letter} has a simple gematria value of`, answerByDifficulty: String(entry.pythagorean) }, englishGematriaPool ); if (template) { bank.push(template); } }); hebrewLetters.forEach((entry) => { if (!entry?.name || !entry?.char || !Number.isFinite(Number(entry?.numerology))) { return; } const template = createQuestionTemplate( { key: `hebrew-number:${entry.hebrewLetterId || entry.name}`, categoryId: "hebrew-numerology", category: "Hebrew Gematria", promptByDifficulty: { easy: `${entry.name} (${entry.char}) has a gematria value of`, normal: `${entry.name} (${entry.char}) has a gematria value of`, hard: `${entry.char} has a gematria value of` }, answerByDifficulty: String(entry.numerology) }, hebrewNumerologyPool ); if (template) { bank.push(template); } }); englishLetters.forEach((entry) => { if (!entry?.letter || !entry?.hebrewLetterId) { return; } const mappedHebrew = hebrewById.get(normalizeId(entry.hebrewLetterId)); if (!mappedHebrew?.name || !mappedHebrew?.char) { return; } const template = createQuestionTemplate( { key: `english-hebrew:${entry.letter}`, categoryId: "english-hebrew-mapping", category: "Alphabet Mapping", promptByDifficulty: { easy: `${entry.letter} maps to which Hebrew letter`, normal: `${entry.letter} maps to which Hebrew letter`, hard: `${entry.letter} maps to which Hebrew glyph` }, answerByDifficulty: { easy: `${mappedHebrew.name} (${mappedHebrew.char})`, normal: `${mappedHebrew.name} (${mappedHebrew.char})`, hard: mappedHebrew.char } }, { easy: hebrewNameAndCharPool, normal: hebrewNameAndCharPool, hard: hebrewCharPool } ); if (template) { bank.push(template); } }); signs.forEach((entry) => { if (!entry?.name || !entry?.rulingPlanetId) { return; } const rulerName = planetsById[normalizeId(entry.rulingPlanetId)]?.name; if (!rulerName) { return; } const template = createQuestionTemplate( { key: `zodiac-ruler:${entry.id || entry.name}`, categoryId: "zodiac-rulers", category: "Zodiac Rulers", promptByDifficulty: `${entry.name} is ruled by`, answerByDifficulty: rulerName }, planetNamePool ); if (template) { bank.push(template); } }); signs.forEach((entry) => { if (!entry?.name || !entry?.element) { return; } const template = createQuestionTemplate( { key: `zodiac-element:${entry.id || entry.name}`, categoryId: "zodiac-elements", category: "Zodiac Elements", promptByDifficulty: `${entry.name} is`, answerByDifficulty: toTitleCase(entry.element) }, zodiacElementPool ); if (template) { bank.push(template); } }); planets.forEach((entry) => { if (!entry?.name || !entry?.weekday) { return; } const template = createQuestionTemplate( { key: `planet-weekday:${entry.id || entry.name}`, categoryId: "planetary-weekdays", category: "Planetary Weekdays", promptByDifficulty: `${entry.name} corresponds to`, answerByDifficulty: entry.weekday }, planetWeekdayPool ); if (template) { bank.push(template); } }); signs.forEach((entry) => { if (!entry?.name || !entry?.tarot?.majorArcana) { return; } const template = createQuestionTemplate( { key: `zodiac-tarot:${entry.id || entry.name}`, categoryId: "zodiac-tarot", category: "Zodiac ↔ Tarot", promptByDifficulty: `${entry.name} corresponds to`, answerByDifficulty: entry.tarot.majorArcana }, zodiacTarotPool ); if (template) { bank.push(template); } }); treePaths.forEach((path) => { const pathNo = Number(path?.pathNumber); if (!Number.isFinite(pathNo)) { return; } const pathNumberLabel = String(Math.trunc(pathNo)); const fromNo = Number(path?.connects?.from); const toNo = Number(path?.connects?.to); const fromName = getSephiraName(fromNo, path?.connectIds?.from); const toName = getSephiraName(toNo, path?.connectIds?.to); const pathLetter = formatPathLetter(path); const tarotCard = normalizeOption(path?.tarot?.card); if (fromName && toName) { const template = createQuestionTemplate( { key: `kabbalah-path-between:${pathNumberLabel}`, categoryId: "kabbalah-path-between-sephirot", category: "Kabbalah Paths", promptByDifficulty: { easy: `Which path is between ${fromName} and ${toName}`, normal: `What path connects ${fromName} and ${toName}`, hard: `${fromName} ↔ ${toName} is which path` }, answerByDifficulty: pathNumberLabel }, pathNumberPool ); if (template) { bank.push(template); } } if (pathLetter) { const numberToLetterTemplate = createQuestionTemplate( { key: `kabbalah-path-letter:${pathNumberLabel}`, categoryId: "kabbalah-path-letter", category: "Kabbalah Paths", promptByDifficulty: { easy: `Which letter is on Path ${pathNumberLabel}`, normal: `Path ${pathNumberLabel} carries which Hebrew letter`, hard: `Letter on Path ${pathNumberLabel}` }, answerByDifficulty: pathLetter }, pathLetterPool ); if (numberToLetterTemplate) { bank.push(numberToLetterTemplate); } const letterToNumberTemplate = createQuestionTemplate( { key: `kabbalah-letter-path-number:${pathNumberLabel}`, categoryId: "kabbalah-path-letter", category: "Kabbalah Paths", promptByDifficulty: { easy: `${pathLetter} belongs to which path`, normal: `${pathLetter} corresponds to Path`, hard: `${pathLetter} is on Path` }, answerByDifficulty: pathNumberLabel }, pathNumberPool ); if (letterToNumberTemplate) { bank.push(letterToNumberTemplate); } } if (tarotCard) { const pathToTarotTemplate = createQuestionTemplate( { key: `kabbalah-path-tarot:${pathNumberLabel}`, categoryId: "kabbalah-path-tarot", category: "Kabbalah ↔ Tarot", promptByDifficulty: { easy: `Path ${pathNumberLabel} corresponds to which Tarot trump`, normal: `Which Tarot trump is on Path ${pathNumberLabel}`, hard: `Tarot trump on Path ${pathNumberLabel}` }, answerByDifficulty: tarotCard }, pathTarotPool ); if (pathToTarotTemplate) { bank.push(pathToTarotTemplate); } const tarotToPathTemplate = createQuestionTemplate( { key: `tarot-trump-path:${pathNumberLabel}`, categoryId: "kabbalah-path-tarot", category: "Tarot ↔ Kabbalah", promptByDifficulty: { easy: `${tarotCard} is on which path`, normal: `Which path corresponds to ${tarotCard}`, hard: `${tarotCard} corresponds to Path` }, answerByDifficulty: pathNumberLabel }, pathNumberPool ); if (tarotToPathTemplate) { bank.push(tarotToPathTemplate); } } }); Object.values(sephirotById).forEach((sephira) => { const sephiraName = String(sephira?.name?.roman || sephira?.name?.en || "").trim(); const planetLabel = getPlanetLabelById(sephira?.planetId); if (!sephiraName || !planetLabel) { return; } const template = createQuestionTemplate( { key: `sephirot-planet:${normalizeId(sephira?.id || sephiraName)}`, categoryId: "sephirot-planets", category: "Sephirot ↔ Planet", promptByDifficulty: { easy: `${sephiraName} corresponds to which planet`, normal: `Planetary correspondence of ${sephiraName}`, hard: `${sephiraName} corresponds to` }, answerByDifficulty: planetLabel }, toUniqueOptionList(Object.values(sephirotById).map((entry) => getPlanetLabelById(entry?.planetId))) ); if (template) { bank.push(template); } }); flattenDecans.forEach((decan) => { const decanId = String(decan?.id || "").trim(); const card = normalizeOption(decan?.tarotMinorArcana); const decanLabel = formatDecanLabel(decan); const rulerLabel = getPlanetLabelById(decan?.rulerPlanetId); if (!decanId || !card) { return; } if (decanLabel) { const template = createQuestionTemplate( { key: `tarot-decan-sign:${decanId}`, categoryId: "tarot-decan-sign", category: "Tarot Decans", promptByDifficulty: { easy: `${card} belongs to which decan`, normal: `Which decan contains ${card}`, hard: `${card} is in` }, answerByDifficulty: decanLabel }, decanLabelPool ); if (template) { bank.push(template); } } if (rulerLabel) { const template = createQuestionTemplate( { key: `tarot-decan-ruler:${decanId}`, categoryId: "tarot-decan-ruler", category: "Tarot Decans", promptByDifficulty: { easy: `The decan of ${card} is ruled by`, normal: `Who rules the decan for ${card}`, hard: `${card} decan ruler` }, answerByDifficulty: rulerLabel }, decanRulerPool ); if (template) { bank.push(template); } } }); cubeWalls.forEach((wall) => { const wallName = String(wall?.name || labelFromId(wall?.id)).trim(); const wallLabel = wallName ? `${wallName} Wall` : ""; const tarotCard = normalizeOption(wall?.associations?.tarotCard); const hebrew = hebrewById.get(normalizeId(wall?.hebrewLetterId)); const hebrewLabel = formatHebrewLetterLabel(hebrew, wall?.hebrewLetterId); if (tarotCard && wallLabel) { const template = createQuestionTemplate( { key: `tarot-cube-wall:${normalizeId(wall?.id || wallName)}`, categoryId: "tarot-cube-location", category: "Tarot ↔ Cube", promptByDifficulty: { easy: `${tarotCard} is on which Cube wall`, normal: `Where is ${tarotCard} on the Cube`, hard: `${tarotCard} location on Cube` }, answerByDifficulty: wallLabel }, cubeLocationPool ); if (template) { bank.push(template); } } if (wallLabel && hebrewLabel) { const template = createQuestionTemplate( { key: `cube-wall-letter:${normalizeId(wall?.id || wallName)}`, categoryId: "cube-hebrew-letter", category: "Cube ↔ Hebrew", promptByDifficulty: { easy: `${wallLabel} corresponds to which Hebrew letter`, normal: `Which Hebrew letter is on ${wallLabel}`, hard: `${wallLabel} letter` }, answerByDifficulty: hebrewLabel }, cubeHebrewLetterPool ); if (template) { bank.push(template); } } }); cubeEdges.forEach((edge) => { const edgeName = String(edge?.name || labelFromId(edge?.id)).trim(); const edgeLabel = edgeName ? `${edgeName} Edge` : ""; const hebrew = hebrewById.get(normalizeId(edge?.hebrewLetterId)); const hebrewLabel = formatHebrewLetterLabel(hebrew, edge?.hebrewLetterId); const tarotCard = normalizeOption(hebrew?.tarot?.card); if (tarotCard && edgeLabel) { const template = createQuestionTemplate( { key: `tarot-cube-edge:${normalizeId(edge?.id || edgeName)}`, categoryId: "tarot-cube-location", category: "Tarot ↔ Cube", promptByDifficulty: { easy: `${tarotCard} is on which Cube edge`, normal: `Where is ${tarotCard} on the Cube edges`, hard: `${tarotCard} edge location` }, answerByDifficulty: edgeLabel }, cubeLocationPool ); if (template) { bank.push(template); } } if (edgeLabel && hebrewLabel) { const template = createQuestionTemplate( { key: `cube-edge-letter:${normalizeId(edge?.id || edgeName)}`, categoryId: "cube-hebrew-letter", category: "Cube ↔ Hebrew", promptByDifficulty: { easy: `${edgeLabel} corresponds to which Hebrew letter`, normal: `Which Hebrew letter is on ${edgeLabel}`, hard: `${edgeLabel} letter` }, answerByDifficulty: hebrewLabel }, cubeHebrewLetterPool ); if (template) { bank.push(template); } } }); if (cubeCenter) { const centerTarot = normalizeOption(cubeCenter?.associations?.tarotCard || cubeCenter?.tarotCard); const centerHebrew = hebrewById.get(normalizeId(cubeCenter?.hebrewLetterId)); const centerHebrewLabel = formatHebrewLetterLabel(centerHebrew, cubeCenter?.hebrewLetterId); if (centerTarot) { const template = createQuestionTemplate( { key: "tarot-cube-center", categoryId: "tarot-cube-location", category: "Tarot ↔ Cube", promptByDifficulty: { easy: `${centerTarot} is located at which Cube position`, normal: `Where is ${centerTarot} on the Cube`, hard: `${centerTarot} Cube location` }, answerByDifficulty: "Center" }, cubeLocationPool ); if (template) { bank.push(template); } } if (centerHebrewLabel) { const template = createQuestionTemplate( { key: "cube-center-letter", categoryId: "cube-hebrew-letter", category: "Cube ↔ Hebrew", promptByDifficulty: { easy: "The Cube center corresponds to which Hebrew letter", normal: "Which Hebrew letter is at the Cube center", hard: "Cube center letter" }, answerByDifficulty: centerHebrewLabel }, cubeHebrewLetterPool ); if (template) { bank.push(template); } } } playingCards.forEach((entry) => { const cardId = String(entry?.id || "").trim(); const rankLabel = normalizeOption(entry?.rankLabel || entry?.rank); const suitLabel = normalizeOption(entry?.suitLabel || labelFromId(entry?.suit)); const tarotCard = normalizeOption(entry?.tarotCard); if (!cardId || !rankLabel || !suitLabel || !tarotCard) { return; } const template = createQuestionTemplate( { key: `playing-card-tarot:${cardId}`, categoryId: "playing-card-tarot", category: "Playing Card ↔ Tarot", promptByDifficulty: { easy: `${rankLabel} of ${suitLabel} maps to which Tarot card`, normal: `${rankLabel} of ${suitLabel} corresponds to`, hard: `${rankLabel} of ${suitLabel} maps to` }, answerByDifficulty: tarotCard }, playingTarotPool ); if (template) { bank.push(template); } }); (dynamicCategoryRegistry || []).forEach(({ builder }) => { try { const dynamicTemplates = builder(referenceData, magickDataset); if (Array.isArray(dynamicTemplates)) { dynamicTemplates.forEach((template) => { if (template) { bank.push(template); } }); } } catch (_error) { // Skip broken plugins silently to preserve quiz availability. } }); return bank; } window.QuizQuestionBank = { buildQuestionBank, createQuestionTemplate, normalizeKey, normalizeOption, toTitleCase, toUniqueOptionList }; })();