From 9b245a178ba54060831008e19771c61b0c7461b6 Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Wed, 26 Nov 2025 18:02:37 -0800 Subject: [PATCH] Delete tests/7_scheduler/outputs_gemini directory --- .../gemini-3-pro-preview TEMP_0.1.js | 59 ----------------- .../gemini-3-pro-preview TEMP_0.2.js | 28 -------- .../gemini-3-pro-preview TEMP_0.3.js | 46 ------------- .../gemini-3-pro-preview TEMP_0.4.js | 31 --------- .../gemini-3-pro-preview TEMP_0.5.js | 51 --------------- .../gemini-3-pro-preview TEMP_0.6.js | 51 --------------- .../gemini-3-pro-preview TEMP_0.7.js | 61 ----------------- .../gemini-3-pro-preview TEMP_0.8.js | 45 ------------- .../gemini-3-pro-preview TEMP_0.9.js | 32 --------- .../gemini-3-pro-preview TEMP_0.js | 40 ------------ .../gemini-3-pro-preview TEMP_1.1.js | 33 ---------- .../gemini-3-pro-preview TEMP_1.2.js | 32 --------- .../gemini-3-pro-preview TEMP_1.3.js | 58 ----------------- .../gemini-3-pro-preview TEMP_1.4.js | 52 --------------- .../gemini-3-pro-preview TEMP_1.5.js | 65 ------------------- .../gemini-3-pro-preview TEMP_1.6.js | 49 -------------- .../gemini-3-pro-preview TEMP_1.7.js | 43 ------------ .../gemini-3-pro-preview TEMP_1.8.js | 45 ------------- .../gemini-3-pro-preview TEMP_1.9.js | 57 ---------------- .../gemini-3-pro-preview TEMP_1.js | 55 ---------------- .../gemini-3-pro-preview TEMP_2.js | 50 -------------- 21 files changed, 983 deletions(-) delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.1.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.2.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.3.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.4.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.5.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.6.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.7.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.8.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.9.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.1.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.2.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.3.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.4.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.5.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.6.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.7.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.8.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.9.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.js delete mode 100644 tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_2.js diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.1.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.1.js deleted file mode 100644 index 5732a0b..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.1.js +++ /dev/null @@ -1,59 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: range, workHours: wh }) => { - const { parseISO } = await import('https://esm.sh/date-fns@2.30.0'); - - const toMs = (t) => parseISO(t).getTime(); - const getMins = (t) => { const [h, m] = t.split(':'); return h * 60 + +m; }; - - const [whStart, whEnd] = [getMins(wh.start), getMins(wh.end)]; - const [rStart, rEnd] = [toMs(range.start), toMs(range.end)]; - const durMs = dur * 60000; - - const busy = [...calA, ...calB] - .map(s => ({ s: toMs(s.start), e: toMs(s.end) })) - .sort((a, b) => a.s - b.s); - - const merged = []; - if (busy.length) { - let curr = busy[0]; - for (let i = 1; i < busy.length; i++) { - if (busy[i].s < curr.e) curr.e = Math.max(curr.e, busy[i].e); - else { merged.push(curr); curr = busy[i]; } - } - merged.push(curr); - } - - const gaps = []; - let ptr = rStart; - const relBusy = [...merged.filter(b => b.e > rStart && b.s < rEnd), { s: rEnd, e: rEnd }]; - - for (const b of relBusy) { - const s = Math.max(ptr, rStart), e = Math.min(b.s, rEnd); - if (e - s >= durMs) gaps.push({ s, e }); - ptr = Math.max(ptr, b.e); - } - - const slots = []; - for (const g of gaps) { - let t = g.s; - while (t + durMs <= g.e) { - const d = new Date(t); - const curM = d.getUTCHours() * 60 + d.getUTCMinutes(); - - if (curM >= whStart && curM + dur <= whEnd) { - slots.push({ start: d.toISOString(), end: new Date(t + durMs).toISOString() }); - t += durMs; - } else { - if (curM < whStart) { - d.setUTCHours(0, whStart, 0, 0); - } else { - d.setUTCDate(d.getUTCDate() + 1); - d.setUTCHours(0, whStart, 0, 0); - } - t = Math.max(t, d.getTime()); - } - } - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.2.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.2.js deleted file mode 100644 index df0df8c..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.2.js +++ /dev/null @@ -1,28 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { DateTime: D, Interval: I } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm'); - const Z = 'utc', parse = t => D.fromISO(t, { zone: Z }); - const busy = I.merge([...calA, ...calB].map(x => I.fromDateTimes(parse(x.start), parse(x.end)))); - const search = I.fromDateTimes(parse(rng.start), parse(rng.end)); - const [sH, sM] = wh.start.split(':'), [eH, eM] = wh.end.split(':'); - const slots = []; - - let curr = search.start.startOf('day'); - while (curr < search.end) { - const wStart = curr.set({ hour: sH, minute: sM }), wEnd = curr.set({ hour: eH, minute: eM }); - const work = I.fromDateTimes(wStart, wEnd).intersection(search); - - if (work?.isValid) { - let free = [work]; - busy.forEach(b => free = free.flatMap(f => f.difference(b))); - free.forEach(f => { - let t = f.start; - while (t.plus({ minutes: dur }) <= f.end) { - slots.push({ start: t.toISO(), end: (t = t.plus({ minutes: dur })).toISO() }); - } - }); - } - curr = curr.plus({ days: 1 }); - } - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.3.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.3.js deleted file mode 100644 index c5653d8..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.3.js +++ /dev/null @@ -1,46 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { DateTime: D, Interval: I } = await import('https://esm.sh/luxon@3.4.4'); - const utc = { zone: 'utc' }; - const parse = t => D.fromISO(t, utc); - - const busy = [...calA, ...calB] - .map(s => I.fromDateTimes(parse(s.start), parse(s.end))) - .filter(i => i.isValid) - .sort((a, b) => a.start - b.start) - .reduce((acc, cur) => { - const last = acc.at(-1); - return (last && last.end >= cur.start) - ? (acc[acc.length - 1] = last.union(cur), acc) - : [...acc, cur]; - }, []); - - const searchI = I.fromDateTimes(parse(rng.start), parse(rng.end)); - const [sH, sM] = wh.start.split(':'); - const [eH, eM] = wh.end.split(':'); - const slots = []; - - let day = searchI.start.startOf('day'); - while (day < searchI.end) { - const wStart = day.set({ hour: sH, minute: sM }); - const wEnd = day.set({ hour: eH, minute: eM }); - const workI = I.fromDateTimes(wStart, wEnd).intersection(searchI); - - if (workI?.isValid) { - let cur = workI.start; - while (cur.plus({ minutes: dur }) <= workI.end) { - const slotI = I.after(cur, { minutes: dur }); - const clash = busy.find(b => b.overlaps(slotI)); - - if (clash) { - cur = clash.end > cur ? clash.end : cur.plus({ minutes: 1 }); - } else { - slots.push({ start: slotI.start.toISO(), end: slotI.end.toISO() }); - cur = slotI.end; - } - } - } - day = day.plus({ days: 1 }); - } - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.4.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.4.js deleted file mode 100644 index 723892b..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.4.js +++ /dev/null @@ -1,31 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { DateTime, Interval } = await import('https://esm.sh/luxon'); - const Z = { zone: 'utc' }, P = s => DateTime.fromISO(s, Z); - const [sH, sM] = wh.start.split(':'), [eH, eM] = wh.end.split(':'); - - let cur = P(rng.start).startOf('day'), end = P(rng.end), work = []; - while (cur < end.plus({ days: 1 })) { - const wS = cur.set({ hour: sH, minute: sM }), wE = cur.set({ hour: eH, minute: eM }); - const i = Interval.fromDateTimes(wS, wE).intersection(Interval.fromDateTimes(P(rng.start), P(rng.end))); - if (i?.isValid) work.push(i); - cur = cur.plus({ days: 1 }); - } - - const busy = [...calA, ...calB].map(x => Interval.fromDateTimes(P(x.start), P(x.end))) - .filter(x => x.isValid).sort((a, b) => a.start - b.start) - .reduce((a, c) => { - const l = a[a.length - 1]; - return l && l.end >= c.start ? (a[a.length - 1] = l.union(c), a) : [...a, c]; - }, []); - - return busy.reduce((acc, b) => acc.flatMap(w => w.difference(b)), work) - .flatMap(i => { - const r = []; - let s = i.start; - while (s.plus({ minutes: dur }) <= i.end) { - r.push({ start: s.toISO(), end: (s = s.plus({ minutes: dur })).toISO() }); - } - return r; - }); -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.5.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.5.js deleted file mode 100644 index 67d9986..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.5.js +++ /dev/null @@ -1,51 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { addMinutes } = await import('https://esm.sh/date-fns@3'); - const D = (d) => new Date(d); - const [sH, sM] = wh.start.split(':').map(Number); - const [eH, eM] = wh.end.split(':').map(Number); - const startMins = sH * 60 + sM; - const endMins = eH * 60 + eM; - - let busy = [...calA, ...calB].map(x => ({ s: D(x.start), e: D(x.end) })).sort((a, b) => a.s - b.s); - let merged = [], c = busy[0]; - if (c) { - for (let i = 1; i < busy.length; i++) busy[i].s < c.e ? c.e = new Date(Math.max(c.e, busy[i].e)) : (merged.push(c), c = busy[i]); - merged.push(c); - } - - let slots = [], cur = D(rng.start), end = D(rng.end), bIdx = 0; - while (cur < end) { - const curMins = cur.getUTCHours() * 60 + cur.getUTCMinutes(); - if (curMins < startMins) { - cur.setUTCHours(sH, sM, 0, 0); - continue; - } - - const nxt = addMinutes(cur, dur); - const nxtMins = nxt.getUTCHours() * 60 + nxt.getUTCMinutes(); - const isNextDay = nxt.getUTCDate() !== cur.getUTCDate(); - - if ((isNextDay && nxtMins !== 0) || (!isNextDay && nxtMins > endMins) || (isNextDay && nxtMins === 0 && endMins < 1440)) { - cur.setUTCDate(cur.getUTCDate() + 1); - cur.setUTCHours(sH, sM, 0, 0); - continue; - } - - if (nxt > end) break; - - while (bIdx < merged.length && merged[bIdx].e <= cur) bIdx++; - let overlap = null; - for (let i = bIdx; i < merged.length; i++) { - if (merged[i].s >= nxt) break; - if (merged[i].s < nxt && merged[i].e > cur) { overlap = merged[i]; break; } - } - - if (overlap) cur = overlap.e; - else { - slots.push({ start: cur.toISOString(), end: nxt.toISOString() }); - cur = nxt; - } - } - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.6.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.6.js deleted file mode 100644 index ebd2541..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.6.js +++ /dev/null @@ -1,51 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { parseISO, addMinutes } = await import('https://cdn.jsdelivr.net/npm/date-fns@2.30.0/+esm'); - const [startR, endR] = [parseISO(rng.start), parseISO(rng.end)]; - - const busy = [...calA, ...calB] - .map(x => ({ s: parseISO(x.start), e: parseISO(x.end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - const last = acc[acc.length - 1]; - if (last && c.s < last.e) last.e = new Date(Math.max(last.e, c.e)); - else acc.push(c); - return acc; - }, []); - - const slots = []; - let currDate = new Date(Date.UTC(startR.getUTCFullYear(), startR.getUTCMonth(), startR.getUTCDate())); - const lastDate = new Date(Date.UTC(endR.getUTCFullYear(), endR.getUTCMonth(), endR.getUTCDate())); - - while (currDate <= lastDate) { - const dStr = currDate.toISOString().split('T')[0]; - const wStart = parseISO(`${dStr}T${wh.start}:00Z`); - const wEnd = parseISO(`${dStr}T${wh.end}:00Z`); - - const winStart = wStart < startR ? startR : wStart; - const winEnd = wEnd > endR ? endR : wEnd; - - if (winStart < winEnd) { - let cursor = winStart; - const relevant = busy.filter(b => b.s < winEnd && b.e > winStart); - - for (const b of relevant) { - while (addMinutes(cursor, dur) <= b.s) { - const next = addMinutes(cursor, dur); - slots.push({ start: cursor.toISOString(), end: next.toISOString() }); - cursor = next; - } - if (cursor < b.e) cursor = b.e; - } - - while (addMinutes(cursor, dur) <= winEnd) { - const next = addMinutes(cursor, dur); - slots.push({ start: cursor.toISOString(), end: next.toISOString() }); - cursor = next; - } - } - currDate.setUTCDate(currDate.getUTCDate() + 1); - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.7.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.7.js deleted file mode 100644 index e7a37d5..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.7.js +++ /dev/null @@ -1,61 +0,0 @@ -export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: range, workHours: wh }) => { - const { default: d } = await import('https://esm.sh/dayjs@1.11.10'); - const { default: u } = await import('https://esm.sh/dayjs@1.11.10/plugin/utc'); - d.extend(u); - - const D = t => d.utc(t); - const rS = D(range.start), rE = D(range.end); - const setT = (dt, t) => { - const [h, m] = t.split(':'); - return dt.hour(h).minute(m).second(0).millisecond(0); - }; - - // 1. Merge and Sort Busy Slots - let busy = [...calA, ...calB] - .map(x => ({ s: D(x.start), e: D(x.end) })) - .filter(x => x.e > rS && x.s < rE) - .sort((a, b) => a.s - b.s); - - let merged = [], curr = busy[0]; - if (curr) { - for (let i = 1; i < busy.length; i++) { - if (busy[i].s < curr.e) curr.e = busy[i].e > curr.e ? busy[i].e : curr.e; - else { merged.push(curr); curr = busy[i]; } - } - merged.push(curr); - } - - // 2. Identify Free Gaps within Search Range - let gaps = [], ptr = rS; - for (const b of merged) { - if (b.s > ptr) gaps.push({ s: ptr, e: b.s }); - ptr = b.e > ptr ? b.e : ptr; - } - if (ptr < rE) gaps.push({ s: ptr, e: rE }); - - // 3. Generate Slots intersecting Work Hours - const slots = []; - for (const g of gaps) { - let day = g.s.clone().startOf('day'); - const endDay = g.e.clone().endOf('day'); - - while (day <= endDay) { - const wS = setT(day, wh.start), wE = setT(day, wh.end); - // Intersection of Gap and Work Hours - const start = g.s > wS ? g.s : wS; - const end = g.e < wE ? g.e : wE; - - if (start < end) { - let s = start; - while (s.add(dur, 'm') <= end) { - slots.push({ start: s.toISOString(), end: s.add(dur, 'm').toISOString() }); - s = s.add(dur, 'm'); - } - } - day = day.add(1, 'd'); - } - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.8.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.8.js deleted file mode 100644 index 5717487..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.8.js +++ /dev/null @@ -1,45 +0,0 @@ -const findAvailableSlots = async (cal1, cal2, { durationMinutes: dur, searchRange: range, workHours: work }) => { - const { parseISO } = await import('https://esm.sh/date-fns@2.30.0') - const toMs = d => parseISO(d).getTime() - - const busy = [...cal1, ...cal2] - .map(c => ({ s: toMs(c.start), e: toMs(c.end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - const last = acc[acc.length - 1] - if (last && c.s < last.e) last.e = Math.max(last.e, c.e) - else acc.push(c) - return acc - }, []) - - const start = toMs(range.start), end = toMs(range.end), ms = dur * 60000 - const [sh, sm] = work.start.split(':'), [eh, em] = work.end.split(':') - const slots = [] - - for (let d = new Date(start); d < end; d.setUTCDate(d.getUTCDate() + 1)) { - d.setUTCHours(0, 0, 0, 0) - const y = d.getUTCFullYear(), m = d.getUTCMonth(), day = d.getUTCDate() - const wStart = Math.max(Date.UTC(y, m, day, sh, sm), start) - const wEnd = Math.min(Date.UTC(y, m, day, eh, em), end) - - if (wStart >= wEnd) continue - - let ptr = wStart - for (const b of busy) { - if (b.e <= ptr) continue - if (b.s >= wEnd) break - while (ptr + ms <= b.s) { - slots.push({ start: new Date(ptr).toISOString(), end: new Date(ptr + ms).toISOString() }) - ptr += ms - } - ptr = Math.max(ptr, b.e) - } - while (ptr + ms <= wEnd) { - slots.push({ start: new Date(ptr).toISOString(), end: new Date(ptr + ms).toISOString() }) - ptr += ms - } - } - - return slots -} -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.9.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.9.js deleted file mode 100644 index af9796f..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.9.js +++ /dev/null @@ -1,32 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes, searchRange, workHours }) => { - const { DateTime, Interval } = await import('https://cdn.jsdelivr.net/npm/luxon@3/+esm'); - const z = { zone: 'utc' }; - const parse = t => DateTime.fromISO(t, z); - const range = Interval.fromDateTimes(parse(searchRange.start), parse(searchRange.end)); - const [wsH, wsM] = workHours.start.split(':'); - const [weH, weM] = workHours.end.split(':'); - - const busy = [...calA, ...calB] - .map(s => Interval.fromDateTimes(parse(s.start), parse(s.end))) - .filter(i => i.isValid) - .sort((a, b) => a.start - b.start) - .reduce((acc, cur) => { - const last = acc[acc.length - 1]; - return last && last.end >= cur.start ? (acc[acc.length - 1] = last.union(cur), acc) : [...acc, cur]; - }, []); - - const slots = []; - for (const free of range.difference(...busy)) { - let cur = free.start; - while (cur < free.end) { - const next = cur.plus({ minutes: durationMinutes }); - if (next > free.end) break; - const ws = cur.set({ hour: wsH, minute: wsM, second: 0, millisecond: 0 }); - const we = cur.set({ hour: weH, minute: weM, second: 0, millisecond: 0 }); - if (cur >= ws && next <= we) slots.push({ start: cur.toISO(), end: next.toISO() }); - cur = next; - } - } - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.js deleted file mode 100644 index 1398f86..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_0.js +++ /dev/null @@ -1,40 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { DateTime, Interval } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm'); - const utc = t => DateTime.fromISO(t, { zone: 'utc' }); - - const busy = [...calA, ...calB] - .map(x => Interval.fromDateTimes(utc(x.start), utc(x.end))) - .sort((a, b) => a.start - b.start) - .reduce((acc, cur) => { - const last = acc[acc.length - 1]; - return last && last.end >= cur.start - ? (acc[acc.length - 1] = last.union(cur), acc) - : [...acc, cur]; - }, []); - - const rangeInt = Interval.fromDateTimes(utc(rng.start), utc(rng.end)); - const [wsH, wsM] = wh.start.split(':'); - const [weH, weM] = wh.end.split(':'); - - let curr = rangeInt.start.startOf('day'), workInts = []; - while (curr <= rangeInt.end) { - const wStart = curr.set({ hour: wsH, minute: wsM }); - const wEnd = curr.set({ hour: weH, minute: weM }); - const i = Interval.fromDateTimes(wStart, wEnd).intersection(rangeInt); - if (i?.isValid && !i.isEmpty()) workInts.push(i); - curr = curr.plus({ days: 1 }); - } - - return workInts - .flatMap(w => busy.reduce((acc, b) => acc.flatMap(a => a.difference(b)), [w])) - .flatMap(i => { - const slots = []; - let s = i.start; - while (s.plus({ minutes: dur }) <= i.end) { - slots.push({ start: s.toISO(), end: s.plus({ minutes: dur }).toISO() }); - s = s.plus({ minutes: dur }); - } - return slots; - }); -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.1.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.1.js deleted file mode 100644 index 4c43ccf..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.1.js +++ /dev/null @@ -1,33 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { addMinutes: add, parseISO: prs, isBefore: isB, isAfter: isA, isEqual: isE } = await import('https://cdn.jsdelivr.net/npm/date-fns@2.30.0/esm/index.js'); - - const [rS, rE] = [prs(rng.start), prs(rng.end)]; - const busy = [...calA, ...calB] - .map(x => ({ s: prs(x.start), e: prs(x.end) })) - .filter(x => isB(x.s, rE) && isA(x.e, rS)) - .sort((a, b) => a.s - b.s); - - let ptr = rS, res = []; - const [wsH, wsM] = wh.start.split(':'), [weH, weM] = wh.end.split(':'); - - for (const b of [...busy, { s: rE, e: rE }]) { - if (isA(b.s, ptr)) { - let cur = ptr; - while (true) { - const nxt = add(cur, dur); - if (isA(nxt, b.s)) break; - - const uDay = new Date(Date.UTC(cur.getUTCFullYear(), cur.getUTCMonth(), cur.getUTCDate())); - const wS = add(uDay, wsH * 60 + +wsM), wE = add(uDay, weH * 60 + +weM); - - if ((isA(cur, wS) || isE(cur, wS)) && (isB(nxt, wE) || isE(nxt, wE))) { - res.push({ start: cur.toISOString(), end: nxt.toISOString() }); - } - cur = nxt; - } - } - ptr = isA(b.e, ptr) ? b.e : ptr; - } - return res; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.2.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.2.js deleted file mode 100644 index 9356733..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.2.js +++ /dev/null @@ -1,32 +0,0 @@ -export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: sRange, workHours: wh }) => { - const { DateTime: D, Interval: I } = await import('https://cdn.skypack.dev/luxon'); - const Z = { zone: 'utc' }; - const toD = t => D.fromISO(t, Z); - const mkI = (s, e) => I.fromDateTimes(s, e); - - const busy = I.merge([...calA, ...calB].map(x => mkI(toD(x.start), toD(x.end)))); - const search = mkI(toD(sRange.start), toD(sRange.end)); - const [hS, mS] = wh.start.split(':'); - const [hE, mE] = wh.end.split(':'); - const res = []; - - let curr = search.start.startOf('day'); - while (curr < search.end) { - const wWin = mkI(curr.set({ hour: hS, minute: mS }), curr.set({ hour: hE, minute: mE })).intersection(search); - if (wWin?.isValid) { - let free = [wWin]; - busy.forEach(b => free = free.flatMap(s => s.difference(b))); - free.forEach(s => { - let t = s.start; - while (t.plus({ minutes: dur }) <= s.end) { - const next = t.plus({ minutes: dur }); - res.push({ start: t.toISO(), end: next.toISO() }); - t = next; - } - }); - } - curr = curr.plus({ days: 1 }); - } - return res; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.3.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.3.js deleted file mode 100644 index 230d943..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.3.js +++ /dev/null @@ -1,58 +0,0 @@ -export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: range, workHours: work }) => { - const { addMinutes, parseISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@4.1.0/+esm'); - - const toTime = d => d.getTime(); - const toISO = d => d.toISOString(); - - const startLimit = parseISO(range.start); - const endLimit = parseISO(range.end); - - let busy = [...calA, ...calB] - .map(c => ({ s: toTime(parseISO(c.start)), e: toTime(parseISO(c.end)) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - const last = acc[acc.length - 1]; - if (last && c.s < last.e) last.e = Math.max(last.e, c.e); - else acc.push(c); - return acc; - }, []); - - const slots = []; - let currDate = new Date(Date.UTC(startLimit.getUTCFullYear(), startLimit.getUTCMonth(), startLimit.getUTCDate())); - - while (toTime(currDate) <= toTime(endLimit)) { - const dateStr = currDate.toISOString().split('T')[0]; - const workStart = new Date(`${dateStr}T${work.start}:00Z`); - const workEnd = new Date(`${dateStr}T${work.end}:00Z`); - - let ptr = toTime(workStart) < toTime(startLimit) ? startLimit : workStart; - const winEnd = toTime(workEnd) > toTime(endLimit) ? endLimit : workEnd; - const winEndT = toTime(winEnd); - - let bIdx = 0; - - while (toTime(ptr) + (dur * 60000) <= winEndT) { - const slotEnd = addMinutes(ptr, dur); - const ptrT = toTime(ptr); - const slotEndT = toTime(slotEnd); - - // Fast-forward busy index - while (busy[bIdx] && busy[bIdx].e <= ptrT) bIdx++; - - const conflict = busy[bIdx]; - - if (!conflict || conflict.s >= slotEndT) { - slots.push({ start: toISO(ptr), end: toISO(slotEnd) }); - ptr = slotEnd; - } else { - // Overlap detected, jump to end of busy slot - // Ensure we reconstruct Date from timestamp correctly - ptr = new Date(conflict.e); - } - } - currDate.setUTCDate(currDate.getUTCDate() + 1); - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.4.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.4.js deleted file mode 100644 index 0fb223d..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.4.js +++ /dev/null @@ -1,52 +0,0 @@ -const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => { - const { parseISO, formatISO } = await import('https://esm.sh/date-fns@2.30.0'); - - const toMs = (d) => parseISO(d).getTime(); - const [wSh, wSm] = wh.start.split(':').map(Number); - const [wEh, wEm] = wh.end.split(':').map(Number); - - const busy = [...calA, ...calB] - .map(x => ({ s: toMs(x.start), e: toMs(x.end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - const last = acc[acc.length - 1]; - if (last && c.s < last.e) last.e = Math.max(last.e, c.e); - else acc.push(c); - return acc; - }, []); - - const res = []; - const limit = toMs(rng.end); - let curr = toMs(rng.start); - const msDur = dur * 60000; - - while (curr + msDur <= limit) { - const slotEnd = curr + msDur; - const d = new Date(curr); - - const dayS = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), wSh, wSm); - const dayE = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), wEh, wEm); - - if (curr < dayS) { - curr = dayS; - continue; - } - - if (slotEnd > dayE) { - curr = dayS + 86400000; - continue; - } - - const clash = busy.find(b => curr < b.e && slotEnd > b.s); - if (clash) { - curr = clash.e; - continue; - } - - res.push({ start: formatISO(curr), end: formatISO(slotEnd) }); - curr = slotEnd; - } - - return res; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.5.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.5.js deleted file mode 100644 index 3b2856a..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.5.js +++ /dev/null @@ -1,65 +0,0 @@ -const findAvailableSlots = async (cal1, cal2, constraints) => { - const { parseISO, formatISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm'); - - const D = constraints.durationMinutes; - const MS = D * 60000; - const sDate = parseISO(constraints.searchRange.start).getTime(); - const eDate = parseISO(constraints.searchRange.end).getTime(); - - const [wsH, wsM] = constraints.workHours.start.split(':').map(Number); - const [weH, weM] = constraints.workHours.end.split(':').map(Number); - const wsMin = wsH * 60 + wsM; - const weMin = weH * 60 + weM; - - const busy = [...cal1, ...cal2] - .map(x => ({ s: parseISO(x.start).getTime(), e: parseISO(x.end).getTime() })) - .filter(x => x.e > sDate && x.s < eDate) - .sort((a, b) => a.s - b.s); - - const res = []; - let curr = sDate; - let bIdx = 0; - - while (curr + MS <= eDate) { - // 1. Jump overlapping busy slots - let collision = false; - while (bIdx < busy.length && busy[bIdx].e <= curr) bIdx++; // Fast forward past busy - - for (let i = bIdx; i < busy.length; i++) { - if (busy[i].s >= curr + MS) break; // Future busy slot - if (curr < busy[i].e && (curr + MS) > busy[i].s) { // Overlap - curr = busy[i].e; - collision = true; - break; - } - } - if (collision) continue; - - // 2. Validate/Adjust Work Hours (UTC) - const d = new Date(curr); - const dMin = d.getUTCHours() * 60 + d.getUTCMinutes(); - - // Calc end time min (handling day boundaries carefully) - const endD = new Date(curr + MS); - const endMin = endD.getUTCHours() * 60 + endD.getUTCMinutes(); - const diffDays = endD.getUTCDate() !== d.getUTCDate(); - - if (dMin < wsMin) { - // Too early: Jump to start of work day - d.setUTCHours(wsH, wsM, 0, 0); - curr = d.getTime(); - } else if (diffDays || endMin > weMin || (endMin === 0 && diffDays)) { // endMin 0 is midnight next day - // Too late: Jump to start of next work day - d.setUTCDate(d.getUTCDate() + 1); - d.setUTCHours(wsH, wsM, 0, 0); - curr = d.getTime(); - } else { - // Valid slot - res.push({ start: formatISO(curr), end: formatISO(curr + MS) }); - curr += MS; - } - } - - return res; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.6.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.6.js deleted file mode 100644 index b516c55..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.6.js +++ /dev/null @@ -1,49 +0,0 @@ -export const findAvailableSlots = async (cal1, cal2, { durationMinutes: dur, searchRange: range, workHours: wh }) => { - const { parseISO, addMinutes } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.3.1/+esm'); - - const toTime = (d) => parseISO(d).getTime(); - const rStart = toTime(range.start); - const rEnd = toTime(range.end); - - const [wStart, wEnd] = [wh.start, wh.end].map(t => t.split(':').reduce((h, m) => h * 60 + +m, 0)); - const getMins = (d) => d.getUTCHours() * 60 + d.getUTCMinutes(); - - const busy = [...cal1, ...cal2] - .map(x => ({ s: Math.max(rStart, toTime(x.start)), e: Math.min(rEnd, toTime(x.end)) })) - .filter(x => x.s < x.e) - .sort((a, b) => a.s - b.s); - - const merged = []; - if (busy.length) { - let curr = busy[0]; - for (const b of busy) { - if (b.s <= curr.e) curr.e = Math.max(curr.e, b.e); - else { merged.push(curr); curr = b; } - } - merged.push(curr); - } - - const slots = []; - let cursor = rStart; - const blocks = [...merged, { s: rEnd, e: rEnd }]; - - for (const b of blocks) { - while (cursor + dur * 60000 <= b.s) { - const start = new Date(cursor); - const end = addMinutes(start, dur); - - if (start.getUTCDay() === end.getUTCDay()) { - const sM = getMins(start); - const eM = getMins(end); - if (sM >= wStart && eM <= wEnd) { - slots.push({ start: start.toISOString(), end: end.toISOString() }); - } - } - cursor = end.getTime(); - } - cursor = Math.max(cursor, b.e); - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.7.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.7.js deleted file mode 100644 index 8d3454d..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.7.js +++ /dev/null @@ -1,43 +0,0 @@ -export const findAvailableSlots = async (calA, calB, { durationMinutes, searchRange, workHours }) => { - const { DateTime, Interval } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm'); - const zone = 'utc'; - const toDt = (iso) => DateTime.fromISO(iso, { zone }); - const totalRange = Interval.fromDateTimes(toDt(searchRange.start), toDt(searchRange.end)); - const busy = Interval.merge([...calA, ...calB].map(({ start, end }) => Interval.fromDateTimes(toDt(start), toDt(end)))); - - const results = []; - let cursor = totalRange.start.startOf('day'); - - while (cursor < totalRange.end) { - const [startH, startM] = workHours.start.split(':'); - const [endH, endM] = workHours.end.split(':'); - - const dailyWork = Interval.fromDateTimes( - cursor.set({ hour: +startH, minute: +startM }), - cursor.set({ hour: +endH, minute: +endM }) - ); - - const effective = dailyWork.intersection(totalRange); - - if (effective?.isValid && !effective.isEmpty()) { - let available = [effective]; - for (const b of busy) { - if (b.overlaps(effective)) { - available = available.flatMap(a => a.difference(b)); - } - } - - for (const period of available) { - period.splitBy({ minutes: durationMinutes }).forEach(slot => { - if (slot.isValid && slot.toDuration('minutes').minutes === durationMinutes) { - results.push({ start: slot.start.toISO(), end: slot.end.toISO() }); - } - }); - } - } - cursor = cursor.plus({ days: 1 }); - } - - return results; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.8.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.8.js deleted file mode 100644 index 467ca2a..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.8.js +++ /dev/null @@ -1,45 +0,0 @@ -const findAvailableSlots = async (c1, c2, { durationMinutes: d, searchRange: r, workHours: wh }) => { - const { addMinutes } = await import('https://esm.sh/date-fns@3.6.0'); - const toMs = x => new Date(x).getTime(); - const [rangeStart, rangeEnd] = [toMs(r.start), toMs(r.end)]; - - const busy = [...c1, ...c2] - .map(x => ({ s: toMs(x.start), e: toMs(x.end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - const last = acc.at(-1); - if (last && c.s <= last.e) last.e = Math.max(last.e, c.e); - else acc.push(c); - return acc; - }, []); - - const slots = [], dm = d * 6e4; - let walker = new Date(rangeStart), bIdx = 0; - walker.setUTCHours(0, 0, 0, 0); - - const [wsH, wsM] = wh.start.split(':'), [weH, weM] = wh.end.split(':'); - - while (walker.getTime() <= rangeEnd) { - const wStart = new Date(walker).setUTCHours(wsH, wsM, 0, 0); - const wEnd = new Date(walker).setUTCHours(weH, weM, 0, 0); - let cur = Math.max(wStart, rangeStart), lim = Math.min(wEnd, rangeEnd); - - while (cur + dm <= lim) { - const next = cur + dm; - while (bIdx < busy.length && busy[bIdx].e <= cur) bIdx++; - - if (bIdx < busy.length && busy[bIdx].s < next) { - cur = busy[bIdx].e; - } else { - slots.push({ - start: new Date(cur).toISOString(), - end: addMinutes(new Date(cur), d).toISOString() - }); - cur = next; - } - } - walker.setUTCDate(walker.getUTCDate() + 1); - } - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.9.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.9.js deleted file mode 100644 index f42f34a..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.9.js +++ /dev/null @@ -1,57 +0,0 @@ -export const findAvailableSlots = async (cal1, cal2, { durationMinutes, searchRange, workHours }) => { - const { parseISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm'); - const toMs = (d) => parseISO(d).getTime(); - const toIso = (ms) => new Date(ms).toISOString(); - const rangeStart = toMs(searchRange.start); - const rangeEnd = toMs(searchRange.end); - const durMs = durationMinutes * 60000; - - // Merge and Sort Busy Intervals - const busy = [...cal1, ...cal2] - .map(({ start, end }) => ({ s: toMs(start), e: toMs(end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, cur) => { - const last = acc[acc.length - 1]; - if (last && cur.s < last.e) last.e = Math.max(last.e, cur.e); - else acc.push(cur); - return acc; - }, []); - - const slots = []; - // Iterate strictly by days in UTC to determine work hours - const cursor = new Date(rangeStart); - cursor.setUTCHours(0, 0, 0, 0); - - while (cursor.getTime() < rangeEnd) { - const dateIso = cursor.toISOString().slice(0, 10); - // Determine available window for this day - const workStart = Date.parse(`${dateIso}T${workHours.start}:00Z`); - const workEnd = Date.parse(`${dateIso}T${workHours.end}:00Z`); - const wStart = Math.max(rangeStart, workStart); - const wEnd = Math.min(rangeEnd, workEnd); - - if (wStart < wEnd) { - let ptr = wStart; - // Subtract busy times from the day's window - for (const b of busy) { - if (b.e <= ptr) continue; - if (b.s >= wEnd) break; - - // Generate slots in the free interval [ptr, b.s] - while (ptr + durMs <= b.s) { - slots.push({ start: toIso(ptr), end: toIso(ptr += durMs) }); - } - ptr = Math.max(ptr, b.e); - if (ptr >= wEnd) break; - } - // Fill remaining time in the day - while (ptr + durMs <= wEnd) { - slots.push({ start: toIso(ptr), end: toIso(ptr += durMs) }); - } - } - cursor.setUTCDate(cursor.getUTCDate() + 1); - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.js deleted file mode 100644 index e196eaf..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_1.js +++ /dev/null @@ -1,55 +0,0 @@ -const findAvailableSlots = async (calendarA, calendarB, { durationMinutes, searchRange, workHours }) => { - const { addMinutes, formatISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm'); - const T = (d) => new Date(d).getTime(); - const durMs = durationMinutes * 60000; - const rangeEnd = T(searchRange.end); - - const busy = [...calendarA, ...calendarB] - .map(s => ({ s: T(s.start), e: T(s.end) })) - .sort((a, b) => a.s - b.s) - .reduce((acc, c) => { - if (acc.length && c.s < acc[acc.length - 1].e) { - acc[acc.length - 1].e = Math.max(acc[acc.length - 1].e, c.e); - } else { - acc.push(c); - } - return acc; - }, []); - - const slots = []; - let currentDay = new Date(searchRange.start); - currentDay.setUTCHours(0, 0, 0, 0); - - while (currentDay.getTime() < rangeEnd) { - const dateStr = currentDay.toISOString().split('T')[0]; - const workStart = T(`${dateStr}T${workHours.start}:00Z`); - const workEnd = T(`${dateStr}T${workHours.end}:00Z`); - - const winStart = Math.max(workStart, T(searchRange.start)); - const winEnd = Math.min(workEnd, rangeEnd); - - if (winStart < winEnd) { - let cursor = winStart; - - for (const b of busy) { - if (b.e <= cursor) continue; - if (b.s >= winEnd) break; - - while (cursor + durMs <= b.s) { - slots.push({ start: formatISO(cursor), end: formatISO(addMinutes(cursor, durationMinutes)) }); - cursor += durMs; - } - cursor = Math.max(cursor, b.e); - } - - while (cursor + durMs <= winEnd) { - slots.push({ start: formatISO(cursor), end: formatISO(addMinutes(cursor, durationMinutes)) }); - cursor += durMs; - } - } - currentDay.setUTCDate(currentDay.getUTCDate() + 1); - } - - return slots; -}; -export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_2.js b/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_2.js deleted file mode 100644 index cfd5a1b..0000000 --- a/tests/7_scheduler/outputs_gemini/gemini-3-pro-preview TEMP_2.js +++ /dev/null @@ -1,50 +0,0 @@ -export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: range, workHours: work }) => { - const { formatISO, addMinutes } = await import('https://esm.sh/date-fns@3.6.0'); - const toMs = (d) => new Date(d).getTime(); - const slotMs = dur * 6e4; - const limit = toMs(range.end); - - const parseTime = t => t.split(':').reduce((h, m) => h * 60 + +m, 0); - const [wStart, wEnd] = [work.start, work.end].map(parseTime); - - const busy = [...calA, ...calB] - .map(x => ({ s: toMs(x.start), e: toMs(x.end) })) - .sort((a, b) => a.s - b.s) - .reduce((a, c) => { - const l = a.at(-1); - (l && c.s <= l.e) ? l.e = Math.max(l.e, c.e) : a.push(c); - return a; - }, []); - - let now = toMs(range.start); - let bIdx = 0; - const res = []; - - while (now + slotMs <= limit) { - const d = new Date(now); - const dayBase = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()); - const [dayStart, dayEnd] = [dayBase + wStart * 6e4, dayBase + wEnd * 6e4]; - - if (now < dayStart) { - now = dayStart; - continue; - } - if (now + slotMs > dayEnd) { - now = dayStart + 864e5; - continue; - } - - while (busy[bIdx] && busy[bIdx].e <= now) bIdx++; - const b = busy[bIdx]; - - if (b && b.s < now + slotMs) { - now = b.e; - } else { - res.push({ start: formatISO(now), end: formatISO(addMinutes(now, dur)) }); - now += slotMs; - } - } - - return res; -}; -export default findAvailableSlots; \ No newline at end of file