docs: archive newer wiki content for comparison

This commit is contained in:
msa46 2026-08-02 17:27:32 +02:00
parent e3891d18af
commit 4e06340aaa
106 changed files with 2963 additions and 0 deletions

245
package-lock.json generated
View file

@ -14,6 +14,8 @@
},
"devDependencies": {
"@astrojs/check": "0.9.10",
"linkedom": "0.18.13",
"turndown": "7.2.4",
"typescript": "6.0.2"
},
"engines": {
@ -1791,6 +1793,13 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/@mixmark-io/domino": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz",
@ -3134,6 +3143,13 @@
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
"license": "CC0-1.0"
},
"node_modules/cssom": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
"integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
"dev": true,
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@ -4124,6 +4140,39 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/htmlparser2": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
"dev": true,
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.2.2",
"entities": "^7.0.1"
}
},
"node_modules/htmlparser2/node_modules/entities": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/http-cache-semantics": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
@ -4547,6 +4596,181 @@
"url": "https://opencollective.com/parcel"
}
},
"node_modules/linkedom": {
"version": "0.18.13",
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.13.tgz",
"integrity": "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw==",
"dev": true,
"license": "ISC",
"dependencies": {
"css-select": "^7.0.0",
"cssom": "^0.5.0",
"html-escaper": "^3.0.3",
"htmlparser2": "^10.1.0",
"uhyphen": "^0.2.0"
},
"engines": {
"node": ">=16"
},
"peerDependencies": {
"canvas": ">= 2"
},
"peerDependenciesMeta": {
"canvas": {
"optional": true
}
}
},
"node_modules/linkedom/node_modules/boolbase": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-2.0.0.tgz",
"integrity": "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/linkedom/node_modules/css-select": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-7.0.0.tgz",
"integrity": "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^2.0.0",
"css-what": "^8.0.0",
"domhandler": "^6.0.1",
"domutils": "^4.0.2",
"nth-check": "^3.0.1"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/linkedom/node_modules/css-what": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-8.0.0.tgz",
"integrity": "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/linkedom/node_modules/dom-serializer": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz",
"integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==",
"dev": true,
"license": "MIT",
"dependencies": {
"domelementtype": "^3.0.0",
"domhandler": "^6.0.0",
"entities": "^8.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/linkedom/node_modules/domelementtype": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz",
"integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause",
"engines": {
"node": ">=20.19.0"
}
},
"node_modules/linkedom/node_modules/domhandler": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz",
"integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^3.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/linkedom/node_modules/domutils": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz",
"integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^3.0.0",
"domelementtype": "^3.0.0",
"domhandler": "^6.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/linkedom/node_modules/entities": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
"integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/linkedom/node_modules/nth-check": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-3.0.1.tgz",
"integrity": "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^2.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/longest-streak": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
@ -6859,6 +7083,20 @@
"license": "0BSD",
"optional": true
},
"node_modules/turndown": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz",
"integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mixmark-io/domino": "^2.2.0"
},
"engines": {
"node": ">=18",
"npm": ">=9"
}
},
"node_modules/typesafe-path": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz",
@ -6896,6 +7134,13 @@
"integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
"license": "MIT"
},
"node_modules/uhyphen": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/uhyphen/-/uhyphen-0.2.0.tgz",
"integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==",
"dev": true,
"license": "ISC"
},
"node_modules/ultrahtml": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz",

View file

@ -10,6 +10,7 @@
"preview": "astro preview",
"check": "astro check && node --test",
"check:migration": "node scripts/check-migration.mjs",
"capture:live-wiki": "node scripts/capture-live-wiki.mjs",
"test": "node --test"
},
"dependencies": {
@ -19,6 +20,8 @@
},
"devDependencies": {
"@astrojs/check": "0.9.10",
"linkedom": "0.18.13",
"turndown": "7.2.4",
"typescript": "6.0.2"
}
}

View file

@ -0,0 +1,47 @@
#!/usr/bin/env node
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { crawlWiki } from './lib/live-wiki.mjs';
const CAPTURE_DATE = '2026-08-02';
const SCRIPT_PATH = fileURLToPath(import.meta.url);
const PROJECT_ROOT = path.resolve(path.dirname(SCRIPT_PATH), '..');
export async function runCapture({
crawlImpl = crawlWiki,
logError = console.error,
logInfo = console.log,
} = {}) {
const manifest = await crawlImpl({
capturedAt: CAPTURE_DATE,
manifestPath: path.join(PROJECT_ROOT, 'to-be-studied', 'manifest.json'),
outputRoot: path.join(PROJECT_ROOT, 'to-be-studied', 'live-wiki', CAPTURE_DATE),
});
const pageCount = manifest.pages.length;
const failureCount = manifest.failures.length;
if (failureCount > 0) {
logError(
`Captured ${pageCount} ${pluralize('page', pageCount)} with ${failureCount} ${pluralize('failure', failureCount)}; inspect to-be-studied/manifest.json.`,
);
return 1;
}
logInfo(`Captured ${pageCount} ${pluralize('page', pageCount)} with no failures.`);
return 0;
}
function pluralize(noun, count) {
return count === 1 ? noun : `${noun}s`;
}
if (process.argv[1] && path.resolve(process.argv[1]) === SCRIPT_PATH) {
try {
process.exitCode = await runCapture();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
}
}

311
scripts/lib/live-wiki.mjs Normal file
View file

