mirror of
https://github.com/multipleof4/lynchmark.git
synced 2026-09-18 20:05:44 +00:00
Compare commits
5 Commits
bb64a4f756
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 43bd290b3a | |||
|
|
0f704a2f22 | ||
| ddcf1af44b | |||
|
|
aab29b41d9 | ||
| 16a6e49ab2 |
1
README
1
README
@@ -9,6 +9,7 @@ SHARED_PROMPT: "Provide production-ready and maintainable JavaScript code. Apply
|
|||||||
The following models are included in the benchmark run.
|
The following models are included in the benchmark run.
|
||||||
|
|
||||||
<!-- MODELS_START -->
|
<!-- MODELS_START -->
|
||||||
|
google/gemini-3.8-flash EFF:high
|
||||||
google/gemini-3.7-flash EFF:high
|
google/gemini-3.7-flash EFF:high
|
||||||
moonshotai/kimi-k3 EFF:medium
|
moonshotai/kimi-k3 EFF:medium
|
||||||
openai/gpt-5.6-luna EFF:high
|
openai/gpt-5.6-luna EFF:high
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export async function hashPassword(password, salt) {
|
||||||
|
const { scrypt } = await import('https://esm.sh/scrypt-js@3.0.1');
|
||||||
|
const enc = new TextEncoder();
|
||||||
|
|
||||||
|
const hash = await scrypt(
|
||||||
|
enc.encode(password),
|
||||||
|
enc.encode(salt),
|
||||||
|
1024,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
32
|
||||||
|
);
|
||||||
|
|
||||||
|
return Array.from(hash, (b) => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
export default hashPassword;
|
||||||
|
// Generation time: 13.651s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
async function hashPassword(password, salt) {
|
||||||
|
const { scrypt } = await import('https://cdn.jsdelivr.net/npm/scrypt-js@3.0.1/+esm');
|
||||||
|
const enc = new TextEncoder();
|
||||||
|
const hash = await scrypt(enc.encode(password), enc.encode(salt), 1024, 8, 1, 32);
|
||||||
|
return Array.from(hash, b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
export default hashPassword;
|
||||||
|
// Generation time: 98.298s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export async function analyzeGPS(readings, boundary) {
|
||||||
|
const turf = await import('https://esm.sh/@turf/turf');
|
||||||
|
|
||||||
|
const pts = readings
|
||||||
|
.filter(r => turf.booleanPointInPolygon(r.loc, boundary, { ignoreBoundary: true }))
|
||||||
|
.sort((a, b) => a.ts - b.ts)
|
||||||
|
.map(r => r.loc);
|
||||||
|
|
||||||
|
return pts.length < 2
|
||||||
|
? 0
|
||||||
|
: +turf.length(turf.lineString(pts), { units: 'kilometers' }).toFixed(2);
|
||||||
|
}
|
||||||
|
export default analyzeGPS;
|
||||||
|
// Generation time: 24.485s
|
||||||
|
// Result: PASS
|
||||||
16
tests/11_geospatial/outputs/stealth_union-alpha EFF_high.js
Normal file
16
tests/11_geospatial/outputs/stealth_union-alpha EFF_high.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
async function analyzeGPS(readings, boundary) {
|
||||||
|
const { booleanPointInPolygon, lineString, length } =
|
||||||
|
await import("https://cdn.jsdelivr.net/npm/@turf/turf@7.2.0/+esm");
|
||||||
|
|
||||||
|
const points = readings
|
||||||
|
.filter(({ loc }) => booleanPointInPolygon(loc, boundary, { ignoreBoundary: true }))
|
||||||
|
.sort((a, b) => a.ts - b.ts)
|
||||||
|
.map(({ loc }) => loc);
|
||||||
|
|
||||||
|
return points.length < 2
|
||||||
|
? 0
|
||||||
|
: +length(lineString(points), { units: "kilometers" }).toFixed(2);
|
||||||
|
}
|
||||||
|
export default analyzeGPS;
|
||||||
|
// Generation time: 53.787s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
class UnionFind {
|
||||||
|
p = new Map();
|
||||||
|
r = new Map();
|
||||||
|
|
||||||
|
constructor(elements) {
|
||||||
|
for (const el of elements) {
|
||||||
|
this.p.set(el, el);
|
||||||
|
this.r.set(el, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
find(i) {
|
||||||
|
if (this.p.get(i) !== i) this.p.set(i, this.find(this.p.get(i)));
|
||||||
|
return this.p.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
union(i, j) {
|
||||||
|
let [rootI, rootJ] = [this.find(i), this.find(j)];
|
||||||
|
if (rootI === rootJ) return false;
|
||||||
|
|
||||||
|
const [rankI, rankJ] = [this.r.get(rootI), this.r.get(rootJ)];
|
||||||
|
if (rankI < rankJ) [rootI, rootJ] = [rootJ, rootI];
|
||||||
|
this.p.set(rootJ, rootI);
|
||||||
|
if (rankI === rankJ) this.r.set(rootI, rankI + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function computeMST(tomlStr) {
|
||||||
|
const [{ parse }, mnemonist, textTableMod] = await Promise.all([
|
||||||
|
import('https://esm.sh/smol-toml'),
|
||||||
|
import('https://esm.sh/mnemonist'),
|
||||||
|
import('https://esm.sh/text-table')
|
||||||
|
]);
|
||||||
|
|
||||||
|
const Heap = mnemonist.Heap || mnemonist.default?.Heap;
|
||||||
|
const table = textTableMod.default || textTableMod;
|
||||||
|
|
||||||
|
const { edges = [] } = parse(tomlStr);
|
||||||
|
const nodes = new Set();
|
||||||
|
const heap = new Heap((a, b) => Number(a.weight) - Number(b.weight));
|
||||||
|
|
||||||
|
for (const edge of edges) {
|
||||||
|
nodes.add(edge.from);
|
||||||
|
nodes.add(edge.to);
|
||||||
|
heap.push(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uf = new UnionFind(nodes);
|
||||||
|
const mst = [];
|
||||||
|
let totalWeight = 0;
|
||||||
|
const targetEdges = Math.max(0, nodes.size - 1);
|
||||||
|
|
||||||
|
while (mst.length < targetEdges && heap.size > 0) {
|
||||||
|
const edge = heap.pop();
|
||||||
|
if (uf.union(edge.from, edge.to)) {
|
||||||
|
mst.push([edge.from, edge.to, String(edge.weight)]);
|
||||||
|
totalWeight += Number(edge.weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
table: table([['From', 'To', 'Weight'], ...mst]),
|
||||||
|
totalWeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export default computeMST;
|
||||||
|
// Generation time: 31.116s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
async function computeMST(toml) {
|
||||||
|
if (typeof toml !== "string")
|
||||||
|
throw new TypeError("Expected a TOML string.");
|
||||||
|
|
||||||
|
const [{ parse }, { default: Heap }, { default: textTable }] =
|
||||||
|
await Promise.all([
|
||||||
|
import("https://esm.sh/smol-toml@1.3.1"),
|
||||||
|
import("https://esm.sh/mnemonist@0.39.8/heap.js"),
|
||||||
|
import("https://esm.sh/text-table@0.2.0")
|
||||||
|
]);
|
||||||
|
|
||||||
|
const { edges } = parse(toml);
|
||||||
|
if (!Array.isArray(edges))
|
||||||
|
throw new TypeError('Expected an "edges" array.');
|
||||||
|
|
||||||
|
const parent = new Map(), rank = new Map();
|
||||||
|
const heap = new Heap((a, b) => a.weight - b.weight || a.index - b.index);
|
||||||
|
|
||||||
|
for (const [index, edge] of edges.entries()) {
|
||||||
|
if (
|
||||||
|
!edge ||
|
||||||
|
typeof edge.from !== "string" ||
|
||||||
|
typeof edge.to !== "string" ||
|
||||||
|
!Number.isFinite(edge.weight)
|
||||||
|
)
|
||||||
|
throw new TypeError(
|
||||||
|
`Invalid edge at index ${index}: expected string endpoints and a finite numeric weight.`
|
||||||
|
);
|
||||||
|
|
||||||
|
const { from, to, weight } = edge;
|
||||||
|
heap.push({ from, to, weight, index });
|
||||||
|
|
||||||
|
for (const node of [from, to]) {
|
||||||
|
if (parent.has(node)) continue;
|
||||||
|
parent.set(node, node);
|
||||||
|
rank.set(node, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function find(node) {
|
||||||
|
while (node !== parent.get(node)) {
|
||||||
|
parent.set(node, parent.get(parent.get(node)));
|
||||||
|
node = parent.get(node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function union(a, b) {
|
||||||
|
a = find(a);
|
||||||
|
b = find(b);
|
||||||
|
if (a === b) return false;
|
||||||
|
if (rank.get(a) < rank.get(b)) [a, b] = [b, a];
|
||||||
|
|
||||||
|
parent.set(b, a);
|
||||||
|
if (rank.get(a) === rank.get(b))
|
||||||
|
rank.set(a, rank.get(a) + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mst = [];
|
||||||
|
let totalWeight = 0;
|
||||||
|
|
||||||
|
while (heap.size && mst.length < parent.size - 1) {
|
||||||
|
const { from, to, weight } = heap.pop();
|
||||||
|
if (!union(from, to)) continue;
|
||||||
|
|
||||||
|
mst.push([from, to, String(weight)]);
|
||||||
|
totalWeight += weight;
|
||||||
|
if (!Number.isFinite(totalWeight))
|
||||||
|
throw new RangeError("Total weight exceeds the finite Number range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
table: textTable(
|
||||||
|
[["From", "To", "Weight"], ...mst],
|
||||||
|
{ align: ["l", "l", "r"] }
|
||||||
|
),
|
||||||
|
totalWeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export default computeMST;
|
||||||
|
// Generation time: 147.182s
|
||||||
|
// Result: PASS
|
||||||
27
tests/1_dijkstra/outputs/google_gemini-3.8-flash EFF_high.js
Normal file
27
tests/1_dijkstra/outputs/google_gemini-3.8-flash EFF_high.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export async function findShortestPath(graph, start, end) {
|
||||||
|
const { default: PriorityQueue } = await import('https://esm.sh/js-priority-queue');
|
||||||
|
|
||||||
|
const dist = new Map([[start, 0]]);
|
||||||
|
const pq = new PriorityQueue({ comparator: (a, b) => a[1] - b[1] });
|
||||||
|
pq.queue([start, 0]);
|
||||||
|
|
||||||
|
while (pq.length) {
|
||||||
|
const [node, cost] = pq.dequeue();
|
||||||
|
|
||||||
|
if (node === end) return cost;
|
||||||
|
if (cost > (dist.get(node) ?? Infinity)) continue;
|
||||||
|
|
||||||
|
for (const [neighbor, weight] of Object.entries(graph[node] ?? {})) {
|
||||||
|
const nextCost = cost + weight;
|
||||||
|
if (nextCost < (dist.get(neighbor) ?? Infinity)) {
|
||||||
|
dist.set(neighbor, nextCost);
|
||||||
|
pq.queue([neighbor, nextCost]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
export default findShortestPath;
|
||||||
|
// Generation time: 16.431s
|
||||||
|
// Result: PASS
|
||||||
38
tests/1_dijkstra/outputs/stealth_union-alpha EFF_high.js
Normal file
38
tests/1_dijkstra/outputs/stealth_union-alpha EFF_high.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
async function findShortestPath(graph, start, end) {
|
||||||
|
for (const edges of Object.values(graph))
|
||||||
|
for (const weight of Object.values(edges))
|
||||||
|
if (!Number.isFinite(weight) || weight < 0)
|
||||||
|
throw new RangeError("Edge weights must be finite, nonnegative numbers.");
|
||||||
|
|
||||||
|
if (!Object.hasOwn(graph, start) || !Object.hasOwn(graph, end))
|
||||||
|
return Infinity;
|
||||||
|
if (start === end) return 0;
|
||||||
|
|
||||||
|
const { default: PriorityQueue } = await import(
|
||||||
|
"https://esm.sh/js-priority-queue@0.1.5"
|
||||||
|
);
|
||||||
|
const queue = new PriorityQueue({ comparator: (a, b) => a[1] - b[1] });
|
||||||
|
const distances = new Map([[start, 0]]);
|
||||||
|
|
||||||
|
queue.queue([start, 0]);
|
||||||
|
|
||||||
|
while (queue.length) {
|
||||||
|
const [node, distance] = queue.dequeue();
|
||||||
|
|
||||||
|
if (distance !== distances.get(node)) continue;
|
||||||
|
if (node === end) return distance;
|
||||||
|
|
||||||
|
for (const [neighbor, weight] of Object.entries(graph[node] ?? {})) {
|
||||||
|
const next = distance + weight;
|
||||||
|
|
||||||
|
if (next >= (distances.get(neighbor) ?? Infinity)) continue;
|
||||||
|
distances.set(neighbor, next);
|
||||||
|
queue.queue([neighbor, next]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
export default findShortestPath;
|
||||||
|
// Generation time: 66.902s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export async function findConvexHull(points) {
|
||||||
|
const { sortBy, uniqWith, isEqual } = await import('https://cdn.jsdelivr.net/npm/lodash-es/+esm');
|
||||||
|
|
||||||
|
const pts = sortBy(uniqWith(points, isEqual), ['x', 'y']);
|
||||||
|
if (pts.length <= 2) return pts;
|
||||||
|
|
||||||
|
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
||||||
|
|
||||||
|
const buildHull = (pList) => pList.reduce((hull, p) => {
|
||||||
|
while (hull.length >= 2 && cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0) {
|
||||||
|
hull.pop();
|
||||||
|
}
|
||||||
|
return hull.push(p), hull;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const lower = buildHull(pts);
|
||||||
|
const upper = buildHull([...pts].reverse());
|
||||||
|
|
||||||
|
return lower.slice(0, -1).concat(upper.slice(0, -1));
|
||||||
|
}
|
||||||
|
export default findConvexHull;
|
||||||
|
// Generation time: 25.877s
|
||||||
|
// Result: PASS
|
||||||
38
tests/2_convex_hull/outputs/stealth_union-alpha EFF_high.js
Normal file
38
tests/2_convex_hull/outputs/stealth_union-alpha EFF_high.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
async function findConvexHull(points) {
|
||||||
|
if (!Array.isArray(points) || points.some(
|
||||||
|
p => !p || !Number.isFinite(p.x) || !Number.isFinite(p.y)
|
||||||
|
)) {
|
||||||
|
throw new TypeError("Expected an array of points with finite numeric x and y.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { default: _ } = await import(
|
||||||
|
"https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm"
|
||||||
|
);
|
||||||
|
const sorted = _.sortBy(
|
||||||
|
_.uniqBy(points, p => JSON.stringify([p.x, p.y])),
|
||||||
|
["x", "y"]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sorted.length < 3) return sorted;
|
||||||
|
|
||||||
|
const cross = (a, b, c) =>
|
||||||
|
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||||||
|
|
||||||
|
const build = list => {
|
||||||
|
const hull = [];
|
||||||
|
for (const p of list) {
|
||||||
|
while (
|
||||||
|
hull.length > 1 &&
|
||||||
|
cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0
|
||||||
|
) hull.pop();
|
||||||
|
hull.push(p);
|
||||||
|
}
|
||||||
|
hull.pop();
|
||||||
|
return hull;
|
||||||
|
};
|
||||||
|
|
||||||
|
return [...build(sorted), ...build([...sorted].reverse())];
|
||||||
|
}
|
||||||
|
export default findConvexHull;
|
||||||
|
// Generation time: 113.790s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export async function analyzeSignal(yamlString) {
|
||||||
|
const [yaml, math, ndarray, fft, DOMPurify] = (
|
||||||
|
await Promise.all([
|
||||||
|
import('https://esm.sh/js-yaml'),
|
||||||
|
import('https://esm.sh/mathjs'),
|
||||||
|
import('https://esm.sh/ndarray'),
|
||||||
|
import('https://esm.sh/ndarray-fft'),
|
||||||
|
import('https://esm.sh/dompurify')
|
||||||
|
])
|
||||||
|
).map(m => m.default ?? m);
|
||||||
|
|
||||||
|
const { sampleRate, duration, components } = yaml.load(yamlString);
|
||||||
|
const N = sampleRate * duration;
|
||||||
|
const halfN = N / 2;
|
||||||
|
|
||||||
|
const signal = Float64Array.from({ length: N }, (_, i) => {
|
||||||
|
const t = i / sampleRate;
|
||||||
|
return components.reduce(
|
||||||
|
(sum, { frequency, amplitude }) => sum + amplitude * math.sin(2 * math.pi * frequency * t),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const real = ndarray(signal, [N]);
|
||||||
|
const imag = ndarray(new Float64Array(N), [N]);
|
||||||
|
fft(1, real, imag);
|
||||||
|
|
||||||
|
const peaks = [];
|
||||||
|
for (let k = 0; k <= halfN; k++) {
|
||||||
|
const magnitude = math.sqrt(real.get(k) ** 2 + imag.get(k) ** 2) / halfN;
|
||||||
|
if (magnitude > 0.1) {
|
||||||
|
peaks.push({ frequencyHz: (k * sampleRate) / N, magnitude });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
peaks.sort((a, b) => b.magnitude - a.magnitude);
|
||||||
|
for (const p of peaks) {
|
||||||
|
p.frequencyHz = Math.round(p.frequencyHz);
|
||||||
|
p.magnitude = +p.magnitude.toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = peaks.map(p => `<tr><td>${p.frequencyHz}</td><td>${p.magnitude}</td></tr>`).join('');
|
||||||
|
const html = DOMPurify.sanitize(`<table><tr><th>Frequency (Hz)</th><th>Magnitude</th></tr>${rows}</table>`);
|
||||||
|
|
||||||
|
return { peaks, html, signalLength: N };
|
||||||
|
}
|
||||||
|
export default analyzeSignal;
|
||||||
|
// Generation time: 54.838s
|
||||||
|
// Result: PASS
|
||||||
100
tests/3_signal_pipeline/outputs/stealth_union-alpha EFF_high.js
Normal file
100
tests/3_signal_pipeline/outputs/stealth_union-alpha EFF_high.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
async function analyzeSignal(yamlString) {
|
||||||
|
if (typeof yamlString !== "string")
|
||||||
|
throw new TypeError("Expected a YAML string.");
|
||||||
|
|
||||||
|
const [yaml, math, { default: ndarray }, { default: fft }, { default: DOMPurify }] =
|
||||||
|
await Promise.all([
|
||||||
|
import("https://esm.sh/js-yaml@4.1.1"),
|
||||||
|
import("https://esm.sh/mathjs@14.8.1"),
|
||||||
|
import("https://esm.sh/ndarray@1.0.19?bundle"),
|
||||||
|
import("https://esm.sh/ndarray-fft@1.0.3?bundle"),
|
||||||
|
import("https://esm.sh/dompurify@3.3.1")
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!DOMPurify.isSupported)
|
||||||
|
throw new Error("HTML sanitization is unavailable in this browser.");
|
||||||
|
|
||||||
|
const config = yaml.load(yamlString, { schema: yaml.JSON_SCHEMA });
|
||||||
|
|
||||||
|
if (!config || typeof config !== "object" || Array.isArray(config))
|
||||||
|
throw new TypeError("Configuration must be a YAML mapping.");
|
||||||
|
|
||||||
|
const { sampleRate, duration, components } = config;
|
||||||
|
|
||||||
|
if (![sampleRate, duration].every(v => Number.isFinite(v) && v > 0))
|
||||||
|
throw new RangeError("sampleRate and duration must be positive finite numbers.");
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Array.isArray(components) ||
|
||||||
|
components.some(c =>
|
||||||
|
!c || !Number.isFinite(c.frequency) || !Number.isFinite(c.amplitude)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
throw new TypeError("components must contain finite frequency and amplitude values.");
|
||||||
|
|
||||||
|
const N = sampleRate * duration;
|
||||||
|
|
||||||
|
if (!Number.isSafeInteger(N) || N < 1)
|
||||||
|
throw new RangeError("sampleRate * duration must be a positive safe integer.");
|
||||||
|
|
||||||
|
const signal = new Float64Array(N);
|
||||||
|
const tau = 2 * math.pi;
|
||||||
|
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
const t = i / sampleRate;
|
||||||
|
let value = 0;
|
||||||
|
|
||||||
|
for (const { frequency, amplitude } of components)
|
||||||
|
value += amplitude * math.sin(tau * frequency * t);
|
||||||
|
|
||||||
|
if (!Number.isFinite(value))
|
||||||
|
throw new RangeError(`Signal computation overflowed at sample ${i}.`);
|
||||||
|
|
||||||
|
signal[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const real = ndarray(signal, [N]);
|
||||||
|
const imag = ndarray(new Float64Array(N), [N]);
|
||||||
|
|
||||||
|
fft(1, real, imag);
|
||||||
|
|
||||||
|
const spectrum = new Float64Array(Math.floor(N / 2) + 1);
|
||||||
|
const candidates = [];
|
||||||
|
|
||||||
|
for (let k = 0; k < spectrum.length; k++) {
|
||||||
|
const magnitude = math.sqrt(real.get(k) ** 2 + imag.get(k) ** 2) / (N / 2);
|
||||||
|
|
||||||
|
if (!Number.isFinite(magnitude))
|
||||||
|
throw new RangeError(`Spectrum computation overflowed at bin ${k}.`);
|
||||||
|
|
||||||
|
spectrum[k] = magnitude;
|
||||||
|
|
||||||
|
if (magnitude > 0.1)
|
||||||
|
candidates.push({ frequencyHz: k * sampleRate / N, magnitude });
|
||||||
|
}
|
||||||
|
|
||||||
|
const peaks = candidates
|
||||||
|
.sort((a, b) => b.magnitude - a.magnitude)
|
||||||
|
.map(({ frequencyHz, magnitude }) => ({
|
||||||
|
frequencyHz: Math.round(frequencyHz),
|
||||||
|
magnitude: Number(magnitude.toFixed(2))
|
||||||
|
}));
|
||||||
|
|
||||||
|
const table =
|
||||||
|
"<table><tr><th>Frequency (Hz)</th><th>Magnitude</th></tr>" +
|
||||||
|
peaks.map(({ frequencyHz, magnitude }) =>
|
||||||
|
`<tr><td>${frequencyHz}</td><td>${magnitude.toFixed(2)}</td></tr>`
|
||||||
|
).join("") +
|
||||||
|
"</table>";
|
||||||
|
|
||||||
|
const html = DOMPurify.sanitize(table, {
|
||||||
|
ALLOWED_TAGS: ["table", "tbody", "tr", "th", "td"],
|
||||||
|
ALLOWED_ATTR: [],
|
||||||
|
RETURN_TRUSTED_TYPE: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return { peaks, html, signalLength: N };
|
||||||
|
}
|
||||||
|
export default analyzeSignal;
|
||||||
|
// Generation time: 203.858s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
export async function hexchain(tomlStr) {
|
||||||
|
const cdn = 'https://esm.sh/';
|
||||||
|
const [
|
||||||
|
{ parse },
|
||||||
|
{ default: seedrandom },
|
||||||
|
{ mean: getMean, standardDeviation: getStd, median: getMedian },
|
||||||
|
{ default: Ajv },
|
||||||
|
{ default: textTable },
|
||||||
|
{ default: DOMPurify }
|
||||||
|
] = await Promise.all([
|
||||||
|
import(`${cdn}smol-toml`),
|
||||||
|
import(`${cdn}seedrandom`),
|
||||||
|
import(`${cdn}simple-statistics`),
|
||||||
|
import(`${cdn}ajv`),
|
||||||
|
import(`${cdn}text-table`),
|
||||||
|
import(`${cdn}dompurify`)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const config = parse(tomlStr);
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const schema = {
|
||||||
|
type: 'object',
|
||||||
|
required: ['seed', 'count', 'label'],
|
||||||
|
properties: {
|
||||||
|
seed: { type: 'string' },
|
||||||
|
count: { type: 'integer', minimum: 1, maximum: 10000 },
|
||||||
|
label: { type: 'string', minLength: 1 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!ajv.validate(schema, config)) {
|
||||||
|
return { valid: false, errors: ajv.errorsText() };
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new seedrandom(config.seed);
|
||||||
|
const nums = Array.from({ length: config.count }, () => rng());
|
||||||
|
const round = fn => +fn(nums).toFixed(6);
|
||||||
|
|
||||||
|
const mean = round(getMean);
|
||||||
|
const stddev = round(getStd);
|
||||||
|
const median = round(getMedian);
|
||||||
|
|
||||||
|
const tableStr = textTable([
|
||||||
|
['Stat', 'Value'],
|
||||||
|
['mean', String(mean)],
|
||||||
|
['stddev', String(stddev)],
|
||||||
|
['median', String(median)]
|
||||||
|
]);
|
||||||
|
|
||||||
|
const table = DOMPurify.sanitize(`<pre class="stats">${tableStr}</pre>`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
label: config.label,
|
||||||
|
stats: { mean, stddev, median },
|
||||||
|
table,
|
||||||
|
count: config.count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export default hexchain;
|
||||||
|
// Generation time: 57.013s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
async function hexchain(toml) {
|
||||||
|
const { parse } = await import('https://cdn.jsdelivr.net/npm/smol-toml@1.0.1/+esm');
|
||||||
|
const config = parse(toml);
|
||||||
|
const Ajv = (await import('https://cdn.jsdelivr.net/npm/ajv@8.12.0/+esm')).default;
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const schema = {
|
||||||
|
type: 'object',
|
||||||
|
required: ['seed', 'count', 'label'],
|
||||||
|
properties: {
|
||||||
|
seed: { type: 'string' },
|
||||||
|
count: { type: 'integer', minimum: 1, maximum: 10000 },
|
||||||
|
label: { type: 'string', minLength: 1 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!ajv.validate(schema, config)) return { valid: false, errors: ajv.errorsText() };
|
||||||
|
const seedrandom = (await import('https://cdn.jsdelivr.net/npm/seedrandom@3.0.5/+esm')).default;
|
||||||
|
const rng = new seedrandom(config.seed);
|
||||||
|
const nums = Array.from({ length: config.count }, () => rng());
|
||||||
|
const { mean, standardDeviation, median } = await import('https://cdn.jsdelivr.net/npm/simple-statistics@7.8.3/+esm');
|
||||||
|
const stats = {
|
||||||
|
mean: +mean(nums).toFixed(6),
|
||||||
|
stddev: +standardDeviation(nums).toFixed(6),
|
||||||
|
median: +median(nums).toFixed(6)
|
||||||
|
};
|
||||||
|
const table = (await import('https://cdn.jsdelivr.net/npm/text-table@0.2.0/+esm')).default;
|
||||||
|
const tableString = table([
|
||||||
|
['Stat', 'Value'],
|
||||||
|
['mean', String(stats.mean)],
|
||||||
|
['stddev', String(stats.stddev)],
|
||||||
|
['median', String(stats.median)]
|
||||||
|
]);
|
||||||
|
const DOMPurify = (await import('https://cdn.jsdelivr.net/npm/dompurify@3.0.6/+esm')).default;
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
label: config.label,
|
||||||
|
stats,
|
||||||
|
table: DOMPurify.sanitize('<pre class="stats">' + tableString + '</pre>'),
|
||||||
|
count: config.count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export default hexchain;
|
||||||
|
// Generation time: 164.666s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
let lib;
|
||||||
|
|
||||||
|
export async function parseMarkdown(text = '') {
|
||||||
|
lib ??= import('https://esm.sh/marked');
|
||||||
|
const { marked } = await lib;
|
||||||
|
return marked.parse(String(text));
|
||||||
|
}
|
||||||
|
export default parseMarkdown;
|
||||||
|
// Generation time: 15.759s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
let loader;
|
||||||
|
|
||||||
|
export async function parseMarkdown(markdown) {
|
||||||
|
loader ||= import('https://esm.sh/marked@12').then((m) => m.marked);
|
||||||
|
const marked = await loader;
|
||||||
|
const source = typeof markdown === 'string' ? markdown : '';
|
||||||
|
return marked.parse(source, { gfm: true, breaks: false });
|
||||||
|
}
|
||||||
|
export default parseMarkdown;
|
||||||
|
// Generation time: 59.989s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export async function processCSV(csvString, { filterColumn, filterValue, groupBy, aggregateColumn, operation }) {
|
||||||
|
const Papa = (await import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/+esm')).default;
|
||||||
|
const { data } = Papa.parse(csvString, { header: true, skipEmptyLines: true });
|
||||||
|
|
||||||
|
const groups = new Map();
|
||||||
|
for (const row of data) {
|
||||||
|
if (row[filterColumn] == filterValue) {
|
||||||
|
const key = row[groupBy];
|
||||||
|
const entry = groups.get(key) || { sum: 0, count: 0 };
|
||||||
|
entry.sum += Number(row[aggregateColumn]) || 0;
|
||||||
|
entry.count++;
|
||||||
|
groups.set(key, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(groups, ([key, { sum, count }]) => ({
|
||||||
|
[groupBy]: key,
|
||||||
|
result: operation === 'count' ? count : operation === 'avg' ? sum / count : sum
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
export default processCSV;
|
||||||
|
// Generation time: 82.511s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
async function processCSV(csv, { filterColumn, filterValue, groupBy, aggregateColumn, operation }) {
|
||||||
|
const { default: Papa } = await import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js');
|
||||||
|
const { default: _ } = await import('https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js');
|
||||||
|
|
||||||
|
const parsed = Papa.parse(csv, { header: true, skipEmptyLines: true });
|
||||||
|
const data = parsed.data;
|
||||||
|
|
||||||
|
const filtered = data.filter(row => row[filterColumn] == filterValue);
|
||||||
|
|
||||||
|
const grouped = _.groupBy(filtered, groupBy);
|
||||||
|
|
||||||
|
const results = Object.keys(grouped).map(groupVal => {
|
||||||
|
const rows = grouped[groupVal];
|
||||||
|
const nums = rows.map(r => {
|
||||||
|
const val = Number(r[aggregateColumn]);
|
||||||
|
return isNaN(val) ? 0 : val;
|
||||||
|
});
|
||||||
|
|
||||||
|
let result;
|
||||||
|
if (operation === 'sum') {
|
||||||
|
result = nums.reduce((a, b) => a + b, 0);
|
||||||
|
} else if (operation === 'avg') {
|
||||||
|
const sum = nums.reduce((a, b) => a + b, 0);
|
||||||
|
result = sum / nums.length;
|
||||||
|
} else if (operation === 'count') {
|
||||||
|
result = nums.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { [groupBy]: groupVal, result };
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
export default processCSV;
|
||||||
|
// Generation time: 72.324s
|
||||||
|
// Result: FAIL
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
export async function findAvailableSlots(cal1, cal2, constraints) {
|
||||||
|
const { DateTime } = await import('https://cdn.jsdelivr.net/npm/luxon@3/+esm');
|
||||||
|
const { durationMinutes, searchRange, workHours } = constraints;
|
||||||
|
const dur = durationMinutes * 60000;
|
||||||
|
const toUtc = s => DateTime.fromISO(s, { zone: 'utc' });
|
||||||
|
const [sH, sM] = workHours.start.split(':').map(Number);
|
||||||
|
const [eH, eM] = workHours.end.split(':').map(Number);
|
||||||
|
|
||||||
|
const rangeStart = toUtc(searchRange.start);
|
||||||
|
const rangeEnd = toUtc(searchRange.end);
|
||||||
|
const rStartMs = rangeStart.toMillis();
|
||||||
|
const rEndMs = rangeEnd.toMillis();
|
||||||
|
|
||||||
|
const busy = [...cal1, ...cal2]
|
||||||
|
.map(({ start, end }) => ({ s: toUtc(start).toMillis(), e: toUtc(end).toMillis() }))
|
||||||
|
.filter(b => b.s < b.e)
|
||||||
|
.sort((a, b) => a.s - b.s);
|
||||||
|
|
||||||
|
const mergedBusy = busy.reduce((acc, b) => {
|
||||||
|
const last = acc[acc.length - 1];
|
||||||
|
last && b.s <= last.e ? (last.e = Math.max(last.e, b.e)) : acc.push({ ...b });
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const slots = [];
|
||||||
|
const addSlots = (from, to) => {
|
||||||
|
for (let t = from; t + dur <= to; t += dur) {
|
||||||
|
slots.push({
|
||||||
|
start: DateTime.fromMillis(t, { zone: 'utc' }).toISO(),
|
||||||
|
end: DateTime.fromMillis(t + dur, { zone: 'utc' }).toISO()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let d = rangeStart.startOf('day'); d <= rangeEnd; d = d.plus({ days: 1 })) {
|
||||||
|
const wStart = Math.max(d.set({ hour: sH, minute: sM, second: 0, millisecond: 0 }).toMillis(), rStartMs);
|
||||||
|
const wEnd = Math.min(d.set({ hour: eH, minute: eM, second: 0, millisecond: 0 }).toMillis(), rEndMs);
|
||||||
|
|
||||||
|
if (wStart < wEnd) {
|
||||||
|
let cur = wStart;
|
||||||
|
for (const b of mergedBusy) {
|
||||||
|
if (b.e <= cur) continue;
|
||||||
|
if (b.s >= wEnd) break;
|
||||||
|
if (b.s > cur) addSlots(cur, Math.min(b.s, wEnd));
|
||||||
|
cur = Math.max(cur, b.e);
|
||||||
|
if (cur >= wEnd) break;
|
||||||
|
}
|
||||||
|
if (cur < wEnd) addSlots(cur, wEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
export default findAvailableSlots;
|
||||||
|
// Generation time: 71.113s
|
||||||
|
// Result: PASS
|
||||||
49
tests/7_scheduler/outputs/stealth_union-alpha EFF_high.js
Normal file
49
tests/7_scheduler/outputs/stealth_union-alpha EFF_high.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
async function findAvailableSlots(cal1, cal2, constraints) {
|
||||||
|
const { DateTime } = await import('https://esm.sh/luxon@3.4.4');
|
||||||
|
const { durationMinutes, searchRange, workHours } = constraints;
|
||||||
|
const s = DateTime.fromISO(searchRange.start, { zone: 'utc' });
|
||||||
|
const e = DateTime.fromISO(searchRange.end, { zone: 'utc' });
|
||||||
|
const dur = { minutes: durationMinutes };
|
||||||
|
const busy = [...cal1, ...cal2]
|
||||||
|
.map(x => [DateTime.fromISO(x.start, { zone: 'utc' }), DateTime.fromISO(x.end, { zone: 'utc' })])
|
||||||
|
.filter(([a, b]) => b > s && a < e)
|
||||||
|
.map(([a, b]) => [a < s ? s : a, b > e ? e : b])
|
||||||
|
.sort((a, b) => a[0] - b[0]);
|
||||||
|
const merged = [];
|
||||||
|
for (const [a, b] of busy) {
|
||||||
|
const last = merged[merged.length - 1];
|
||||||
|
if (!last || a > last[1]) merged.push([a, b]);
|
||||||
|
else if (b > last[1]) last[1] = b;
|
||||||
|
}
|
||||||
|
const [wsh, wsm] = workHours.start.split(':').map(Number);
|
||||||
|
const [weh, wem] = workHours.end.split(':').map(Number);
|
||||||
|
const slots = [];
|
||||||
|
for (let day = s.startOf('day'); day <= e; day = day.plus({ days: 1 })) {
|
||||||
|
const ws = day.set({ hour: wsh, minute: wsm, second: 0, millisecond: 0 });
|
||||||
|
const we = day.set({ hour: weh, minute: wem, second: 0, millisecond: 0 });
|
||||||
|
const winS = ws < s ? s : ws;
|
||||||
|
const winE = we > e ? e : we;
|
||||||
|
if (winS >= winE) continue;
|
||||||
|
let cur = winS;
|
||||||
|
for (const [a, b] of merged) {
|
||||||
|
if (b <= cur) continue;
|
||||||
|
if (a >= winE) break;
|
||||||
|
if (a > cur) add(cur, a < winE ? a : winE);
|
||||||
|
if (b > cur) cur = b > winE ? winE : b;
|
||||||
|
if (cur >= winE) break;
|
||||||
|
}
|
||||||
|
if (cur < winE) add(cur, winE);
|
||||||
|
}
|
||||||
|
function add(a, b) {
|
||||||
|
let t = a;
|
||||||
|
while (t.plus(dur) <= b) {
|
||||||
|
const n = t.plus(dur);
|
||||||
|
slots.push({ start: t.toUTC().toISO(), end: n.toUTC().toISO() });
|
||||||
|
t = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
export default findAvailableSlots;
|
||||||
|
// Generation time: 191.955s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export async function validateJSON(data, schema) {
|
||||||
|
try {
|
||||||
|
const { default: Ajv } = await import('https://esm.sh/ajv@8');
|
||||||
|
const validate = new Ajv({ allErrors: true, strict: false }).compile(schema);
|
||||||
|
const valid = !!validate(data);
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid,
|
||||||
|
errors: valid ? [] : validate.errors.map(e => e.instancePath ? `${e.instancePath} ${e.message}` : e.message)
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
errors: [err.message]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default validateJSON;
|
||||||
|
// Generation time: 22.203s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
async function validateJSON(data, schema) {
|
||||||
|
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
||||||
|
throw new TypeError("Schema must be a JSON Schema object.");
|
||||||
|
|
||||||
|
const [{ default: Ajv }, { default: addFormats }] = await Promise.all([
|
||||||
|
import("https://esm.sh/ajv@8.17.1"),
|
||||||
|
import("https://esm.sh/ajv-formats@3.0.1?deps=ajv@8.17.1")
|
||||||
|
]);
|
||||||
|
|
||||||
|
const ajv = new Ajv({ allErrors: true, strict: false });
|
||||||
|
addFormats(ajv);
|
||||||
|
|
||||||
|
const validate = ajv.compile(schema);
|
||||||
|
if (validate.$async)
|
||||||
|
throw new TypeError("Asynchronous schema extensions are not supported.");
|
||||||
|
|
||||||
|
const valid = validate(data);
|
||||||
|
return {
|
||||||
|
valid,
|
||||||
|
errors: valid
|
||||||
|
? []
|
||||||
|
: (validate.errors ?? []).map(
|
||||||
|
({ instancePath, message }) => `${instancePath || "/"}: ${message}`
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export default validateJSON;
|
||||||
|
// Generation time: 99.796s
|
||||||
|
// Result: PASS
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
export async function createStreamVisualizer(asyncIterable, { maxPoints, alpha, width, height, yDomain }) {
|
||||||
|
const [d3, data] = await Promise.all([
|
||||||
|
import('d3'),
|
||||||
|
(async () => {
|
||||||
|
const buffer = [];
|
||||||
|
let ema;
|
||||||
|
for await (const { timestamp, value } of asyncIterable) {
|
||||||
|
ema = ema == null ? value : alpha * value + (1 - alpha) * ema;
|
||||||
|
buffer.push({ timestamp, value, ema });
|
||||||
|
if (buffer.length > maxPoints) buffer.shift();
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
})()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!data.length) return { data, path: '' };
|
||||||
|
|
||||||
|
const x = d3.scaleLinear()
|
||||||
|
.domain([data[0].timestamp, data.at(-1).timestamp])
|
||||||
|
.range([0, width]);
|
||||||
|
|
||||||
|
const y = d3.scaleLinear()
|
||||||
|
.domain(yDomain)
|
||||||
|
.range([height, 0]);
|
||||||
|
|
||||||
|
const path = d3.line()
|
||||||
|
.x(d => x(d.timestamp))
|
||||||
|
.y(d => y(d.ema))(data) ?? '';
|
||||||
|
|
||||||
|
return { data, path };
|
||||||
|
}
|
||||||
|
export default createStreamVisualizer;
|
||||||
|
// Generation time: 21.189s
|
||||||
|
// Result: FAIL
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
async function createStreamVisualizer(asyncIterable, options = {}) {
|
||||||
|
const { maxPoints, alpha, width, height, yDomain } = options;
|
||||||
|
|
||||||
|
if (typeof asyncIterable?.[Symbol.asyncIterator] !== "function")
|
||||||
|
throw new TypeError("Expected an async iterable.");
|
||||||
|
|
||||||
|
if (!Number.isSafeInteger(maxPoints) || maxPoints < 1)
|
||||||
|
throw new RangeError("maxPoints must be a positive safe integer.");
|
||||||
|
|
||||||
|
if (!Number.isFinite(alpha) || alpha < 0 || alpha > 1)
|
||||||
|
throw new RangeError("alpha must be between 0 and 1.");
|
||||||
|
|
||||||
|
if (![width, height].every(n => Number.isFinite(n) && n >= 0))
|
||||||
|
throw new RangeError("width and height must be finite and nonnegative.");
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Array.isArray(yDomain) ||
|
||||||
|
yDomain.length !== 2 ||
|
||||||
|
!yDomain.every(Number.isFinite) ||
|
||||||
|
yDomain[0] >= yDomain[1]
|
||||||
|
)
|
||||||
|
throw new RangeError("yDomain must contain two increasing finite numbers.");
|
||||||
|
|
||||||
|
const domain = [...yDomain];
|
||||||
|
const d3 = await import("https://cdn.jsdelivr.net/npm/d3@7.9.0/+esm");
|
||||||
|
const buffer = [];
|
||||||
|
let cursor = 0, ema;
|
||||||
|
|
||||||
|
for await (const point of asyncIterable) {
|
||||||
|
const { timestamp, value } = point ?? {};
|
||||||
|
const time = timestamp instanceof Date ? timestamp.getTime() : timestamp;
|
||||||
|
|
||||||
|
if (!Number.isFinite(time) || !Number.isFinite(value))
|
||||||
|
throw new TypeError("Each point needs a valid timestamp and finite value.");
|
||||||
|
|
||||||
|
ema = ema === undefined ? value : alpha * value + (1 - alpha) * ema;
|
||||||
|
buffer[cursor] = { timestamp: time, value, ema };
|
||||||
|
cursor = (cursor + 1) % maxPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = buffer.length === maxPoints
|
||||||
|
? buffer.slice(cursor).concat(buffer.slice(0, cursor))
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
if (!data.length) return { data, path: "" };
|
||||||
|
|
||||||
|
const x = d3.scaleLinear()
|
||||||
|
.domain([data[0].timestamp, data[data.length - 1].timestamp])
|
||||||
|
.range([0, width]);
|
||||||
|
|
||||||
|
const y = d3.scaleLinear()
|
||||||
|
.domain(domain)
|
||||||
|
.range([height, 0]);
|
||||||
|
|
||||||
|
const path = d3.line()
|
||||||
|
.x(d => x(d.timestamp))
|
||||||
|
.y(d => y(d.ema))(data) ?? "";
|
||||||
|
|
||||||
|
return { data, path };
|
||||||
|
}
|
||||||
|
export default createStreamVisualizer;
|
||||||
|
// Generation time: 101.222s
|
||||||
|
// Result: PASS
|
||||||
Reference in New Issue
Block a user