1(function (global) { 2 "use strict"; 3 4 const MAX_SEARCH_STEPS = 250000; 5 6 function compare(left, operator, right) { 7 if (operator === "=") return left === right; 8 if (operator === "!=") return left !== right; 9 if (operator === "<") return left < right; 10 if (operator === "<=") return left <= right; 11 if (operator === ">") return left > right; 12 if (operator === ">=") return left >= right; 13 return false; 14 } 15 16 function invariantMatches(node, reading) { 17 if (!node || !node.TYPE) return true; 18 if (node.TYPE === "COMPARISON") { 19 return compare(String(reading[node.OPERAND1]), node.OPERATOR, String(node.OPERAND2)); 20 } 21 if (node.TYPE === "BOOLEAN-OPERATION") { 22 const left = invariantMatches(node.OPERAND1, reading); 23 const right = invariantMatches(node.OPERAND2, reading); 24 return node.OPERATOR === "AND" ? left && right : left || right; 25 } 26 return false; 27 } 28 29 function allRanges(length) { 30 const ranges = []; 31 for (let end = 0; end < length; end += 1) { 32 for (let start = end; start >= 0; start -= 1) { 33 ranges.push({ start: start, end: end, duration: end - start + 1 }); 34 } 35 } 36 return ranges; 37 } 38 39 function matchingRanges(declaration, stream) { 40 if (declaration.TYPE === "PURE-TIME-INTERVAL") return allRanges(stream.length); 41 42 const runs = []; 43 let start = null; 44 for (let index = 0; index <= stream.length; index += 1) { 45 const matches = index < stream.length && invariantMatches(declaration["DATA-INVARIANTS"], stream[index]); 46 if (matches && start === null) start = index; 47 if (!matches && start !== null) { 48 runs.push({ start: start, end: index - 1, duration: index - start }); 49 start = null; 50 } 51 } 52 53 if (declaration.MODIFIER !== "PARTIAL") return runs; 54 55 const partials = []; 56 runs.forEach(function (run) { 57 for (let end = run.start; end <= run.end; end += 1) { 58 for (let rangeStart = end; rangeStart >= run.start; rangeStart -= 1) { 59 partials.push({ start: rangeStart, end: end, duration: end - rangeStart + 1 }); 60 } 61 } 62 }); 63 return partials; 64 } 65 66 function intervalRelation(node, assignments) { 67 const left = assignments[node.OPERAND1.ID]; 68 const right = assignments[node.OPERAND2.ID]; 69 if (!left || !right) return null; 70 71 const relation = node.OPERATORS[0]; 72 if (relation === "PRECEDES") return left.end + 1 < right.start; 73 if (relation === "MEETS") return left.end + 1 === right.start; 74 if (relation === "OVERLAPS") { 75 return left.start < right.start && right.start <= left.end && left.end < right.end; 76 } 77 if (relation === "STARTS") return left.start === right.start && left.end < right.end; 78 if (relation === "CONTAINS") return left.start < right.start && left.end > right.end; 79 if (relation === "ENDS") return left.start > right.start && left.end === right.end; 80 if (relation === "EQUALS") return left.start === right.start && left.end === right.end; 81 if (relation === "DIFFERS") return left.start !== right.start || left.end !== right.end; 82 return false; 83 } 84 85 function durationValue(operand, assignments) { 86 if (operand.TYPE === "INTEGER") return Number(operand.VALUE); 87 const interval = assignments[operand.ID]; 88 return interval ? interval.duration : null; 89 } 90 91 function evaluateNode(node, assignments) { 92 if (!node || !node.TYPE) return true; 93 94 if (node.TYPE === "BOOLEAN-OPERATION") { 95 const left = evaluateNode(node.OPERAND1, assignments); 96 const right = evaluateNode(node.OPERAND2, assignments); 97 if (node.OPERATOR === "AND") { 98 if (left === false || right === false) return false; 99 return left === true && right === true ? true : null; 100 } 101 if (left === true || right === true) return true; 102 return left === false && right === false ? false : null; 103 } 104 105 if (node.TYPE === "INTERVAL-RELATION") return intervalRelation(node, assignments); 106 107 if (node.TYPE === "DURATION-RELATION") { 108 const left = durationValue(node.OPERAND1, assignments); 109 const right = durationValue(node.OPERAND2, assignments); 110 if (left === null || right === null) return null; 111 return compare(left, node.OPERATOR, right); 112 } 113 114 if (node.TYPE === "NON-EXISTENCE") { 115 const nested = evaluateNode(node.STATEMENT && node.STATEMENT["INTERVAL-RELATIONS"], assignments); 116 return nested === null ? null : !nested; 117 } 118 119 return false;
120 } 121 122 function evaluate(ast, stream) { 123 const declarations = (ast && ast["INTERVAL-DECLARATIONS"]) || []; 124 if (!declarations.length || !stream.length) return { result: false, intervals: {} }; 125 126 const candidates = {}; 127 declarations.forEach(function (declaration) { 128 candidates[declaration.ID] = matchingRanges(declaration, stream); 129 }); 130 if (declarations.some(function (declaration) { return !candidates[declaration.ID].length; })) { 131 return { result: false, intervals: {} }; 132 } 133 134 const ordered = declarations.slice().sort(function (left, right) { 135 return candidates[left.ID].length - candidates[right.ID].length; 136 }); 137 const assignments = {}; 138 const relation = ast["INTERVAL-RELATIONS"] || {}; 139 let steps = 0; 140 let solution = null; 141 142 function search(index) { 143 if (solution || steps >= MAX_SEARCH_STEPS) return; 144 steps += 1; 145 146 const status = evaluateNode(relation, assignments); 147 if (status === false) return; 148 if (index === ordered.length) { 149 if (status === true) solution = Object.assign({}, assignments); 150 return; 151 } 152 153 const declaration = ordered[index]; 154 for (const candidate of candidates[declaration.ID]) { 155 assignments[declaration.ID] = candidate; 156 search(index + 1); 157 if (solution) return; 158 } 159 delete assignments[declaration.ID]; 160 } 161 162 search(0); 163 if (!solution) return { result: false, intervals: {} }; 164 165 const intervals = {}; 166 declarations.forEach(function (declaration) { 167 const interval = solution[declaration.ID]; 168 intervals[declaration.ID] = interval 169 ? { start: interval.start, duration: interval.duration } 170 : null; 171 }); 172 return { result: true, intervals: intervals }; 173 } 174 175 global.EveXLEvaluator = { evaluate: evaluate }; 176 if (typeof module !== "undefined" && module.exports) module.exports = global.EveXLEvaluator; 177})(typeof window !== "undefined" ? window : globalThis);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.