d5ef93b13b
gates / gates (push) Successful in 6m42s
A household ticks apps and sees, for an 8, 16 and 32 GB box: fits well / fits, but tight / does not fit, the totals, and the apps that burst on CPU. One rule in assets/sizing.js, every number from assets/sizing-data.json (built by scripts/build_sizing_web.py from the 2026-10-13 N100 measurement; test: 7 cases, red-proofed). Unlisted: noindex, robots Disallow, not in the sitemap, linked from nowhere — site_gates.py gate 25 enforces it (UNLISTED twin pairs keep every twin check). SIZING.md §5 corrected: the 8 GB line contradicted its own x1.5 rule; guest sizes 4.0/11.4/27.4 GB with the measured 612 MiB MemTotal shortfall. R-993 gains the fact that the installer accepts a host below any minimum.
184 lines
8.5 KiB
JavaScript
184 lines
8.5 KiB
JavaScript
/* sizing.js — the machine estimator (/gepigeny, /en/sizing).
|
|
*
|
|
* THE RULE lives in estimate() and guestMib() below, and nowhere else on the site. Every number it uses
|
|
* comes from /assets/sizing-data.json (built by scripts/build_sizing_web.py from the 2026-10-13 N100
|
|
* measurement); this file holds none of its own — scripts/test_build_sizing_web.py checks that.
|
|
*
|
|
* typical = platform + sum of the selected apps' typical figures
|
|
* peak = platform + sum of their peaks (all at peak at once: pessimistic on purpose)
|
|
* per box: guest memory by the installer's rule, then
|
|
* well peak * headroom <= guest
|
|
* tight peak <= guest < peak * headroom
|
|
* no guest < peak
|
|
*
|
|
* The page text is not here: each page carries its own strings (#sizer-strings), so this file is the
|
|
* same for both languages.
|
|
*/
|
|
(function (root) {
|
|
'use strict';
|
|
|
|
function guestMib(data, gb) {
|
|
var r = data.guest_rule;
|
|
var total = gb * 1024 - r.memtotal_shortfall_mib;
|
|
var mem = total - r.reserve_mib;
|
|
if (mem > total - r.max_gap_mib) { mem = total - r.max_gap_mib; }
|
|
if (mem < r.min_mib) { mem = r.min_mib; }
|
|
if (mem > total - r.ceiling_gap_mib) { mem = total - r.ceiling_gap_mib; }
|
|
return mem;
|
|
}
|
|
|
|
function estimate(data, slugs) {
|
|
var bySlug = {};
|
|
data.apps.forEach(function (a) { bySlug[a.slug] = a; });
|
|
var typical = data.platform_mb, peak = data.platform_mb, busy = [], unmeasured = [];
|
|
slugs.forEach(function (s) {
|
|
var a = bySlug[s];
|
|
if (!a || a.builtin) { return; }
|
|
typical += a.typical_mb;
|
|
peak += a.peak_mb;
|
|
if (a.cpu_class === 'medium' || a.cpu_class === 'heavy-in-bursts') { busy.push(a); }
|
|
if (!a.measured) { unmeasured.push(a); }
|
|
});
|
|
var boxes = data.boxes_gb.map(function (gb) {
|
|
var guest = guestMib(data, gb);
|
|
var verdict = peak * data.headroom <= guest ? 'well' : (peak <= guest ? 'tight' : 'no');
|
|
return { gb: gb, guest_mb: guest, verdict: verdict };
|
|
});
|
|
var heavy = busy.filter(function (a) { return a.cpu_class === 'heavy-in-bursts'; });
|
|
return { typical_mb: typical, peak_mb: peak, boxes: boxes, busy: busy, heavy: heavy, unmeasured: unmeasured };
|
|
}
|
|
|
|
root.FelhomSizing = { estimate: estimate, guestMib: guestMib };
|
|
|
|
/* ---------------------------------------------------------------- the page (drawing only) */
|
|
if (typeof document === 'undefined') { return; }
|
|
|
|
function el(tag, cls, txt) {
|
|
var e = document.createElement(tag);
|
|
if (cls) { e.className = cls; }
|
|
if (txt !== undefined) { e.textContent = txt; }
|
|
return e;
|
|
}
|
|
|
|
function icon(name) {
|
|
var ns = 'http://www.w3.org/2000/svg';
|
|
var s = document.createElementNS(ns, 'svg');
|
|
s.setAttribute('class', 'ico');
|
|
s.setAttribute('aria-hidden', 'true');
|
|
var u = document.createElementNS(ns, 'use');
|
|
u.setAttribute('href', '/assets/icons.svg?v=1#' + name);
|
|
s.appendChild(u);
|
|
return s;
|
|
}
|
|
|
|
function start() {
|
|
var host = document.getElementById('sizer');
|
|
var strEl = document.getElementById('sizer-strings');
|
|
if (!host || !strEl) { return; }
|
|
var T = JSON.parse(strEl.textContent);
|
|
var lang = document.documentElement.lang === 'en' ? 'en' : 'hu';
|
|
var gbText = function (mb) {
|
|
var v = (mb / 1024).toFixed(1);
|
|
return (lang === 'hu' ? v.replace('.', ',') : v) + ' GB';
|
|
};
|
|
var appsBox = document.getElementById('sizer-apps');
|
|
var result = document.getElementById('sizer-result');
|
|
|
|
fetch(host.getAttribute('data-src')).then(function (r) { return r.json(); }).then(function (data) {
|
|
data.categories.forEach(function (c) {
|
|
var fs = el('fieldset', 'sizer-group');
|
|
fs.appendChild(el('legend', '', lang === 'en' ? c.name_en : c.name_hu));
|
|
data.apps.filter(function (a) { return a.category === c.id; }).forEach(function (a) {
|
|
var lab = el('label', 'sizer-app');
|
|
var cb = el('input');
|
|
cb.type = 'checkbox';
|
|
cb.value = a.slug;
|
|
if (a.builtin) { cb.checked = true; cb.disabled = true; }
|
|
lab.appendChild(cb);
|
|
var name = el('span', 'sizer-app-name', lang === 'en' ? a.name_en : a.name_hu);
|
|
lab.appendChild(name);
|
|
var tag = a.builtin ? T.builtin : (lang === 'en' ? a.tagline_en : a.tagline_hu);
|
|
if (tag) { lab.appendChild(el('span', 'sizer-app-tag', tag)); }
|
|
fs.appendChild(lab);
|
|
});
|
|
appsBox.appendChild(fs);
|
|
});
|
|
|
|
function selected() {
|
|
return Array.prototype.map.call(appsBox.querySelectorAll('input[type=checkbox]:checked:not(:disabled)'),
|
|
function (c) { return c.value; });
|
|
}
|
|
|
|
function draw() {
|
|
var r = estimate(data, selected());
|
|
result.textContent = '';
|
|
var totals = el('p', 'sizer-totals');
|
|
totals.appendChild(el('span', '', T.typical + ': '));
|
|
totals.appendChild(el('strong', 'sizer-num', gbText(r.typical_mb)));
|
|
totals.appendChild(el('span', '', ' · ' + T.peak + ': '));
|
|
totals.appendChild(el('strong', 'sizer-num', gbText(r.peak_mb)));
|
|
result.appendChild(totals);
|
|
result.appendChild(el('p', 'sizer-fine', T.platform_note));
|
|
|
|
var ul = el('ul', 'sizer-boxes');
|
|
r.boxes.forEach(function (b) {
|
|
var li = el('li', 'sizer-box sizer-' + b.verdict);
|
|
var head = el('div', 'sizer-box-head');
|
|
head.appendChild(icon(b.verdict === 'well' ? 'i-check' : (b.verdict === 'tight' ? 'i-triangle-alert' : 'i-x')));
|
|
head.appendChild(el('strong', 'sizer-box-size', b.gb + ' GB'));
|
|
head.appendChild(el('span', 'sizer-verdict', T.verdict[b.verdict]));
|
|
li.appendChild(head);
|
|
li.appendChild(el('p', 'sizer-fine', T.guest.replace('{x}', gbText(b.guest_mb))));
|
|
if (b.verdict === 'tight') { li.appendChild(el('p', 'sizer-why', T.tight_why)); }
|
|
ul.appendChild(li);
|
|
});
|
|
result.appendChild(ul);
|
|
|
|
if (r.busy.length) {
|
|
result.appendChild(el('h3', 'sizer-sub', T.cpu_head));
|
|
var cl = el('ul', 'sizer-cpu');
|
|
r.busy.forEach(function (a) {
|
|
var li = el('li');
|
|
li.appendChild(el('strong', '', (lang === 'en' ? a.name_en : a.name_hu) + ': '));
|
|
li.appendChild(el('span', '', lang === 'en' ? a.cpu_note_en : a.cpu_note_hu));
|
|
cl.appendChild(li);
|
|
});
|
|
if (r.heavy.length >= 2) {
|
|
cl.appendChild(el('li', 'sizer-pair', T.heavy_pair.replace('{names}', r.heavy.map(function (a) {
|
|
return lang === 'en' ? a.name_en : a.name_hu;
|
|
}).join(T.and))));
|
|
}
|
|
result.appendChild(cl);
|
|
}
|
|
if (r.unmeasured.length) {
|
|
result.appendChild(el('p', 'sizer-why', T.unmeasured + ': ' + r.unmeasured.map(function (a) {
|
|
return lang === 'en' ? a.name_en : a.name_hu;
|
|
}).join(', ')));
|
|
}
|
|
}
|
|
|
|
appsBox.addEventListener('change', draw);
|
|
Array.prototype.forEach.call(document.querySelectorAll('[data-preset]'), function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
var want = (btn.getAttribute('data-preset') || '').split(',').filter(Boolean);
|
|
Array.prototype.forEach.call(appsBox.querySelectorAll('input[type=checkbox]:not(:disabled)'), function (c) {
|
|
c.checked = want.indexOf(c.value) !== -1;
|
|
});
|
|
draw();
|
|
});
|
|
});
|
|
host.hidden = false;
|
|
draw();
|
|
}).catch(function () {
|
|
result.textContent = T.load_error;
|
|
host.hidden = false;
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', start);
|
|
} else {
|
|
start();
|
|
}
|
|
})(this);
|