@@ -42,7 +42,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
+
{
@@ -56,35 +56,21 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
- QR
-
+
+
+
+ {profile.npub}
+
+
+
-
-
{profile.handle}
- {profile.about ?
{profile.about}
:
No public bio in kind 0.
}
-
-
+ {profile.about ?
{profile.about}
:
No public bio.
}
))
}
@@ -92,98 +78,39 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
-
-
@@ -195,7 +122,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
}
.alumni-hero {
- min-height: 74vh;
+ min-height: 0;
position: relative;
}
@@ -288,7 +215,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
background:
linear-gradient(180deg, rgb(255 255 255 / 4%), transparent 38%),
#030303;
- min-height: 19rem;
+ min-height: 16.5rem;
padding: 1rem;
}
@@ -298,17 +225,16 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
#050505;
}
- .alumni-card-top,
- .alumni-card-foot {
+ .alumni-card-top {
align-items: center;
display: flex;
- gap: 1rem;
- justify-content: space-between;
+ gap: 0.85rem;
}
.alumni-avatar-link {
color: inherit;
display: inline-flex;
+ flex: 0 0 auto;
text-decoration: none;
}
@@ -346,33 +272,14 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
border-color: var(--color-primary);
}
- .alumni-qr-button {
- align-items: center;
- background: transparent;
- border: 1px solid rgb(255 255 255 / 14%);
- color: rgb(255 255 255 / 48%);
- cursor: pointer;
- display: inline-flex;
- font-family: var(--font-primary);
- font-size: 0.68rem;
- justify-content: center;
- letter-spacing: 0.16em;
- min-height: 2.75rem;
- min-width: 2.75rem;
- padding: 0.45rem 0.55rem;
- text-transform: uppercase;
- }
-
- .alumni-qr-button:hover,
- .alumni-qr-button:focus-visible {
- border-color: var(--color-primary);
- color: var(--color-primary);
+ .alumni-card-identity {
+ min-width: 0;
}
.alumni-card-title {
font-size: 1.45rem;
line-height: 1.05;
- margin: 1.1rem 0 0;
+ margin: 0;
text-transform: none;
}
@@ -388,13 +295,59 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
color: var(--color-primary);
}
- .alumni-handle {
+ .alumni-npub-copy {
+ align-items: flex-start;
+ background: transparent;
+ border: 0;
color: rgb(255 255 255 / 42%);
+ cursor: pointer;
+ display: inline-flex;
font-family: var(--font-primary);
- font-size: 0.78rem;
- letter-spacing: 0.04em;
- margin: 0.45rem 0 0;
+ font-size: 0.74rem;
+ gap: 0.45rem;
+ letter-spacing: 0.03em;
+ margin: 0.35rem 0 0;
+ max-width: 100%;
+ min-width: 0;
+ padding: 0;
+ text-align: left;
+ }
+
+ .alumni-npub-copy:hover,
+ .alumni-npub-copy:focus-visible,
+ .alumni-npub-copy.is-copied {
+ color: var(--color-primary);
+ }
+
+ .alumni-npub-copy.is-copy-failed {
+ color: #fff;
+ }
+
+ .alumni-npub {
+ min-width: 0;
overflow-wrap: anywhere;
+ word-break: break-word;
+ }
+
+ .alumni-copy-icon {
+ background: currentColor;
+ display: inline-flex;
+ flex: 0 0 auto;
+ height: 0.95rem;
+ line-height: 1;
+ mask: url('/images/copy-to-clipboard.svg') center / contain no-repeat;
+ width: 0.95rem;
+ margin-top: 0.05rem;
+ }
+
+ .alumni-npub-copy.is-copied .alumni-copy-icon,
+ .alumni-npub-copy.is-copy-failed .alumni-copy-icon {
+ align-items: center;
+ background: transparent;
+ font-size: 0.9rem;
+ font-weight: 700;
+ justify-content: center;
+ mask: none;
}
.alumni-about {
@@ -414,134 +367,9 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
font-style: italic;
}
- .alumni-card-foot {
- border-top: 1px solid rgb(255 255 255 / 8%);
- color: rgb(255 255 255 / 34%);
- font-size: 0.72rem;
- letter-spacing: 0.12em;
- margin-top: 1rem;
- padding-top: 0.85rem;
- text-transform: uppercase;
- }
-
- .alumni-card-foot a {
- color: rgb(255 255 255 / 50%);
- text-decoration: none;
- }
-
- .alumni-card-foot a:hover,
- .alumni-card-foot a:focus-visible {
- color: var(--color-primary);
- }
-
.alumni-card a:focus-visible,
- .alumni-card button:focus-visible,
- .alumni-dialog-close:focus-visible,
- .alumni-dialog-copy:focus-visible,
- .alumni-dialog-link:focus-visible {
+ .alumni-card button:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 3px;
}
-
- .alumni-qr-dialog {
- background: transparent;
- border: 0;
- color: #fff;
- inset: 0;
- margin: auto;
- max-width: min(92vw, 420px);
- padding: 0;
- position: fixed;
- width: min(92vw, 420px);
- }
-
- .alumni-qr-dialog::backdrop {
- background: rgb(0 0 0 / 78%);
- backdrop-filter: blur(8px);
- }
-
- .alumni-qr-panel {
- background:
- linear-gradient(180deg, rgb(255 255 255 / 8%), transparent 32%),
- #050505;
- border: 1px solid rgb(255 255 255 / 16%);
- display: grid;
- gap: 1rem;
- padding: 1.25rem;
- position: relative;
- text-align: center;
- }
-
- .alumni-qr-panel h2 {
- font-size: 2rem;
- line-height: 1;
- margin: 0;
- text-transform: none;
- }
-
- .alumni-dialog-close {
- align-items: center;
- background: transparent;
- border: 0;
- color: rgb(255 255 255 / 54%);
- cursor: pointer;
- display: inline-flex;
- font-size: 2rem;
- height: 2.75rem;
- justify-content: center;
- line-height: 1;
- position: absolute;
- right: 0.45rem;
- top: 0.35rem;
- width: 2.75rem;
- }
-
- .alumni-dialog-close:hover {
- color: var(--color-primary);
- }
-
- .alumni-qr-image {
- background: #fff;
- border: 8px solid #fff;
- height: 240px;
- justify-self: center;
- width: 240px;
- }
-
- .alumni-dialog-npub {
- color: rgb(255 255 255 / 62%);
- font-size: 0.86rem;
- margin: 0;
- overflow-wrap: anywhere;
- }
-
- .alumni-dialog-actions {
- align-items: center;
- display: flex;
- flex-wrap: wrap;
- gap: 0.75rem;
- justify-content: center;
- }
-
- .alumni-dialog-copy {
- background: transparent;
- border: 1px solid rgb(255 255 255 / 18%);
- color: rgb(255 255 255 / 68%);
- cursor: pointer;
- font-family: var(--font-primary);
- font-size: 0.72rem;
- letter-spacing: 0.14em;
- min-height: 2.75rem;
- padding: 0.7rem 0.9rem;
- text-transform: uppercase;
- }
-
- .alumni-dialog-copy:hover {
- border-color: var(--color-primary);
- color: var(--color-primary);
- }
-
- .alumni-dialog-link {
- justify-self: center;
- }
From f36d39f68b673a02d4a9ed5b99c04eebce4afc89 Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Fri, 19 Jun 2026 22:01:55 +0530
Subject: [PATCH 11/29] fix(alumni): refresh source list and polish grid
---
scripts/extract-alumni-kind0.mjs | 138 ++-
scripts/test-alumni-page-source.mjs | 14 +
src/data/sovengAlumni.json | 1359 ++++++++++++++++++---------
src/pages/alumni.astro | 122 ++-
4 files changed, 1138 insertions(+), 495 deletions(-)
diff --git a/scripts/extract-alumni-kind0.mjs b/scripts/extract-alumni-kind0.mjs
index b376e4f4..f07a2a55 100644
--- a/scripts/extract-alumni-kind0.mjs
+++ b/scripts/extract-alumni-kind0.mjs
@@ -7,6 +7,17 @@ import { createHash } from 'node:crypto';
const root = process.cwd();
const alumniPath = join(root, 'src/data/sovengAlumni.json');
const membershipSourceUrl = 'https://following.space/d/sier9e7ih6k2?p=83d999a148625c3d2bb819af3064c0f6a12d7da88f68b2c69221f3a746171d19';
+const membershipAuthorPubkey = '83d999a148625c3d2bb819af3064c0f6a12d7da88f68b2c69221f3a746171d19';
+const membershipListId = 'sier9e7ih6k2';
+const membershipListKind = 39089;
+const followListRelayUrls = [
+ 'wss://relay.damus.io',
+ 'wss://relay.nostr.band',
+ 'wss://nostr.oxtr.dev',
+ 'wss://nostr-pub.wellorder.net',
+ 'wss://nos.lol',
+ 'wss://relay.primal.net',
+];
const relayUrls = [
'wss://nos.lol',
'wss://relay.damus.io',
@@ -81,10 +92,74 @@ function parseEventLines(stdout, eventsByPubkey, allowedPubkeys) {
}
}
-function fetchKind0Events(seedRecords) {
+function parseJsonEventLines(stdout) {
+ const events = [];
+ for (const line of stdout.split('\n')) {
+ const trimmed = line.trim();
+ if (!trimmed.startsWith('{')) continue;
+ try {
+ events.push(JSON.parse(trimmed));
+ } catch {
+ // Ignore relay notices and partial lines.
+ }
+ }
+ return events;
+}
+
+function isValidMembershipListEvent(event) {
+ if (!event || event.kind !== membershipListKind || event.pubkey !== membershipAuthorPubkey || !isHex64(event.id)) return false;
+ if (!Number.isInteger(event.created_at) || event.created_at <= 0) return false;
+ if (!Array.isArray(event.tags) || event.tags.some((tag) => !Array.isArray(tag) || tag.some((item) => typeof item !== 'string'))) return false;
+ if (typeof event.content !== 'string') return false;
+ if (computeNostrEventId(event) !== event.id) return false;
+ return event.tags.some((tag) => tag[0] === 'd' && tag[1] === membershipListId);
+}
+
+function hexToNpub(pubkey, existingByPubkey) {
+ const existing = existingByPubkey.get(pubkey);
+ if (existing?.npub) return existing.npub;
+ const result = spawnSync('nak', ['encode', 'npub', pubkey], { cwd: root, encoding: 'utf8', maxBuffer: 1024 * 1024 });
+ if (result.error) throw result.error;
+ if (result.status !== 0) throw new Error(`nak encode npub exited with ${result.status}: ${result.stderr}`);
+ const npub = result.stdout.trim();
+ if (!/^npub1[023456789acdefghjklmnpqrstuvwxyz]+$/.test(npub)) throw new Error(`nak returned invalid npub for ${pubkey}`);
+ return npub;
+}
+
+function fetchMembershipSeedRecords(existingRecords) {
+ const existingByPubkey = new Map(existingRecords.map((record) => [record.pubkey, record]));
+ const args = ['req', '-k', String(membershipListKind), '-a', membershipAuthorPubkey, '-d', membershipListId, '-l', '20', ...followListRelayUrls];
+ console.error(`fetching source follow-list ${membershipListKind}:${membershipAuthorPubkey}:${membershipListId}`);
+ const result = spawnSync('nak', args, { cwd: root, encoding: 'utf8', maxBuffer: 20 * 1024 * 1024, timeout: 90_000 });
+ if (result.error) throw result.error;
+ if (result.status !== 0) throw new Error(`nak follow-list req exited with ${result.status}: ${result.stderr}`);
+
+ const events = parseJsonEventLines(result.stdout).filter(isValidMembershipListEvent);
+ if (events.length === 0) throw new Error('no valid source follow-list event returned from relays');
+ events.sort((left, right) => right.created_at - left.created_at || right.id.localeCompare(left.id));
+
+ const event = events[0];
+ const seen = new Set();
+ const seedRecords = [];
+ for (const tag of event.tags) {
+ if (tag[0] !== 'p' || !isHex64(tag[1]) || seen.has(tag[1])) continue;
+ seen.add(tag[1]);
+ seedRecords.push({ pubkey: tag[1], npub: hexToNpub(tag[1], existingByPubkey) });
+ }
+ if (seedRecords.length === 0) throw new Error('source follow-list event has no p tags');
+ console.error(`source follow-list event ${event.id} has ${seedRecords.length} unique pubkeys`);
+ return seedRecords;
+}
+
+function seedExistingKind0Events(eventsByPubkey, existingRecords, allowedPubkeys) {
+ for (const record of existingRecords) rememberEvent(eventsByPubkey, record.kind0, allowedPubkeys);
+}
+
+function fetchKind0Events(seedRecords, existingRecords) {
const pubkeys = seedRecords.map((record) => record.pubkey);
const allowedPubkeys = new Set(pubkeys);
const eventsByPubkey = new Map();
+ seedExistingKind0Events(eventsByPubkey, existingRecords, allowedPubkeys);
for (let index = 0; index < pubkeys.length; index += chunkSize) {
const chunk = pubkeys.slice(index, index + chunkSize);
const chunkSet = new Set(chunk);
@@ -120,10 +195,11 @@ function fetchKind0Events(seedRecords) {
return eventsByPubkey;
}
-const seedRecords = uniqueByPubkey(JSON.parse(readFileSync(alumniPath, 'utf8')));
+const existingRecords = uniqueByPubkey(JSON.parse(readFileSync(alumniPath, 'utf8')));
+const seedRecords = fetchMembershipSeedRecords(existingRecords);
const pubkeys = seedRecords.map((record) => record.pubkey);
const fetchedAt = new Date().toISOString();
-const eventsByPubkey = fetchKind0Events(seedRecords);
+const eventsByPubkey = fetchKind0Events(seedRecords, existingRecords);
const missing = pubkeys.filter((pubkey) => !eventsByPubkey.has(pubkey));
if (missing.length > 0) {
@@ -132,31 +208,37 @@ if (missing.length > 0) {
process.exit(1);
}
-const records = seedRecords.map((seed) => {
- const kind0 = eventsByPubkey.get(seed.pubkey);
- const metadata = parseMetadata(kind0);
- const name = asCleanString(metadata.name);
- const displayName = asCleanString(metadata.display_name) ?? asCleanString(metadata.displayName);
- const about = asCleanString(metadata.about);
- const picture = asCleanString(metadata.picture);
- const nip05 = asCleanString(metadata.nip05);
-
- return {
- pubkey: seed.pubkey,
- npub: seed.npub,
- ...(name ? { name } : {}),
- ...(displayName ? { displayName } : {}),
- ...(about ? { about } : {}),
- ...(nip05 ? { nip05 } : {}),
- ...(picture ? { picture } : {}),
- kind0,
- source: {
- membershipSourceUrl,
- relayUrls,
- fetchedAt,
- },
- };
-});
+const records = seedRecords
+ .map((seed) => {
+ const kind0 = eventsByPubkey.get(seed.pubkey);
+ const metadata = parseMetadata(kind0);
+ const name = asCleanString(metadata.name);
+ const displayName = asCleanString(metadata.display_name) ?? asCleanString(metadata.displayName);
+ const about = asCleanString(metadata.about);
+ const picture = asCleanString(metadata.picture);
+ const nip05 = asCleanString(metadata.nip05);
+
+ return {
+ pubkey: seed.pubkey,
+ npub: seed.npub,
+ ...(name ? { name } : {}),
+ ...(displayName ? { displayName } : {}),
+ ...(about ? { about } : {}),
+ ...(nip05 ? { nip05 } : {}),
+ ...(picture ? { picture } : {}),
+ kind0,
+ source: {
+ membershipSourceUrl,
+ relayUrls,
+ fetchedAt,
+ },
+ };
+ })
+ .sort((left, right) => {
+ const leftName = left.displayName || left.name || left.npub;
+ const rightName = right.displayName || right.name || right.npub;
+ return leftName.localeCompare(rightName, undefined, { sensitivity: 'base' }) || left.npub.localeCompare(right.npub);
+ });
writeFileSync(alumniPath, `${JSON.stringify(records, null, 2)}\n`);
console.log(`wrote ${records.length} source-locked alumni records with raw kind0 events to ${alumniPath}`);
diff --git a/scripts/test-alumni-page-source.mjs b/scripts/test-alumni-page-source.mjs
index 4449cfb9..4b3535f2 100644
--- a/scripts/test-alumni-page-source.mjs
+++ b/scripts/test-alumni-page-source.mjs
@@ -21,6 +21,16 @@ assert.match(page, /class="[^"]*alumni-total-count[^"]*"[\s\S]*\{stats\.total\}/
assert.match(page, /getAlumniProfileViewModel/, 'alumni route should render safe profile view models');
assert.match(page, /class="[^"]*alumni-grid/, 'alumni route should render the profile grid');
assert.match(page, /class="[^"]*alumni-card/, 'alumni route should render profile cards');
+const alumniGridRule = page.match(/\.alumni-grid\s*\{[\s\S]*?\n \}/)?.[0] ?? '';
+assert.doesNotMatch(alumniGridRule, /\bborder\s*:/, 'profile grid should not draw an outer border');
+assert.match(alumniGridRule, /gap:\s*0/, 'grid should avoid gap-based outer border artifacts');
+assert.match(page, /\.alumni-card::after\s*\{[\s\S]*linear-gradient\(to bottom[\s\S]*linear-gradient\(to right/, 'card separators should be internal fading lines');
+assert.match(page, /--sep-right[\s\S]*--sep-bottom/, 'separator rules should suppress outer grid edges');
+const sparkleRule = page.match(/\.alumni-card::before\s*\{[\s\S]*?\n \}/)?.[0] ?? '';
+assert.match(sparkleRule, /radial-gradient[\s\S]*var\(--color-primary\)/, 'cards should define red sparkle overlay');
+assert.match(sparkleRule, /0\.35px[\s\S]*0\.55px[\s\S]*0\.85px/, 'sparkle dots should use varied tiny sizes, not uniform dots');
+assert.doesNotMatch(sparkleRule, /82%, transparent|1\.1px|1\.9px/, 'sparkle dots should stay subtle, not oversized or over-bright');
+assert.match(page, /\.alumni-card:hover::before[^{]*\{[\s\S]*opacity:\s*1/, 'card hover should show full-card red sparkle overlay');
assert.match(page, /class="[^"]*alumni-hero bg-black pt-16 pb-4 text-white sm:pt-20 sm:pb-6/, 'hero should keep top breathing room but tighten bottom gap');
assert.match(page, /\.alumni-hero\s*\{[\s\S]*min-height:\s*0/, 'hero should not force tall viewport spacing');
assert.match(page, /class="[^"]*alumni-directory bg-black pt-0 pb-16 text-white sm:pb-20/, 'directory should start immediately after hero');
@@ -33,6 +43,10 @@ assert.match(page, /navigator\.clipboard\.writeText\(value\)/, 'copy control sho
assert.match(page, /icon\.textContent = '✓'/, 'copy icon should turn into a tick after copying');
assert.match(page, /classList\.add\('is-copied'\)/, 'copy control should expose copied visual state');
assert.match(page, /data-alumni-avatar-image/, 'avatar images should have an error fallback hook');
+assert.match(page, /width="64"[\s\S]*height="64"/, 'avatar images should declare dimensions to reduce layout shift');
+assert.match(page, /loading=\{index < 6 \? 'eager' : 'lazy'\}/, 'above-fold avatars should load eagerly while offscreen avatars stay lazy');
+assert.match(page, /fetchpriority=\{index < 3 \? 'high' : 'auto'\}/, 'first visible avatars should get higher fetch priority');
+assert.match(page, /contain:\s*layout paint/, 'cards should contain layout/paint without hiding visible content');
assert.match(page, /referrerpolicy="no-referrer"/, 'external profile images should avoid leaking referrers');
assert.doesNotMatch(page, /
{
- alumni.map((profile) => (
+ alumni.map((profile, index) => (
- {profile.picture && }
+ {profile.picture && (
+
+ )}
{profile.initials}
@@ -203,26 +216,117 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
}
.alumni-grid {
- background: rgb(255 255 255 / 10%);
- border: 1px solid rgb(255 255 255 / 10%);
+ background: transparent;
display: grid;
- gap: 1px;
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
+ gap: 0;
+ grid-template-columns: minmax(0, 1fr);
overflow: hidden;
}
+ @media (min-width: 720px) {
+ .alumni-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
+
+ @media (min-width: 1040px) {
+ .alumni-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+ }
+
.alumni-card {
+ --sep-bottom: 1px;
+ --sep-right: 0px;
background:
linear-gradient(180deg, rgb(255 255 255 / 4%), transparent 38%),
#030303;
+ contain: layout paint;
+ isolation: isolate;
min-height: 16.5rem;
+ overflow: hidden;
padding: 1rem;
+ position: relative;
+ transition: background-color 150ms ease;
}
- .alumni-card:hover {
+ .alumni-card:last-child {
+ --sep-bottom: 0px;
+ }
+
+ @media (min-width: 720px) {
+ .alumni-card {
+ --sep-bottom: 1px;
+ --sep-right: 1px;
+ }
+
+ .alumni-card:nth-child(2n) {
+ --sep-right: 0px;
+ }
+
+ .alumni-card:nth-last-child(-n + 2) {
+ --sep-bottom: 0px;
+ }
+ }
+
+ @media (min-width: 1040px) {
+ .alumni-card:nth-child(2n) {
+ --sep-right: 1px;
+ }
+
+ .alumni-card:nth-child(3n) {
+ --sep-right: 0px;
+ }
+
+ .alumni-card:nth-last-child(-n + 3) {
+ --sep-bottom: 0px;
+ }
+ }
+
+ .alumni-card::before {
+ background:
+ radial-gradient(circle at 13% 18%, color-mix(in srgb, var(--color-primary) 42%, transparent) 0 0.35px, transparent 0.95px),
+ radial-gradient(circle at 31% 72%, color-mix(in srgb, var(--color-primary) 30%, transparent) 0 0.55px, transparent 1.15px),
+ radial-gradient(circle at 54% 34%, color-mix(in srgb, var(--color-primary) 24%, transparent) 0 0.28px, transparent 0.85px),
+ radial-gradient(circle at 72% 66%, color-mix(in srgb, var(--color-primary) 36%, transparent) 0 0.85px, transparent 1.45px),
+ radial-gradient(circle at 87% 24%, color-mix(in srgb, var(--color-primary) 28%, transparent) 0 0.42px, transparent 1px),
+ radial-gradient(circle at 18% 88%, color-mix(in srgb, var(--color-primary) 22%, transparent) 0 0.62px, transparent 1.25px),
+ radial-gradient(circle at 43% 51%, color-mix(in srgb, var(--color-primary) 20%, transparent) 0 0.22px, transparent 0.8px),
+ radial-gradient(circle at 94% 82%, color-mix(in srgb, var(--color-primary) 32%, transparent) 0 0.72px, transparent 1.35px),
+ radial-gradient(ellipse at 48% 42%, color-mix(in srgb, var(--color-primary) 7%, transparent), transparent 64%),
+ linear-gradient(color-mix(in srgb, var(--color-primary) 5%, transparent), color-mix(in srgb, var(--color-primary) 5%, transparent));
+ content: '';
+ inset: 0;
+ opacity: 0;
+ pointer-events: none;
+ position: absolute;
+ transition: opacity 150ms ease;
+ z-index: 0;
+ }
+
+ .alumni-card::after {
background:
- linear-gradient(180deg, color-mix(in srgb, var(--color-primary) 9%, transparent), transparent 42%),
- #050505;
+ linear-gradient(to bottom, transparent, rgb(255 255 255 / 11%) 18%, rgb(255 255 255 / 7%) 72%, transparent) right top / var(--sep-right) 100% no-repeat,
+ linear-gradient(to right, transparent, rgb(255 255 255 / 11%) 18%, rgb(255 255 255 / 7%) 72%, transparent) left bottom / 100% var(--sep-bottom) no-repeat;
+ content: '';
+ inset: 0;
+ pointer-events: none;
+ position: absolute;
+ z-index: 0;
+ }
+
+ .alumni-card > * {
+ position: relative;
+ z-index: 1;
+ }
+
+ .alumni-card:hover {
+ background-color: #070202;
+ }
+
+ .alumni-card:hover::before,
+ .alumni-card:focus-within::before {
+ opacity: 1;
}
.alumni-card-top {
From e7f2dbb741a34a34dcf7b2af047977eabd1b0f0d Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Fri, 19 Jun 2026 22:35:15 +0530
Subject: [PATCH 12/29] style(alumni): add grid breathing room
---
scripts/test-alumni-page-source.mjs | 2 +-
src/pages/alumni.astro | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/test-alumni-page-source.mjs b/scripts/test-alumni-page-source.mjs
index 4b3535f2..f615dcc3 100644
--- a/scripts/test-alumni-page-source.mjs
+++ b/scripts/test-alumni-page-source.mjs
@@ -33,7 +33,7 @@ assert.doesNotMatch(sparkleRule, /82%, transparent|1\.1px|1\.9px/, 'sparkle dots
assert.match(page, /\.alumni-card:hover::before[^{]*\{[\s\S]*opacity:\s*1/, 'card hover should show full-card red sparkle overlay');
assert.match(page, /class="[^"]*alumni-hero bg-black pt-16 pb-4 text-white sm:pt-20 sm:pb-6/, 'hero should keep top breathing room but tighten bottom gap');
assert.match(page, /\.alumni-hero\s*\{[\s\S]*min-height:\s*0/, 'hero should not force tall viewport spacing');
-assert.match(page, /class="[^"]*alumni-directory bg-black pt-0 pb-16 text-white sm:pb-20/, 'directory should start immediately after hero');
+assert.match(page, /class="[^"]*alumni-directory bg-black pt-6 pb-16 text-white sm:pt-8 sm:pb-20/, 'directory should leave a small breathing gap before the grid');
assert.match(page, /class="[^"]*alumni-card-top[\s\S]*alumni-avatar-link[\s\S]*alumni-card-identity[\s\S]*alumni-card-title/, 'card name should sit next to profile image');
assert.match(page, /class="[^"]*alumni-card-identity[\s\S]*alumni-card-title[\s\S]*alumni-npub-copy/, 'npub copy control should sit under card name');
assert.match(page, /class="[^"]*alumni-npub-copy[^"]*"[\s\S]*data-alumni-copy[\s\S]*data-npub=\{profile\.npub\}[\s\S]*\{profile\.npub\}[\s\S]*copy-to-clipboard\.svg/, 'npub and copy icon should be one clickable copy control');
diff --git a/src/pages/alumni.astro b/src/pages/alumni.astro
index 2f72b493..88481442 100644
--- a/src/pages/alumni.astro
+++ b/src/pages/alumni.astro
@@ -42,7 +42,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
+
{
From 56556c6725ff7d171a481f369581809dc4c0f18b Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Fri, 19 Jun 2026 23:27:09 +0530
Subject: [PATCH 13/29] style(alumni): increase grid spacing
---
scripts/test-alumni-page-source.mjs | 2 +-
src/pages/alumni.astro | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/test-alumni-page-source.mjs b/scripts/test-alumni-page-source.mjs
index f615dcc3..1f4f3ac1 100644
--- a/scripts/test-alumni-page-source.mjs
+++ b/scripts/test-alumni-page-source.mjs
@@ -33,7 +33,7 @@ assert.doesNotMatch(sparkleRule, /82%, transparent|1\.1px|1\.9px/, 'sparkle dots
assert.match(page, /\.alumni-card:hover::before[^{]*\{[\s\S]*opacity:\s*1/, 'card hover should show full-card red sparkle overlay');
assert.match(page, /class="[^"]*alumni-hero bg-black pt-16 pb-4 text-white sm:pt-20 sm:pb-6/, 'hero should keep top breathing room but tighten bottom gap');
assert.match(page, /\.alumni-hero\s*\{[\s\S]*min-height:\s*0/, 'hero should not force tall viewport spacing');
-assert.match(page, /class="[^"]*alumni-directory bg-black pt-6 pb-16 text-white sm:pt-8 sm:pb-20/, 'directory should leave a small breathing gap before the grid');
+assert.match(page, /class="[^"]*alumni-directory bg-black pt-8 pb-16 text-white sm:pt-10 sm:pb-20/, 'directory should leave a measured breathing gap before the grid');
assert.match(page, /class="[^"]*alumni-card-top[\s\S]*alumni-avatar-link[\s\S]*alumni-card-identity[\s\S]*alumni-card-title/, 'card name should sit next to profile image');
assert.match(page, /class="[^"]*alumni-card-identity[\s\S]*alumni-card-title[\s\S]*alumni-npub-copy/, 'npub copy control should sit under card name');
assert.match(page, /class="[^"]*alumni-npub-copy[^"]*"[\s\S]*data-alumni-copy[\s\S]*data-npub=\{profile\.npub\}[\s\S]*\{profile\.npub\}[\s\S]*copy-to-clipboard\.svg/, 'npub and copy icon should be one clickable copy control');
diff --git a/src/pages/alumni.astro b/src/pages/alumni.astro
index 88481442..0cd9b402 100644
--- a/src/pages/alumni.astro
+++ b/src/pages/alumni.astro
@@ -42,7 +42,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
+
{
From 61f13b773cae067ab77a2cc17648fa0ea0802941 Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Fri, 19 Jun 2026 23:32:10 +0530
Subject: [PATCH 14/29] Revert "style(alumni): increase grid spacing"
This reverts commit 56556c6725ff7d171a481f369581809dc4c0f18b.
---
scripts/test-alumni-page-source.mjs | 2 +-
src/pages/alumni.astro | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/test-alumni-page-source.mjs b/scripts/test-alumni-page-source.mjs
index 1f4f3ac1..f615dcc3 100644
--- a/scripts/test-alumni-page-source.mjs
+++ b/scripts/test-alumni-page-source.mjs
@@ -33,7 +33,7 @@ assert.doesNotMatch(sparkleRule, /82%, transparent|1\.1px|1\.9px/, 'sparkle dots
assert.match(page, /\.alumni-card:hover::before[^{]*\{[\s\S]*opacity:\s*1/, 'card hover should show full-card red sparkle overlay');
assert.match(page, /class="[^"]*alumni-hero bg-black pt-16 pb-4 text-white sm:pt-20 sm:pb-6/, 'hero should keep top breathing room but tighten bottom gap');
assert.match(page, /\.alumni-hero\s*\{[\s\S]*min-height:\s*0/, 'hero should not force tall viewport spacing');
-assert.match(page, /class="[^"]*alumni-directory bg-black pt-8 pb-16 text-white sm:pt-10 sm:pb-20/, 'directory should leave a measured breathing gap before the grid');
+assert.match(page, /class="[^"]*alumni-directory bg-black pt-6 pb-16 text-white sm:pt-8 sm:pb-20/, 'directory should leave a small breathing gap before the grid');
assert.match(page, /class="[^"]*alumni-card-top[\s\S]*alumni-avatar-link[\s\S]*alumni-card-identity[\s\S]*alumni-card-title/, 'card name should sit next to profile image');
assert.match(page, /class="[^"]*alumni-card-identity[\s\S]*alumni-card-title[\s\S]*alumni-npub-copy/, 'npub copy control should sit under card name');
assert.match(page, /class="[^"]*alumni-npub-copy[^"]*"[\s\S]*data-alumni-copy[\s\S]*data-npub=\{profile\.npub\}[\s\S]*\{profile\.npub\}[\s\S]*copy-to-clipboard\.svg/, 'npub and copy icon should be one clickable copy control');
diff --git a/src/pages/alumni.astro b/src/pages/alumni.astro
index 0cd9b402..88481442 100644
--- a/src/pages/alumni.astro
+++ b/src/pages/alumni.astro
@@ -42,7 +42,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
-
+
{
From b9c25ef464a856c47900167ccd3829713012f24b Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Fri, 19 Jun 2026 23:50:07 +0530
Subject: [PATCH 15/29] style(alumni): add grid top spacing
---
scripts/test-alumni-page-source.mjs | 1 +
src/pages/alumni.astro | 1 +
2 files changed, 2 insertions(+)
diff --git a/scripts/test-alumni-page-source.mjs b/scripts/test-alumni-page-source.mjs
index f615dcc3..85105786 100644
--- a/scripts/test-alumni-page-source.mjs
+++ b/scripts/test-alumni-page-source.mjs
@@ -24,6 +24,7 @@ assert.match(page, /class="[^"]*alumni-card/, 'alumni route should render profil
const alumniGridRule = page.match(/\.alumni-grid\s*\{[\s\S]*?\n \}/)?.[0] ?? '';
assert.doesNotMatch(alumniGridRule, /\bborder\s*:/, 'profile grid should not draw an outer border');
assert.match(alumniGridRule, /gap:\s*0/, 'grid should avoid gap-based outer border artifacts');
+assert.match(alumniGridRule, /margin-top:\s*5mm/, 'grid should sit about 5mm below the top section');
assert.match(page, /\.alumni-card::after\s*\{[\s\S]*linear-gradient\(to bottom[\s\S]*linear-gradient\(to right/, 'card separators should be internal fading lines');
assert.match(page, /--sep-right[\s\S]*--sep-bottom/, 'separator rules should suppress outer grid edges');
const sparkleRule = page.match(/\.alumni-card::before\s*\{[\s\S]*?\n \}/)?.[0] ?? '';
diff --git a/src/pages/alumni.astro b/src/pages/alumni.astro
index 88481442..f3963523 100644
--- a/src/pages/alumni.astro
+++ b/src/pages/alumni.astro
@@ -220,6 +220,7 @@ const sourceMembershipHref = alumni[0]?.sourceHref;
display: grid;
gap: 0;
grid-template-columns: minmax(0, 1fr);
+ margin-top: 5mm;
overflow: hidden;
}
From 265d061cff953be115451b40bc56c95126b822af Mon Sep 17 00:00:00 2001
From: jo <36855907+jodobear@users.noreply.github.com>
Date: Sat, 20 Jun 2026 00:03:33 +0530
Subject: [PATCH 16/29] perf(alumni): serve cached avatar assets
---
package.json | 1 +
...xrns37ml9tss82jvymv8fymwdtu6cts3h6pvr.webp | Bin 0 -> 2948 bytes
...zc7xx3qpvzs3w4etgemauy9thegr43sf485vg.webp | Bin 0 -> 5990 bytes
...8svd9lc7vlqrkx7hepe7nq6jggn7kfq92rrm3.webp | Bin 0 -> 272 bytes
...5f88y2fv780c2kfs89ge5qk6q3sfm7spks880.webp | Bin 0 -> 1870 bytes
...ur4djeehf50xagxq3y3pchhzjptz7yqenvn7c.webp | Bin 0 -> 982 bytes
...8h3wpwn2d7s2xecw2ygnrxqp4wgsklq9g722q.webp | Bin 0 -> 3346 bytes
...r74wzyjshvl65za5k5rl69264ar2exs5cyejr.webp | Bin 0 -> 822 bytes
...mawegxf688v0gtqwhjpgtp0a4k2mesqshkwwx.webp | Bin 0 -> 3576 bytes
...f7q7uhhxaw2p3d0w487zadym7gt90cqdqn6cc.webp | Bin 0 -> 4418 bytes
...9m7xy994tatxd6sm7kmxaygkq4lertsfnacfm.webp | Bin 0 -> 2686 bytes
...7vla23a38j689jssaqlqqlzrtqtd0kqex0nkq.webp | Bin 0 -> 3322 bytes
...z6pygqm4pwc6gve4mrned3xs8tz42gq7kfhdw.webp | Bin 0 -> 1028 bytes
...x62akgrjezygmdfsgkjpdde3yykfuhscgxcms.webp | Bin 0 -> 2264 bytes
...waq29az753wr9th3hyrm5p63kz2zu8qzumhgd.webp | Bin 0 -> 5864 bytes
...xmdtp6e5wq77ys203dp3s88pjhgpxpsvgkemm.webp | Bin 0 -> 5302 bytes
...s5ts4n7gewxax53m7f2m4f464ls92cqr5qjta.webp | Bin 0 -> 2268 bytes
...3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf.webp | Bin 0 -> 3322 bytes
...8qdlavsn334m9mfhurjsge08grg82zq6hu9su.webp | Bin 0 -> 1824 bytes
...uypmc226vrudxz9y64se6heda35jdescaeqct.webp | Bin 0 -> 2408 bytes
...54v96cuvqv6j9fmu4cgfjqkt5vjuvjsc47nzf.webp | Bin 0 -> 2398 bytes
...cg5ktun3al4c5xu2pts3ewckv0y70ys0gupzr.webp | Bin 0 -> 5054 bytes
...7fvzy37kcfp67aqjtmv2qgy4lp34nhsda8p6k.webp | Bin 0 -> 3282 bytes
...rrrnsg2pyv7za06pxjduv25lq5sdujs2qmdj6.webp | Bin 0 -> 5598 bytes
...3dvfp72456x6nezjw4sd850q879rxqsthg9jp.webp | Bin 0 -> 4656 bytes
...z6xj4lfj7qfssqamg60fkfp5f6mlzaskklrf3.webp | Bin 0 -> 1494 bytes
...wdjs952h2ux2ha2ed598ngwu9w7a6fsh9xzpc.webp | Bin 0 -> 554 bytes
...s4krrt6sj7l6gtnf2q7d47nmqtldpgqgctgtm.webp | Bin 0 -> 5430 bytes
...e9gffsyu9ew7cu3ld3f9y7k79nxzjxqf4d4rm.webp | Bin 0 -> 2112 bytes
...vwn4c8ypqjl72u2sh4rt8zy2kss0j5qct7mh9.webp | Bin 0 -> 796 bytes
...3qzdjr4kyvaparuyuttyrx6e8xp7xnq32cume.webp | Bin 0 -> 2736 bytes
...sxkwgwrqypfgeqx0lx9pgjam7gnj4ysaqhkj6.webp | Bin 0 -> 1548 bytes
...ffmr2tgkzjz92rkafyfyz5463wr8ars8zls5t.webp | Bin 0 -> 5694 bytes
...mvgz0z6g2v5rakr65shxemyvjwwdjzqcpeavj.webp | Bin 0 -> 3064 bytes
...aqy5ux5mseqcrzy05g26ml43xf74nyqsredsh.webp | Bin 0 -> 1394 bytes
...qutdz2ukq4ks0gvy5af25rgmwsl4ngq43drvk.webp | Bin 0 -> 1848 bytes
...ydxa32v67gyn2z3lykdvupvvhl47k7spf8ypc.webp | Bin 0 -> 1824 bytes
...37tysglvz43hzjler9nssk6kav0m66sv7xjkt.webp | Bin 0 -> 4262 bytes
...hygvc8ldeyhrgxuwg744dn5khnpk3gs3ea5ds.webp | Bin 0 -> 2286 bytes
...hpqx0t0pwanpae9z25crn7m9uy7yarse465gr.webp | Bin 0 -> 5068 bytes
...azszg7gue83c4hkktunhs3lkfy7mpdqx6zden.webp | Bin 0 -> 1162 bytes
...zamv2u60923ncgfea0e6thkza5p7c3q0afmzy.webp | Bin 0 -> 2254 bytes
...hq7rc8dpegj3ndf82c3ks2sk40dxt7qulx3vt.webp | Bin 0 -> 3840 bytes
...px73rprcmrvd5dc7ck8esg8f8es06qs427gxc.webp | Bin 0 -> 2432 bytes
...vn29faehy9hy34ygaclpn66ukqp3afqutajft.webp | Bin 0 -> 1902 bytes
...wxyzamuy5qcsqcu4uwu7pa3dpapleysf7aap5.webp | Bin 0 -> 5144 bytes
...wgwjw2wcn06daxtverq068dtgwkd98sf6ge63.webp | Bin 0 -> 1754 bytes
...fmtkqmm7ggutdtnc4hyuux2skr4ttcqr827lj.webp | Bin 0 -> 3254 bytes
...vdfz2h95mm04r23t8pau2uzxwsdnpgs0gpdjc.webp | Bin 0 -> 1754 bytes
...00n2t03n8gdx83zhxzculk6sh9nhwlq7uc226.webp | Bin 0 -> 2238 bytes
...2tf23upfs70uwyetneq0szquqamu7jqkhlfa7.webp | Bin 0 -> 3580 bytes
...wsauj5p2qxq95v4a9j0jxl8wnkfvuyque23vg.webp | Bin 0 -> 2052 bytes
...4rskv40zutkfs38t0hqhkvnwlhagp6s3psn5p.webp | Bin 0 -> 3902 bytes
...u745k0fzel6thksv0gwfxy3wanprcxq79mymx.webp | Bin 0 -> 4170 bytes
...p953dflcnw7ppn72tad4htkpsckwcmqjef6um.webp | Bin 0 -> 3614 bytes
...v3d5rqghfc6d8sez8240rf3gja4vsmsd2yha8.webp | Bin 0 -> 3336 bytes
...pl5du8pa96xl6uy8xndweeckjkn964qjs23sn.webp | Bin 0 -> 2372 bytes
...8u8uuskh6sut77tulcqljue7rr7m6hquzh9ph.webp | Bin 0 -> 4878 bytes
...samj00rm2gt4q5wfuyu3tg0x3jg3gesvncxf8.webp | Bin 0 -> 4182 bytes
...ftnv6zc2mzpdc569yjm6ks4k2jhezcs53uksr.webp | Bin 0 -> 1846 bytes
...jgmn7yxrrjklmsr0wwjl2707vhk965sp7dx3u.webp | Bin 0 -> 6216 bytes
...hvw4ec53z0ncdpre0t0huyl8s8zqrfquvz7zr.webp | Bin 0 -> 3040 bytes
...772s7zae6hqncmw5wj27ejud5wcxf7q0nx7d5.webp | Bin 0 -> 3184 bytes
...ls4ytcux6my606tgfx9xttut907h0zs76lgjw.webp | Bin 0 -> 1854 bytes
...7ykgmepk57p0yrzw8fzc7lfhjkmjmqqmd9r6h.webp | Bin 0 -> 2188 bytes
...8hvmpsn5jvhfzn3kk38rfcel6awznks7znspg.webp | Bin 0 -> 2862 bytes
...v02lgu6q6sez4gvs63d696putzyezqs65qqsd.webp | Bin 0 -> 5992 bytes
...6l3jt4nypj8q5d2dc572uhz94nyeytq02tuyu.webp | Bin 0 -> 6846 bytes
...eu4v37jtjmwvev0jyk3zjhxg2wnt56seyez97.webp | Bin 0 -> 3078 bytes
...fw8h4t75kf6w8vmga2zz9jsx3atzpuqlmw8vy.webp | Bin 0 -> 1780 bytes
...jpyt649z33hu82wc2hpv6m5xdqmuxhs46turz.webp | Bin 0 -> 3058 bytes
...p2y6ta3enfcg7ywnayshvlw9r5w6ehsqq99rx.webp | Bin 0 -> 4136 bytes
...5dnhvfeh6d8w0g6eayaep5dhps6rsgs43dgh9.webp | Bin 0 -> 2800 bytes
...x6cfprl848ev4lsmx5h4mznyz3xft9sen050h.webp | Bin 0 -> 4150 bytes
...lj2t5ddsj2eu0xwt4kh4xw5ses2rauqnstrdv.webp | Bin 0 -> 662 bytes
...ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr.webp | Bin 0 -> 506 bytes
...azsen8yd7dtuzcz5uv8d3vkast9hlks4725sl.webp | Bin 0 -> 4700 bytes
...vvvwts4p6v9l045dmn9rp570dqry7zsyll0dt.webp | Bin 0 -> 1958 bytes
...2qeqs2mu0emrm9xknkhgw7hfl7csrnq6wxm56.webp | Bin 0 -> 2972 bytes
...p5r79p7ljq7aw37eek64hf0ef6v0mxqgwljrv.webp | Bin 0 -> 2088 bytes
scripts/cache-alumni-avatars.mjs | 175 +++++
scripts/test-alumni-static-avatars.mjs | 67 ++
scripts/test-soveng-alumni-helpers.mjs | 8 +-
src/data/sovengAlumniAvatarCache.js | 3 +
src/data/sovengAlumniAvatarCache.json | 658 ++++++++++++++++++
src/lib/sovengAlumni.ts | 36 +-
86 files changed, 945 insertions(+), 3 deletions(-)
create mode 100644 public/images/alumni/avatars/npub10wzfa7jkqj6c65xyr93hhxrns37ml9tss82jvymv8fymwdtu6cts3h6pvr.webp
create mode 100644 public/images/alumni/avatars/npub12rv5lskctqxxs2c8rf2zlzc7xx3qpvzs3w4etgemauy9thegr43sf485vg.webp
create mode 100644 public/images/alumni/avatars/npub12w53uwny68m936vr4s0yl8svd9lc7vlqrkx7hepe7nq6jggn7kfq92rrm3.webp
create mode 100644 public/images/alumni/avatars/npub12zpfs3yq7we83yvypgsrw5f88y2fv780c2kfs89ge5qk6q3sfm7spks880.webp
create mode 100644 public/images/alumni/avatars/npub13nfdp7p3pacqn6202q33sur4djeehf50xagxq3y3pchhzjptz7yqenvn7c.webp
create mode 100644 public/images/alumni/avatars/npub149p5act9a5qm9p47elp8w8h3wpwn2d7s2xecw2ygnrxqp4wgsklq9g722q.webp
create mode 100644 public/images/alumni/avatars/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr.webp
create mode 100644 public/images/alumni/avatars/npub15ymzglvv4alrp06q85eqqmawegxf688v0gtqwhjpgtp0a4k2mesqshkwwx.webp
create mode 100644 public/images/alumni/avatars/npub169d679h2ugm9s3j84w63mf7q7uhhxaw2p3d0w487zadym7gt90cqdqn6cc.webp
create mode 100644 public/images/alumni/avatars/npub16c9a45p5dr6l3jzmrvgdh9m7xy994tatxd6sm7kmxaygkq4lertsfnacfm.webp
create mode 100644 public/images/alumni/avatars/npub16dhgpql60vmd4mnydjut87vla23a38j689jssaqlqqlzrtqtd0kqex0nkq.webp
create mode 100644 public/images/alumni/avatars/npub16p8v7varqwjes5hak6q7mz6pygqm4pwc6gve4mrned3xs8tz42gq7kfhdw.webp
create mode 100644 public/images/alumni/avatars/npub16q4rk48xgvlu0snq36v7lx62akgrjezygmdfsgkjpdde3yykfuhscgxcms.webp
create mode 100644 public/images/alumni/avatars/npub16vzjeglr653mrmyqvu0trwaq29az753wr9th3hyrm5p63kz2zu8qzumhgd.webp
create mode 100644 public/images/alumni/avatars/npub175aemydge5thld9peuyp5xmdtp6e5wq77ys203dp3s88pjhgpxpsvgkemm.webp
create mode 100644 public/images/alumni/avatars/npub17ngcvm59n9trc5kwam03rs5ts4n7gewxax53m7f2m4f464ls92cqr5qjta.webp
create mode 100644 public/images/alumni/avatars/npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf.webp
create mode 100644 public/images/alumni/avatars/npub18gr2m5cflkzpn6jdfer4a8qdlavsn334m9mfhurjsge08grg82zq6hu9su.webp
create mode 100644 public/images/alumni/avatars/npub18r5cznu8e4632p4w7htahuypmc226vrudxz9y64se6heda35jdescaeqct.webp
create mode 100644 public/images/alumni/avatars/npub18vay956v7zs5qtgc65mvn54v96cuvqv6j9fmu4cgfjqkt5vjuvjsc47nzf.webp
create mode 100644 public/images/alumni/avatars/npub19at4nqjjymca2lh3v546vcg5ktun3al4c5xu2pts3ewckv0y70ys0gupzr.webp
create mode 100644 public/images/alumni/avatars/npub19wavu4f7l6l43h24jyskn7fvzy37kcfp67aqjtmv2qgy4lp34nhsda8p6k.webp
create mode 100644 public/images/alumni/avatars/npub1a3um269aaf3u5cy37kuykrrrnsg2pyv7za06pxjduv25lq5sdujs2qmdj6.webp
create mode 100644 public/images/alumni/avatars/npub1aljazgxlpnpfp7n5sunlk3dvfp72456x6nezjw4sd850q879rxqsthg9jp.webp
create mode 100644 public/images/alumni/avatars/npub1d7exvqfvxqyrq0j54e23gz6xj4lfj7qfssqamg60fkfp5f6mlzaskklrf3.webp
create mode 100644 public/images/alumni/avatars/npub1dergggklka99wwrs92yz8wdjs952h2ux2ha2ed598ngwu9w7a6fsh9xzpc.webp
create mode 100644 public/images/alumni/avatars/npub1dmhju6xrn8y09malwrvrrs4krrt6sj7l6gtnf2q7d47nmqtldpgqgctgtm.webp
create mode 100644 public/images/alumni/avatars/npub1dvdcmtp5llrp63jdlmhspe9gffsyu9ew7cu3ld3f9y7k79nxzjxqf4d4rm.webp
create mode 100644 public/images/alumni/avatars/npub1e5tfhk8m65teu25dfx8lcvwn4c8ypqjl72u2sh4rt8zy2kss0j5qct7mh9.webp
create mode 100644 public/images/alumni/avatars/npub1elta7cneng3w8p9y4dw633qzdjr4kyvaparuyuttyrx6e8xp7xnq32cume.webp
create mode 100644 public/images/alumni/avatars/npub1equrmqway3qxw3dkssymusxkwgwrqypfgeqx0lx9pgjam7gnj4ysaqhkj6.webp
create mode 100644 public/images/alumni/avatars/npub1ez8efu9rjxu64g0lalty2ffmr2tgkzjz92rkafyfyz5463wr8ars8zls5t.webp
create mode 100644 public/images/alumni/avatars/npub1fcthj78n5re7dcyrva89gmvgz0z6g2v5rakr65shxemyvjwwdjzqcpeavj.webp
create mode 100644 public/images/alumni/avatars/npub1ftt05tgku25m2akgvw6v7aqy5ux5mseqcrzy05g26ml43xf74nyqsredsh.webp
create mode 100644 public/images/alumni/avatars/npub1g53mukxnjkcmr94fhryzkqutdz2ukq4ks0gvy5af25rgmwsl4ngq43drvk.webp
create mode 100644 public/images/alumni/avatars/npub1g5ax26gr5qcnjh29puccyydxa32v67gyn2z3lykdvupvvhl47k7spf8ypc.webp
create mode 100644 public/images/alumni/avatars/npub1gz8kx67jdlx972vgjqemg37tysglvz43hzjler9nssk6kav0m66sv7xjkt.webp
create mode 100644 public/images/alumni/avatars/npub1gzuushllat7pet0ccv9yuhygvc8ldeyhrgxuwg744dn5khnpk3gs3ea5ds.webp
create mode 100644 public/images/alumni/avatars/npub1hw6amg8p24ne08c9gdq8hhpqx0t0pwanpae9z25crn7m9uy7yarse465gr.webp
create mode 100644 public/images/alumni/avatars/npub1jmm9yfymp9rwz46a0z5tcazszg7gue83c4hkktunhs3lkfy7mpdqx6zden.webp
create mode 100644 public/images/alumni/avatars/npub1jss47s4fvv6usl7tn6yp5zamv2u60923ncgfea0e6thkza5p7c3q0afmzy.webp
create mode 100644 public/images/alumni/avatars/npub1klkk3vrzme455yh9rl2jshq7rc8dpegj3ndf82c3ks2sk40dxt7qulx3vt.webp
create mode 100644 public/images/alumni/avatars/npub1klr0dy2ul2dx9llk58czvpx73rprcmrvd5dc7ck8esg8f8es06qs427gxc.webp
create mode 100644 public/images/alumni/avatars/npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft.webp
create mode 100644 public/images/alumni/avatars/npub1l5u0zd00va02ch5n6ke2wwxyzamuy5qcsqcu4uwu7pa3dpapleysf7aap5.webp
create mode 100644 public/images/alumni/avatars/npub1lg7fsn24xm47yx7yr7xl2wgwjw2wcn06daxtverq068dtgwkd98sf6ge63.webp
create mode 100644 public/images/alumni/avatars/npub1lunaq893u4hmtpvqxpk8hfmtkqmm7ggutdtnc4hyuux2skr4ttcqr827lj.webp
create mode 100644 public/images/alumni/avatars/npub1mgvwnpsqgrem7jfcwm7pdvdfz2h95mm04r23t8pau2uzxwsdnpgs0gpdjc.webp
create mode 100644 public/images/alumni/avatars/npub1mhcr4j594hsrnen594d7700n2t03n8gdx83zhxzculk6sh9nhwlq7uc226.webp
create mode 100644 public/images/alumni/avatars/npub1mqa4auvfmalgs338999h22tf23upfs70uwyetneq0szquqamu7jqkhlfa7.webp
create mode 100644 public/images/alumni/avatars/npub1mutnyacc9uc4t5mmxvpprwsauj5p2qxq95v4a9j0jxl8wnkfvuyque23vg.webp
create mode 100644 public/images/alumni/avatars/npub1mygerccwqpzyh9pvp6pv44rskv40zutkfs38t0hqhkvnwlhagp6s3psn5p.webp
create mode 100644 public/images/alumni/avatars/npub1mz3vx0ew9le6n48l9f2e8u745k0fzel6thksv0gwfxy3wanprcxq79mymx.webp
create mode 100644 public/images/alumni/avatars/npub1n3w4uts2r4srq3adqu9trp953dflcnw7ppn72tad4htkpsckwcmqjef6um.webp
create mode 100644 public/images/alumni/avatars/npub1nmr6w7qk0ta36vxysv77jv3d5rqghfc6d8sez8240rf3gja4vsmsd2yha8.webp
create mode 100644 public/images/alumni/avatars/npub1nqulzcxcj0d2uesusstgupl5du8pa96xl6uy8xndweeckjkn964qjs23sn.webp
create mode 100644 public/images/alumni/avatars/npub1nyxg7ps82r86u0gunspsn8u8uuskh6sut77tulcqljue7rr7m6hquzh9ph.webp
create mode 100644 public/images/alumni/avatars/npub1p4kg8zxukpym3h20erfa3samj00rm2gt4q5wfuyu3tg0x3jg3gesvncxf8.webp
create mode 100644 public/images/alumni/avatars/npub1pmhevxtlt3478pvmdqt7dftnv6zc2mzpdc569yjm6ks4k2jhezcs53uksr.webp
create mode 100644 public/images/alumni/avatars/npub1q2s36929z99tv0pfjkqf8jgmn7yxrrjklmsr0wwjl2707vhk965sp7dx3u.webp
create mode 100644 public/images/alumni/avatars/npub1q4hnxfzu5nxylg7p6mj40hvw4ec53z0ncdpre0t0huyl8s8zqrfquvz7zr.webp
create mode 100644 public/images/alumni/avatars/npub1q6mcr8tlr3l4gus3sfnw6772s7zae6hqncmw5wj27ejud5wcxf7q0nx7d5.webp
create mode 100644 public/images/alumni/avatars/npub1qjgcmlpkeyl8mdkvp4s0xls4ytcux6my606tgfx9xttut907h0zs76lgjw.webp
create mode 100644 public/images/alumni/avatars/npub1qnw27f2jsqvn05wzpd56m7ykgmepk57p0yrzw8fzc7lfhjkmjmqqmd9r6h.webp
create mode 100644 public/images/alumni/avatars/npub1r7psmkr4zv93xnal8un6d8hvmpsn5jvhfzn3kk38rfcel6awznks7znspg.webp
create mode 100644 public/images/alumni/avatars/npub1rtcjydw22laa0ymwatlrtv02lgu6q6sez4gvs63d696putzyezqs65qqsd.webp
create mode 100644 public/images/alumni/avatars/npub1tlhjzdhlskz9xvmkufucl6l3jt4nypj8q5d2dc572uhz94nyeytq02tuyu.webp
create mode 100644 public/images/alumni/avatars/npub1u07xw079lxwv24xslarh2eu4v37jtjmwvev0jyk3zjhxg2wnt56seyez97.webp
create mode 100644 public/images/alumni/avatars/npub1u37h8rhgm9f95d90lpk2afw8h4t75kf6w8vmga2zz9jsx3atzpuqlmw8vy.webp
create mode 100644 public/images/alumni/avatars/npub1u8lnhlw5usp3t9vmpz60ejpyt649z33hu82wc2hpv6m5xdqmuxhs46turz.webp
create mode 100644 public/images/alumni/avatars/npub1uac67zc9er54ln0kl6e4qp2y6ta3enfcg7ywnayshvlw9r5w6ehsqq99rx.webp
create mode 100644 public/images/alumni/avatars/npub1wf4pufsucer5va8g9p0rj5dnhvfeh6d8w0g6eayaep5dhps6rsgs43dgh9.webp
create mode 100644 public/images/alumni/avatars/npub1y3yqdp44vg62ys8anqnjpx6cfprl848ev4lsmx5h4mznyz3xft9sen050h.webp
create mode 100644 public/images/alumni/avatars/npub1yay8e9sqk94jfgdlkpgeelj2t5ddsj2eu0xwt4kh4xw5ses2rauqnstrdv.webp
create mode 100644 public/images/alumni/avatars/npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr.webp
create mode 100644 public/images/alumni/avatars/npub1zc6ts76lel22d38l9uk7zazsen8yd7dtuzcz5uv8d3vkast9hlks4725sl.webp
create mode 100644 public/images/alumni/avatars/npub1zel8lcq6w6mtajwj4xcedvvvwts4p6v9l045dmn9rp570dqry7zsyll0dt.webp
create mode 100644 public/images/alumni/avatars/npub1zthq85gksjsjthv8h6rec2qeqs2mu0emrm9xknkhgw7hfl7csrnq6wxm56.webp
create mode 100644 public/images/alumni/avatars/npub1zzt0d0s2f4lsanpd7nkjep5r79p7ljq7aw37eek64hf0ef6v0mxqgwljrv.webp
create mode 100644 scripts/cache-alumni-avatars.mjs
create mode 100644 scripts/test-alumni-static-avatars.mjs
create mode 100644 src/data/sovengAlumniAvatarCache.js
create mode 100644 src/data/sovengAlumniAvatarCache.json
diff --git a/package.json b/package.json
index b4413e2b..f33e3029 100755
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"build": "astro build",
"preview": "astro preview",
"check": "astro check",
+ "cache-alumni-avatars": "bun scripts/cache-alumni-avatars.mjs",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.astro",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx,.astro --fix",
"format": "prettier --write .",
diff --git a/public/images/alumni/avatars/npub10wzfa7jkqj6c65xyr93hhxrns37ml9tss82jvymv8fymwdtu6cts3h6pvr.webp b/public/images/alumni/avatars/npub10wzfa7jkqj6c65xyr93hhxrns37ml9tss82jvymv8fymwdtu6cts3h6pvr.webp
new file mode 100644
index 0000000000000000000000000000000000000000..44fc050960c230caf2e2531017bab5c86c472422
GIT binary patch
literal 2948
zcmV-~3w!iZNk&F|3jhFDMM6+kP&goP3jhF6EdZSXDu4ih06uv%l}Mzbq9G@gO<<4@
z326~POC|#%KY*B{=iDWZ8}3eczpd||fLpZf4!`g4eAMEr{jZ5<+rQ)b4)u!f_xssV
zS`9!vu!(r4VnGM+|1`QXdx!aiBDayfu~*+&X;J;ur#2D*@&s~|x#K>k@1V|4SjY#O
zvaWf`3#$ny*%8%qiL6mUbL13Wa$W
CLr
zx@S5voOHcaEBENr#j-mmMV0*!lR+WG!E3-S_0mniN(?LQr>q65q!&a_9kasu%cDm)Lwjd4z=>*%pG52IZ00L+&uDIT1qK{
zhIDDHg?%gnXV&%4uywrajWaFG;mWvrw3>IptL|D*0jyf&o}(jJ;7QtjD0_qz3YDM@
zZ-B&sn;ueT{3DU%G06h)F%{O8)Oh`2TRE3$d(z18x94*M2`OwkLD+^Se`zt<3)EyAg5NjKaN(5NK(rpI&mjs@^e@`+W8YEH+!Q?^JzTt
z#wp;yS4J+++`;?0uo*7#6q>;_ASHQ095>c7N%h3ev}pgs`)8?xhJnHaWR76XCIXcrn^c5LE*4
zoDhgk`d@1MTHVR|jfU;GuH9t|$rb5Nk~WlAnsTvSiE~4OxAE|9RLFe)409Bo)1iTK
z&G(=9ji2H8v|0a=K;wL(Wvnj5diQ$G!7wIaj(4`MWzK-nm=|(m^Z`6COr4X(2b_&ie$Lpm-c^G>tX@pP*{kAV=YpQZ-om5}l!j
zxZZ!WU`_~EzIF5zVK7qr@Hn+M{@U_B2wvN}$A6)xJcR%{2Hn2ZW>)bPEQZ-}V-2@-
zV}Q{&X1s7W5v!1gChdgADO;Z;LH?r6~#bcG@huzie+U$@v~j|(1+
z89EueQofWR#rNA-A)h!G*)bj}q0cK8(F_T002CR3zd{s|t!V2e90RH9OR>n~
ztkXsuxArvsYd3!=$>RJwwvlqRga^#gnX|W8?k4WP?m$06hNtrCPDto1v;M+<9(0>@8kdG7Ei0zCvxn(hCTlCw3Uxzm1M6{B^
zEsu@H7J#nb$_?;B_BYZzE{Z=YIVcCmh@sT`|2#h$ZQsozb1kEtQc3}D4(9fT&?#gn
zI1k(RisB~Df8~V9*{o*pS;x~6{xH(Sh9->H_yO3O_VVHKgq}IK`<7?Rc~UyG^s9j(
zr7DB6(2brAA;f)cH-5a9hE8je*oF;>XB5s17ph6Z4tCdMryE}fT|1P`uGjF@`ajU!
zc>ri30PF>LYQZiCho?|38NKX-sPec>k|HwSzBQftH+_)|m2ff|N=May#vU7$t_MM>
zS!)Yg*yG*|s$nG6Q#G;Y!VmsdX^8<;w?c42D1R0d3quG!31WE~;~1?BSlg$whr2>*
zI6JM{`=i*63S#O@U@Q&U4>T8m>8)WH3X#M7{bt|hCdVHm$=O}=upF>#60pGpVNs-H;IPlCT!;>z0}G6
zi<=@h7KuX3e>`NNo
zOJYZB?$8tVwz4}@^z-?i)Nk^GIK`tpgnNQ#Z_-xdpp43Au4gSbyn)=r3Xq*hC*ZTH
z@aXKEG71w`R~6aY-qp~1EI&ih&9{PYTBk$^chZ=2%mu(i+_Q80Is4d@e`$8HzCEnJ
zv2u`t$_$1KWp(OE$l;W8T)C&qnuqmdI6p*6&8Gb1
z>OcY{M}Ww45gQ+&iD3TE5-2Mh09(7l~UB!;j@Gq3_P!{>TqIqr_X!&+y;V`T?
z84&;8Ebxkw?&noQ0e{vh+8}-JYH-~o{-Og?l(h)d;^So!<|E71wBf1(vFKch9ncD_
zAorI;wWczeA5$oQ6cr9OJm=jYT3U?}78gT(+cy9NWgp5b;>cWN`?j+AMb1=ofnMxW
zb=2b+*nUp_yS0!{6oL_sO{9qq&)*jAI$88evq-702{oR?MP4p3kPah|*+EDkJw+iI
uVU~C%<)7MuhP;1iH0Vg4*hmp{^pfdf2ClNv8Hb%B!&?Tl{~&~oL;wKNe7uPO
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub12rv5lskctqxxs2c8rf2zlzc7xx3qpvzs3w4etgemauy9thegr43sf485vg.webp b/public/images/alumni/avatars/npub12rv5lskctqxxs2c8rf2zlzc7xx3qpvzs3w4etgemauy9thegr43sf485vg.webp
new file mode 100644
index 0000000000000000000000000000000000000000..7fa3d4ebab2ce55ee5ebcd905207ccb112300f8a
GIT binary patch
literal 5990
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
Uui=+Rq>ae#beK5%=>C8J0NP8;&;S4c
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub12w53uwny68m936vr4s0yl8svd9lc7vlqrkx7hepe7nq6jggn7kfq92rrm3.webp b/public/images/alumni/avatars/npub12w53uwny68m936vr4s0yl8svd9lc7vlqrkx7hepe7nq6jggn7kfq92rrm3.webp
new file mode 100644
index 0000000000000000000000000000000000000000..2ab25fce5502939846f6fee1ed8384c95439af11
GIT binary patch
literal 272
zcmV+r0q_1&Nk&Ep0RRA3MM6+kP&gp`0002+2mqY{Du4ih06uvQ;^tsCe8i#!5^B}`Xu6k740vuvH5dD*%Zi77qPBlcGss~vvGEC6AVQt++GxwwX56++B*scuAj~6we3{!|9i`u6_d6C}ao)+d}FrfqrB0-QD
zomsCP=;M*WJEF!_I#!MhDd$*>Ji+2HFvjxt_Lod
zSCf8ng$sM%w*b5}vagKBgiY&0M659N&F`r8z9RxHHB@V_t~ozzNOb~w=l?R@A{88$u0IhuBgj^i++Hc@=ffn{bFW*e^S`vctlb}H)
zKtHw?@Lml1zx>jsbL*R!2jaDw2rT9N!+o={E1$tXo8|F7Gqhbo=2&uAEq^0zlUn%{
zTh<#HuDc{Zh*2PYnS#CA%pdt^30KlzsQ%q8`BL&s^5eI=>rWpL{@x0n--1(frpEYg
zieE(e)!}}I|60Gf3j5yek=3z{7W6m0VWTaNk}v=O{`|rFAtWuFftU151rC!@^G$4L
z6{qw*(wB)z(qn<<#^Nv2A~%HJWKIW1zT5e*wyY^JO#E?NO_5ddzZ<>%UJ+XZVGL*9
ziq8NzY`EjVl~|YLnL>BEUJ^c6smTr0
z@%;q*FnWuddRMz>a1ww6%&D`Yt_T5YK;+8Qf$7cVkFk4f+YCFTU!bSshkk(77~*g^
zgf;rqYO7$dFwFZtJDYtMvHkSbF(0wZo=KKiTX%tX6y@(q^#@n?c&QITy%X+<>A$WR
zDJ&QfE-lsH6<0688#2k~{)A|o0stLR7%aDf1P=t*Y&qfeCdw83i>5}r%*w9UOLz5_G|TlKn^LCG_{*+CjYcRJKe
zsg|hL}G9Ys}~&V+T;QR
zsQJG)8V?%hNW1xlcPn`X1U@!{as)!mTy^FZf+RR3+w+@&AP+!P7W~p>lb9JW<&Nfy
z=isvJ0fYNJ&%qD&Zmo*`YmN)~&>388iA^8Yoi+78+2s%Dc^ugv<*)IpV42e-2(>-x
zrMscqN^QtB@Msi!7@xKBbbCkzDKVtQ5Q+3$@kpBSxE#4j?tSA8*6>X?cD3PXHW60aP~0gB2XdR`Y-eVXUlL9?qP++
z*r(TR1^8^m1ue_aDylxWCdQ&((wQ{6D5!XnTOyYg-cKdqij)zi^%rQux;1)0d;Xt$
zQ;6|g)!*NTM*zl?b;d9@>C~oihmwDCNI<iyqgg*oP*vF5JM6HQz-gTM-6VY(~hh>mOIXwXBAN7$K4|G0X
zts{GM9RFdmYcP0y?c_kFI^$$J?IR7N^Lse`}4|lA?#j&uD
z$GE+%1~42gx94i+IVduSije@Uz*i+aDiYMJ2q<|tE>PE?dUl2dZv9pj)I}ysu1pMG
zgca30I&C05>~BaX;Gnul(-VQf87Rp4>}Zu&JL21bn_Vv2Qra&=D1xJ_3`F=NmJ`vF
z!Pl;HJFpKVM_;jjayjqna`Vhd$%2!>hIwxSdrZW>z|Yxu@hB~U5P!?=$V?;+!$*)$
zBLN8IH)bC1Tw`MikG^h$w6>WvfiMR9vjEFmtoL%5g`Blxt^CNS5Hw>}CW|5&Kl5AP
zIQ7P}Aj1nJxb^o25=KC2G(2DX2S`34nQbSgI6`VhvdLfPu?$}Dhy5S{;~Kg?lKs2~
z4Vee_uIFvHLYCU}6JC0<&rkXKl1w&`omzJu36;Lt%(5Pss|i$74(S5fiIJPdatuQB
ICvX4&08mMSH~;_u
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub13nfdp7p3pacqn6202q33sur4djeehf50xagxq3y3pchhzjptz7yqenvn7c.webp b/public/images/alumni/avatars/npub13nfdp7p3pacqn6202q33sur4djeehf50xagxq3y3pchhzjptz7yqenvn7c.webp
new file mode 100644
index 0000000000000000000000000000000000000000..57777fe6c37710ddda3dd86c93544e9f681a6920
GIT binary patch
literal 982
zcmV;{11bDcNk&G_0{{S5MM6+kP&gpM0{{RJC;*)SDu4ih06ujvkwzq{p`kQ&d?`>4
ziDhdnSQ+$oOV&**78`EmM_2s6$og$9o^ZiW+I5b6a~$I)6MGGBq$4@%n!1Dcw@O*#
ze3XFX#czosKFv29N=f)~_3vidPb_j)PW(b5?qK(117VF}w9DSm5_n)V%WNp33g2=S
zV5&Y`jr@3f6tr^#9J8ExhDf%yW9Rx3ZG-F&CeZiAhHV{vpV8M}x%>XgZ*oi{9>#@m
zrB?B?4Lkfiz>KoL01?r|fBk*uQW
zA9?OQXt*pQ+M}~;-+aSK9)GNQsz|MEz0RH(Gg4TR}
ztq4tPj*s*PNA%4=2k;B?ubyHt|XpjQ*K6=mjl;nC!-37)9`$P4?Gb?zYIqFLKfL_O)0deZ}=^Z6S{cyQD
zx}5!NXK1DMoG*Xpud^eq#x26^O(dgdo-y)tqbKoUNI98`Y-awxlo%|~OlFXa0fP=X
za&Ldq)OFa4bSKtQVY-KExhUCef#M)rU%>=%31%I`f~HIS
zlSj5m-r-9>T{QoP!#^%v@u*RiS9^SRN%h$lkMaQ6i-k_*H?~liWLKSG(J76rcQcH4
z>^0f>AgTUW45KoBX4Qd`hbL+u8~x55D2S01*rf>C^mi21xOg4DC_^xm7m7NtiU;=C
z0$->eS9XASVflmCHvj|75^{b|BixjbZM|iiTF;>6f!(k`h5LTa#@@!FC+vCU^I33*
zk~@1g!Pmw?pK20xVnS&2g5i9sEp`kC9zW|U9
ziDUq>QQ`jG%emkEhvk2?)ziB;c>9;mH>BS%o_yYCJl1_bZ%g_BbkBJ}V61WT_8t-W
zJqmkI>d(Ttf$v=)Yq>(FPtVe~*iAk(IaN2Yw3?sOaF
z!~g5E4mh-@d4)K6&qfEm`olVz8$HrVUY(p-!s7fmaB!wFl%p^`BJ5>+ComdCwc>^No8>Ykh|=tK7jUBU?biiRJR2LP$-bJ}xD)0uWb_B*es-PY
z)9*@FC+c1|HNJml<6UR$?p3tAmYPCx5rFx>>8bzsE(~?D$`P`;Rh%mOW|*nY7H7PK
zlXtw{3oAcyx;ti#jDww^a<^w}=0bSEYb1vlq0{T|1Shdp_qg4Rmv{DV6hv4VSGIN-
zf*x1@7$RndPwX!?!s^Hx*AnE?^7|;NWQrfh=SOc=TEIzxIdUKX{@zX?sboM~X%u`2
z{{la?N1Y>G^w+SGV9^6Zh_^HQJsrk`+h4kLYyKQjj!kk?HZE`1dGh5nb+n1>=e+8j
z9#=e4Vvz?{kbnJYSasv6H9@2rymejW_R?n{w>>o$Rc)_z7JRhSGAkaFfj~Qhy*GxU
z!j7{^99CUO96y0>LXBeoIG-pMyf-sMofFhSxf9ZCQ7nbrtwh4Pce?c>;td$K&pD1-
z!*wPf21A6D+DiTb&W9o{k^+q96s>Ut>1nK=jbn;H-;^*(#IhVwqs}R#9&s@{o4djU
zyMzwV8zDT-knGVH)!MbWn9_rE{u?35wapwKh-hKUlz7yMSTvx9SR(ohXL
zNcR!B9u`iwHtpcuM!cT%VkzKhGoR<=-lG^a-C+&jE4fYGPg`Otd}j-*wlZrhkLZ^BUy9H~RBe2D&UFYJuJTA3#v(?HpFHX)&vq?X`xo8^0khlE^(udo2!P(E?X2%5b2r!x
zf<$-`sZP`-N&{UI(nqhI89g0PcvBqzL0Tmlog&7@n0rsj>#
zzD7>0C!)K;gT3EO**sN#XNJ_0iRxF_zVg0ztrl4`9;qxC+pP2(J6`jzDlW|W%ptI2
zqH}hic4%dFjpSkIIxE4O$;|0YycNrt6eQlRd+D3zR#zq9hV?qLqHWqOG
zu^xR#wov&zkg`Ya4ezw6sIpfvYpy?tV-hMY0nLLvmI6*?lZa2^nH)2_=U{(m-%~8_
zR_#5&%R0w=(DaRSfB>`8bZd#SQSfTWAlPJw?!ZqmBJb+j^A=M5dKhJ`Odbm
zj))sr%gKu?TIaA17L8rK3@qkWnG7stxf5qUs8F8)}STp-8Nb#Dt&Og6f)g@
zoW0vCHTT1!se3P;%C9nKAk{#+L>Zl&Cku=JLh|P-j1+?~Y)O_K70A~Gl$2yASEPU`
zS27X8vOf0exFiGxLqm3QL(OfYdNyRE&|sX@Klg`Dy6=3}Aqw`YD9A<*vKPjG9`o?T
zM`C#ED*sKwsj-v}a}q&es5^dBKUe6q<+hDkcgt4r-4kcrj2;-^8>2!w*d!J{Y)-NY
zkaWXjC)r<3=n#?V2^#RA21pq=tBznIhEa$QF7yQWgN3wZ(x3mkQJ`#J!50L%AoqjF
zPDY4Q5dNAF+Nt{AxHJ%!IeM+3dUFg<@;6hp`wz-S5Lt;)CA-^0O36tiAdauE0_V)Q
zW2HD~kVqX6Sv`61SFS$NPm0Hi$GY>xsyJITGP-TaJOEEOjZ|f%A3P^
zK02FBSFVIp1?74P#~g5_$7EFL2$}&e0oWfeV7`$C*xP5Vtl<}VyM`&X)Tu?9p;nFH
zY%Cxq4nFI0Lo?x1x}p@#nU4#6r+YqvF3mu+L8i>ef^_dgiFG9Ar9niq^*X3)%Y-#e
zIpym;7661grd=|Wl!3}^380J)8x)_`p>xXT!(hJ6S!@d$#76YOE#l2!(E~lA7R;Ws
zlxf*Jn!)Z0;@B7}ml5nme7G-nul4!uLrmXC
zpE6zS&e1T)7S(ldka1KaMh3thz9AZbu6pn3y=qp_n$E+T*2;T2{lyr*)TgIuy^t($
z0CoN*tMpqy*^~{>zIa6?4nHR(O<&36A4$@R!f(bVO-)P)uPSzp3vRxZ^qkxS|I67$`Ts#3=+Dk^CU4CzUF7?(cwSvtv)
zNp;z*Kpz$zpW;o_$7M4*lXZ#DXjA3}c0Ve(JCDMP!*1vnt#l+W5{1|Lsa&Vu
z62O2GB<4W|ju`3g)ur7`H*YYhhueRZTMZVK0H6rYsfr+NDnx10l8>uV_P2_f-BLBQ
zfDLIY$6(b{&D8gig=I=em`5{M+2;=7MyIZ0rfWAKG;N@m%Lo-P=lvgHias|bFm{0A
z#miP&(eeJwY*8$;9#6%_7f`kd1SnMNLUPR8T#jPlV?7rm2(7$b%~W8eF^XOy`sbCX-`>Iid(>cU9@FO!?fRlTM%1nqIz*8BKHQ
z3i@+;J=z~$(Sx1fBXGCrM8`D9u*O&3f-N|!N4&^f3UD_3N#1D9&A1fGEBc
zXV*6YPwMQcDVO1-|DHA6C~;ZR@`&$@UCz;7{aWd+&hWKZLGz1Hj+6TD1#R7tzcT2w
zQMf=Ik5q;}mKU9p+G-93t)ULNtn_9D5iw*ypZk!rQ8y@9$yqr!{|j-kEvcJ)R<3TN
z45nH2hZW%~_3_YY-#-ocJpz#?cED!~$&|Zv20n!63{MDEquWW?N}zs>;zk~Imj~si
zBQZmmFECp}TqomCCaK%H)SREma$uUKKVV{dJu*r`eQKOZn3+^J{w$;7LCQe4DoA_j
ztic)8S$2qm+n*-QQ#B#+;BZ7ssj81VE`U3WyQBQ%ZREndL`RHme*8cup)+L#Es!3V
z53HKa)sOZ;xT~pa+(A2&yYv`1P2GT)+@=x(ZK`D+kY+V5JUC*woor
cw*#YT(ZV6HC$@vN^xAYaL@`Sh2D4xQ0FOR=)&Kwi
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr.webp b/public/images/alumni/avatars/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr.webp
new file mode 100644
index 0000000000000000000000000000000000000000..820ba3b5588385b0c471697be17c3a16e09e8609
GIT binary patch
literal 822
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
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub169d679h2ugm9s3j84w63mf7q7uhhxaw2p3d0w487zadym7gt90cqdqn6cc.webp b/public/images/alumni/avatars/npub169d679h2ugm9s3j84w63mf7q7uhhxaw2p3d0w487zadym7gt90cqdqn6cc.webp
new file mode 100644
index 0000000000000000000000000000000000000000..6161f815cd3771c38a88c6a98b2ebc1064826ea2
GIT binary patch
literal 4418
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
E05>e4oB#j-
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub16p8v7varqwjes5hak6q7mz6pygqm4pwc6gve4mrned3xs8tz42gq7kfhdw.webp b/public/images/alumni/avatars/npub16p8v7varqwjes5hak6q7mz6pygqm4pwc6gve4mrned3xs8tz42gq7kfhdw.webp
new file mode 100644
index 0000000000000000000000000000000000000000..5806e28d5b23a3ba2fb031c62ab1451a45c83452
GIT binary patch
literal 1028
zcmV+f1pE6^Nk&He0{{S5MM6+kP&gp)0{{RJ6#$(9Du4ih06uv(9pW)KbLz)8jB(pvj`;C~G!Isnh;D#Z$v?wo8ZJM5
z?+s{>vtGAsBBupyJ^!3@_r{k*Wum%Ep8uwW!b#s;pErtW{t0YBa)y^s%isb40RH=w
z0CN6@@wWn7;A)FGdJdyl_rsYTCEKAIkI=1$7lrxMWSsL3A>=eJh|Wy!32+N>m&W0B
zJ&2cV;Ak{~XO;I3{vY^{Ut)S;L=3vy7>cRS41Hu$J{-CHtvkzdtxL!|eO2$6S%0_+
zHIZ1~la4L5AHzlH-KpJ(l&8ww>%2OM7GwQm9o@eqq%Xu7(~T_WihKab_mWyn)MmW)
zW%c-UD4P=)u}|{Fu<5R;dw7ya6I}(+U~+rUnP|$)pv)VzFO3seP?c-s7U!MUW$Qiy
z8VU4G#8pISd0MaP@yihXq*EGrc{@Q-&&_#)^j^1cVA+O!t|)xgxbAfPT*BP-_wFyA
zhW5RIa@EE3*%vchLlQ$CxKR0zPpfxO(<#dBuNoO?&7Tdb)qqLo@GPc>TZ6&uxx9^9
z?_^oTaEmos({_7q_CfTVBUy{LdgTb$oM2sQ8#C#xSdDv!TDsN6_436t9ma&g
zvRZ2q`!Zu!jKW`-y1tYR#p1l_-_$j)z9opVP05xioA=<~`{mH$89fS2qzv`LpBnE?
z)Sf)A2)C)yifTZoog_3|VGWAwUn-yghhvzdOS#IRE2DKn>Iz}d|M7EZ_LyvRUarf*
zQ?W**To$C&z*_CodA
z<%x}tMSvhn1H$Xq>1c>J!6bsmI?>1C0sm!ZT6gRqP8yce2N=zhkU8*eQw&uwUa}bM
zt{z5gR2wDVq2db}3gHuG8J(?+p4shvD(I8M0Eu3+y+^y+*c=_-Nd>~o-yEpi($lNV
z^7hmbl%sw&Vqzb9HCS*uk_%&fS(f#|&N}+M1x__eN>}oWWft%+DZKgpmbCW%4M~io
z?)=vIrht#a*92GyM@w@Ye*2-_s)KUj`pN$hVS3cNBZyAyzsJV&undN4X?X+b&zqk{
yxQd;BX;I~i1m0Jl?lp^c-Mw~%{KH7lTrQJMvX?a3XG5yZeQefw5|97@0000mz7lEx
literal 0
HcmV?d00001
diff --git a/public/images/alumni/avatars/npub16q4rk48xgvlu0snq36v7lx62akgrjezygmdfsgkjpdde3yykfuhscgxcms.webp b/public/images/alumni/avatars/npub16q4rk48xgvlu0snq36v7lx62akgrjezygmdfsgkjpdde3yykfuhscgxcms.webp
new file mode 100644
index 0000000000000000000000000000000000000000..03ff03e0b7362d4d7d018f2d2be675bced4860ba
GIT binary patch
literal 2264
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