Spaces:
Running
Running
Update index.html
Browse files- index.html +173 -18
index.html
CHANGED
|
@@ -1,19 +1,174 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>Masking Millionaire</title>
|
| 6 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 7 |
+
</head>
|
| 8 |
+
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-6">
|
| 9 |
+
<div class="bg-white p-8 rounded-2xl shadow-xl w-full max-w-2xl">
|
| 10 |
+
<h1 class="text-4xl font-bold text-indigo-600 text-center mb-2">Masking Millionaire</h1>
|
| 11 |
+
<p class="text-center text-sm text-gray-500 mb-6">
|
| 12 |
+
Content source:
|
| 13 |
+
<a href="https://learn.microsoft.com/en-us/fabric/data-warehouse/dynamic-data-masking"
|
| 14 |
+
target="_blank"
|
| 15 |
+
class="underline hover:text-indigo-700">
|
| 16 |
+
Dynamic Data Masking in Fabric Data Warehouse
|
| 17 |
+
</a>
|
| 18 |
+
</p>
|
| 19 |
+
|
| 20 |
+
<div id="board">
|
| 21 |
+
<div id="question" class="text-2xl font-semibold text-gray-800 mb-4"></div>
|
| 22 |
+
<div id="choices" class="space-y-3"></div>
|
| 23 |
+
<div id="lifelines" class="flex justify-around mt-6">
|
| 24 |
+
<button id="life5050" class="lifeline bg-yellow-400 hover:bg-yellow-500 text-white font-medium py-2 px-4 rounded-lg shadow">
|
| 25 |
+
50:50
|
| 26 |
+
</button>
|
| 27 |
+
<button id="lifePoll" class="lifeline bg-blue-400 hover:bg-blue-500 text-white font-medium py-2 px-4 rounded-lg shadow">
|
| 28 |
+
Ask the Class
|
| 29 |
+
</button>
|
| 30 |
+
<button id="lifeHint" class="lifeline bg-green-400 hover:bg-green-500 text-white font-medium py-2 px-4 rounded-lg shadow">
|
| 31 |
+
Ask an Expert
|
| 32 |
+
</button>
|
| 33 |
+
</div>
|
| 34 |
+
<div id="poll" class="text-sm text-gray-700 mt-4"></div>
|
| 35 |
+
<div id="hint" class="text-sm italic text-gray-600 mt-2"></div>
|
| 36 |
+
<button id="next" class="hidden mt-8 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-6 rounded-lg shadow">
|
| 37 |
+
Next Question
|
| 38 |
+
</button>
|
| 39 |
+
</div>
|
| 40 |
+
</div>
|
| 41 |
+
|
| 42 |
+
<script>
|
| 43 |
+
// Masking quiz data
|
| 44 |
+
const questions = [
|
| 45 |
+
{ q: "Which feature simplifies obfuscation of sensitive data without modifying existing application queries?", choices: ["Column-level security","Dynamic data masking","Row-level security","Transparent data encryption"], correct: 1, hint: "It applies masks at query results, not at storage." },
|
| 46 |
+
{ q: "How many built-in masking functions does dynamic data masking provide in Fabric Data Warehouse?", choices: ["2","3","4","5"], correct: 2, hint: "The options: default, email, random, custom string." },
|
| 47 |
+
{ q: "Which mask function replaces string data with 'XXXX' based on data type?", choices: ["default()","email()","random()","partial()"], correct: 0, hint: "This is full masking according to the data type." },
|
| 48 |
+
{ q: "Which mask function exposes the first letter of an email and the constant suffix '.com'?", choices: ["default()","email()","random()","partial()"], correct: 1, hint: "It formats answer like aXXX@XXXX.com." },
|
| 49 |
+
{ q: "Which function masks numeric data with a random value within a specified range?", choices: ["default()","email()","random(start,end)","partial()"], correct: 2, hint: "Syntax: random([start],[end])." },
|
| 50 |
+
{ q: "Which masking function allows you to expose prefix and suffix with custom padding?", choices: ["default()","email()","random()","partial(prefix,pad,suffix)"], correct: 3, hint: "It’s called 'partial'." },
|
| 51 |
+
{ q: "Which Transact-SQL command is used to add a mask to an existing column?", choices: ["ADD MASK","MASK COLUMN","ALTER COLUMN... ADD MASKED WITH","CREATE MASK"], correct: 2, hint: "Use ALTER COLUMN ... ADD MASKED WITH." },
|
| 52 |
+
{ q: "Which permission is required to add, replace, or remove a mask on a column?", choices: ["UNMASK","ALTER ANY MASK","CONTROL","SELECT"], correct: 1, hint: "This permission targets mask operations." },
|
| 53 |
+
{ q: "Which permission grants a user the ability to view unmasked data specifically?", choices: ["UNMASK","ALTER ANY MASK","CONTROL","SELECT"], correct: 0, hint: "It’s literally named UNMASK." },
|
| 54 |
+
{ q: "The CONTROL permission on the database includes which of the following?", choices: ["UNMASK only","ALTER ANY MASK only","Both UNMASK and ALTER ANY MASK","None of the above"], correct: 2, hint: "It covers full mask management." },
|
| 55 |
+
{ q: "Dynamic data masking in Fabric Data Warehouse is complementary to which security feature?", choices: ["Transparent data encryption","Column-level security","Backup encryption","Data classification"], correct: 1, hint: "Think of restricting rows and fields." },
|
| 56 |
+
{ q: "By default, what value is used to mask datetime columns?", choices: ["0000-00-00","1900-01-01 00:00:00.0000000","1970-01-01","NULL"], correct: 1, hint: "It uses SQL Server’s default minimal date." },
|
| 57 |
+
{ q: "What is a limitation of dynamic data masking regarding security?", choices: ["Cannot mask numeric data","Protects against brute-force inference","Only applies to SELECT queries","Doesn't prevent malicious inference"], correct: 3, hint: "Unprivileged users can still infer data." },
|
| 58 |
+
{ q: "Who sees unmasked data by default in a masked table?", choices: ["Contributors","All database users","Unprivileged users","All users"], correct: 0, hint: "Workspace roles like Admin, Member or Contributor." },
|
| 59 |
+
{ q: "Which object-level security should you combine with dynamic data masking?", choices: ["Row-level security only","Column-level security only","Both row-level and column-level security","None"], correct: 2, hint: "Use multiple data protection features." }
|
| 60 |
+
];
|
| 61 |
+
const prizes = [100,200,300,500,1000,2000,4000,8000,16000,32000,64000,125000,250000,500000,1000000];
|
| 62 |
+
let idx = 0;
|
| 63 |
+
let currentPrize = prizes[0];
|
| 64 |
+
// Redistribute correct answers evenly across A–D
|
| 65 |
+
questions.forEach((q, i) => {
|
| 66 |
+
const target = i % 4;
|
| 67 |
+
if (q.correct !== target) {
|
| 68 |
+
[q.choices[target], q.choices[q.correct]] = [q.choices[q.correct], q.choices[target]];
|
| 69 |
+
q.correct = target;
|
| 70 |
+
}
|
| 71 |
+
});
|
| 72 |
+
const qEl = document.getElementById('question');
|
| 73 |
+
const cEl = document.getElementById('choices');
|
| 74 |
+
const pollEl = document.getElementById('poll');
|
| 75 |
+
const hintEl = document.getElementById('hint');
|
| 76 |
+
const nextBtn = document.getElementById('next');
|
| 77 |
+
const boardEl = document.getElementById('board');
|
| 78 |
+
function updateQuestionDisplay() {
|
| 79 |
+
qEl.textContent = `$${currentPrize}: ${questions[idx].q}`;
|
| 80 |
+
}
|
| 81 |
+
function showQuestion() {
|
| 82 |
+
['life5050','lifePoll','lifeHint'].forEach(id => {
|
| 83 |
+
const btn = document.getElementById(id);
|
| 84 |
+
btn.disabled = false;
|
| 85 |
+
btn.classList.remove('opacity-50');
|
| 86 |
+
});
|
| 87 |
+
pollEl.textContent = '';
|
| 88 |
+
hintEl.textContent = '';
|
| 89 |
+
nextBtn.classList.add('hidden');
|
| 90 |
+
currentPrize = prizes[idx];
|
| 91 |
+
updateQuestionDisplay();
|
| 92 |
+
cEl.innerHTML = questions[idx].choices.map((ch,i) =>
|
| 93 |
+
`<button class="choice bg-indigo-500 hover:bg-indigo-600 text-white font-medium py-2 px-4 rounded w-full" data-i="${i}">` +
|
| 94 |
+
`${String.fromCharCode(65+i)}. ${ch}</button>`
|
| 95 |
+
).join('');
|
| 96 |
+
document.querySelectorAll('.choice').forEach(btn => {
|
| 97 |
+
btn.disabled = false;
|
| 98 |
+
btn.onclick = selectAnswer;
|
| 99 |
+
});
|
| 100 |
+
}
|
| 101 |
+
function selectAnswer(e) {
|
| 102 |
+
const chosen = +e.target.dataset.i;
|
| 103 |
+
const corr = questions[idx].correct;
|
| 104 |
+
document.querySelectorAll('.choice').forEach(b => b.disabled = true);
|
| 105 |
+
if (chosen === corr) {
|
| 106 |
+
e.target.classList.replace('bg-indigo-500','bg-green-500');
|
| 107 |
+
} else {
|
| 108 |
+
e.target.classList.replace('bg-indigo-500','bg-red-500');
|
| 109 |
+
document.querySelector(`.choice[data-i="${corr}"]`).classList.replace('bg-indigo-500','bg-green-500');
|
| 110 |
+
}
|
| 111 |
+
nextBtn.classList.remove('hidden');
|
| 112 |
+
}
|
| 113 |
+
// 50:50 Lifeline
|
| 114 |
+
document.getElementById('life5050').onclick = () => {
|
| 115 |
+
const btn = document.getElementById('life5050');
|
| 116 |
+
if (btn.disabled) return;
|
| 117 |
+
btn.disabled = true;
|
| 118 |
+
btn.classList.add('opacity-50');
|
| 119 |
+
const corr = questions[idx].correct;
|
| 120 |
+
questions[idx].choices
|
| 121 |
+
.map((_, i) => i)
|
| 122 |
+
.filter(i => i !== corr)
|
| 123 |
+
.sort(() => Math.random() - 0.5)
|
| 124 |
+
.slice(0, 2)
|
| 125 |
+
.forEach(i => {
|
| 126 |
+
const b = document.querySelector(`.choice[data-i="${i}"]`);
|
| 127 |
+
b.disabled = true;
|
| 128 |
+
b.classList.add('opacity-50');
|
| 129 |
+
});
|
| 130 |
+
currentPrize = Math.floor(currentPrize / 2);
|
| 131 |
+
updateQuestionDisplay();
|
| 132 |
+
};
|
| 133 |
+
// Ask the Class
|
| 134 |
+
document.getElementById('lifePoll').onclick = () => {
|
| 135 |
+
const btn = document.getElementById('lifePoll');
|
| 136 |
+
if (btn.disabled) return;
|
| 137 |
+
btn.disabled = true;
|
| 138 |
+
btn.classList.add('opacity-50');
|
| 139 |
+
const corr = questions[idx].correct;
|
| 140 |
+
const pct = [0,0,0,0];
|
| 141 |
+
pct[corr] = 70 + Math.floor(Math.random() * 21);
|
| 142 |
+
let rem = 100 - pct[corr];
|
| 143 |
+
questions[idx].choices.forEach((_, i) => {
|
| 144 |
+
if (i !== corr) {
|
| 145 |
+
const alloc = Math.floor(rem / 3);
|
| 146 |
+
pct[i] = alloc;
|
| 147 |
+
rem -= alloc;
|
| 148 |
+
}
|
| 149 |
+
});
|
| 150 |
+
pollEl.textContent = `Class Poll: A:${pct[0]}% B:${pct[1]}% C:${pct[2]}% D:${pct[3]}%`;
|
| 151 |
+
};
|
| 152 |
+
// Ask an Expert
|
| 153 |
+
document.getElementById('lifeHint').onclick = () => {
|
| 154 |
+
const btn = document.getElementById('lifeHint');
|
| 155 |
+
if (btn.disabled) return;
|
| 156 |
+
btn.disabled = true;
|
| 157 |
+
btn.classList.add('opacity-50');
|
| 158 |
+
hintEl.textContent = `Expert Hint: ${questions[idx].hint}`;
|
| 159 |
+
};
|
| 160 |
+
// Next Question
|
| 161 |
+
nextBtn.onclick = () => {
|
| 162 |
+
idx++;
|
| 163 |
+
if (idx < questions.length) {
|
| 164 |
+
showQuestion();
|
| 165 |
+
} else {
|
| 166 |
+
boardEl.innerHTML = '<div class="text-3xl font-bold text-green-600 text-center">🎉 Congratulations! You’ve mastered Masking Millionaire! 🎉</div>';
|
| 167 |
+
}
|
| 168 |
+
};
|
| 169 |
+
// Start
|
| 170 |
+
showQuestion();
|
| 171 |
+
</script>
|
| 172 |
+
</body>
|
| 173 |
</html>
|
| 174 |
+
|