1144 lines
36 KiB
JavaScript
1144 lines
36 KiB
JavaScript
'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.
|