| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <title>Data Factory TicTacToe</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| </head> |
| <body class="bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center min-h-screen"> |
| <div class="max-w-5xl w-full bg-white rounded-2xl shadow-lg p-6"> |
| <h1 class="text-3xl font-extrabold mb-4 text-center text-indigo-800">Data Factory TicTacToe</h1> |
| <p class="text-center text-sm text-gray-600 mb-4"> |
| Source: <a href="https://learn.microsoft.com/en-us/azure/architecture/databases/architecture/azure-data-factory-on-azure-landing-zones-baseline" |
| class="text-blue-600 underline" |
| target="_blank"> |
| Azure Data Factory on Azure Landing Zones - Baseline |
| </a> |
| </p> |
|
|
| <div id="banner" class="hidden bg-green-100 border border-green-300 text-green-800 font-bold text-center py-2 rounded mb-4"></div> |
|
|
| <div class="flex items-start justify-center space-x-4"> |
| <div id="board" class="grid grid-cols-3 gap-1 border-4 border-gray-300 rounded-lg p-2 bg-white mx-auto"></div> |
| <div id="questionPanel" class="w-1/2 bg-gray-50 rounded-lg shadow p-4"> |
| <h2 id="panelQuestion" class="text-xl font-semibold text-gray-800">Select a square to view the question</h2> |
| <ul id="panelChoices" class="mt-4 space-y-2"></ul> |
| <p id="panelHint" class="mt-3 text-sm text-gray-600 hidden"></p> |
| <button id="hintBtn" class="mt-4 px-3 py-1 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">Show Hint</button> |
| </div> |
| </div> |
|
|
| <div class="flex justify-between mt-6"> |
| <p id="status" class="text-lg font-medium text-gray-800"></p> |
| <button id="restartBtn" class="px-4 py-2 bg-indigo-700 text-white rounded hover:bg-indigo-800">Restart</button> |
| </div> |
| </div> |
|
|
| <script> |
| const questions = [ |
| { |
| question: 'What role does Azure Data Factory play in a landing zone architecture?', |
| choices: [ |
| 'Used only for SQL data ingestion', |
| 'Mainly responsible for security policies', |
| 'Orchestrates and operationalizes data movement and transformation', |
| 'Acts as a backup tool for Azure Blob storage' |
| ], |
| answer: 3, |
| hint: 'Think of it as a control tower for your data.' |
| }, |
| { |
| question: 'What is a recommended best practice for integrating ADF in an enterprise-scale landing zone?', |
| choices: [ |
| 'Deploy ADF in the sandbox environment only', |
| 'Use managed virtual networks and private endpoints', |
| 'Always expose ADF over the public internet', |
| 'Avoid using parameterized pipelines' |
| ], |
| answer: 2, |
| hint: 'Security and isolation are key.' |
| }, |
| { |
| question: 'Why should managed identity be enabled for ADF?', |
| choices: [ |
| 'To allow GitHub integration', |
| 'To access other Azure services securely', |
| 'To improve dashboard rendering', |
| 'To manage DNS zones' |
| ], |
| answer: 2, |
| hint: 'It’s a way for ADF to securely authenticate with other resources.' |
| }, |
| { |
| question: 'What type of data flow can be used within ADF for transformation at scale?', |
| choices: [ |
| 'Synapse pipelines', |
| 'Mapping Data Flows', |
| 'Azure Monitor logs', |
| 'Power BI models' |
| ], |
| answer: 2, |
| hint: 'It’s a visual data transformation feature built into ADF.' |
| }, |
| { |
| question: 'ADF pipelines are best managed with which DevOps approach?', |
| choices: [ |
| 'Drag and drop only', |
| 'Random deployment', |
| 'CI/CD using Git integration and Azure DevOps', |
| 'PowerShell only deployments' |
| ], |
| answer: 3, |
| hint: 'Think automation, source control, and repeatability.' |
| }, |
| { |
| question: 'What’s the benefit of using a managed VNet in ADF?', |
| choices: [ |
| 'More internet bandwidth', |
| 'Can bypass firewalls', |
| 'Enables secure access to data sources without public exposure', |
| 'Increases billing efficiency' |
| ], |
| answer: 3, |
| hint: 'This feature is important for securing access to data sources.' |
| }, |
| { |
| question: 'Which Azure service is often paired with ADF for data storage in a pipeline?', |
| choices: [ |
| 'Azure Bastion', |
| 'Azure Blob Storage or Data Lake', |
| 'Azure Kubernetes Service', |
| 'Azure Front Door' |
| ], |
| answer: 2, |
| hint: 'Think storage for structured and unstructured data.' |
| }, |
| { |
| question: 'What helps ensure traceability and observability in ADF pipelines?', |
| choices: [ |
| 'Private DNS Zones', |
| 'Diagnostic Settings with Log Analytics', |
| 'Azure Load Balancer', |
| 'Virtual Machines' |
| ], |
| answer: 2, |
| hint: 'Logs, metrics, and monitoring dashboards.' |
| }, |
| { |
| question: 'What should be used to protect ADF against data exfiltration?', |
| choices: [ |
| 'NSG rules alone', |
| 'Private endpoints and VNet integration', |
| 'Disabling all triggers', |
| 'Using public endpoints only' |
| ], |
| answer: 2, |
| hint: 'Prevent data leakage by restricting public access.' |
| } |
| ]; |
| |
| let currentPlayer, boardState, cellQuestions, selectedCell; |
| const boardEl = document.getElementById('board'); |
| const statusEl = document.getElementById('status'); |
| const bannerEl = document.getElementById('banner'); |
| const hintBtn = document.getElementById('hintBtn'); |
| const panelQuestion = document.getElementById('panelQuestion'); |
| const panelChoices = document.getElementById('panelChoices'); |
| const panelHint = document.getElementById('panelHint'); |
| const restartBtn = document.getElementById('restartBtn'); |
| |
| function initGame() { |
| currentPlayer = 'X'; |
| boardState = Array(9).fill(''); |
| bannerEl.classList.add('hidden'); |
| statusEl.innerText = ''; |
| const shuffled = questions.sort(() => 0.5 - Math.random()); |
| cellQuestions = shuffled.slice(0, 9); |
| panelQuestion.innerText = 'Select a square to view the question'; |
| panelChoices.innerHTML = ''; |
| panelHint.classList.add('hidden'); |
| renderBoard(); |
| } |
| |
| function renderBoard() { |
| boardEl.innerHTML = ''; |
| boardState.forEach((mark, idx) => { |
| const btn = document.createElement('button'); |
| let cls = 'bg-white h-24 w-24 flex items-center justify-center text-2xl font-bold rounded-lg shadow hover:bg-gray-100'; |
| if (mark === 'X') cls += ' text-blue-600'; |
| if (mark === 'O') cls += ' text-red-600'; |
| btn.className = cls; |
| btn.innerText = mark; |
| btn.disabled = mark !== ''; |
| btn.addEventListener('click', () => openQuestion(idx)); |
| boardEl.appendChild(btn); |
| }); |
| statusEl.innerText = `Current: ${currentPlayer}`; |
| } |
| |
| function openQuestion(idx) { |
| selectedCell = idx; |
| const q = cellQuestions[idx]; |
| panelQuestion.innerText = q.question; |
| panelChoices.innerHTML = ''; |
| panelHint.classList.add('hidden'); |
| panelHint.innerText = q.hint; |
| q.choices.forEach((c, i) => { |
| const li = document.createElement('li'); |
| const btn = document.createElement('button'); |
| btn.innerText = c; |
| btn.className = 'w-full text-left px-4 py-2 bg-gray-100 rounded hover:bg-gray-200'; |
| btn.addEventListener('click', () => handleAnswer(i + 1)); |
| li.appendChild(btn); |
| panelChoices.appendChild(li); |
| }); |
| } |
| |
| function handleAnswer(choice) { |
| const q = cellQuestions[selectedCell]; |
| if (choice === q.answer) { |
| boardState[selectedCell] = currentPlayer; |
| renderBoard(); |
| if (checkWin()) return endGame(`${currentPlayer} wins!`); |
| if (boardState.every(c => c)) return endGame('Stalemate!'); |
| } else { |
| alert('Incorrect! Turn missed.'); |
| } |
| currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; |
| statusEl.innerText = `Current: ${currentPlayer}`; |
| } |
| |
| function checkWin() { |
| const wins = [ |
| [0,1,2],[3,4,5],[6,7,8], |
| [0,3,6],[1,4,7],[2,5,8], |
| [0,4,8],[2,4,6] |
| ]; |
| return wins.some(combo => combo.every(i => boardState[i] === currentPlayer)); |
| } |
| |
| function endGame(msg) { |
| bannerEl.innerText = `🎉 ${msg}`; |
| bannerEl.classList.remove('hidden'); |
| document.querySelectorAll('#board button').forEach(b => b.disabled = true); |
| } |
| |
| hintBtn.addEventListener('click', () => panelHint.classList.toggle('hidden')); |
| restartBtn.addEventListener('click', initGame); |
| initGame(); |
| </script> |
| </body> |
| </html> |
|
|