diff --git a/dsu/index.html b/dsu/index.html
index c9d3584..38b2b93 100644
--- a/dsu/index.html
+++ b/dsu/index.html
@@ -1,429 +1,19 @@
-`
-
+
+
+
DSU Speaker Selector
-
-
-
-
-
-DSURandomUserSelector
-Welcome!
-
-
-
-
-
-
-
-
-
-
+
+
+
+ DSURandomUserSelector
+ Welcome!
+
+
+
+
+
diff --git a/dsu/script.js b/dsu/script.js
new file mode 100644
index 0000000..2521ad7
--- /dev/null
+++ b/dsu/script.js
@@ -0,0 +1,177 @@
+const images = [
+ "./images/Jed.png",
+ "./images/Carlos.png",
+ "./images/Shahbaz.png",
+ "./images/Sheridan.png",
+ "./images/Gayane.png",
+ "./images/Sanjay.png",
+ "./images/DJ.png"
+];
+const userName = document.getElementById("userName");
+const imageGrid = document.getElementById("imageGrid");
+const selectButton = document.getElementById("selectButton");
+const timerDisplay = document.getElementById("timerDisplay");
+
+let timerRunning = false;
+const userTimers = [];
+let availableImages = [...images];
+
+function init() {
+ images.forEach(() => {
+ const div = document.createElement("div");
+ div.classList.add("imageContainer", "empty");
+ imageGrid.appendChild(div);
+ });
+}
+
+function startMainTimer() {
+ timerDisplay.parentElement.classList.add("running");
+ const startTimestamp = Date.now();
+ const updateMainTimer = () => {
+ const elapsed = Math.floor((Date.now() - startTimestamp) / 1000);
+ const mins = Math.floor(elapsed / 60);
+ const secs = elapsed % 60;
+ timerDisplay.textContent = `${mins}:${secs.toString().padStart(2, "0")}`;
+ };
+ updateMainTimer();
+ const mainTimerId = setInterval(updateMainTimer, 1000);
+ timerDisplay.dataset.timerId = mainTimerId;
+ timerRunning = true;
+}
+
+function displaySpeaker(imagePath) {
+ const name = imagePath.split("/").pop().split(".")[0];
+ userName.textContent = name;
+ if (!timerRunning) startMainTimer();
+ selectButton.textContent = "Next Speaker";
+
+ const container = document.querySelector("div.imageContainer.empty");
+ container.id = name;
+ container.classList.remove("empty");
+ container.classList.add("selected", "filled");
+
+ const img = document.createElement("img");
+ img.src = imagePath;
+ img.alt = name;
+ img.classList.add("imageItem");
+
+ const timerDiv = document.createElement("div");
+ timerDiv.classList.add("timer");
+ timerDiv.textContent = "0:00";
+
+ container.appendChild(img);
+ container.appendChild(timerDiv);
+
+ // Resume timer on click
+ container.addEventListener("click", () => {
+ removeSelected();
+ container.classList.add("selected");
+ const prevTime = userTimers.find(u => u.user === name)?.time || 0;
+ const resumeStart = Date.now() - prevTime * 1000;
+ const updateResume = () => {
+ const elapsed = Math.floor((Date.now() - resumeStart) / 1000);
+ const mins = Math.floor(elapsed / 60);
+ const secs = elapsed % 60;
+ timerDiv.textContent = `${mins}:${secs.toString().padStart(2, "0")}`;
+ };
+ updateResume();
+ const resumeId = setInterval(updateResume, 1000);
+ container.dataset.timerId = resumeId;
+ if (selectButton.textContent === "End Meeting") {
+ selectButton.classList.remove("reset");
+ selectButton.textContent = "Done!";
+ }
+ });
+
+ // Remove used image from list
+ availableImages = availableImages.filter(p => p !== imagePath);
+
+ // Start new speaker timer
+ const start = Date.now();
+ const updateTimer = () => {
+ const elapsed = Math.floor((Date.now() - start) / 1000);
+ const mins = Math.floor(elapsed / 60);
+ const secs = elapsed % 60;
+ timerDiv.textContent = `${mins}:${secs.toString().padStart(2, "0")}`;
+ };
+ updateTimer();
+ const timerId = setInterval(updateTimer, 1000);
+ container.dataset.timerId = timerId;
+
+ if (availableImages.length === 0) {
+ selectButton.classList.add("reset");
+ selectButton.textContent = "Done!";
+ }
+}
+
+function removeSelected() {
+ const sel = imageGrid.querySelector("div.selected");
+ if (!sel) return;
+ sel.classList.remove("selected");
+ clearInterval(parseInt(sel.dataset.timerId));
+ const name = sel.id;
+ const time = toSeconds(sel.querySelector(".timer").textContent);
+ const idx = userTimers.findIndex(u => u.user === name);
+ if (idx !== -1) userTimers[idx].time = time;
+ else userTimers.push({ user: name, time });
+}
+
+function toSeconds(str) {
+ const [m, s] = str.split(":").map(Number);
+ return m * 60 + s;
+}
+
+function selectRandomImage() {
+ removeSelected();
+ const idx = Math.floor(Math.random() * availableImages.length);
+ displaySpeaker(availableImages[idx]);
+}
+
+function endSpeakers() {
+ userName.textContent = "Done!";
+ selectButton.textContent = "End Meeting";
+ imageGrid.classList.add("done");
+ removeSelected();
+}
+
+function endMeeting() {
+ userName.textContent = "Done!";
+ selectButton.textContent = "Reset Meeting";
+ selectButton.classList.add("reset");
+ imageGrid.classList.add("finished");
+ removeSelected();
+ timerDisplay.parentElement.classList.remove("running");
+ if (timerDisplay.dataset.timerId) clearInterval(parseInt(timerDisplay.dataset.timerId));
+ timerDisplay.dataset.timerId = null;
+ timerRunning = false;
+}
+
+function resetMeeting() {
+ imageGrid.classList.remove("finished");
+ availableImages = [...images];
+ clearTimers();
+ document.querySelectorAll(".imageContainer").forEach(div => {
+ div.classList.remove("selected", "filled");
+ div.classList.add("empty");
+ div.innerHTML = "";
+ });
+ selectButton.textContent = "Start Meeting";
+ selectButton.classList.remove("reset");
+}
+
+function clearTimers() {
+ timerDisplay.parentElement.classList.remove("running");
+ timerDisplay.textContent = "0:00";
+ document.querySelectorAll(".imageContainer").forEach(div => {
+ if (div.dataset.timerId) clearInterval(parseInt(div.dataset.timerId));
+ });
+}
+
+selectButton.addEventListener("click", () => {
+ if (availableImages.length > 0) selectRandomImage();
+ else if (selectButton.textContent === "Done!") endSpeakers();
+ else if (selectButton.textContent === "End Meeting") endMeeting();
+ else if (selectButton.textContent === "Reset Meeting") resetMeeting();
+});
+
+init();
\ No newline at end of file
diff --git a/dsu/style.css b/dsu/style.css
new file mode 100644
index 0000000..fc76936
--- /dev/null
+++ b/dsu/style.css
@@ -0,0 +1,144 @@
+html {
+ background-color: #333;
+}
+body {
+ font-family: sans-serif;
+ text-align: center;
+ background: #333;
+ background: linear-gradient(180deg, #333, transparent, #333);
+ color: #fff;
+}
+h1 {
+ font-weight: 300;
+ font-size: 28px;
+}
+h1 span {
+ font-weight: 400;
+ color: #aaaaaacc;
+}
+#userName {
+ font-size: 44px;
+ color: #fff;
+ font-weight: 400;
+ margin: 0;
+}
+#imageGrid {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+ margin: 50px auto;
+ border: solid 1px #666;
+ padding: 20px;
+ max-width: 1200px;
+}
+#imageGrid div.imageContainer {
+ width: 160px;
+ height: 220px;
+ border: solid 1px #757575;
+ background: linear-gradient(45deg, #000, transparent);
+}
+#imageGrid > div {
+ opacity: 0.33;
+ transition: all 0.3s ease;
+}
+#imageGrid.done > div {
+ opacity: 1;
+}
+#imageGrid.finished > div {
+ opacity: 0.75;
+}
+#imageGrid div.selected {
+ opacity: 1;
+ border: solid 1px #999;
+ box-shadow: 0 0 16px #000;
+ transform: scale(1.25);
+ font-weight: 300;
+ position: absolute;
+ z-index: 2;
+ border-radius: 20px;
+}
+#imageGrid div.selected img {
+ border-radius: 20px 20px 0 0;
+}
+#imageGrid .selected {
+ animation: spinHorizontal 0.8s ease-in-out;
+}
+@keyframes spinHorizontal {
+ from {
+ transform: rotateX(270deg) scale(0.05);
+ }
+ to {
+ transform: rotateX(0) scale(1.25);
+ }
+}
+.imageItem {
+ width: 160px;
+ height: 180px;
+ object-fit: cover;
+ cursor: pointer;
+}
+.timer {
+ font-size: 28px;
+ font-family: monospace;
+ background: #000;
+ color: #999;
+ margin-top: -5px;
+ padding: 4px;
+ border-radius: 0 0 20px 20px;
+}
+#selectButton {
+ padding: 10px 20px;
+ font-size: 16px;
+ background-color: #4CAF50;
+ color: #fff;
+ border: none;
+ cursor: pointer;
+ border-radius: 5px;
+}
+#selectButton.reset {
+ background-color: #2d6a2f;
+}
+#mainTimer {
+ display: none;
+ color: #666;
+ margin-top: 50px;
+ font-weight: 300;
+}
+#mainTimer.running {
+ display: block;
+}
+#mainTimer.finished,
+#mainTimer.finished > #timerDisplay {
+ color: #ddd;
+}
+#timerDisplay {
+ color: #404040;
+ font-size: 100px;
+ font-weight: 600;
+ text-shadow: 1px 1px 0 #666;
+}
+.imageContainer.empty {
+ font-size: 200px;
+ color: #ffffff22;
+}
+.imageContainer.empty:first-child:after {
+ content: 'J';
+}
+.imageContainer.empty:nth-child(2):after {
+ content: 'A';
+}
+.imageContainer.empty:nth-child(3):after {
+ content: 'V';
+}
+.imageContainer.empty:nth-child(4):after {
+ content: 'E';
+}
+.imageContainer.empty:nth-child(5):after {
+ content: 'L';
+}
+.imageContainer.empty:nth-child(6):after {
+ content: 'I';
+}
+.imageContainer.empty:nth-child(7):after {
+ content: 'N';
+}