<% /* ---- Next occurrence ------------------------------------------------- All arithmetic happens on a UTC Date that carries the *Eastern calendar date*, never a wall-clock instant. That keeps day-of-week and day-adding correct across DST without needing a timezone library. */ const TZ = site.timezone || "America/New_York"; const now = new Date(); const todayISO = new Intl.DateTimeFormat("en-CA", { timeZone: TZ, year: "numeric", month: "2-digit", day: "2-digit", }).format(now); const hourET = Number( new Intl.DateTimeFormat("en-US", { timeZone: TZ, hour: "2-digit", hourCycle: "h23" }).format(now) ) % 24; const toDate = (iso) => { const [y, m, d] = iso.split("-").map(Number); return new Date(Date.UTC(y, m - 1, d)); }; const isoOf = (dt) => dt.toISOString().slice(0, 10); let next = toDate(todayISO); const first = toDate(site.firstEvent); if (next < first) next = first; while (next.getUTCDay() !== site.weekday) next.setUTCDate(next.getUTCDate() + 1); if (isoOf(next) === todayISO && hourET >= (site.endHour24 || 21)) next.setUTCDate(next.getUTCDate() + 7); const cancelled = site.cancelled || []; let skippedWeek = null; // Keep the FIRST skipped date: with two cancellations in a row the notice // should name the soonest one people were expecting, not the last one. while (cancelled.includes(isoOf(next))) { if (!skippedWeek) skippedWeek = isoOf(next); next.setUTCDate(next.getUTCDate() + 7); } const nextISO = isoOf(next); const isTonight = nextISO === todayISO; const fmtDate = (opts) => new Intl.DateTimeFormat("en-US", Object.assign({ timeZone: "UTC" }, opts)).format(next); const nextLong = fmtDate({ weekday: "long", month: "long", day: "numeric" }); const nextShort = fmtDate({ weekday: "short", month: "short", day: "numeric" }); const weekdayName = new Intl.DateTimeFormat("en-US", { timeZone: "UTC", weekday: "long" }).format(next); const heroLine = isTonight ? `Tonight at ${site.venue}, ${site.startTime} to ${site.endTime}. Grab a cue and meet the people building things in ${site.city}.` : `Every ${weekdayName} at ${site.venue}, ${site.startTime} to ${site.endTime}. The next one is ${nextLong}.`; const details = [ { label: "When", value: `Every ${weekdayName}` }, { label: "Time", value: `${site.startTime} to ${site.endTime}` }, { label: "Where", value: `${site.venue}, ${site.city}`, href: site.mapUrl }, { label: "Entry", value: site.entry }, ]; %> <%= site.name %> | <%= site.tagline %>

<%= site.tagline %>

<%= site.name %>

<%= heroLine %>

Four people talking beside a lit pool table in a dark bar.
<% if (skippedWeek) { %>

No Break on <%= new Intl.DateTimeFormat("en-US", { timeZone: "UTC", month: "long", day: "numeric" }).format(toDate(skippedWeek)) %>. Back on <%= nextLong %>.

<% } %>
<% details.forEach(function (d) { %>
<%= d.label %>
<% if (d.href) { %><%= d.value %><% } else { %><%= d.value %><% } %>
<% }) %>

class="is-live"<% } %>><%= isTonight ? "Happening tonight" : `Next: ${nextShort}` %> Add the whole series to your calendar

We are building Gainesville's startup culture, one terrible pool shot at a time.

Whether you are an engineer, a designer, a business strategist, or just an ambitious person driven to build things from the ground up, this is your crowd.

Zero pool skills required. Seriously. We are here to build startups, not run the table.

What to expect

Three students laughing over a napkin sketch at the rail of a pool table.
<% site.expect.forEach(function (item, i) { %>
<%= i === 1 ? " cell-tint" : "" %> reveal">

<%= item.title %>

<%= item.body %>

<% }) %>

RSVP for <%= isTonight ? "tonight" : nextLong %>

Not required, but it helps us know how many tables to hold. We will email you a reminder the day before.

For the weekly reminder. Nothing else.

A few words is plenty. It helps us introduce you to the right people.

One email a week at most. Unsubscribe any time.