async function fetch_packages() { const resp = await fetch('../packages.csv'); const data = await resp.text(); return data .split('\n') .map(line => line.split(';')) .filter(fields => fields.length >= 4) .map(fields => ({ section: fields[0], id: fields[1], desc: fields[2], licence: fields[3], })); } async function fetch_commit_info() { const resp = await fetch('../commit.csv'); const data = await resp.text(); const fields = data.split(';'); return { sha: fields[0] || '', when: fields[1] || '', branch: fields[2] || '', }; } function create_commit_info(commit) { const date = commit.when.slice(0, 10); const time = commit.when.slice(11, 16); const text = `Last update: ${date} ${time}, ${commit.branch} branch at ${commit.sha}`; document.getElementById('commit').innerHTML = text; } function get_pkg_licence_name(pkg) { return pkg.licence ? pkg.licence.split(' ', 1)[0] : 'Unknown'; } function get_pkg_licence_link(pkg) { if (pkg.licence) { const url = pkg.licence.split(' ', 2)[1]; if (url) { const anchor = document.createElement('a'); anchor.href = url; anchor.target = '_blank'; anchor.innerText = 'link'; return anchor.outerHTML; } } return null; } const CATEGORIES = [ 'copyleft', 'permissive', 'nonfree', 'other', 'unknown', ]; const CATEGORY_COLORS = { unknown: '#555', copyleft: '#d11', permissive: '#1d1', nonfree: '#fc0', other: '#aaa', }; function categorize_licence(licence) { if (licence == 'Unknown') return 'unknown'; if (/^L?GPL/.test(licence) || /^MPL/.test(licence)) return 'copyleft'; if (['ZLIB', 'MIT', 'BSD'].includes(licence)) return 'permissive'; if (['PROP', 'NONCOM'].includes(licence)) return 'nonfree'; return 'other'; } function create_pie(packages) { const counts = new Map(); packages .map(get_pkg_licence_name) .map(categorize_licence) .forEach(lic => counts.set(lic, (counts.get(lic) || 0) + 1)); const categories = CATEGORIES.filter(cat => counts.has(cat)); const canvas = document.getElementById('pie'); const chart = new Chart(canvas, { type: 'doughnut', data: { labels: CATEGORIES, datasets: [{ data: categories.map(cat => counts.get(cat)), backgroundColor: categories.map(cat => CATEGORY_COLORS[cat]), }], }, options: { legend: { position: 'bottom', }, }, }); } function append_cell(parent, html) { const cell = document.createElement('td'); cell.innerHTML = html; parent.appendChild(cell); } function create_section_row(type, cell_htmls) { const row = document.createElement(type); cell_htmls.forEach(str => append_cell(row, str)) return row; } function create_package_tables(packages) { const pkg_licences = new Map(); packages.forEach(pkg => { const licence = get_pkg_licence_name(pkg); const packages = pkg_licences.get(licence) || []; packages.push(pkg); pkg_licences.set(licence, packages); }); const fragment = new DocumentFragment(); const licence_names = [...pkg_licences.keys()].sort(); licence_names.forEach(lic => { const lic_category = categorize_licence(lic); const lic_color = CATEGORY_COLORS[lic_category]; const container = document.createElement('section'); container.style.backgroundColor = lic_color + '2'; const title = document.createElement('h3'); title.innerText = lic; container.appendChild(title); const table = document.createElement('table'); const thead = create_section_row('thead', ['Package', 'Description', 'Section', 'Licence']); table.appendChild(thead); pkg_licences .get(lic) .sort((a, b) => a.id.localeCompare(b.id)) .map(pkg => [ pkg.id, pkg.desc, pkg.section || '—', get_pkg_licence_link(pkg) || '—', ]) .map(fields => create_section_row('tr', fields)) .forEach(row => table.appendChild(row)); container.appendChild(table); fragment.appendChild(container); }); document.getElementById('packages').appendChild(fragment); } window.onload = async () => { const packages = await fetch_packages(); const commit = await fetch_commit_info(); create_pie(packages); create_commit_info(commit); create_package_tables(packages); };