@ -0,0 +1,311 @@
import { createHash } from 'node:crypto';
import { mkdir, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { parseHTML } from 'linkedom';
import TurndownService from 'turndown';
export const LIVE_WIKI_BASE_URL = 'https://wiki.msvincognito.nl/';
const ASSET_EXTENSION = /\.(?:avif|bmp|css|csv|docx?|eot|gif|ico|jpe?g|js|json|map|mp3|mp4|ogg|otf|pdf|png|pptx?|rar|rss|svg|tar|tiff?|tsv|txt|wav|webm|webmanifest|webp|woff2?|xlsx?|xml|zip)$/i;
const NON_CONTENT_SELECTOR = [
'script',
'style',
'header',
'nav',
'aside',
'form',
'button',
'footer',
'noscript',
'iframe',
'dialog',
'[role="navigation"]',
'[role="contentinfo"]',
].join(',');
class PageLimitError extends Error {}
class SoftNotFoundError extends Error {}
export function normalizeWikiUrl(input, relativeTo = LIVE_WIKI_BASE_URL) {
let url;
try {
url = new URL(input, relativeTo);
} catch {
return null;
}
const baseUrl = new URL(LIVE_WIKI_BASE_URL);
if (url.origin !== baseUrl.origin || !['http:', 'https:'].includes(url.protocol)) {
return null;
}
url.search = '';
url.hash = '';
url.pathname = url.pathname.replace(/\/{2,}/g, '/');
if (url.pathname !== '/') {
url.pathname = url.pathname.replace(/\/+$/, '');
}
if (ASSET_EXTENSION.test(url.pathname)) {
return null;
}
return url.href;
}
export function routeToCapturePath(input) {
const normalizedUrl = normalizeWikiUrl(input);
if (!normalizedUrl) {
throw new TypeError(`Cannot map non-content URL to a capture path: ${input}`);
}
const { pathname } = new URL(normalizedUrl);
if (pathname === '/') {
return 'index.md';
}
const route = pathname
.split('/')
.filter(Boolean)
.map((segment) => sanitizePathSegment(segment))
.join('/');
return `${route}.md`;
}
export function extractPage(html, url) {
const { document } = parseHTML(html);
const content = document.querySelector('main')
?? document.querySelector('article')
?? document.body;
if (!content) {
throw new Error(`No readable content root found at ${url}`);
}
const links = new Set();
const currentUrl = normalizeWikiUrl(url);
for (const anchor of content.querySelectorAll('a[href]')) {
const normalizedLink = normalizeWikiUrl(anchor.getAttribute('href'), url);
if (normalizedLink && normalizedLink !== currentUrl) {
links.add(normalizedLink);
anchor.setAttribute('href', normalizedLink);
}
}
const heading = content.querySelector('h1, h2, h3');
const title = cleanText(heading?.textContent)
|| cleanText(document.querySelector('title')?.textContent)
|| titleFromUrl(url);
for (const element of content.querySelectorAll(NON_CONTENT_SELECTOR)) {
element.remove();
}
removeLiveWikiChrome(content);
const turndown = new TurndownService({
bulletListMarker: '-',
codeBlockStyle: 'fenced',
emDelimiter: '*',
headingStyle: 'atx',
});
turndown.addRule('lineBreakWithoutTrailingWhitespace', {
filter: 'br',
replacement: () => '<br>\n',
});
const markdown = `${turndown.turndown(content).trim().replace(/[ \t]+$/gm, '')}\n`;
return {
title,
markdown,
links: [...links].sort(),
};
}
export async function crawlWiki({
capturedAt = new Date().toISOString().slice(0, 10),
delayMs = 150,
fetchImpl = globalThis.fetch,
manifestPath,
maxPages = 500,
outputRoot,
startUrls = [LIVE_WIKI_BASE_URL],
waitImpl = wait,
} = {}) {
if (!outputRoot || !manifestPath) {
throw new TypeError('crawlWiki requires outputRoot and manifestPath.');
}
if (!/^\d{4}-\d{2}-\d{2}$/.test(capturedAt)) {
throw new TypeError('capturedAt must use YYYY-MM-DD format.');
}
if (!Number.isInteger(maxPages) || maxPages < 1) {
throw new TypeError('maxPages must be a positive integer.');
}
const queue = [];
const discovered = new Set();
for (const startUrl of startUrls) {
discover(startUrl, LIVE_WIKI_BASE_URL, discovered, queue, maxPages);
}
const pages = [];
const failures = [];
let requestCount = 0;
await mkdir(outputRoot, { recursive: true });
while (queue.length > 0) {
queue.sort();
const url = queue.shift();
if (requestCount > 0) {
await waitImpl(delayMs);
}
requestCount += 1;
const capturePath = routeToCapturePath(url);
const destination = path.join(outputRoot, ...capturePath.split('/'));
try {
const response = await fetchImpl(url, {
headers: {
accept: 'text/html,application/xhtml+xml',
'user-agent': 'Incognito-Wiki research capture (+https://msvincognito.nl/)',
},
redirect: 'follow',
});
if (!response) {
throw new Error('No response');
}
if (!response.ok) {
throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
}
const contentType = response.headers.get('content-type') ?? '';
if (contentType && !/\b(?:text\/html|application\/xhtml\+xml)\b/i.test(contentType)) {
throw new Error(`Unexpected content type: ${contentType}`);
}
const page = extractPage(await response.text(), url);
if (page.title === '404' && /This page could not be found\./i.test(page.markdown)) {
throw new SoftNotFoundError('Soft 404: This page could not be found.');
}
for (const link of page.links) {
discover(link, url, discovered, queue, maxPages);
}
const content = `> Source: ${url}\n> Captured: ${capturedAt}\n\n${page.markdown}`;
await mkdir(path.dirname(destination), { recursive: true });
await writeFile(destination, content, 'utf8');
pages.push({
url,
title: page.title,
path: toPosixPath(path.relative(path.dirname(manifestPath), destination)),
contentHash: createHash('sha256').update(content).digest('hex'),
});
} catch (error) {
if (error instanceof PageLimitError) {
throw error;
}
await rm(destination, { force: true });
if (error instanceof SoftNotFoundError) {
continue;
}
failures.push({
url,
error: error instanceof Error ? error.message : String(error),
});
}
}
const manifest = {
capturedAt,
baseUrl: LIVE_WIKI_BASE_URL,
pages: pages.sort(compareByUrl),
failures: failures.sort(compareByUrl),
};
await mkdir(path.dirname(manifestPath), { recursive: true });
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
return manifest;
}
function cleanText(value = '') {
return value.replace(/\s+/g, ' ').trim();
}
function removeLiveWikiChrome(content) {
for (const element of content.querySelectorAll('[class]')) {
const classes = new Set(element.classList);
const text = cleanText(element.textContent);
const isPreviousNextNavigation = classes.has('mt-16');
const isRepeatedPageFooter = classes.has('hidden')
&& classes.has('text-sm')
&& classes.has('lg:block')
&& /Star on GitHub|Create Issues/.test(text);
if (isPreviousNextNavigation || isRepeatedPageFooter) {
element.remove();
}
}
}
function sanitizePathSegment(segment) {
let decoded;
try {
decoded = decodeURIComponent(segment);
} catch {
decoded = segment;
}
const safe = decoded
.normalize('NFKC')
.replace(/[^\p{Letter}\p{Number}._-]+/gu, '-')
.replace(/^-+|-+$/g, '');
if (!safe || safe === '.' || safe === '..') {
throw new Error(`Unsafe live-wiki route segment: ${segment}`);
}
return safe;
}
function titleFromUrl(url) {
const { pathname } = new URL(url);
const lastSegment = pathname.split('/').filter(Boolean).at(-1) ?? 'Home';
return decodeURIComponent(lastSegment)
.replace(/[-_]+/g, ' ')
.replace(/\b\p{Letter}/gu, (letter) => letter.toUpperCase());
}
function discover(input, relativeTo, discovered, queue, maxPages) {
const url = normalizeWikiUrl(input, relativeTo);
if (!url || discovered.has(url)) {
return;
}
discovered.add(url);
if (discovered.size > maxPages) {
throw new PageLimitError(`Discovered more than ${maxPages} content pages; refusing to truncate the crawl.`);
}
queue.push(url);
}
function compareByUrl(left, right) {
return left.url.localeCompare(right.url);
}
function toPosixPath(input) {
return input.split(path.sep).join('/');
}
function wait(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

222
tests/live-wiki.test.mjs Normal file
View file

@ -0,0 +1,222 @@
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import test from 'node:test';
import {
crawlWiki,
extractPage,
normalizeWikiUrl,
routeToCapturePath,
} from '../scripts/lib/live-wiki.mjs';
import { runCapture } from '../scripts/capture-live-wiki.mjs';
test('normalizes only same-origin content routes', () => {
assert.equal(
normalizeWikiUrl('/useful-guides/description?draft=1#details'),
'https://wiki.msvincognito.nl/useful-guides/description',
);
assert.equal(
normalizeWikiUrl('https://wiki.msvincognito.nl/useful-guides/description/'),
'https://wiki.msvincognito.nl/useful-guides/description',
);
assert.equal(normalizeWikiUrl('https://example.com/page'), null);
assert.equal(normalizeWikiUrl('/assets/diagram.png'), null);
assert.equal(normalizeWikiUrl('mailto:board@msvincognito.nl'), null);
});
test('maps routes to readable Markdown files', () => {
assert.equal(
routeToCapturePath('https://wiki.msvincognito.nl/useful-guides/description'),
'useful-guides/description.md',
);
assert.equal(routeToCapturePath('https://wiki.msvincognito.nl/'), 'index.md');
});
test('extracts the main article and internal links', () => {
const html = `
<html>
<body>
<nav><a href="/ignored">Repeated navigation</a></nav>
<main>
<h1>Guide</h1>
<p>Text<br>Second line</p>
<a href="/next?from=guide#part">Next</a>
<a href="https://example.com/external">External</a>
<form><input name="secret"><button>Submit</button></form>
<script>throw new Error('not content')</script>
</main>
<footer>Repeated footer</footer>
</body>
</html>
`;
const page = extractPage(html, 'https://wiki.msvincognito.nl/guide');
assert.equal(page.title, 'Guide');
assert.match(page.markdown, /^# Guide/m);
assert.match(page.markdown, /Text/);
assert.doesNotMatch(page.markdown, /[ \t]+$/m);
assert.doesNotMatch(page.markdown, /Submit|not content|Repeated footer/);
assert.deepEqual(page.links, ['https://wiki.msvincognito.nl/next']);
});
test('falls back from main to article and then body', () => {
const articlePage = extractPage(
'<article><h2>Article title</h2><p>Article text</p></article>',
'https://wiki.msvincognito.nl/article',
);
const bodyPage = extractPage(
'<html><head><title>Body title</title></head><body><header>Site chrome</header><p>Body text</p></body></html>',
'https://wiki.msvincognito.nl/body',
);
assert.equal(articlePage.title, 'Article title');
assert.match(articlePage.markdown, /Article text/);
assert.equal(bodyPage.title, 'Body title');
assert.match(bodyPage.markdown, /Body text/);
assert.doesNotMatch(bodyPage.markdown, /Site chrome/);
});
test('removes the live wiki previous-next panel and repeated page footer', () => {
const page = extractPage(`
<main>
<div>
<h1>Course</h1>
<p>Useful article content.</p>
<div class="mt-16"><a href="/previous">Previous</a></div>
</div>
<div class="hidden text-sm lg:block">
<a href="https://github.com/example">Star on GitHub</a>
</div>
</main>
`, 'https://wiki.msvincognito.nl/course');
assert.match(page.markdown, /Useful article content/);
assert.doesNotMatch(page.markdown, /Previous|Star on GitHub/);
assert.deepEqual(page.links, ['https://wiki.msvincognito.nl/previous']);
});
test('crawls in sorted order, writes successful pages, and records failures', async (context) => {
const captureRoot = await mkdtemp(path.join(tmpdir(), 'live-wiki-crawl-'));
context.after(() => rm(captureRoot, { recursive: true, force: true }));
const outputRoot = path.join(captureRoot, 'live-wiki', '2026-08-02');
const manifestPath = path.join(captureRoot, 'manifest.json');
const requests = [];
const waits = [];
const responses = new Map([
[
'https://wiki.msvincognito.nl/',
response('<main><h1>Home</h1><a href="/z-last">Z</a><a href="/a-first">A</a></main>'),
],
[
'https://wiki.msvincognito.nl/a-first',
response('<main><h1>First</h1><p>Captured text.</p></main>'),
],
['https://wiki.msvincognito.nl/z-last', response('Unavailable', 503)],
]);
const manifest = await crawlWiki({
capturedAt: '2026-08-02',
manifestPath,
outputRoot,
fetchImpl: async (url) => {
requests.push(url);
return responses.get(url);
},
waitImpl: async (milliseconds) => waits.push(milliseconds),
});
assert.deepEqual(requests, [
'https://wiki.msvincognito.nl/',
'https://wiki.msvincognito.nl/a-first',
'https://wiki.msvincognito.nl/z-last',
]);
assert.deepEqual(waits, [150, 150]);
assert.deepEqual(manifest.pages.map(({ url }) => url), [
'https://wiki.msvincognito.nl/',
'https://wiki.msvincognito.nl/a-first',
]);
assert.deepEqual(manifest.failures, [{
url: 'https://wiki.msvincognito.nl/z-last',
error: 'HTTP 503 Service Unavailable',
}]);
const captured = await readFile(path.join(outputRoot, 'a-first.md'), 'utf8');
assert.match(captured, /^> Source: https:\/\/wiki\.msvincognito\.nl\/a-first\n> Captured: 2026-08-02\n\n/);
assert.match(captured, /# First\n\nCaptured text\./);
assert.equal(
manifest.pages[1].contentHash,
createHash('sha256').update(captured).digest('hex'),
);
const savedManifest = JSON.parse(await readFile(manifestPath, 'utf8'));
assert.deepEqual(savedManifest, manifest);
});
test('rejects discovery beyond the configured page ceiling', async (context) => {
const captureRoot = await mkdtemp(path.join(tmpdir(), 'live-wiki-limit-'));
context.after(() => rm(captureRoot, { recursive: true, force: true }));
await assert.rejects(
crawlWiki({
capturedAt: '2026-08-02',
manifestPath: path.join(captureRoot, 'manifest.json'),
outputRoot: path.join(captureRoot, 'live-wiki', '2026-08-02'),
maxPages: 2,
fetchImpl: async () => response(
'<main><h1>Home</h1><a href="/one">One</a><a href="/two">Two</a></main>',
),
waitImpl: async () => {},
}),
/more than 2 content pages/i,
);
});
test('excludes soft 404 navigation placeholders and removes stale captures', async (context) => {
const captureRoot = await mkdtemp(path.join(tmpdir(), 'live-wiki-soft-404-'));
context.after(() => rm(captureRoot, { recursive: true, force: true }));
const outputRoot = path.join(captureRoot, 'live-wiki', '2026-08-02');
const stalePath = path.join(outputRoot, 'missing.md');
await mkdir(outputRoot, { recursive: true });
await writeFile(stalePath, 'stale capture', 'utf8');
const manifest = await crawlWiki({
capturedAt: '2026-08-02',
manifestPath: path.join(captureRoot, 'manifest.json'),
outputRoot,
fetchImpl: async (url) => url.endsWith('/missing')
? response('<main><h3>404</h3><p>This page could not be found.</p></main>')
: response('<main><h1>Home</h1><a href="/missing">Missing category</a></main>'),
waitImpl: async () => {},
});
assert.deepEqual(manifest.pages.map(({ url }) => url), ['https://wiki.msvincognito.nl/']);
assert.deepEqual(manifest.failures, []);
await assert.rejects(readFile(stalePath, 'utf8'), { code: 'ENOENT' });
});
test('capture command reports failure after the crawler preserves its manifest', async () => {
const messages = [];
const exitCode = await runCapture({
crawlImpl: async () => ({
pages: [{ url: 'https://wiki.msvincognito.nl/' }],
failures: [{ url: 'https://wiki.msvincognito.nl/broken', error: 'HTTP 503' }],
}),
logError: (message) => messages.push(message),
logInfo: () => {},
});
assert.equal(exitCode, 1);
assert.deepEqual(messages, ['Captured 1 page with 1 failure; inspect to-be-studied/manifest.json.']);
});
function response(body, status = 200) {
return new Response(body, {
status,
statusText: status === 200 ? 'OK' : status === 503 ? 'Service Unavailable' : 'Error',
headers: { 'content-type': 'text/html; charset=utf-8' },
});
}

9
to-be-studied/README.md Normal file
View file

@ -0,0 +1,9 @@
# Live-wiki research snapshot
This directory is a research snapshot of public, unauthenticated pages from `https://wiki.msvincognito.nl/`. It is not a source for the published migration and may contain incomplete, superseded, or outdated material.
The snapshot was captured on 2026-08-02 with `npm run capture:live-wiki`. The crawler stays on the live wiki's origin, never authenticates or submits forms, waits 150 ms between requests, refuses to crawl more than 500 content pages, and records request failures in `manifest.json`. It converts the first `<main>` element (falling back to `<article>` and then `<body>`) to readable Markdown after removing site chrome. Public navigation enumerated the content; the site's `/sitemap.xml` and `/robots.txt` routes both render its soft-404 page, so neither supplied additional URLs. The capture excludes navigation category URLs that return the same deterministic soft-404 page instead of content.
Files under `live-wiki/2026-08-02/` retain their public source URL and capture date. `manifest.json` records the sorted capture inventory and SHA-256 hash of every Markdown file. `comparison.md` compares that inventory with the 29-entry DokuWiki export manifest.
Nothing in this directory is published by Starlight. This directory must never be moved or copied into `src/content/docs/` without a separate content review. It must also remain outside `public/`.

View file

@ -0,0 +1,76 @@
# Export and live-wiki comparison
This is a research inventory, not a merge decision. It compares the 98 successful pages in `manifest.json` with all 29 source entries in `docs/migration-manifest.json`. The comparison is page-level: a live course page can be new-only even when its surrounding year/programme taxonomy overlaps an exported index page.
## New live-wiki pages with no exported page equivalent
These 88 successful live pages have no one-to-one page in the export. Course titles are listed so every captured course page is concretely classified rather than represented only by a count.
| Live route or family | Count | Captured pages | Classification |
| --- | ---: | --- | --- |
| `/computer-science` and `/computer-science/course-description` | 2 | Course Description (two routes with the same sparse content) | The export has no Computer Science programme page; its bachelor programme is Data Science and Artificial Intelligence. |
| `/computer-science/year-1/**` | 12 | Discrete Math; Introduction to Computer Science; Procedural Programming; Calculus; Logic; Objects in Programming; Computer Architecture; Data Structures and Algorithms; Linear Algebra; Databases; Algorithmic Design; Statistics | New course-level hierarchy organized by year and period; the export has no corresponding course pages. |
| `/computer-science/year-2/**` | 14 | Intelligent User Interfaces; Introduction to Artificial Intelligence; Operating Systems; Computer Networks; Software Engineering and Architectures; Computer Security; Embedded Programming; Parallel Programming; Numerical Methods; Principles of Programming Languages; M2-1: AI and Machine Learning; M2-1: Intelligent Interaction; M2-2: Cybersecurity; M2-2: High Performance Computing | New course/elective pages; no exported equivalents. |
| `/computer-science/year-3/**` | 16 | Digital Society; Game Theory; Graph Theory; Introduction to Quantum Computing; Robotics and Embedded Systems; Ubiquitous Computing & Internet of Things; Block Chains; Cryptography; Immersive Technologies; Introduction to Bio-Informatics; Large Scale IT and Cloud Computing; Software and Systems Verification; Startup Engineering: Building Scalable Tech Ventures; The History and Philosophy of Computing; Operating Systems; Theory of Computing | New course/elective pages; no exported equivalents. |
| `/data-science-and-artificial-intelligence/year-1/**` | 12 | Discrete Mathematics; Introduction to Data Science and Artificial Intelligence; Procedural Programming; Calculus; Logic; Objects in Programming; Data Structures and Algorithms; Linear Algebra; Principles of Data Science; Computational and Cognitive Neuroscience; Numerical Methods; Software Engineering | The exported Year 1 page is only a schedule/index shell and has no individual course pages. |
| `/data-science-and-artificial-intelligence/year-2/**` | 13 | Databases; Graph Theory; Probability and Statistics; Machine Learning; Reasoning Techniques; Simulation and Statistical Analysis; Human Computer Interaction & Affective Computing; Mathematical Modelling; Natural Language Processing; Game Theory; Introduction to Image & Video Processing; Linear Programming; Philosophy & Artificial Intelligence | The exported Year 2 branch contains projects and an honours placeholder, not these course pages. |
| `/data-science-and-artificial-intelligence/year-3/**` | 16 | Digital Society; Game Theory; Introduction to Quantum Computing; Multi-Scale Modelling of Biological Systems; Robotics and Embedded Systems; Semantic Web; Business Process & Knowledge Management; Computer Security; Introduction to Bio-Informatics; Large Scale IT and Cloud Computing; Logic for Artificial Intelligence; Parallel Programming; Recommender Systems; Data Analysis; Intelligent Systems; Operations Research | The exported Year 3 branch contains thesis/project/study-abroad material, not these course pages. |
| `/useful-guides/housing-guide` | 1 | Housing Guide | New 2025 housing-market and scam-avoidance guide; the exported Handy Locations page only names study/food-location categories. |
| `/useful-guides/linux-tricks` | 1 | Linux Tricks | Linux-specific Eduroam, VPN, file-service, and remote-desktop advice; there is no matching exported page. |
| `/useful-guides/survivingdacs` | 1 | DACS Survival Guide | Broad study, projects, exams, programming, mathematics, and student-life advice; there is no one-to-one export page. |
## Exported pages with no obvious live-wiki page equivalent
All seven exported project pages are called out explicitly. Year landing pages are included because their apparent live category URLs are soft 404s; their taxonomy is compared separately below.
| Export source path | Exported topic | Evidence/classification |
| --- | --- | --- |
| `pages/study/msv_incognito.txt` | MSV Incognito association | The live home page links the association but has no association-history/membership page. |
| `pages/study/bachelor/year_1.txt` | Bachelor Year 1 index and schedule | No valid live Year 1 landing page; live leaf courses are a structural overlap only. |
| `pages/study/bachelor/year_1/project_1-1.txt` | Project 1-1 | Exported project page; no live project page. |
| `pages/study/bachelor/year_1/project_1-2.txt` | Project 1-2 | Exported project page; no live project page. |
| `pages/study/bachelor/year_2.txt` | Bachelor Year 2 index and schedule | No valid live Year 2 landing page; live leaf courses are a structural overlap only. |
| `pages/study/bachelor/year_2/honours_programme.txt` | Year 2 honours programme | No live honours page. |
| `pages/study/bachelor/year_2/project_2-1.txt` | Project 2-1 | Exported project page; no live project page. |
| `pages/study/bachelor/year_2/project_2-2.txt` | Project 2-2 | Exported project page; no live project page. |
| `pages/study/bachelor/year_3.txt` | Bachelor Year 3 index and schedule | No valid live Year 3 landing page; live leaf courses are a structural overlap only. |
| `pages/study/bachelor/year_3/bachelors_thesis.txt` | Bachelor thesis | No live thesis page. |
| `pages/study/bachelor/year_3/honours_programme.txt` | Year 3 honours programme | No live honours page. |
| `pages/study/bachelor/year_3/project_3-1.txt` | Project 3-1 | Exported project page; no live project page. |
| `pages/study/bachelor/year_3/study_abroad.txt` | Study abroad | No live study-abroad page. |
| `pages/study/master_ai/year_1.txt` | MSc AI Year 1 index | The live MSc AI branch has only a sparse course-description page and no year hierarchy. |
| `pages/study/master_ai/year_1/project_mai_1.txt` | MSc AI Research Project 1 | Exported project page; no live project page. |
| `pages/study/master_ai/year_1/project_mai_2.txt` | MSc AI Research Project 2 | Exported project page; no live project page. |
| `pages/study/master_ai/year_2.txt` | MSc AI Year 2 index | No live MSc AI Year 2 page. |
| `pages/study/master_dsdm/year_1.txt` | MSc DSDM Year 1 index | The live DSDM branch has only a sparse course-description page and no year hierarchy. |
| `pages/study/master_dsdm/year_2.txt` | MSc DSDM Year 2 index | No live DSDM Year 2 page. |
| `pages/study/useful_information/pages/dke_locations.txt` | DKE/DACS teaching locations | No live locations page. |
| `pages/study/useful_information/pages/handy_locations.txt` | Study, food, and other locations | The Housing Guide is materially different and is not an equivalent. |
| `pages/study/useful_information/pages/it_services.txt` | General UM IT services | Linux Tricks overlaps a few technologies but is Linux-specific and not a replacement for the exported service-desk, portal, enrolment, grades, VPN, and printing page. |
## Overlapping topics and substantive differences
| Export source path | Live URL | Substantive difference |
| --- | --- | --- |
| `pages/start.txt` + `pages/study.txt` | `https://wiki.msvincognito.nl/` | The export has association/registration/editing instructions, official links, Maastricht University context, and programme descriptions. The live home is a short DACS landing page linking four programme areas and Useful Guides. |
| `pages/study/bachelor.txt` | `https://wiki.msvincognito.nl/data-science-and-artificial-intelligence` and `/course-description` | Both identify the Data Science and Artificial Intelligence bachelor area. The export explains the programme index and contribution workflow; both live routes currently contain only a sparse “Course Description / #Hello” page. |
| `pages/study/bachelor/year_1.txt` | `https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-1/discrete-mathematics` (representative of 12 Year 1 leaf pages) | The export is a year index with a missing schedule image and page-creation controls. The live wiki has period/course leaf pages but its Year 1 and period category URLs render soft 404s. |
| `pages/study/bachelor/year_2.txt` | `https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-1/databases` (representative of 13 Year 2 leaf pages) | The export is a schedule/index shell plus upload instructions. The live wiki replaces that organization with period/elective course leaves and no valid Year 2 landing page. |
| `pages/study/bachelor/year_3.txt` | `https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-4/data-analysis` (representative of 16 Year 3 leaf pages) | The export discusses thesis timing and indexes thesis/project/study-abroad pages. The live branch lists course/elective leaves and contains no thesis or project page. |
| `pages/study/master_ai.txt` | `https://wiki.msvincognito.nl/artificial-intelligence` and `/course-description` | Both label the MSc Artificial Intelligence area. The export describes course summaries, exams, year navigation, and contribution flow; the live routes are currently a sparse “Course Description / #Hello” page with no year/course content. |
| `pages/study/master_dsdm.txt` | `https://wiki.msvincognito.nl/data-science-for-decision-making` and `/course-description` | Both label the MSc Data Science for Decision Making area. The export has year navigation and contribution context; the live routes contain only the sparse description placeholder. |
| `pages/study/useful_information.txt` | `https://wiki.msvincognito.nl/useful-guides` and `/description` | The export indexes locations, IT services, and laptop advice. The live index instead presents Housing, Laptop Buying Advice, Linux Tricks, and Surviving DACS, and claims the guides are updated “somewhat regularly.” |
| `pages/study/useful_information/pages/laptop_buy_advice.txt` | `https://wiki.msvincognito.nl/useful-guides/laptop-buying-advice` | The live page preserves and edits the exported tier guide, marks it as last updated 2021, and adds a current minimum of 16 GB RAM/512 GB SSD, Apple M-series compatibility, and an Nvidia/CUDA recommendation for data-science programmes. |
## Navigation placeholders excluded from the capture
Public navigation enumerated 31 category URLs that return HTTP 200 but render exactly `404` and `This page could not be found.` They are navigation/taxonomy placeholders, not content pages, so the crawler excludes them and `manifest.json` has no failures. All leaf pages reachable through the same public navigation were retained.
| Route family | Excluded count | Exact category suffixes |
| --- | ---: | --- |
| `/computer-science/year-1` | 5 | year root; `period-1`; `period-2`; `period-4`; `period-5` |
| `/computer-science/year-2` | 7 | year root; `period-1`; `period-2`; `period-4`; `period-5`; `semester-1-electives`; `semester-2-electives` |
| `/computer-science/year-3` | 4 | year root; `period-1-electives`; `period-2-electives`; `period-4` |
| `/data-science-and-artificial-intelligence/year-1` | 5 | year root; `period-1`; `period-2`; `period-4`; `period-5` |
| `/data-science-and-artificial-intelligence/year-2` | 6 | year root; `period-1`; `period-2`; `period-4`; `period-5`; `period-5-electives` |
| `/data-science-and-artificial-intelligence/year-3` | 4 | year root; `period-1-electives`; `period-2-electives`; `period-4` |

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/artificial-intelligence
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/artificial-intelligence/course-description
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/course-description
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-1/discrete-math
> Captured: 2026-08-02
# Discrete Math
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-1/discrete-math.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-1/introduction-to-computer-science
> Captured: 2026-08-02
# Introduction to Computer Science
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-1/introduction-to-computer-science.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-1/procedural-programming
> Captured: 2026-08-02
# Procedural Programming
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-1/procedural-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-2/calculus
> Captured: 2026-08-02
# Calculus
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-2/calculus.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-2/logic
> Captured: 2026-08-02
# Logic
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-2/logic.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-2/objects-in-programming
> Captured: 2026-08-02
# Objects in Programming
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-2/objects-in-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-4/computer-architecture
> Captured: 2026-08-02
# Computer Architecture
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-4/computer-architecture.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-4/data-structures-and-algorithms
> Captured: 2026-08-02
# Data Structures and Algorithms
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-4/data-structures-and-algorithms.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-4/linear-algebra
> Captured: 2026-08-02
# Linear Algebra
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-4/linear-algebra.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-5/databases
> Captured: 2026-08-02
# Databases
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-5/databases.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-5/discrete-math
> Captured: 2026-08-02
# Algorithmic Design
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-5/discrete-math.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-1/period-5/statistics
> Captured: 2026-08-02
# Statistics
##### Empty Page
Start writing in `content/1.computer-science/year-1/period-5/statistics.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-1/intelligent-user-interfaces
> Captured: 2026-08-02
# Intelligent User Interfaces
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-1/intelligent-user-interfaces.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-1/introduction-to-artificial-intelligence
> Captured: 2026-08-02
# Introduction to Artificial Intelligence
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-1/introduction-to-artificial-intelligence.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-1/operating-systems
> Captured: 2026-08-02
# Operating Systems
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-1/operating-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-2/computer-networks
> Captured: 2026-08-02
# Computer Networks
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-2/computer-networks.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-2/software-engineering-and-architectures
> Captured: 2026-08-02
# Software Engineering and Architectures
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-2/software-engineering-and-architectures.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-4/computer-security
> Captured: 2026-08-02
# Computer Security
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-4/computer-security.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-4/embedded-programming
> Captured: 2026-08-02
# Embedded Programming
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-4/embedded-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-4/parallel-programming
> Captured: 2026-08-02
# Parallel Programming
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-4/parallel-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-5/numerical-methods
> Captured: 2026-08-02
# Numerical Methods
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-5/numerical-methods.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/period-5/principles-of-programming-languages
> Captured: 2026-08-02
# Principles of Programming Languages
##### Empty Page
Start writing in `content/1.computer-science/year-2/period-5/principles-of-programming-languages.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/semester-1-electives/ai-and-machine-learning
> Captured: 2026-08-02
# M2-1: AI and Machine Learning
##### Empty Page
Start writing in `content/1.computer-science/year-2/semester-1-electives/ai-and-machine-learning.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/semester-1-electives/intelligent-interaction
> Captured: 2026-08-02
# M2-1: Intelligent Interaction
##### Empty Page
Start writing in `content/1.computer-science/year-2/semester-1-electives/intelligent-interaction.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/semester-2-electives/cybersecurity
> Captured: 2026-08-02
# M2-2: Cybersecurity
##### Empty Page
Start writing in `content/1.computer-science/year-2/semester-2-electives/cybersecurity.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-2/semester-2-electives/high-performance-computing
> Captured: 2026-08-02
# M2-2: High Performance Computing
##### Empty Page
Start writing in `content/1.computer-science/year-2/semester-2-electives/high-performance-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/digital-society
> Captured: 2026-08-02
# Digital Society
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/digital-society.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/game-theory
> Captured: 2026-08-02
# Game Theory
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/game-theory.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/graph-theory
> Captured: 2026-08-02
# Graph Theory
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/graph-theory.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/introduction-to-quantum-computing
> Captured: 2026-08-02
# Introduction to Quantum Computing
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/introduction-to-quantum-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/robotics-and-embedded-systems
> Captured: 2026-08-02
# Robotics and Embedded Systems
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/robotics-and-embedded-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-1-electives/ubiquitous-computing-iot
> Captured: 2026-08-02
# Ubiquitous Computing & Internet of Things
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-1-electives/ubiquitous-computing-iot.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/block-chains
> Captured: 2026-08-02
# Block Chains
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/block-chains.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/cryptography
> Captured: 2026-08-02
# Cryptography
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/cryptography.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/immersive-technologies
> Captured: 2026-08-02
# Immersive Technologies
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/immersive-technologies.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/introduction-to-bio-informatics
> Captured: 2026-08-02
# Introduction to Bio-Informatics
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/introduction-to-bio-informatics.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/large-scale-it-and-cloud-computing
> Captured: 2026-08-02
# Large Scale IT and Cloud Computing
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/large-scale-it-and-cloud-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/software-and-systems-verification
> Captured: 2026-08-02
# Software and Systems Verification
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/software-and-systems-verification.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-2-electives/startup-engineering
> Captured: 2026-08-02
# Startup Engineering: Building Scalable Tech Ventures
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-2-electives/startup-engineering.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-4/history-and-philosophy-of-computing
> Captured: 2026-08-02
# The History and Philosophy of Computing
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-4/history-and-philosophy-of-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-4/operating-systems
> Captured: 2026-08-02
# Operating Systems
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-4/operating-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/computer-science/year-3/period-4/theory-of-computing
> Captured: 2026-08-02
# Theory of Computing
##### Empty Page
Start writing in `content/1.computer-science/year-3/period-4/theory-of-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/course-description
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-1/discrete-mathematics
> Captured: 2026-08-02
# Discrete Mathematics
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-1/discrete-mathematics.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-1/introduction-to-data-science-and-ai
> Captured: 2026-08-02
# Introduction to Data Science and Artificial Intelligence
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-1/introduction-to-data-science-and-ai.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-1/procedural-programming
> Captured: 2026-08-02
# Procedural Programming
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-1/procedural-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-2/calculus
> Captured: 2026-08-02
# Calculus
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-2/calculus.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-2/logic
> Captured: 2026-08-02
# Logic
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-2/logic.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-2/objects-in-programming
> Captured: 2026-08-02
# Objects in Programming
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-2/objects-in-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-4/data-structures-and-algorithms
> Captured: 2026-08-02
# Data Structures and Algorithms
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-4/data-structures-and-algorithms.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-4/linear-algebra
> Captured: 2026-08-02
# Linear Algebra
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-4/linear-algebra.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-4/principles-of-data-science
> Captured: 2026-08-02
# Principles of Data Science
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-4/principles-of-data-science.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-5/computational-and-cognitive-neuroscience
> Captured: 2026-08-02
# Computational and Cognitive Neuroscience
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-5/computational-and-cognitive-neuroscience.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-5/numerical-methods
> Captured: 2026-08-02
# Numerical Methods
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-5/numerical-methods.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-1/period-5/software-engineering
> Captured: 2026-08-02
# Software Engineering
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-1/period-5/software-engineering.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-1/databases
> Captured: 2026-08-02
# Databases
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-1/databases.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-1/graph-theory
> Captured: 2026-08-02
# Graph Theory
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-1/graph-theory.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-1/probability-and-statistics
> Captured: 2026-08-02
# Probability and Statistics
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-1/probability-and-statistics.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-2/machine-learning
> Captured: 2026-08-02
# Machine Learning
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-2/machine-learning.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-2/reasoning-techniques
> Captured: 2026-08-02
# Reasoning Techniques
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-2/reasoning-techniques.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-2/simulation-and-statistical-analysis
> Captured: 2026-08-02
# Simulation and Statistical Analysis
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-2/simulation-and-statistical-analysis.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-4/human-computer-interaction-affective-computing
> Captured: 2026-08-02
# Human Computer Interaction & Affective Computing
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-4/human-computer-interaction-affective-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-4/mathematical-modelling
> Captured: 2026-08-02
# Mathematical Modelling
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-4/mathematical-modelling.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-4/natural-language-processing
> Captured: 2026-08-02
# Natural Language Processing
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-4/natural-language-processing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-5-electives/game-theory
> Captured: 2026-08-02
# Game Theory
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-5-electives/game-theory.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-5-electives/introduction-to-image-video-processing
> Captured: 2026-08-02
# Introduction to Image & Video Processing
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-5-electives/introduction-to-image-video-processing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-5/linear-programming
> Captured: 2026-08-02
# Linear Programming
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-5/linear-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-2/period-5/philosophy-and-artificial-intelligence
> Captured: 2026-08-02
# Philosophy & Artificial Intelligence
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-2/period-5/philosophy-and-artificial-intelligence.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/digital-society
> Captured: 2026-08-02
# Digital Society
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/digital-society.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/game-theory
> Captured: 2026-08-02
# Game Theory
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/game-theory.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/introduction-to-quantum-computing
> Captured: 2026-08-02
# Introduction to Quantum Computing
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/introduction-to-quantum-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/multi-scale-modelling-biological-systems
> Captured: 2026-08-02
# Multi-Scale Modelling of Biological Systems
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/multi-scale-modelling-biological-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/robotics-and-embedded-systems
> Captured: 2026-08-02
# Robotics and Embedded Systems
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/robotics-and-embedded-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-1-electives/semantic-web
> Captured: 2026-08-02
# Semantic Web
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-1-electives/semantic-web.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/business-process-knowledge-management
> Captured: 2026-08-02
# Business Process & Knowledge Management
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/business-process-knowledge-management.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/computer-security
> Captured: 2026-08-02
# Computer Security
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/computer-security.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/introduction-to-bio-informatics
> Captured: 2026-08-02
# Introduction to Bio-Informatics
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/introduction-to-bio-informatics.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/large-scale-it-and-cloud-computing
> Captured: 2026-08-02
# Large Scale IT and Cloud Computing
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/large-scale-it-and-cloud-computing.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/logic-for-artificial-intelligence
> Captured: 2026-08-02
# Logic for Artificial Intelligence
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/logic-for-artificial-intelligence.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/parallel-programming
> Captured: 2026-08-02
# Parallel Programming
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/parallel-programming.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-2-electives/recommender-systems
> Captured: 2026-08-02
# Recommender Systems
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-2-electives/recommender-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-4/data-analysis
> Captured: 2026-08-02
# Data Analysis
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-4/data-analysis.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-4/intelligent-systems
> Captured: 2026-08-02
# Intelligent Systems
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-4/intelligent-systems.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-and-artificial-intelligence/year-3/period-4/operations-research
> Captured: 2026-08-02
# Operations Research
##### Empty Page
Start writing in `content/2.data-science-and-artificial-intelligence/year-3/period-4/operations-research.md` to see this page taking shape.

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-for-decision-making
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,8 @@
> Source: https://wiki.msvincognito.nl/data-science-for-decision-making/course-description
> Captured: 2026-08-02
# Course Description
#Hello
#Hello

View file

@ -0,0 +1,14 @@
> Source: https://wiki.msvincognito.nl/
> Captured: 2026-08-02
[🎒
Just moved in? Check out our guides for helpful informationJust moved in? Check out our guides for helpful information](https://wiki.msvincognito.nl/useful-guides)
# Welcome to the Incognito Wiki!
The comprehensive knowledge base for DACS students at Maastricht University.<br>
Find course materials, exam resources, study guides, and everything you need to succeed in your DACS journey.<br>
<br>
[](https://wiki.msvincognito.nl/computer-science)[](https://wiki.msvincognito.nl/data-science-and-artificial-intelligence)[](https://wiki.msvincognito.nl/artificial-intelligence)[](https://wiki.msvincognito.nl/data-science-for-decision-making)[](https://wiki.msvincognito.nl/useful-guides)

View file

@ -0,0 +1,50 @@
> Source: https://wiki.msvincognito.nl/useful-guides
> Captured: 2026-08-02
# Useful Guides
Essential resources and tips for your academic journey at Maastricht University
Welcome to the **Useful Guides** section of the Incognito Wiki! This collection contains practical resources and tips to help you navigate your academic journey and student life at **Maastricht University**.
[
### Housing Guide
Essential information for finding accommodation in **Maastricht**. Navigate the housing market, understand rental agreements, and discover the best neighborhoods for students.
](https://wiki.msvincognito.nl/useful-guides/housing-guide)
[
### Laptop Buying Advice
Recommendations for choosing the right laptop for your studies. Get insights on specifications, brands, and budget considerations tailored for **DACS students**.
](https://wiki.msvincognito.nl/useful-guides/laptop-buying-advice)
[
### Linux Tricks
Helpful tips and commands for working with **Linux systems**. Master the command line, learn essential shortcuts, and boost your productivity.
](https://wiki.msvincognito.nl/useful-guides/linux-tricks)
[
### Surviving DACS
Insider tips for making the most of your time in the **Department of Data Science & Knowledge Engineering**. Study strategies, course insights, and academic advice.
](https://wiki.msvincognito.nl/useful-guides/survivingdacs)
These guides are created by fellow students and updated somewhat regularly to ensure they remain relevant and helpful. Whether you're a first-year student just starting out or a senior looking for specific technical advice, you'll find valuable information here to support your academic success.

Some files were not shown because too many files have changed in this diff Show more