Great idea, Ray. Let’s create a 1-hour class for beginners that teaches how to make a simple PWA, step-by-step — hands-on, clear, and paced for learners.
All posts by raymay14
Glasswork
#!/bin/bash
# Base directory for PWAs
BASE_DIR="$HOME/16_PWAs"
mkdir -p "$BASE_DIR"
for i in {1..16}
do
DIR="$BASE_DIR/$i"
mkdir -p "$DIR"
# Create index.html
cat > "$DIR/index.html" <<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PWA #$i</title>
<link rel="manifest" href="manifest.json" />
</head>
<body>
<h1>PWA #$i</h1>
<p>This is PWA number $i.</p>
</body>
</html>
EOF
# Create manifest.json
cat > "$DIR/manifest.json" <<EOF
{
"name": "PWA #$i",
"short_name": "PWA$i",
"start_url": ".",
"display": "standalone",
"background_color": "#ffffff",
"description": "Progressive Web App number $i.",
"icons": []
}
EOF
# Create sw.js
cat > "$DIR/sw.js" <<EOF
self.addEventListener(‘install’, function(event) {
console.log(‘Service Worker installing PWA #$i’);
self.skipWaiting();
});
self.addEventListener(‘activate’, function(event) {
console.log(‘Service Worker activating PWA #$i’);
});
self.addEventListener(‘fetch’, function(event) {
event.respondWith(fetch(event.request));
});
EOF
done
# Create ZIP file
cd "$HOME"
zip -r 16_PWAs.zip 16_PWAs
echo "All PWAs created and zipped at $HOME/16_PWAs.zip"
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz
Bingo checker, V2
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″ />
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″/>
<title>Bingo Checker PWA</title>
<link rel=”manifest” href=”manifest.json”>
<style>
body { font-family: sans-serif; padding: 20px; background: #f0f0f0; }
input, select, button, textarea {
display: block; width: 100%; margin: 10px 0; padding: 10px; font-size: 16px;
}
#result { font-weight: bold; margin-top: 20px; }
</style>
</head>
<body>
<h1>Bingo Checker</h1>
<label for=”pattern”>Choose Bingo Pattern:</label>
<select id=”pattern”>
<option>Blackout</option>
<option>Four Corners</option>
<option>Horizontal Line</option>
<option>Vertical Line</option>
<option>Diagonal Line</option>
<option>X Pattern</option>
<option>T Pattern</option>
<option>L Pattern</option>
<option>Z Pattern</option>
<option>Diamond Pattern</option>
<option>Postage Stamp</option>
<option>Crazy Kite</option>
<option>Arrow Pattern</option>
<option>Plus Sign (+)</option>
<option>Small Picture Frame</option>
<option>Large Picture Frame</option>
<option>Outside Edge</option>
<option>Inside Square</option>
<option>Custom Pattern</option>
<option>Any Bingo</option>
</select>
<label for=”card”>Enter Bingo Card (5×5 grid, comma-separated rows):</label>
<textarea id=”card” rows=”5″ placeholder=”e.g. 1,16,31,46,61\n2,17,32,47,62…”></textarea>
<label for=”called”>Enter Called Numbers (comma-separated):</label>
<textarea id=”called” rows=”2″ placeholder=”e.g. 1,2,3,4,5,10,15,…”></textarea>
<button onclick=”checkBingo()”>Check for Bingo</button>
<div id=”result”></div>
<script>
function parseCard(text) {
return text.trim().split(‘\n’).map(row => row.split(‘,’).map(n => parseInt(n.trim())));
}
function isMarked(card, called, r, c) {
return called.includes(card[r][c]);
}
function checkPattern(card, called, pattern) {
const marked = (r, c) => isMarked(card, called, r, c);
switch (pattern) {
case ‘Blackout’:
return card.every((row, r) => row.every((_, c) => marked(r, c)));
case ‘Four Corners’:
return marked(0,0) && marked(0,4) && marked(4,0) && marked(4,4);
case ‘Horizontal Line’:
return card.some((_, r) => card[r].every((_, c) => marked(r, c)));
case ‘Vertical Line’:
return card[0].some((_, c) => card.every((_, r) => marked(r, c)));
case ‘Diagonal Line’:
return [0,1,2,3,4].every(i => marked(i,i)) || [0,1,2,3,4].every(i => marked(i,4-i));
case ‘X Pattern’:
return [0,1,2,3,4].every(i => marked(i,i) && marked(i,4-i));
case ‘T Pattern’:
return card[0].every((_, c) => marked(0,c)) && [0,1,2,3,4].every(r => marked(r,2));
case ‘L Pattern’:
return [0,1,2,3,4].every(r => marked(r,0)) && card[4].every((_, c) => marked(4,c));
case ‘Z Pattern’:
return [0,1,2,3,4].every(i => marked(i,4-i)) && (marked(0,0) && marked(0,1) && marked(4,3) && marked(4,4));
case ‘Diamond Pattern’:
return marked(0,2) && marked(1,1) && marked(1,3) && marked(2,0) && marked(2,4) && marked(3,1) && marked(3,3) && marked(4,2);
case ‘Postage Stamp’:
return marked(0,0) && marked(0,1) && marked(1,0) && marked(1,1);
case ‘Crazy Kite’:
return marked(0,4) && marked(1,3) && marked(2,2) && marked(3,1) && marked(4,0);
case ‘Arrow Pattern’:
return marked(0,2) && marked(1,2) && marked(2,2) && marked(2,1) && marked(2,3);
case ‘Plus Sign (+)’:
return [0,1,2,3,4].every(i => marked(i,2)) && card[2].every((_, c) => marked(2,c));
case ‘Small Picture Frame’:
return [0,1,3,4].every(r => card[r].every((_, c) => (c === 0 || c === 4) ? marked(r, c) : true));
case ‘Large Picture Frame’:
return card.map((row, r) => row.map((_, c) =>
(r === 0 || r === 4 || c === 0 || c === 4) ? marked(r, c) : true)).flat().every(v => v);
case ‘Outside Edge’:
return checkPattern(card, called, ‘Large Picture Frame’);
case ‘Inside Square’:
return [1,2,3].every(r => [1,2,3].every(c => marked(r,c)));
case ‘Any Bingo’:
return checkPattern(card, called, ‘Horizontal Line’) ||
checkPattern(card, called, ‘Vertical Line’) ||
checkPattern(card, called, ‘Diagonal Line’);
case ‘Custom Pattern’:
return false; // Placeholder
default:
return false;
}
}
function checkBingo() {
const pattern = document.getElementById(‘pattern’).value;
const cardText = document.getElementById(‘card’).value;
const calledText = document.getElementById(‘called’).value;
const called = calledText.split(‘,’).map(n => parseInt(n.trim()));
const card = parseCard(cardText);
const valid = checkPattern(card, called, pattern);
document.getElementById(‘result’).innerText = valid ? ‘✅ Bingo!’ : ‘❌ Not a Bingo Yet’;
}
// PWA
if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘sw.js’);
}
</script>
<script type=”application/json” id=”manifest”>
{
“name”: “Bingo Checker”,
“short_name”: “Bingo”,
“start_url”: “.”,
“display”: “standalone”,
“background_color”: “#ffffff”,
“theme_color”: “#317EFB”,
“icons”: [{
“src”: “https://cdn-icons-png.flaticon.com/512/1048/1048940.png”,
“sizes”: “512×512”,
“type”: “image/png”
}]
}
</script>
<script id=”sw” type=”javascript/worker”>
self.addEventListener(‘install’, event => {
event.waitUntil(caches.open(‘bingo-v1’).then(cache => {
return cache.addAll([‘./’]);
}));
});
self.addEventListener(‘fetch’, event => {
event.respondWith(
caches.match(event.request).then(response => response || fetch(event.request))
);
});
</script>
</body>
</html>
One minute apps and sites image
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz

One minute apps and sites image
New bingo APP I built it this morning please approve
https://ray2407.github.io/250529bingo/
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz
On Fri, May 30, 2025 at 7:12 AM Clifford Hackett <3659745> wrote:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Bingo Checker</title>
<link rel="manifest" href="manifest.json" />
<style>
body { font-family: sans-serif; text-align: center; background: #f0f0f0; }
table { border-collapse: collapse; margin: 10px auto; }
td { width: 60px; height: 60px; text-align: center; vertical-align: middle;
border: 1px solid #888; font-size: 20px; cursor: pointer; }
.marked { background-color: #4caf50; color: white; }
input, button { margin: 10px; padding: 10px; font-size: 16px; }
#status { font-size: 1.2em; margin-top: 10px; color: #d32f2f; }
</style>
</head>
<body>
<h1>Bingo Checker</h1>
<div>
<table id="bingoCard"></table>
<input type="text" id="calledInput" placeholder="Enter called number (e.g., B5)" />
<button onclick="markCalled()">Mark</button>
<div id="status"></div>
</div>
<script>
const bingoCard = [
["B1", "B2", "B3", "B4", "B5"],
["I16", "I17", "I18", "I19", "I20"],
["N31", "N32", "FREE", "N34", "N35"],
["G46", "G47", "G48", "G49", "G50"],
["O61", "O62", "O63", "O64", "O65"]
];
const marked = Array.from({ length: 5 }, () => Array(5).fill(false));
marked[2][2] = true; // Free space
function renderCard() {
const table = document.getElementById("bingoCard");
table.innerHTML = "";
for (let r = 0; r < 5; r++) {
const row = document.createElement("tr");
for (let c = 0; c < 5; c++) {
const cell = document.createElement("td");
cell.textContent = bingoCard[r][c];
if (marked[r][c]) cell.classList.add("marked");
row.appendChild(cell);
}
table.appendChild(row);
}
}
function markCalled() {
const input = document.getElementById("calledInput").value.toUpperCase().trim();
for (let r = 0; r < 5; r++) {
for (let c = 0; c < 5; c++) {
if (bingoCard[r][c] === input) {
marked[r][c] = true;
renderCard();
checkBingo();
return;
}
}
}
document.getElementById("status").textContent = "Number not found.";
}
function checkBingo() {
const status = document.getElementById("status");
// Rows
for (let r = 0; r < 5; r++) if (marked[r].every(Boolean)) return status.textContent = "🎉 BINGO!";
// Columns
for (let c = 0; c < 5; c++) if (marked.every(row => row[c])) return status.textContent = "🎉 BINGO!";
// Diagonals
if ([0,1,2,3,4].every(i => marked[i][i]) || [0,1,2,3,4].every(i => marked[i][4-i]))
return status.textContent = "🎉 BINGO!";
status.textContent = "";
}
window.onload = () => {
renderCard();
if (‘serviceWorker’ in navigator) navigator.serviceWorker.register(‘sw.js’);
};
</script>
<!– Manifest (inlined for PWA functionality) –>
<script type="application/json" id="manifest.json">
{
"name": "Bingo Checker",
"short_name": "BingoApp",
"start_url": ".",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4caf50",
"icons": [{
"src": "https://ray2407.github.io/250527b/icon.png",
"sizes": "192×192",
"type": "image/png"
}]
}
</script>
<!– Service Worker (inlined for offline support) –>
<script id="sw.js" type="javascript/worker">
const cacheName = "bingo-cache-v1";
self.addEventListener("install", e => {
e.waitUntil(
caches.open(cacheName).then(cache => cache.addAll([".", "index.html"]))
);
});
self.addEventListener("fetch", e => {
e.respondWith(
caches.match(e.request).then(res => res || fetch(e.request))
);
});
</script>
</body>
</html>
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz
New bingo APP I built it this morning please approve
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Bingo Checker</title>
<link rel="manifest" href="manifest.json" />
<style>
body { font-family: sans-serif; text-align: center; background: #f0f0f0; }
table { border-collapse: collapse; margin: 10px auto; }
td { width: 60px; height: 60px; text-align: center; vertical-align: middle;
border: 1px solid #888; font-size: 20px; cursor: pointer; }
.marked { background-color: #4caf50; color: white; }
input, button { margin: 10px; padding: 10px; font-size: 16px; }
#status { font-size: 1.2em; margin-top: 10px; color: #d32f2f; }
</style>
</head>
<body>
<h1>Bingo Checker</h1>
<div>
<table id="bingoCard"></table>
<input type="text" id="calledInput" placeholder="Enter called number (e.g., B5)" />
<button onclick="markCalled()">Mark</button>
<div id="status"></div>
</div>
<script>
const bingoCard = [
["B1", "B2", "B3", "B4", "B5"],
["I16", "I17", "I18", "I19", "I20"],
["N31", "N32", "FREE", "N34", "N35"],
["G46", "G47", "G48", "G49", "G50"],
["O61", "O62", "O63", "O64", "O65"]
];
const marked = Array.from({ length: 5 }, () => Array(5).fill(false));
marked[2][2] = true; // Free space
function renderCard() {
const table = document.getElementById("bingoCard");
table.innerHTML = "";
for (let r = 0; r < 5; r++) {
const row = document.createElement("tr");
for (let c = 0; c < 5; c++) {
const cell = document.createElement("td");
cell.textContent = bingoCard[r][c];
if (marked[r][c]) cell.classList.add("marked");
row.appendChild(cell);
}
table.appendChild(row);
}
}
function markCalled() {
const input = document.getElementById("calledInput").value.toUpperCase().trim();
for (let r = 0; r < 5; r++) {
for (let c = 0; c < 5; c++) {
if (bingoCard[r][c] === input) {
marked[r][c] = true;
renderCard();
checkBingo();
return;
}
}
}
document.getElementById("status").textContent = "Number not found.";
}
function checkBingo() {
const status = document.getElementById("status");
// Rows
for (let r = 0; r < 5; r++) if (marked[r].every(Boolean)) return status.textContent = "🎉 BINGO!";
// Columns
for (let c = 0; c < 5; c++) if (marked.every(row => row[c])) return status.textContent = "🎉 BINGO!";
// Diagonals
if ([0,1,2,3,4].every(i => marked[i][i]) || [0,1,2,3,4].every(i => marked[i][4-i]))
return status.textContent = "🎉 BINGO!";
status.textContent = "";
}
window.onload = () => {
renderCard();
if (‘serviceWorker’ in navigator) navigator.serviceWorker.register(‘sw.js’);
};
</script>
<!– Manifest (inlined for PWA functionality) –>
<script type="application/json" id="manifest.json">
{
"name": "Bingo Checker",
"short_name": "BingoApp",
"start_url": ".",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4caf50",
"icons": [{
"src": "https://ray2407.github.io/250527b/icon.png",
"sizes": "192×192",
"type": "image/png"
}]
}
</script>
<!– Service Worker (inlined for offline support) –>
<script id="sw.js" type="javascript/worker">
const cacheName = "bingo-cache-v1";
self.addEventListener("install", e => {
e.waitUntil(
caches.open(cacheName).then(cache => cache.addAll([".", "index.html"]))
);
});
self.addEventListener("fetch", e => {
e.respondWith(
caches.match(e.request).then(res => res || fetch(e.request))
);
});
</script>
</body>
</html>
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz
Image for flyer approval requested
Mahalo
SIGNATURE:
Clifford "RAY" Hackett I founded www.adapt.org in 1980 it now has over 50 million members.
$500 of material=World’s fastest hydrofoil sailboat. http://sunrun.biz
Our Signal Safety Number:
Our Signal Safety Number:
76851 77022 10443 11569
34688 41318 99861 71312
22032 95019 08211 28281

