'use strict'; // Use luxon for date and time handling import * as luxon from "../luxon/luxon.es6.js"; // --------------------------------------------------------- // Helpers // :: A -> Option[A] let optional = (x) => x === null ? undefined : x; // :: A -> Bool let defined = (x) => x !== undefined; // :: Option[A] -> (()->B) -> Option[B] let withDefined = (x, f) => defined(x) ? f() : undefined; //-:: Option[A] -> (A->B) -> Option[B] let ifDefined = (x, f) => defined(x) ? f(x) : undefined; // Note: use only for primitive values ("primary keys") // :: List[A] -> List[A] let distinct = (xs) => Array.from(new Set(xs)); // :: List[A] -> List[A] -> List[A] let intersection = (xs, ys) => xs.filter(v => ys.includes(v)); //-:: String -> String -> Int let stringCompare = (s1, s2) => { if (s1 < s2) { return -1; }; if (s1 > s2) { return 1; }; return 0; }; // --------------------------------------------------------- // Transform Json into proper Arrays and Maps //-:: EventAnswerJson -> EventAnswer let processEventAnswer = (answerJ) => { let m = new Map(); m.set('question', answerJ.question); m.set('answer', answerJ.answer); return m; }; //-:: AttachmentJson -> Attachment let processAttachment = (attachmentJ) => undefined; //-:: LinkJson -> Link let processLink = (linkJ) => undefined; //-:: PersonAnswerJson -> PersonAnswer let processPersonAnswer = (answerJ) => undefined; //-:: PersonJson -> Person let processPerson = (personJ) => { let m = new Map(); m.set('id', personJ.id); m.set('code', personJ.code); // Renamed field: m.set('name', personJ.public_name); m.set('biography', optional(personJ.biography)); m.set('answers', personJ.answers.map(aj => processPersonAnswer(aj))); return m; }; //-:: EventJson -> DayIndex -> Event let processEvent = (eventJ, dayIndex) => { let start_date = luxon.DateTime.fromISO(eventJ.date); let duration = luxon.Duration.fromISOTime(eventJ.duration); let end_date = start_date.plus(duration); let m = new Map(); m.set('id', eventJ.id); m.set('guid', eventJ.guid); m.set('logo', eventJ.logo); // Same as processed start date //m.set('date', // luxon.DateTime.fromISO(eventJ.date)); m.set('start_date', start_date); // Synthetic field: m.set('end_date', end_date); m.set('duration', duration); // Synthetic field: m.set('day_index', dayIndex); m.set('room', eventJ.room); m.set('slug', eventJ.slug); m.set('url', eventJ.url); // m.set('title', eventJ.title || ""); m.set('title', withDefined(eventJ.title, () => eventJ.title)); m.set('subtitle', withDefined(eventJ.subtitle, () => eventJ.subtitle)); m.set('track', eventJ.track); m.set('type', eventJ.type); m.set('language', eventJ.language); // TODO: Rethink empty strings m.set('abstract', eventJ.abstract || ""); m.set('description', eventJ.description || ""); m.set('recording_license', eventJ.recording_license); m.set('do_not_record', eventJ.do_not_record); m.set('persons', eventJ.persons.map(pj => processPerson(pj))); m.set('links', eventJ.links.map(lj => processLink(lj))); m.set('attachments', eventJ.attachments.map(aj => processAttachment(aj))); m.set('answers', withDefined(eventJ.answers, () => eventJ.answers.map(aj => processEventAnswer(aj)))); return m; }; //-:: RoomJson -> DayIndex -> Map[RoomName, List[Event]] let processRooms = (roomJ, dayIndex) => { let m = new Map( Object.entries(roomJ).map( item => [item[0], item[1].map(e => processEvent(e, dayIndex))] ) ); return m; }; //-:: DayJson -> Day let processDay = (dayJ) => { let main_date = luxon.DateTime.fromISO(dayJ.date); let start_date = luxon.DateTime.fromISO(dayJ.day_start); let end_date = luxon.DateTime.fromISO(dayJ.day_end); let duration = end_date.diff(start_date); let m = new Map(); m.set('index', dayJ.index); m.set('date', main_date); m.set('start_date', start_date); m.set('end_date', end_date); // Synthetic field: m.set('duration', duration); // Note: Pass day index down to rooms and finally events m.set('rooms', processRooms(dayJ.rooms, dayJ.index)); return m; }; //-:: RoomDefinitionJson -> Room let processRoomDefinition = (roomJ) => { let m = new Map(); m.set('name', roomJ.name); m.set('guid', optional(roomJ.guid)); m.set('description', optional(roomJ.description)); m.set('capacity', optional(roomJ.capacity)); return m; }; //-:: ConferenceJson -> Conference let processConference = (conferenceJ) => { let start_date = luxon.DateTime.fromISO(conferenceJ.start); let end_date = luxon.DateTime.fromISO(conferenceJ.end); let duration = end_date.diff(start_date); let m = new Map(); m.set('acronym', conferenceJ.acronym); m.set('title', conferenceJ.title); m.set('start_date', start_date); m.set('end_date', end_date); // Synthetic field: m.set('duration', duration); m.set('days_count', conferenceJ.daysCount); m.set('timeslot_duration', luxon.Duration.fromISOTime(conferenceJ.timeslot_duration)); // TODO: //m.set('time_zone_name', // luxon.IANAZone.create(conferenceJ.time_zone_name)); m.set('rooms', conferenceJ.rooms.map(rj => processRoomDefinition(rj))); m.set('days', conferenceJ.days.map(dj => processDay(dj))); return m; }; //-:: ScheduleJson -> Schedule let processSchedule = (scheduleJ) => { let m = new Map(); m.set('version', scheduleJ.version); m.set('base_url', scheduleJ.base_url); m.set('conference', processConference(scheduleJ.conference)); return m; }; // :: ScheduleFile -> ScheduleJson let processScheduleFile = (scheduleFile) => processSchedule(scheduleFile.schedule); //processSchedule(JSON.parse(scheduleFile).schedule); // --------------------------------------------------------- // Properties and Accessors ('Data Types') // :: Schedule -> String let scheduleVersion = (schedule) => schedule.get('version'); // :: Schedule -> String let scheduleBaseUrl = (schedule) => schedule.get('base_url'); // :: Conference -> String let conferenceAcronym = (conference) => conference.get('acronym'); // :: Conference -> String let conferenceTitle = (conference) => conference.get('title'); // :: Conference -> luxon.DateTime let conferenceStartDate = (conference) => conference.get('start_date'); // :: Conference -> luxon.DateTime let conferenceEndDate = (conference) => conference.get('end_date'); // :: Conference -> luxon.Duration let conferenceDuration = (conference) => conference.get('duration'); // :: Conference -> Int let conferenceDaysCount = (conference) => conference.get('days_count'); // :: Conference -> luxon.Duration let conferenceTimeslotDuration = (conference) => conference.get('timeslot_duration'); // :: Conference -> luxon.IANATimeZone let conferenceTimezoneName = (conference) => conference.get('time_zone_name'); // :: Day -> DayIndex let dayIndex = (day) => day.get('index'); // :: Day -> luxon.DateTime let dayDate = (day) => day.get('date'); // :: Day -> luxon.DateTime let dayStartDate = (day) => day.get('start_date'); // :: Day -> luxon.DateTime let dayEndDate = (day) => day.get('end_date'); // :: Day -> luxon.Duration let dayDuration = (day) => day.get('duration'); // :: Room -> String let roomName = (room) => room.get('name'); // :: Room -> String let roomGuid = (room) => room.get('guid'); let roomId = (room) => room.get('guid'); // :: Room -> String let roomDescription = (room) => room.get('description'); // :: Room -> Int let roomCapacity = (room) => room.get('capacity'); // :: Event -> Int let eventId = (event) => event.get('id'); // :: Event -> String let eventGuid = (event) => event.get('guid'); // :: Event -> String let eventLogo = (event) => event.get('logo'); // :: Event -> luxon.DateTime let eventStartDate = (event) => event.get('start_date'); // :: Event -> luxon.DateTime let eventEndDate = (event) => event.get('end_date'); // :: Event -> luxon.Duration let eventDuration = (event) => event.get('duration'); // :: Event -> Int let eventDayIndex = (event) => event.get('day_index'); // :: Event -> RoomName let eventRoomName = (event) => event.get('room'); // :: Event -> String let eventSlug = (event) => event.get('slug'); // :: Event -> String let eventUrl = (event) => event.get('url'); // :: Event -> String let eventTitle = (event) => event.get('title'); // :: Event -> String let eventSubtitle = (event) => event.get('subtitle'); // :: Event -> TrackName let eventTrack = (event) => event.get('track'); // :: Event -> EventType let eventType = (event) => event.get('type'); // :: Event -> Language let eventLanguage = (event) => event.get('language'); // :: Event -> String let eventAbstract = (event) => event.get('abstract'); // :: Event -> String let eventDescription = (event) => event.get('description'); // :: Event -> String let eventRecordingLicense = (event) => event.get('recording_license'); // :: Event -> Bool let eventDoNotRecord = (event) => event.get('do_not_record'); // :: Event -> List[Person] let eventPersons = (event) => event.get('persons'); // :: Event -> Int let eventPersonCount = (event) => eventPersons(event).length; // :: Event -> List[AnswerMap] let eventAnswers = (event) => event.get('answers'); // :: Person -> Int let personId = (person) => person.get('id'); // :: Person -> String let personCode = (person) => person.get('code'); // :: Person -> String let personName = (person) => person.get('name'); // :: Person -> String let personBiography = (person) => person.get('biography'); // --------------------------------------------------------- // Filters, Maps and other Pieces of Lisp // TODO: Use own stable IDs // :: List[Event] -> DayIndex -> List[Event] let eventsByDayIndex = (events, dIndex) => events.filter(e => eventDayIndex(e) === dIndex); // :: List[Event] -> Day -> List[Event] let eventsByDay = (events, day) => events.filter(e => eventDayIndex(e) === dayIndex(day)); // :: List[Event] -> RoomName -> List[Event] let eventsByRoomName = (events, rName) => events.filter(e => eventRoomName(e) === rName); // :: List[Event] -> Room -> List[Event] let eventsByRoom = (events, room) => eventsByRoomName(events, roomName(room)); // :: List[Event] -> PersonId -> List[Event] let eventsByPersonId = (events, pId) => events.filter(e => eventPersons(e).some(p => personId(p) === pId)); // :: List[Event] -> PersonName -> List[Event] let eventsByPersonName = (events, pName) => events.filter(e => eventPersons(e).some(p => personName(p) === pName)); // :: List[Event] -> Person -> List[Event] let eventsByPerson = (events, person) => eventsByPersonName(events, personName(person)); // :: List[Event] -> TrackName -> List[Event] let eventsByTrack = (events, eventTrackName) => events.filter(e => eventTrack(e) === eventTrackName); // :: List[Event] -> EventType -> List[Event] let eventsByType = (events, eventTypeName) => events.filter(e => eventType(e) === eventTypeName); // :: List[Event] -> Language -> List[Event] let eventsByLanguage = (events, language) => events.filter(e => eventLanguage(e) === language); // :: List[Room] -> GUID -> Option[Room] let roomById = (rooms, id) => rooms.find(r => roomId(r) === id); // :: List[Room] -> RoomName -> List[Room] let roomsByName = (rooms, name) => rooms.filter(r => roomName(r) === name); // :: List[Day] -> Int -> Option[Day] let dayByIndex = (days, index) => days.find(d => dayIndex(d) === index); // :: List[Person] -> Int -> Option[Person] let personById = (persons, id) => persons.find(p => personId(p) === id); // :: List[Person] -> PersonName -> List[Person] let personsByName = (persons, name) => persons.filter(p => personName(p) === name); // :: List[Event] -> Int -> Option[Event] let eventById = (events, id) => events.find(e => eventId === id); // :: List[Room] -> List[Room] let distinctRooms = (rooms) => { //let ids = distinct(rooms.map(roomId)); //return ids.map(i => rooms.find(r => roomId(r) === i)); // TODO: Room Id might be optional? let rns = distinct(rooms.map(roomName)); return rns.map(i => rooms.find(r => roomName(r) === i)); }; // :: List[Day] -> List[Day] let distinctDays = (days) => { let ids = distinct(days.map(dayIndex)); return ids.map(i => days.find(d => dayIndex(d) === i)); }; // :: List[Event] -> List[Event] let distinctEvents = (events) => { let ids = distinct(events.map(eventId)); return ids.map(i => events.find(e => eventId(e) === i)); }; // :: List[Person] -> List[Person] let distinctPersons = (persons) => { let ids = distinct(persons.map(personId)); return ids.map(i => persons.find(p => personId(p) === i)); }; // :: List[Person] -> List[Person] let sortPersonsByName = (persons) => persons.sort((p1, p2) => stringCompare(personName(p1), personName(p2))); // :: List[Room] -> List[Room] let sortRoomsByName = (rooms) => rooms.sort((r1, r2) => stringCompare(roomName(r1), roomName(r2))); // :: List[Event] -> List[Event] let sortEventsByTitle = (events) => events.sort((e1, e2) => stringCompare(eventTitle(e1), eventTitle(e2))); // --------------------------------------------------------- // Advanced Accessors // Note: Maybe deprecate and replace with 'eventsByDay'? // :: Day -> List[Event] let eventsOfDay = (day) => Array.from(day.get('rooms').values()).flat(); // :: List[Day] -> List[Event] let eventsOfDays = (days) => days.flatMap(eventsOfDay); // Note: Can not implement this, needs more information. // Use 'eventsByRoom' and 'eventsByRooms' instead. //-:: Room -> List[Event] //let eventsOfRoom = (room) => // Array.from(room.values()); //-:: List[Room] -> List[Event] //let eventsOfRooms = (rooms) => rooms.flatMap(eventsOfRoom); // :: List[Event] -> List[TrackName] let tracksOfEvents = (events) => distinct(events.flatMap(eventLanguage)); // :: List[Event] -> List[EventType] let typesOfEvents = (events) => distinct(events.flatMap(eventType)); // :: List[Event] -> List[Language] let languagesOfEvents = (events) => distinct(events.flatMap(eventLanguage)); // :: Conference -> List[Day] let conferenceDays = (conference) => distinctDays(conference.get('days')); // :: Conference -> List[Room] let conferenceRooms = (conference) => distinctRooms(Array.from(conference.get('rooms').values())); // :: Conference -> List[Event] let conferenceEvents = (conference) => distinctEvents(conferenceDays(conference).flatMap(d => eventsOfDay(d))); // :: Conference -> List[Person] let conferencePersons = (conference) => distinctPersons(conferenceEvents(conference).flatMap(eventPersons)); // :: Conference -> List[TrackName] let conferenceTracks = (conference) => distinct(conferenceEvents(conference).flatMap(eventTrack)); // :: Conference -> List[EventType] let conferenceTypes = (conference) => distinct(conferenceEvents(conference).flatMap(eventType)); // :: Conference -> List[Language] let conferenceLanguages = (conference) => distinct(conferenceEvents(conference).flatMap(eventLanguage)); // :: Schedule -> Conference let conference = (schedule) => schedule.get('conference'); // --------------------------------------------------------- // Advanced Filters, Maps and Traces of SQL // TODO: Use own stable IDs // :: Conference -> List[RoomName] -> DayIndex -> List[RoomName] let roomNamesByDayIndex = (conference, roomNames, dayIndex) => { let evs = eventsByDayIndex(conferenceEvents(conference), dayIndex); let rns = distinct(evs.map(eventRoomName)); return distinct(roomNames.filter(rn => rns.includes(rn))); }; // :: Conference -> List[RoomName] -> Day -> List[RoomName] let roomNamesByDay = (conference, roomNames, day) => roomNamesByDayIndex(conference, roomNames, dayIndex(day)); // :: Conference -> List[Room] -> DayIndex -> List[Room] let roomsByDayIndex = (conference, rooms, dayIndex) => { let rns = roomNamesByDayIndex(conference, rooms.map(roomName), dayIndex); return rooms.filter(r => rns.includes(roomName(r))); }; // :: Conference -> List[Room] -> Day => List[Room] let roomsByDay = (conference, rooms, day) => roomsByDayIndex(conference, rooms, dayIndex(day)); // :: Conference -> List[RoomName] -> PersonId -> List[RoomName] let roomNamesByPersonId = (conference, roomNames, id) => { let evs = eventsByPersonId(conferenceEvents(conference), id); let rns = distinct(evs.map(eventRoomName)); return distinct(roomNames.filter(rn => rns.includes(rn))); }; // :: Conference -> List[RoomName] -> Person -> List[RoomName] let roomNamesByPerson = (conference, roomNames, person) => roomNamesByPersonId(conference, roomNames, personId(person)); // :: Conference -> List[Room] -> PersonId -> List[Room] let roomsByPersonId = (conference, rooms, id) => { let rns = roomNamesByPersonId(conference, rooms.map(roomName), id); return rooms.filter(r => rns.includes(roomName(r))); }; // :: Conference -> List[Room] -> Person -> List[Room] let roomsByPerson = (conference, rooms, person) => roomsByPersonId(conference, rooms, personId(person)); // :: Conference -> List[RoomName] -> Track -> List[RoomName] let roomNamesByTrack = (conference, roomNames, track) => { let evs = eventsByTrack(conferenceEvents(conference), track); let rns = evs.map(eventRoomName); return distinct(roomNames.filter(rn => rns.includes(rn))); }; // :: Conference -> List[Room] -> Track -> List[Room] let roomsByTrack = (conference, rooms, track) => roomNamesByTrack(conference, rooms.map(roomName), track).flatMap(rn => roomsByName(rooms, rn)); // :: Conference -> List[RoomName] -> Type -> List[RoomName] let roomNamesByType = (conference, roomNames, type) => { let evs = eventsByType(conferenceEvents(conference), type); let rns = evs.map(eventRoomName); return distinct(roomNames.filter(rn => rns.includes(rn))); }; // :: Conference -> List[Room] -> Type -> List[Room] let roomsByType = (conference, rooms, type) => roomNamesByType(conference, rooms.map(roomName), type).flatMap(rn => roomsByName(rooms, rn)); // :: Conference -> List[RoomName] -> Language -> List[RoomName] let roomNamesByLanguage = (conference, roomNames, language) => { let evs = eventsByLanguage(conferenceEvents(conference), language); let rns = evs.map(eventRoomName); return distinct(roomNames.filter(rn => rns.includes(rn))); }; // :: Conference -> List[Room] -> Language -> List[Room] let roomsByLanguage = (conference, rooms, language) => roomNamesByLanguage(conference, rooms.map(roomName), language).flatMap(rn => roomsByName(rooms, rn)); // :: Conference -> List[PersonId] -> DayIndex -> List[PersonId] let personIdsByDayIndex = (conference, personIds, dayIndex) => { let evs = eventsByDayIndex(conferenceEvents(conference), dayIndex); let pids = distinct(evs.flatMap(eventPersons).map(personId)); return distinct(personIds.filter(pi => pids.includes(pi))); }; // :: Conference -> List[PersonId] -> Day -> List[PersonId] let personIdsByDay = (conference, personIds, day) => personIdsByDayIndex(conference, personIds, dayIndex(day)); // :: Conference -> List[Person] -> DayIndex -> List[Person] let personsByDayIndex = (conference, persons, dayIndex) => personIdsByDayIndex(conference, persons.map(personId), dayIndex).map(pi => personById(persons, pi)); // :: Conference -> List[Person] -> Day -> List[Person] let personsByDay = (conference, persons, day) => personsByDayIndex(conference, persons, dayIndex(day)); // :: Conference -> List[PersonId] -> RoomName -> List[PersonId] let personIdsByRoomName = (conference, personIds, roomName) => { let evs = eventsByRoomName(conferenceEvents(conference), roomName); let pids = distinct(evs.flatMap(eventPersons).map(personId)); return distinct(personIds.filter(pi => pids.includes(pi))); }; // :: Conference -> List[PersonId] -> Room -> List[PersonId] let personIdsByRoom = (conference, personIds, room) => personIdsByRoomName(conference, personIds, roomName(room)); // :: Conference -> List[Person] -> RoomName -> List[Person] let personsByRoomName = (conference, persons, roomName) => personIdsByRoomName(conference, persons.map(personId), roomName).map(pi => personById(persons, pi)); // :: Conference -> List[Person] -> Room -> List[Person] let personsByRoom = (conference, persons, room) => personsByRoomName(conference, persons, roomName(room)); // :: Conference -> List[PersonId] -> Track -> List[PersonId] let personIdsByTrack = (conference, personIds, track) => { let evs = eventsByTrack(conferenceEvents(conference), track); let pids = evs.flatMap(eventPersons).map(personId); return distinct(personIds.filter(pi => pids.includes(pi))); }; // :: Conference -> List[PersonId] -> Track -> List[PersonId] let personsByTrack = (conference, persons, track) => personIdsByTrack(conference, persons.map(personId), track).map(pi => personById(persons, pi)); // :: Conference -> List[PersonId] -> Type -> List[PersonId] let personIdsByType = (conference, personIds, type) => { let evs = eventsByType(conferenceEvents(conference), type); let pids = evs.flatMap(eventPersons).map(personId); return distinct(personIds.filter(pi => pids.includes(pi))); }; // :: Conference -> List[Person] -> Type -> List[Person] let personsByType = (conference, persons, type) => personIdsByType(conference, persons.map(personId), type).map(pi => personById(persons, pi)); // :: Conference -> List[PersonId] -> Language -> List[PersonId] let personIdsByLanguage = (conference, personIds, language) => { let evs = eventsByLanguage(conferenceEvents(conference), language); let pids = evs.flatMap(eventPersons).map(personId); return distinct(personIds.filter(pi => pids.includes(pi))); }; // :: Conference -> List[Person] -> Language -> List[Person] let personsByLanguage = (conference, persons, language) => personIdsByLanguage(conference, persons.map(personId), language).map(pi => personById(persons, pi)); // :: Conference -> List[DayIndex] -> RoomName -> List[DayIndex] let dayIndicesByRoomName = (conference, dayIndices, roomName) => { let evs = eventsByRoomName(conferenceEvents(conference), roomName); let dis = distinct(evs.map(eventDayIndex)); return distinct(dayIndices.filter(di => dis.includes(di))); }; // :: Conference -> List[DayIndex] -> Room -> List[DayIndex] let dayIndicesByRoom = (conference, dayIndices, room) => dayIndicesByRoomName(conference, dayIndices, roomName(room)); // :: Conference -> List[Day] -> RoomName -> List[Day] let daysByRoomName = (conference, days, roomName) => dayIndicesByRoomName(conference, days.map(dayIndex), roomName).map(di => dayByIndex(days, di)); // :: Conference -> List[Day] -> Room -> List[Day] let daysByRoom = (conference, days, room) => daysByRoomName(conference, days, roomName(room)); // :: Conference -> List[DayIndex] -> PersonId -> List[DayIndex] let dayIndicesByPersonId = (conference, dayIndices, id) => { let evs = eventsByPersonId(conferenceEvents(conference), id); let dis = distinct(evs.map(eventDayIndex)); return distinct(dayIndices.filter(di => dis.includes(di))); }; // :: Conference -> List[DayIndex] -> Person -> List[DayIndex] let dayIndicesByPerson = (conference, dayIndices, person) => dayIndicesByPersonId(conference, dayIndices, personId(person)); // :: Conference -> List[Day] -> PersonId -> List[Day] let daysByPersonId = (conference, days, id) => dayIndicesByPersonId(conference, days.map(dayIndex), id).map(di => dayByIndex(days, di)); // :: Conference -> List[Day] -> Person -> List[Day] let daysByPerson = (conference, days, person) => daysByPersonId(conference, days, personId(person)); // :: Conference -> List[DayIndex] -> Track -> List[DayIndex] let dayIndicesByTrack = (conference, dayIndices, track) => { let evs = eventsByTrack(conferenceEvents(conference), track); let dis = evs.map(eventDayIndex); return distinct(dayIndices.filter(di => dis.includes(di))); }; // :: Conference -> List[Day] -> Track -> List[Day] let daysByTrack = (conference, days, track) => dayIndicesByTrack(conference, days.map(dayIndex), track).map(di => dayByIndex(days, di)); // :: Conference -> List[DayIndex] -> Type -> List[DayIndex] let dayIndicesByType = (conference, dayIndices, type) => { let evs = eventsByType(conferenceEvents(conference), type); let dis = evs.map(eventDayIndex); return distinct(dayIndices.filter(di => dis.includes(di))); }; // :: Conference -> List[Day] -> Type -> List[Day] let daysByType = (conference, days, type) => dayIndicesByType(conference, days.map(dayIndex), type).map(di => dayByIndex(days, di)); // :: Conference -> List[DayIndex] -> Language -> List[DayIndex] let dayIndicesByLanguage = (conference, dayIndices, language) => { let evs = eventsByLanguage(conferenceEvents(conference), language); let dis = evs.map(eventDayIndex); return distinct(dayIndices.filter(di => dis.includes(di))); }; // :: Conference -> List[Day] -> Language -> List[Day] let daysByLanguage = (conference, days, language) => dayIndicesByLanguage(conference, days.map(dayIndex), language).map(di => dayByIndex(days, di)); // :: Conference -> List[Track] -> DayIndex -> List[Track] let tracksByDayIndex = (conference, tracks, dayIndex) => tracksOfEvents(eventsByDayIndex(conferenceEvents(conference), dayIndex)); // :: Conference -> List[Track] -> Day -> List[Track] let tracksByDay = (conference, tracks, day) => tracksOfEvents(eventsByDay(conferenceEvents(conference), day)); // :: Conference -> List[Track] -> RoomName -> List[Track] let tracksByRoomName = (conference, tracks, roomName) => tracksOfEvents(eventsByRoomName(conferenceEvents(conference), roomName)); // :: Conference -> List[Track] -> Room -> List[Track] let tracksByRoom = (conference, tracks, room) => tracksOfEvents(eventsByRoom(conferenceEvents(conference), room)); // :: Conference -> List[Type] -> DayIndex -> List[Type] let typesByDayIndex = (conference, types, dayIndex) => typesOfEvents(eventsByDayIndex(conferenceEvents(conference), dayIndex)); // :: Conference -> List[Type] -> Day -> List[Type] let typesByDay = (conference, types, day) => typesOfEvents(eventsByDay(conferenceEvents(conference), day)); // :: Conference -> List[Type] -> RoomName -> List[Type] let typesByRoomName = (conference, types, roomName) => typesOfEvents(eventsByRoomName(conferenceEvents(conference), roomName)); // :: Conference -> List[Type] -> Room -> List[Type] let typesByRoom = (conference, types, room) => typesOfEvents(eventsByRoom(conferenceEvents(conference), room)); // :: Conference -> List[Language] -> DayIndex -> List[Language] let languagesByDayIndex = (conference, languages, dayIndex) => languagesOfEvents(eventsByDayIndex(conferenceEvents(conference), dayIndex)); // :: Conference -> List[Language] -> Day -> List[Language] let languagesByDay = (conference, languages, day) => languagesOfEvents(eventsByDay(conferenceEvents(conference), day)); // :: Conference -> List[Language] -> RoomName -> List[Language] let languagesByRoomName = (conference, languages, roomName) => languagesOfEvents(eventsByRoomName(conferenceEvents(conference), roomName)); // :: Conference -> List[Language] -> Room -> List[Language] let languagesByRoom = (conference, languages, room) => languagesOfEvents(eventsByRoom(conferenceEvents(conference), room)); // --------------------------------------------------------- // Timing of Events and Days // :: Event -> luxon.DateTime -> Bool let isFutureEvent = (event, now) => now.toMillis() < eventStartDate(event).toMillis(); // :: Event -> luxon.DateTime -> Bool let isCurrentEvent = (event, now) => (eventStartDate(event).toMillis() <= now.toMillis() && now.toMillis() <= eventEndDate(event).toMillis()); // :: Event -> luxon.DateTime -> Bool let isPastEvent = (event, now) => eventEndDate(event).toMillis() < now.toMillis(); // :: Event -> luxon.DateTime -> luxon.Duration -> Bool let isStartingEvent = (event, now, dt) => { const esd = eventStartDate(event); return esd.minus(dt).toMillis() <= now.toMillis() && now.toMillis() < esd.toMillis(); }; // :: Event -> luxon.DateTime -> luxon.Duration -> Bool let isStartedEvent = (event, now, dt) => { const esd = eventStartDate(event); return esd.toMillis() <= now.toMillis() && now.toMillis() <= esd.plus(dt).toMillis(); }; // :: Event -> luxon.DateTime -> luxon.Duration -> Bool let isEndingEvent = (event, now, dt) => { const eed = eventEndDate(event); return eed.minus(dt).toMillis() <= now.toMillis() && now.toMillis() <= eed.toMillis(); }; // :: Event -> luxon.DateTime -> luxon.Duration -> Bool let isEndedEvent = (event, now, dt) => { const eed = eventEndDate(event); return eed.toMillis() < now.toMillis() && now.toMillis() <= eed.plus(dt).toMillis(); }; // :: List[Event] -> luxon.DateTime -> List[Event] let futureEvents = (events, now) => events.filter(e => isFutureEvent(e, now)); // :: List[Event] -> luxon.DateTime -> List[Event] let currentEvents = (events, now) => events.filter(e => isCurrentEvent(e, now)); // :: List[Event] -> luxon.DateTime -> List[Event] let pastEvents = (events, now) => events.filter(e => isPastEvent(e, now)); // :: List[Event] -> luxon.DateTime -> luxon.Duration -> List[Event] let startingEvents = (events, now, dt) => events.filter(e => isStartingEvent(e, now, dt)); // :: List[Event] -> luxon.DateTime -> luxon.Duration -> List[Event] let startedEvents = (events, now, dt) => events.filter(e => isStartedEvent(e, now, dt)); // :: List[Event] -> luxon.DateTime -> luxon.Duration -> List[Event] let endingEvents = (events, now, dt) => events.filter(e => isEndingEvent(e, now, dt)); // :: List[Event] -> luxon.DateTime -> luxon.Duration -> List[Event] let endedEvents = (events, now, dt) => events.filter(e => isEndedEvent(e, now, dt)); // :: List[Event] -> List[Event] let sortEventsByStartDate = (events) => events.sort((e1, e2) => eventStartDate(e1).toMillis() - eventStartDate(e2).toMillis()); // :: List[Event] -> List[Event] let sortEventsByEndDate = (events) => events.sort((e1, e2) => eventEndDate(e1).toMillis() - eventEndDate(e2).toMillis()); // :: List[Event] -> List[Event] let sortEventsByDuration = (events) => events.sort((e1, e2) => eventDuration(e1).toMillis() - eventDuration(e2).toMillis()); // :: Day -> luxon.DateTime -> Bool let isFutureDay = (day, now) => now.toMillis() < dayStartDate(day).toMillis(); // :: Day -> luxon.DateTime -> Bool let isCurrentDay = (day, now) => dayStartDate(day).toMillis() <= now.toMillis() && now.toMillis() <= dayEndDate(day).toMillis(); // :: Day -> luxon.DateTime -> Bool let isPastDay = (day, now) => dayEndDate(day).toMillis() < now.toMillis(); // :: List[Day] -> luxon.DateTime -> List[Day] let futureDays = (days, now) => days.filter(d => isFutureDay(d, now)); // :: List[Day] -> luxon.DateTime -> List[Day] let currentDays = (days, now) => days.filter(d => isCurrentDay(d, now)); // :: List[Day] -> luxon.DateTime -> List[Day] let pastDays = (days, now) => days.filter(d => isPastDay(d, now)); // :: List[Day] -> List[Day] let sortDaysByStartDate = (days) => days.sort((d1, d2) => dayStartDate(d1).toMillis() - dayStartDate(d2).toMillis()); // :: List[Day] -> List[Day] let sortDaysByEndDate = (days) => days.sort((d1, d2) => dayEndDate(d1).toMillis() - dayEndDate(d2).toMillis()); // :: List[Day] -> List[Day] let sortDaysByDuration = (days) => days.sort((d1, d2) => dayDuration(d1).toMillis() - dayDuration(d2).toMillis()); // --------------------------------------------------------- // Extractors: Shortcut entry points // :: Schedule -> List[Day] let allDays = (schedule) => conferenceDays(conference(schedule)); // :: Schedule -> List[Room] let allRooms = (schedule) => conferenceRooms(conference(schedule)); // :: Schedule -> List[Event] let allEvents = (schedule) => conferenceEvents(conference(schedule)); // :: Schedule -> List[Person] let allPersons = (schedule) => conferencePersons(conference(schedule)); // :: Schedule -> List[TrackName] let allTracks = (schedule) => conferenceTracks(conference(schedule)); // :: Schedule -> List[EventType] let allTypes = (schedule) => conferenceTypes(conference(schedule)); // :: Schedule -> List[Language] let allLanguages = (schedule) => conferenceLanguages(conference(schedule)); // --------------------------------------------------------- // Public API Exports export { optional, defined, withDefined, distinct, intersection, processScheduleFile, scheduleVersion, scheduleBaseUrl, conferenceAcronym, conferenceTitle, conferenceStartDate, conferenceEndDate, conferenceDuration, conferenceDaysCount, conferenceTimeslotDuration, conferenceTimezoneName, dayIndex, dayDate, dayStartDate, dayEndDate, dayDuration, roomName, roomGuid, roomDescription, roomCapacity, eventId, eventGuid, eventLogo, eventStartDate, eventEndDate, eventDuration, eventDayIndex, eventRoomName, eventSlug, eventUrl, eventTitle, eventSubtitle, eventTrack, eventType, eventLanguage, eventAbstract, eventDescription, eventRecordingLicense, eventDoNotRecord, eventPersons, eventPersonCount, eventAnswers, personId, personCode, personName, personBiography, eventsByDayIndex, eventsByDay, eventsByRoomName, eventsByRoom, eventsByPersonId, eventsByPersonName, eventsByPerson, eventsByTrack, eventsByType, eventsByLanguage, roomById, roomsByName, dayByIndex, personById, personsByName, eventById, distinctRooms, distinctDays, distinctEvents, distinctPersons, sortPersonsByName, sortRoomsByName, sortEventsByTitle, eventsOfDay, eventsOfDays, tracksOfEvents, typesOfEvents, languagesOfEvents, conferenceDays, conferenceRooms, conferenceEvents, conferencePersons, conferenceTracks, conferenceTypes, conferenceLanguages, conference, roomNamesByDayIndex, roomNamesByDay, roomsByDayIndex, roomsByDay, roomNamesByPersonId, roomNamesByPerson, roomsByPersonId, roomsByPerson, roomNamesByTrack, roomsByTrack, roomNamesByType, roomsByType, roomNamesByLanguage, roomsByLanguage, personIdsByDayIndex, personIdsByDay, personsByDayIndex, personsByDay, personIdsByRoomName, personIdsByRoom, personsByRoomName, personsByRoom, personIdsByTrack, personsByTrack, personIdsByType, personsByType, personIdsByLanguage, personsByLanguage, dayIndicesByRoomName, dayIndicesByRoom, daysByRoomName, daysByRoom, dayIndicesByPersonId, dayIndicesByPerson, daysByPersonId, daysByPerson, dayIndicesByTrack, daysByTrack, dayIndicesByType, daysByType, dayIndicesByLanguage, daysByLanguage, tracksByDayIndex, tracksByDay, tracksByRoomName, tracksByRoom, typesByDayIndex, typesByDay, typesByRoomName, typesByRoom, languagesByDayIndex, languagesByDay, languagesByRoomName, languagesByRoom, isFutureEvent, isCurrentEvent, isPastEvent, isStartingEvent, isStartedEvent, isEndingEvent, isEndedEvent, futureEvents, currentEvents, pastEvents, startingEvents, startedEvents, endingEvents, endedEvents, sortEventsByStartDate, sortEventsByEndDate, sortEventsByDuration, isFutureDay, isCurrentDay, isPastDay, futureDays, currentDays, pastDays, sortDaysByStartDate, sortDaysByEndDate, sortDaysByDuration, allDays, allRooms, allEvents, allPersons, allTracks, allTypes, allLanguages }; // Command to generate API exports: // grep -A 1 -e '// :: ' sol.js | sed -e '/^--$/d' -e '/ :: /d' -e 's/^let / /g' -e 's/ = .*$/,/g' > names.txt // Note: Type signatures starting with '//-:: ' instead of '// :: ' denote unexported internal functions.