Merged in [19954] from jennifer@painless-security.com:
Refactor session overlap computation to treat overlapping sessions correctly.
- Legacy-Id: 19961
Note: SVN reference [19954] has been migrated to Git commit f0d40680fe
This commit is contained in:
commit
2564e9ba1b
|
@ -552,10 +552,43 @@ jQuery(document).ready(function () {
|
||||||
|
|
||||||
// hints for the current schedule
|
// hints for the current schedule
|
||||||
|
|
||||||
function updateSessionConstraintViolations() {
|
/** Find all pairs of overlapping intervals
|
||||||
// do a sweep on sessions sorted by start time
|
*
|
||||||
let scheduledSessions = [];
|
* @param data Array of arbitrary interval-like objects with 'start' and 'end' properties
|
||||||
|
* @returns Map from data item index to a list of overlapping data item indexes
|
||||||
|
*/
|
||||||
|
function findOverlappingIntervals(data) {
|
||||||
|
const overlaps = {}; // results
|
||||||
|
// Build ordered lists of start/end times, keeping track of the original index for each item
|
||||||
|
const startIndexes = data.map((d, i) => ({time: d.start, index: i}));
|
||||||
|
startIndexes.sort((a, b) => (b.time - a.time)); // sort reversed
|
||||||
|
const endIndexes = data.map((d, i) => ({time: d.end, index: i}));
|
||||||
|
endIndexes.sort((a, b) => (b.time - a.time)); // sort reversed
|
||||||
|
|
||||||
|
// items are sorted in reverse, so pop() will get the earliest item from each list
|
||||||
|
let nextStart = startIndexes.pop();
|
||||||
|
let nextEnd = endIndexes.pop();
|
||||||
|
const openIntervalIndexes = [];
|
||||||
|
while (nextStart && nextEnd) {
|
||||||
|
if (nextStart.time < nextEnd.time) {
|
||||||
|
// an interval opened - it overlaps all open intervals and all open intervals overlap it
|
||||||
|
for (const intervalIndex of openIntervalIndexes) {
|
||||||
|
overlaps[intervalIndex].push(nextStart.index);
|
||||||
|
}
|
||||||
|
overlaps[nextStart.index] = [...openIntervalIndexes]; // make a copy of the open list
|
||||||
|
openIntervalIndexes.push(nextStart.index);
|
||||||
|
nextStart = startIndexes.pop();
|
||||||
|
} else {
|
||||||
|
// an interval closed - remove its index from the list of open intervals
|
||||||
|
openIntervalIndexes.splice(openIntervalIndexes.indexOf(nextEnd.index), 1);
|
||||||
|
nextEnd = endIndexes.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overlaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSessionConstraintViolations() {
|
||||||
|
let scheduledSessions = [];
|
||||||
sessions.each(function () {
|
sessions.each(function () {
|
||||||
let timeslot = jQuery(this).closest(".timeslot");
|
let timeslot = jQuery(this).closest(".timeslot");
|
||||||
if (timeslot.length === 1) {
|
if (timeslot.length === 1) {
|
||||||
|
@ -569,19 +602,8 @@ jQuery(document).ready(function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduledSessions.sort(function (a, b) {
|
// helper function to mark constraint violations
|
||||||
if (a.start < b.start) {
|
const markSessionConstraintViolations = function (sess, currentlyOpen) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a.start > b.start) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
let currentlyOpen = {};
|
|
||||||
let openedIndex = 0;
|
|
||||||
let markSessionConstraintViolations = function (sess, currentlyOpen) {
|
|
||||||
sess.element.find(".constraints > span").each(function() {
|
sess.element.find(".constraints > span").each(function() {
|
||||||
let sessionIds = this.dataset.sessions;
|
let sessionIds = this.dataset.sessions;
|
||||||
|
|
||||||
|
@ -600,25 +622,15 @@ jQuery(document).ready(function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < scheduledSessions.length; ++i) {
|
// now go through the sessions and mark constraint violations
|
||||||
let s = scheduledSessions[i];
|
const overlaps = findOverlappingIntervals(scheduledSessions);
|
||||||
|
for (const index in overlaps) {
|
||||||
// prune
|
const currentlyOpen = {};
|
||||||
for (let sessionIdStr in currentlyOpen) {
|
for (const overlapIndex of overlaps[index]) {
|
||||||
if (currentlyOpen[sessionIdStr].end <= s.start) {
|
const otherSess = scheduledSessions[overlapIndex];
|
||||||
delete currentlyOpen[sessionIdStr];
|
currentlyOpen[otherSess.id] = otherSess;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
markSessionConstraintViolations(scheduledSessions[index], currentlyOpen);
|
||||||
// expand
|
|
||||||
while (openedIndex < scheduledSessions.length && scheduledSessions[openedIndex].start < s.end) {
|
|
||||||
let toAdd = scheduledSessions[openedIndex];
|
|
||||||
currentlyOpen[toAdd.id] = toAdd;
|
|
||||||
++openedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for violated constraints
|
|
||||||
markSessionConstraintViolations(s, currentlyOpen);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue