Docs: Update Gemini benchmark results

This commit is contained in:
github-actions[bot]
2025-11-18 19:30:39 +00:00
parent 51a98c1e1b
commit 76fb066932
133 changed files with 2340 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
const [djs, utc] = await Promise.all([
import('https://esm.sh/dayjs@1.11.10'),
import('https://esm.sh/dayjs@1.11.10/plugin/utc')
]).then(m => m.map(i => i.default));
djs.extend(utc);
const U = (d) => djs(d).utc();
const [wsH, wsM] = wh.start.split(':').map(Number);
const [weH, weM] = wh.end.split(':').map(Number);
const busy = [...calA, ...calB]
.map(s => ({ s: U(s.start), e: U(s.end) }))
.sort((a, b) => a.s - b.s)
.reduce((acc, c) => {
const last = acc[acc.length - 1];
if (last && c.s.diff(last.e) < 0) last.e = c.e.diff(last.e) > 0 ? c.e : last.e;
else acc.push(c);
return acc;
}, []);
const slots = [];
let curDay = U(rng.start).startOf('day');
const limit = U(rng.end);
while (curDay.isBefore(limit)) {
let wStart = curDay.hour(wsH).minute(wsM);
let wEnd = curDay.hour(weH).minute(weM);
if (wStart.isBefore(U(rng.start))) wStart = U(rng.start);
if (wEnd.isAfter(limit)) wEnd = limit;
let ptr = wStart;
while (ptr.add(dur, 'm').diff(wEnd) <= 0) {
const next = ptr.add(dur, 'm');
const clash = busy.find(b => ptr.isBefore(b.e) && next.isAfter(b.s));
if (clash) ptr = clash.e;
else {
slots.push({ start: ptr.format(), end: next.format() });
ptr = next;
}
}
curDay = curDay.add(1, 'day');
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,44 @@
const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
const { DateTime: DT, Interval: IV } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm');
const z = { zone: 'utc' }, parse = s => DT.fromISO(s, z);
const range = IV.fromDateTimes(parse(rng.start), parse(rng.end));
const busy = [...calA, ...calB]
.map(s => IV.fromDateTimes(parse(s.start), parse(s.end)))
.filter(i => i.isValid)
.sort((a, b) => a.start - b.start);
const merged = busy.reduce((acc, curr) => {
const last = acc[acc.length - 1];
if (last && (last.overlaps(curr) || last.abutsStart(curr))) {
acc[acc.length - 1] = last.union(curr);
} else acc.push(curr);
return acc;
}, []);
const slots = [];
let day = range.start.startOf('day');
const [sH, sM] = wh.start.split(':'), [eH, eM] = wh.end.split(':');
while (day < range.end) {
const wStart = day.set({ hour: sH, minute: sM }), wEnd = day.set({ hour: eH, minute: eM });
let work = IV.fromDateTimes(wStart, wEnd).intersection(range);
if (work && work.isValid) {
let cursor = work.start;
while (cursor < work.end) {
const block = merged.find(b => b.end > cursor && b.start < work.end);
const limit = (block && block.start < work.end) ? block.start : work.end;
while (cursor.plus({ minutes: dur }) <= limit) {
slots.push({ start: cursor.toISO(), end: cursor.plus({ minutes: dur }).toISO() });
cursor = cursor.plus({ minutes: dur });
}
cursor = block ? (block.end > cursor ? block.end : cursor) : work.end;
}
}
day = day.plus({ days: 1 });
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,55 @@
export const findAvailableSlots = async (calendarA, calendarB, { durationMinutes, searchRange, workHours }) => {
const { default: dayjs } = await import('https://esm.sh/dayjs');
const { default: utc } = await import('https://esm.sh/dayjs/plugin/utc');
dayjs.extend(utc);
const parse = (d) => dayjs.utc(d);
const msDuration = durationMinutes * 60000;
const rangeStart = parse(searchRange.start);
const rangeEnd = parse(searchRange.end);
let busy = [...calendarA, ...calendarB]
.map(s => ({ s: parse(s.start).valueOf(), e: parse(s.end).valueOf() }))
.sort((a, b) => a.s - b.s)
.reduce((acc, curr) => {
const last = acc[acc.length - 1];
if (last && curr.s < last.e) last.e = Math.max(last.e, curr.e);
else acc.push(curr);
return acc;
}, []);
const slots = [];
let currentDay = rangeStart.startOf('day');
const finalDay = rangeEnd.endOf('day');
while (currentDay.isBefore(finalDay) || currentDay.isSame(finalDay)) {
const dateStr = currentDay.format('YYYY-MM-DD');
let start = parse(`${dateStr}T${workHours.start}`);
let end = parse(`${dateStr}T${workHours.end}`);
if (start.isBefore(rangeStart)) start = rangeStart;
if (end.isAfter(rangeEnd)) end = rangeEnd;
let ptr = start.valueOf();
const limit = end.valueOf();
while (ptr + msDuration <= limit) {
const slotEnd = ptr + msDuration;
const conflict = busy.find(b => b.s < slotEnd && b.e > ptr);
if (conflict) {
ptr = conflict.e;
} else {
slots.push({
start: dayjs(ptr).utc().format(),
end: dayjs(slotEnd).utc().format()
});
ptr += msDuration;
}
}
currentDay = currentDay.add(1, 'day');
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,44 @@
export const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange, workHours }) => {
const { DateTime, Interval } = await import('https://esm.sh/luxon@3.4.4');
const utc = (t) => DateTime.fromISO(t, { zone: 'utc' });
const bounds = Interval.fromDateTimes(utc(searchRange.start), utc(searchRange.end));
const busy = [...calA, ...calB]
.map(s => Interval.fromDateTimes(utc(s.start), utc(s.end)))
.filter(i => i.isValid && i.overlaps(bounds))
.sort((a, b) => a.start - b.start)
.reduce((acc, cur) => {
const last = acc.at(-1);
return last && last.end >= cur.start ? [...acc.slice(0, -1), last.union(cur)] : [...acc, cur];
}, []);
const slots = [];
let cursor = bounds.start.startOf('day');
while (cursor <= bounds.end) {
const [sH, sM] = workHours.start.split(':');
const [eH, eM] = workHours.end.split(':');
const workInt = Interval.fromDateTimes(
cursor.set({ hour: sH, minute: sM }),
cursor.set({ hour: eH, minute: eM })
).intersection(bounds);
if (workInt?.isValid) {
let free = [workInt];
busy.filter(b => b.overlaps(workInt)).forEach(b => free = free.flatMap(f => f.difference(b)));
free.forEach(f => {
let s = f.start;
while (s.plus({ minutes: dur }) <= f.end) {
const e = s.plus({ minutes: dur });
slots.push({ start: s.toISO(), end: e.toISO() });
s = e;
}
});
}
cursor = cursor.plus({ days: 1 });
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,41 @@
export const findAvailableSlots = async (c1, c2, { durationMinutes: d, searchRange: r, workHours: w }) => {
const { parseISO } = await import('https://cdn.jsdelivr.net/npm/date-fns@2.30.0/+esm');
const toMs = x => parseISO(x).getTime();
const [wsH, wsM] = w.start.split(':').map(Number);
const [weH, weM] = w.end.split(':').map(Number);
const rStart = toMs(r.start), rEnd = toMs(r.end), durMs = d * 6e4;
const busy = [...c1, ...c2]
.map(x => ({ s: toMs(x.start), e: toMs(x.end) }))
.sort((a, b) => a.s - b.s)
.reduce((acc, cur) => {
if (acc.length && cur.s <= acc[acc.length - 1].e) acc[acc.length - 1].e = Math.max(acc[acc.length - 1].e, cur.e);
else acc.push(cur);
return acc;
}, []);
let free = [], curr = new Date(rStart);
curr.setUTCHours(0, 0, 0, 0);
while (curr.getTime() < rEnd) {
const s = Math.max(new Date(curr).setUTCHours(wsH, wsM, 0, 0), rStart);
const e = Math.min(new Date(curr).setUTCHours(weH, weM, 0, 0), rEnd);
if (s < e) free.push({ s, e });
curr.setUTCDate(curr.getUTCDate() + 1);
}
return busy.reduce((acc, b) => acc.flatMap(f => {
if (b.e <= f.s || b.s >= f.e) return [f];
return [
...(f.s < b.s ? [{ s: f.s, e: b.s }] : []),
...(f.e > b.e ? [{ s: b.e, e: f.e }] : [])
];
}), free).flatMap(f => {
const slots = [];
for (let t = f.s; t + durMs <= f.e; t += durMs) {
slots.push({ start: new Date(t).toISOString(), end: new Date(t + durMs).toISOString() });
}
return slots;
});
};
export default findAvailableSlots;

View File

@@ -0,0 +1,45 @@
export const findAvailableSlots = async (cal1, cal2, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon');
const zone = 'utc';
const fromISO = t => DateTime.fromISO(t, { zone });
const searchIv = Interval.fromDateTimes(fromISO(rng.start), fromISO(rng.end));
const busy = [...cal1, ...cal2]
.map(s => Interval.fromDateTimes(fromISO(s.start), fromISO(s.end)))
.filter(i => i.isValid && i.overlaps(searchIv))
.sort((a, b) => a.start - b.start)
.reduce((acc, cur) => {
const last = acc[acc.length - 1];
return last && (last.overlaps(cur) || last.abutsStart(cur))
? [...acc.slice(0, -1), last.union(cur)]
: [...acc, cur];
}, []);
const slots = [];
let curDate = searchIv.start.startOf('day');
const [wsH, wsM] = wh.start.split(':');
const [weH, weM] = wh.end.split(':');
while (curDate < searchIv.end) {
const workStart = curDate.set({ hour: wsH, minute: wsM });
const workEnd = curDate.set({ hour: weH, minute: weM });
const workIv = Interval.fromDateTimes(workStart, workEnd).intersection(searchIv);
if (workIv && workIv.isValid) {
let free = [workIv];
busy.forEach(b => { free = free.flatMap(f => f.difference(b)); });
free.forEach(iv => {
iv.splitBy({ minutes: dur }).forEach(chunk => {
if (Math.abs(chunk.length('minutes') - dur) < 0.01) {
slots.push({ start: chunk.start.toISO(), end: chunk.end.toISO() });
}
});
});
}
curDate = curDate.plus({ days: 1 });
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,52 @@
const findAvailableSlots = async (calA, calB, constraints) => {
const { DateTime: D } = await import('https://cdn.jsdelivr.net/npm/luxon@3.4.4/+esm');
const { durationMinutes: dur, searchRange: rng, workHours: wh } = constraints;
const utc = { zone: 'utc' };
const parse = s => D.fromISO(s, utc);
const durMs = dur * 60000;
const busy = [...calA, ...calB]
.map(x => ({ s: parse(x.start).valueOf(), e: parse(x.end).valueOf() }))
.sort((a, b) => a.s - b.s)
.reduce((acc, cur) => {
const last = acc.at(-1);
if (last && cur.s <= last.e) last.e = Math.max(last.e, cur.e);
else acc.push(cur);
return acc;
}, []);
const slots = [];
const rangeStart = parse(rng.start).valueOf();
const rangeEnd = parse(rng.end).valueOf();
const [wsH, wsM] = wh.start.split(':').map(Number);
const [weH, weM] = wh.end.split(':').map(Number);
let currDay = parse(rng.start).startOf('day');
while (currDay.valueOf() < rangeEnd) {
const wStart = Math.max(currDay.set({ hour: wsH, minute: wsM }).valueOf(), rangeStart);
const wEnd = Math.min(currDay.set({ hour: weH, minute: weM }).valueOf(), rangeEnd);
if (wStart < wEnd) {
let ptr = wStart;
for (const b of busy) {
if (b.e <= ptr) continue;
if (b.s >= wEnd) break;
while (ptr + durMs <= b.s) {
slots.push({ start: D.fromMillis(ptr, utc).toISO(), end: D.fromMillis(ptr + durMs, utc).toISO() });
ptr += durMs;
}
ptr = Math.max(ptr, b.e);
}
while (ptr + durMs <= wEnd) {
slots.push({ start: D.fromMillis(ptr, utc).toISO(), end: D.fromMillis(ptr + durMs, utc).toISO() });
ptr += durMs;
}
}
currDay = currDay.plus({ days: 1 });
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,53 @@
export const findAvailableSlots = async (cal1, cal2, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
const [djs, utc] = await Promise.all([
import('https://esm.sh/dayjs@1.11.10'),
import('https://esm.sh/dayjs@1.11.10/plugin/utc')
]);
const dayjs = djs.default;
dayjs.extend(utc.default);
const parse = d => dayjs(d).utc();
const [wsH, wsM] = wh.start.split(':').map(Number);
const [weH, weM] = wh.end.split(':').map(Number);
let now = parse(rng.start);
const endLimit = parse(rng.end);
const slots = [];
const busy = [...cal1, ...cal2]
.map(s => ({ s: parse(s.start), e: parse(s.end) }))
.sort((a, b) => a.s - b.s)
.reduce((acc, c) => {
const last = acc.at(-1);
if (last && c.s <= last.e) last.e = c.e > last.e ? c.e : last.e;
else acc.push(c);
return acc;
}, []);
while (now.add(dur, 'm') <= endLimit) {
const wStart = now.hour(wsH).minute(wsM).second(0).millisecond(0);
const wEnd = now.hour(weH).minute(weM).second(0).millisecond(0);
if (now < wStart) now = wStart;
const next = now.add(dur, 'm');
if (next > wEnd) {
now = wStart.add(1, 'd');
continue;
}
if (next > endLimit) break;
const clash = busy.find(b => now < b.e && next > b.s);
if (clash) {
now = clash.e;
} else {
slots.push({ start: now.toISOString(), end: next.toISOString() });
now = next;
}
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,59 @@
const findAvailableSlots = async (calA, calB, { durationMinutes, searchRange, workHours }) => {
const { parseISO, formatISO, addMinutes } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm');
const rangeStart = parseISO(searchRange.start).getTime();
const rangeEnd = parseISO(searchRange.end).getTime();
const durationMs = durationMinutes * 60 * 1000;
const busy = [...calA, ...calB]
.map(s => ({ start: parseISO(s.start).getTime(), end: parseISO(s.end).getTime() }))
.sort((a, b) => a.start - b.start);
const merged = [];
if (busy.length) {
let curr = busy[0];
for (const next of busy.slice(1)) {
if (curr.end >= next.start) {
curr.end = Math.max(curr.end, next.end);
} else {
merged.push(curr);
curr = next;
}
}
merged.push(curr);
}
const slots = [];
let now = rangeStart;
while (now + durationMs <= rangeEnd) {
const currentDate = new Date(now);
const dateStr = currentDate.toISOString().split('T')[0];
const workStart = parseISO(`${dateStr}T${workHours.start}:00Z`).getTime();
const workEnd = parseISO(`${dateStr}T${workHours.end}:00Z`).getTime();
if (now < workStart) {
now = workStart;
continue;
}
if (now + durationMs > workEnd) {
now = addMinutes(workStart, 24 * 60).getTime();
continue;
}
const conflict = merged.find(b => now < b.end && (now + durationMs) > b.start);
if (conflict) {
now = conflict.end;
} else {
const start = new Date(now);
const end = new Date(now + durationMs);
slots.push({ start: formatISO(start), end: formatISO(end) });
now += durationMs;
}
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,40 @@
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;

View File

@@ -0,0 +1,49 @@
const findAvailableSlots = async (calendarA, calendarB, constraints) => {
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 = d.utc;
const ms = constraints.durationMinutes * 60000;
const rangeS = D(constraints.searchRange.start);
const rangeE = D(constraints.searchRange.end);
const [wS_H, wS_M] = constraints.workHours.start.split(':').map(Number);
const [wE_H, wE_M] = constraints.workHours.end.split(':').map(Number);
const busy = [...calendarA, ...calendarB]
.map(x => ({ s: D(x.start).valueOf(), e: D(x.end).valueOf() }))
.sort((a, b) => a.s - b.s)
.reduce((acc, c) => {
const l = acc[acc.length - 1];
if (l && c.s < l.e) l.e = Math.max(l.e, c.e);
else acc.push(c);
return acc;
}, []);
const slots = [];
let curr = rangeS.startOf('day');
const endDay = rangeE.endOf('day');
while (curr.isBefore(endDay)) {
let sTime = curr.hour(wS_H).minute(wS_M).second(0).millisecond(0);
let eTime = curr.hour(wE_H).minute(wE_M).second(0).millisecond(0);
const sVal = Math.max(sTime.valueOf(), rangeS.valueOf());
const eVal = Math.min(eTime.valueOf(), rangeE.valueOf());
let ptr = sVal;
while (ptr + ms <= eVal) {
const conflict = busy.find(b => b.s < ptr + ms && b.e > ptr);
if (conflict) {
ptr = conflict.e;
} else {
slots.push({ start: D(ptr).format(), end: D(ptr + ms).format() });
ptr += ms;
}
}
curr = curr.add(1, 'day');
}
return slots;
};
export default findAvailableSlots;

View File

@@ -0,0 +1,49 @@
const findAvailableSlots = async (calA, calB, { durationMinutes: dur, searchRange: rng, workHours: wh }) => {
const { addMinutes } = await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm');
const parse = d => new Date(d).getTime();
const toIso = t => new Date(t).toISOString();
const [rStart, rEnd] = [parse(rng.start), parse(rng.end)];
const msDur = dur * 60000;
const busy = [...calA, ...calB]
.map(x => ({ s: parse(x.start), e: parse(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 slots = [];
let curr = new Date(rStart);
curr.setUTCHours(0, 0, 0, 0);
while (curr.getTime() < rEnd) {
const [wsH, wsM] = wh.start.split(':'), [weH, weM] = wh.end.split(':');
const wStart = new Date(curr).setUTCHours(+wsH, +wsM, 0, 0);
const wEnd = new Date(curr).setUTCHours(+weH, +weM, 0, 0);
const winStart = Math.max(wStart, rStart);
const winEnd = Math.min(wEnd, rEnd);
if (winStart < winEnd) {
let t = winStart;
while (t + msDur <= winEnd) {
const tEnd = addMinutes(t, dur).getTime();
const clash = busy.find(b => t < b.e && tEnd > b.s);
if (clash) t = clash.e;
else {
slots.push({ start: toIso(t), end: toIso(tEnd) });
t = tEnd;
}
}
}
curr.setUTCDate(curr.getUTCDate() + 1);
}
return slots;
};
export default findAvailableSlots;