// this one written by claude, it is shit so dont blame me for any misaccuracy LOL const { readFile } = require("node:fs/promises") const FILES = [ "01.json", "06.json", "10.json" ] const OPEN_TIME = "08:00" const CLOSE_TIME = "17:00" const DAY_ORDER = { "Senin": 1, "Selasa": 2, "Rabu": 3, "Kamis": 4, "Jumat": 5, "Sabtu": 6, "Minggu": 7 } async function loadFiles() { const results = await Promise.all(FILES.map(async file => { const content = await readFile(file, "utf8") const json = JSON.parse(content) return json.data })) return results.flat() } function parseDateRoom(value) { const match = value.match(/^([^,]+),\s*(\d{2}[:.]\d{2})-(\d{2}[:.]\d{2})\s+\((.*)$/) if (!match) return null const [ , day, rawStart, rawEnd, rawRoom] = match const start = rawStart.replace(".", ":") const end = rawEnd.replace(".", ":") const room = rawRoom.endsWith(")") ? rawRoom.slice(0, -1) : rawRoom return { day, start, end, room } } function timeToMinutes(time) { const [hours, minutes] = time.split(":").map(Number) return hours * 60 + minutes } function minutesToTime(minutes) { const hours = Math.floor(minutes / 60) const mins = minutes % 60 return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}` } function buildSchedule(classes) { const schedule = new Map() for (const classInfo of classes) { if (!Array.isArray(classInfo.dates_rooms)) { console.warn(`Skipping ${classInfo.classname}: invalid dates_rooms`) continue } for (const dateRoom of classInfo.dates_rooms) { const parsed = parseDateRoom(dateRoom) if (!parsed) { console.warn(`Could not parse: ${dateRoom}`) continue } const { day, start, end, room } = parsed if (!schedule.has(room)) { schedule.set(room, new Map()) } const roomSchedule = schedule.get(room) if (!roomSchedule.has(day)) { roomSchedule.set(day, []) } roomSchedule.get(day).push({ start, end, className: classInfo.classname }) } } return schedule } function buildEmptySchedule(schedule) { const emptySchedule = new Map() const dayStartMin = timeToMinutes(OPEN_TIME) const dayEndMin = timeToMinutes(CLOSE_TIME) for (const [room, roomSchedule] of schedule) { emptySchedule.set(room, new Map()) // Process all days for (const day of Object.keys(DAY_ORDER)) { const classes = roomSchedule.get(day) || [] if (classes.length === 0) { // No classes = room won't be opened that day continue } // Sort classes by start time const sorted = classes.sort((a, b) => timeToMinutes(a.start) - timeToMinutes(b.start)) const emptySlots = [] let currentTime = dayStartMin for (const classInfo of sorted) { const classStart = timeToMinutes(classInfo.start) const classEnd = timeToMinutes(classInfo.end) // Gap before this class if (currentTime < classStart) { emptySlots.push({ start: minutesToTime(currentTime), end: classInfo.start }) } // Move current time to after this class (or keep it if overlapping) currentTime = Math.max(currentTime, classEnd) } // Gap after last class if (currentTime < dayEndMin) { emptySlots.push({ start: minutesToTime(currentTime), end: CLOSE_TIME }) } // Only add day if there are empty slots if (emptySlots.length > 0) { emptySchedule.get(room).set(day, emptySlots) } } } return emptySchedule } function formatEmptySchedule(emptySchedule) { const lines = [] const rooms = [...emptySchedule.keys()].sort((a, b) => a.localeCompare(b)) for (const room of rooms) { const roomSchedule = emptySchedule.get(room) lines.push(`## ${room} \`${OPEN_TIME} - ${CLOSE_TIME}\``) const days = [...roomSchedule.keys()].sort((a, b) => DAY_ORDER[a] - DAY_ORDER[b]) for (const day of days) { const emptySlots = roomSchedule.get(day) lines.push(` - **${day}:**`) for (const slot of emptySlots) { lines.push(` - \`${slot.start} - ${slot.end}\` (KOSONG)`) } } lines.push("") } return lines.join("\n") } ///////////////// async function main() { const cl = await loadFiles() const sc = buildSchedule(cl) const emptySchedule = buildEmptySchedule(sc) console.log(formatEmptySchedule(emptySchedule)) } main().catch(error => { console.error(error) process.exitCode = 1 })