File size: 11,531 Bytes
30a7905
 
 
1b8760e
30a7905
 
1b8760e
30a7905
 
 
 
 
1b8760e
 
 
30a7905
 
 
 
 
1b8760e
30a7905
 
1b8760e
30a7905
1b8760e
 
 
30a7905
1b8760e
30a7905
 
1b8760e
30a7905
 
 
 
 
 
 
1b8760e
 
 
 
 
 
30a7905
1b8760e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30a7905
 
1b8760e
 
 
30a7905
1b8760e
 
 
 
 
 
30a7905
1b8760e
 
30a7905
 
1b8760e
 
 
 
 
 
30a7905
1b8760e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30a7905
1b8760e
 
 
 
 
 
 
 
 
 
 
 
 
 
30a7905
1b8760e
 
 
 
 
30a7905
1b8760e
 
 
 
 
30a7905
1b8760e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30a7905
 
25562f8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Concept to Code Millionaire</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-6">
  <div class="bg-white p-8 rounded-2xl shadow-xl w-full max-w-2xl">
    <h1 class="text-4xl font-bold text-indigo-600 text-center mb-2">Concept to Code Millionaire</h1>
    <p class="text-center text-sm text-gray-500 mb-6">
      Source:
      <a class="underline hover:text-indigo-700" target="_blank"
         href="https://www.linkedin.com/pulse/docker-from-concept-commands-michael-lively-mndwe/">
        Docker: From Concept to Commands — Michael Lively (Aug 23, 2025)
      </a>
    </p>

    <div id="board">
      <div id="error" class="hidden mb-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded p-2"></div>
      <div id="question" class="text-2xl font-semibold text-gray-800 mb-4"></div>
      <div id="choices" class="space-y-3"></div>

      <div id="lifelines" class="flex justify-around mt-6">
        <button id="life5050" class="lifeline bg-yellow-400 hover:bg-yellow-500 text-white font-medium py-2 px-4 rounded-lg shadow">50:50</button>
        <button id="lifePoll" class="lifeline bg-blue-400 hover:bg-blue-500 text-white font-medium py-2 px-4 rounded-lg shadow">Ask the Class</button>
        <button id="lifeHint" class="lifeline bg-green-400 hover:bg-green-500 text-white font-medium py-2 px-4 rounded-lg shadow">Ask an Expert</button>
      </div>

      <div id="poll" class="text-sm text-gray-700 mt-4"></div>
      <div id="hint" class="text-sm italic text-gray-600 mt-2"></div>

      <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">
        Next Question
      </button>
    </div>
  </div>

  <script>
  window.addEventListener('DOMContentLoaded', () => {
    const showError = (msg) => {
      const el = document.getElementById('error');
      el.textContent = msg;
      el.classList.remove('hidden');
    };

    try {
      const questions = [
        { q: "What core problem does Docker reduce by packaging apps with all dependencies?",
          choices: ["\"My CPU is too slow\" problem","\"It works on my machine\" problem","Vendor lock-in of cloud credits","I/O bottlenecks from HDDs"],
          correct: 1, hint: "Called out explicitly as a dreaded phrase." },
        { q: "Which command verifies a fresh Docker install with a tiny test image?",
          choices: ["docker info","docker run hello-world","docker version","docker verify install"],
          correct: 1, hint: "It both pulls and runs a simple image." },
        { q: "Best description of image vs. container?",
          choices: ["Image is the running process; container is the template","Image is a blueprint; container is a running instance","Both are the same","Container builds images automatically"],
          correct: 1, hint: "Blueprint vs. instance." },
        { q: "Which pairing lists Docker’s foundational components?",
          choices: ["Daemon (dockerd) and Client (CLI)","Supervisor and Operator","Scheduler and Controller","Planner and Runner"],
          correct: 0, hint: "One manages objects; one is your command tool." },
        { q: "On Windows/macOS, which bundle includes daemon, CLI, and tools?",
          choices: ["Docker Desktop","Docker Studio","Docker Workstation","Docker Hub Client"],
          correct: 0, hint: "Standard local install for devs." },
        { q: "Most well-known public image registry?",
          choices: ["Artifact Registry","Docker Hub","Harbor","Quay"],
          correct: 1, hint: "Default source for many pulls." },
        { q: "Which pair runs Nginx and maps 80→8080 on host?",
          choices: ["docker pull nginx  &&  docker run -d -p 8080:80 nginx","docker build nginx  &&  docker start -p 8080:80 nginx","docker fetch nginx  &&  docker exec -p 8080:80 nginx","docker clone nginx  &&  docker up -p 8080:80"],
          correct: 0, hint: "Pull, then run detached with -p host:container." },
        { q: "Which file defines how to build your image?",
          choices: ["compose.yaml","Dockerfile","package.json","Container.toml"],
          correct: 1, hint: "Plain text build instructions." },
        { q: "Which build/run pair tags and launches on port 5000?",
          choices: ["docker build -t myapp:1.0 .  &&  docker run -d -p 5000:5000 myapp:1.0","docker build myapp .  &&  docker start -p 5000:5000 myapp","docker compile -t myapp .  &&  docker exec -p 5000 myapp","docker make -t myapp .  &&  docker deploy -p 5000 myapp"],
          correct: 0, hint: "Tag with -t, run with -p host:container." },
        { q: "Day-to-day container lifecycle commands?",
          choices: ["docker ps, docker stop, docker rm, docker logs","docker get, docker halt, docker purge, docker read","docker view, docker end, docker delete, docker cat","docker list, docker kill, docker trash, docker echo"],
          correct: 0, hint: "Canonical verbs in the article." },
        { q: "Keep images small and efficient by…",
          choices: ["Installing all dev tools in final image","Using multi-stage builds and small bases (e.g., alpine)","Bundling multiple apps per container","Avoiding .dockerignore"],
          correct: 1, hint: "Less is more." },
        { q: "Reclaim disk by removing unused images:",
          choices: ["docker image prune -a","docker images --rm all","docker clean images","docker rmi --unused"],
          correct: 0, hint: "Prune is the key." },
        { q: "Simplest built-in clustering for small projects:",
          choices: ["Enable Swarm with docker swarm init","Install Kubernetes the hard way","Write a custom scheduler","Use a systemd unit file"],
          correct: 0, hint: "Built into Docker." },
        { q: "Swarm vs. Kubernetes — best summary:",
          choices: ["Swarm is richer for enterprises","Kubernetes is the de facto standard for large-scale orchestration","Equal production adoption","Swarm has the larger ecosystem"],
          correct: 1, hint: "Think ecosystem and adoption." },
        { q: "Kubernetes quick start sequence from the article:",
          choices: ["minikube start → kubectl create deployment nginx --image=nginx → kubectl expose deployment nginx --port=80 --type=NodePort",
                    "kubeadm up → kctl make deploy nginx → kctl service open 80",
                    "kubestart → kubectl add nginx → kubectl publish 80",
                    "kind boot → kubectl run nginx --image=nginx → kubectl open service 80"],
          correct: 0, hint: "Minikube, create deployment, expose NodePort." }
      ];

      // Evenly redistribute correct answers across A–D
      questions.forEach((q, i) => {
        const target = i % 4; // 0=A,1=B,2=C,3=D
        if (q.correct !== target) {
          [q.choices[target], q.choices[q.correct]] = [q.choices[q.correct], q.choices[target]];
          q.correct = target;
        }
      });

      const prizes = [100,200,300,500,1000,2000,4000,8000,16000,32000,64000,125000,250000,500000,1000000];
      let idx = 0;
      let currentPrize = prizes[0];

      const qEl     = document.getElementById('question');
      const cEl     = document.getElementById('choices');
      const pollEl  = document.getElementById('poll');
      const hintEl  = document.getElementById('hint');
      const nextBtn = document.getElementById('next');
      const boardEl = document.getElementById('board');

      function updateQuestionDisplay() {
        qEl.textContent = `$${currentPrize}: ${questions[idx].q}`;
      }

      function showQuestion() {
        // Reset lifelines
        ['life5050','lifePoll','lifeHint'].forEach(id => {
          const btn = document.getElementById(id);
          btn.disabled = false;
          btn.classList.remove('opacity-50');
        });
        document.getElementById('error').classList.add('hidden');
        pollEl.textContent = '';
        hintEl.textContent = '';
        nextBtn.classList.add('hidden');

        currentPrize = prizes[idx];
        updateQuestionDisplay();

        cEl.innerHTML = questions[idx].choices.map((ch,i) =>
          `<button class="choice bg-indigo-500 hover:bg-indigo-600 text-white font-medium py-2 px-4 rounded w-full" data-i="${i}">
            ${String.fromCharCode(65+i)}. ${ch}
          </button>`
        ).join('');

        document.querySelectorAll('.choice').forEach(btn => {
          btn.disabled = false;
          btn.onclick = selectAnswer;
        });
      }

      function selectAnswer(e) {
        const chosen = +e.currentTarget.dataset.i;
        const corr = questions[idx].correct;
        document.querySelectorAll('.choice').forEach(b => b.disabled = true);

        if (chosen === corr) {
          e.currentTarget.classList.replace('bg-indigo-500','bg-green-500');
        } else {
          e.currentTarget.classList.replace('bg-indigo-500','bg-red-500');
          const correctBtn = document.querySelector(`.choice[data-i="${corr}"]`);
          if (correctBtn) correctBtn.classList.replace('bg-indigo-500','bg-green-500');
        }
        nextBtn.classList.remove('hidden');
      }

      // Lifelines
      document.getElementById('life5050').onclick = () => {
        const btn = document.getElementById('life5050');
        if (btn.disabled) return;
        btn.disabled = true; btn.classList.add('opacity-50');

        const corr = questions[idx].correct;
        [0,1,2,3].filter(i => i !== corr).sort(() => Math.random()-0.5).slice(0,2).forEach(i => {
          const b = document.querySelector(`.choice[data-i="${i}"]`);
          if (b) { b.disabled = true; b.classList.add('opacity-50'); }
        });

        currentPrize = Math.floor(currentPrize / 2);
        updateQuestionDisplay();
      };

      document.getElementById('lifePoll').onclick = () => {
        const btn = document.getElementById('lifePoll');
        if (btn.disabled) return;
        btn.disabled = true; btn.classList.add('opacity-50');

        const corr = questions[idx].correct;
        const pct = [0,0,0,0];
        pct[corr] = 70 + Math.floor(Math.random() * 21);
        let rem = 100 - pct[corr];
        [0,1,2,3].filter(i => i !== corr).forEach((i,j,arr) => {
          const last = j === arr.length - 1;
          const alloc = last ? rem : Math.floor(rem / (arr.length - j));
          pct[i] = alloc; rem -= alloc;
        });
        pollEl.textContent = `Class Poll: A:${pct[0]}% B:${pct[1]}% C:${pct[2]}% D:${pct[3]}%`;
      };

      document.getElementById('lifeHint').onclick = () => {
        const btn = document.getElementById('lifeHint');
        if (btn.disabled) return;
        btn.disabled = true; btn.classList.add('opacity-50');
        hintEl.textContent = `Expert Hint: ${questions[idx].hint}`;
      };

      nextBtn.onclick = () => {
        idx++;
        if (idx < questions.length) {
          showQuestion();
        } else {
          boardEl.innerHTML = '<div class="text-3xl font-bold text-green-600 text-center">🎉 Congratulations! You’ve mastered Concept to Code Millionaire! 🎉</div>';
        }
      };

      // Kickoff
      showQuestion();

    } catch (err) {
      console.error(err);
      showError("JavaScript error prevented the questions from rendering. Open the browser console for details.");
    }
  });
  </script>
</body>
</html>