From 02b3745b88acf28103e05d84180820dcf3311595 Mon Sep 17 00:00:00 2001 From: Philippe Torrel Date: Thu, 1 Oct 2026 10:37:23 +0200 Subject: [PATCH] --- .../u25-26-csv-string-parsen/index.js | 22 +++++++ .../uebungen/u27_zlip/data/products.json.gz | Bin 0 -> 531 bytes 02_advanced/uebungen/u27_zlip/index.js | 46 ++++++++++++++- .../uebungen/u27_zlip/package-lock.json | 28 +++++++++ .../uebungen/u28_password-generator/index.js | 21 ++++++- 02_advanced/uebungen/u29_stream/index.js | 20 ++++++- 02_advanced/uebungen/u32_os-info/index.js | 55 ++++++++++++++++++ .../unterricht/tag18/01_csv-to-html/index.js | 14 +++-- 8 files changed, 197 insertions(+), 9 deletions(-) create mode 100644 02_advanced/uebungen/u27_zlip/data/products.json.gz create mode 100644 02_advanced/uebungen/u27_zlip/package-lock.json diff --git a/02_advanced/uebungen/u25-26-csv-string-parsen/index.js b/02_advanced/uebungen/u25-26-csv-string-parsen/index.js index d5f1847..7e2827b 100644 --- a/02_advanced/uebungen/u25-26-csv-string-parsen/index.js +++ b/02_advanced/uebungen/u25-26-csv-string-parsen/index.js @@ -8,6 +8,28 @@ const quotedCSV = '"very big, soft computer mouse","the cutest peripheral ever", const mixedCSV = '"very big, soft computer mouse","the cutest peripheral ever",10,39.90'; +const parseCSVRecord = (record) => { + const fields = []; + let field = ''; + let inQuotes = false; + + for (const character of record) { + if (character === '"') { + inQuotes = !inQuotes; + } else if (character === ',' && !inQuotes) { + fields.push(field); + field = ''; + } else { + field += character; + } + } + + fields.push(field); + return fields; +}; + +console.log(parseCSVRecord(quotedCSV)); +console.log(parseCSVRecord(mixedCSV)); /* Übung 25: CSV-Datensätze mit Anführungszeichen Bisher haben wir die Felder in einem CSV-Datensatz einfach mit der Anweisung: diff --git a/02_advanced/uebungen/u27_zlip/data/products.json.gz b/02_advanced/uebungen/u27_zlip/data/products.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..914b3a2468261c31d74731b1f6ede4b239b02a3d GIT binary patch literal 531 zcmV+u0_^=CiwFP!000006OEL?ZWJ*LhF`_X38XEW>F$EsBQ50sRf|fwAP#Qgory^7 zQQ~wdh<8WX-AX%cXT>p!?R>xeJKz79GjU{2&E@UKrfJ@pnYrmDDV$Tb$q(v<&8e}n zS`k4k9jv|f@cHZ<0^L&p&(2#^NoHogVi!EuYE1W(06X*yiO}}2k_6flP#pB37BVyQ zr68-<2XktU8#6Q4$=jN}IC*o@n7^|zTs!|yxVunDMYKP%!c11l!7iptQrKn47MUq+ zsIaI+RR5b?J!@eCr4T%KBTYlmje;C8DR@?SteObjHhN0Y$x}sF7Z>w(v7Ase5O1Xn ziH_EoB02E<6J9Chsz!K2awA21xRyY#N2K+xmhc&(?|SuAdym^BE5VIPm;0p0Pf5?N zF59MQCrB~gc}KrANy%U(4n-+Jl#*$LMC>-NJ8u=0KvocFrGV@pRmL$=yN}eqfYdCS z#RSp^%$0$<{jq%qih-*qpHayfrHLG`IRUiPpk zqRofNwjmYnG5avx$ZF5F{OWzPTu$x8X6=Svn80GD-KrNK^vE-0n~3;@KPdW~0U=V( V*wKL@&bK%}{sHz~=C>0C005En1qA>A literal 0 HcmV?d00001 diff --git a/02_advanced/uebungen/u27_zlip/index.js b/02_advanced/uebungen/u27_zlip/index.js index 14b70e6..5c9c5ec 100644 --- a/02_advanced/uebungen/u27_zlip/index.js +++ b/02_advanced/uebungen/u27_zlip/index.js @@ -3,8 +3,52 @@ import zlib from 'node:zlib'; import color from 'chalk'; const data = fs.readFileSync('data/products.csv', 'utf-8'); +const products = data.split('\n'); +const header = products.shift().split(','); +// console.log('header', header); // => Code,Short Description,Tagline,Quantity,Price -const convertCsvToJson = (products, ar) => {}; +const convertCsvToJson = (productRow) => { + // console.log('products', products); + // console.log('ar', ar); + + const cols = productRow.split(/\s*,\s*/); + // console.log(product); + // let obj = {}; + + // for (let i = 0; i < header.length; i++) { + // obj[header[i]] = cols[i]; + // } + + const product = header.reduce((obj, str, idx) => { + obj[str] = cols[idx]; + return obj; + }, {}); + + return product; +}; + +const entries = products + .filter((row) => row !== '') // + .map(convertCsvToJson); +console.log(entries); + +// fs.writeFile('a.json', JSON.stringify(entries), 'UTF-8', (err) => { +// console.warn(err); +// }); + +const compressedData = zlib.gzipSync(JSON.stringify(entries)); +try { + fs.writeFileSync('data/products.json.gz', compressedData); + console.log('compressed file'); +} catch (err) { + console.error(err); +} + +/* +Übung 27: Ohne Umwege + +Die Datei products.csv soll in eine products.json umgewandelt werden und in products.json.gz komprimiert werden. +*/ /* Übung 27: Ohne Umwege diff --git a/02_advanced/uebungen/u27_zlip/package-lock.json b/02_advanced/uebungen/u27_zlip/package-lock.json new file mode 100644 index 0000000..7f4d4f9 --- /dev/null +++ b/02_advanced/uebungen/u27_zlip/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "u27_zlib", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "u27_zlib", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chalk": "^6.0.1" + } + }, + "node_modules/chalk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-6.0.1.tgz", + "integrity": "sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + } + } +} diff --git a/02_advanced/uebungen/u28_password-generator/index.js b/02_advanced/uebungen/u28_password-generator/index.js index e565896..3335622 100644 --- a/02_advanced/uebungen/u28_password-generator/index.js +++ b/02_advanced/uebungen/u28_password-generator/index.js @@ -1,16 +1,31 @@ // const crypto = require('node:crypto'); import crypto from 'node:crypto'; +import _ from 'lodash'; const PASSWORD_LENGTH = 10; const s = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ!.,;#$%/+*'; const buf = crypto.randomBytes(PASSWORD_LENGTH); + +console.log('s.length:', s.length); // => 64 +console.log('buf:', buf); // => +console.log('Array:', Array.from(buf)); // => [ 17, 181, 126, 182, 190, 212, 137, 233, 140, 75] const password = Array.from(buf) - .map((byte) => s.charAt(byte % s.length)) + .map((byte) => s.charAt(byte % s.length)) // => kZ+!+pbMed .join(''); console.log(password); +const generatePassword = (length) => { + const chars = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ!.,;#$%/+*'.split(''); + return _.shuffle(chars) + .slice(0, length + 1) + .join(''); +}; + +const pwd = generatePassword(10); +console.log('Password: ', pwd); + // Übung 28: Passwortgenerator // Was macht der folgende Code? @@ -18,3 +33,7 @@ console.log(password); // OK: Der Titel verrät es schon. Versuche dennoch, das Programm zu verstehen! Benutze die Dokumentation der Standardbibliothek, um nachzuschlagen, was crypto.randomBytes(…) genau macht! // Bonusfrage: Warum sind in den Zeichen «1», «i» und «l» nicht enthalten, genau so wenig wie «0» und «o»? + +// const asciiLetters = Array.from({ length: 26 }, (_, i) => +// String.fromCharCode(65 + i) + String.fromCharCode(97 + i) +// ).join(''); // "AaBbCc..." oder getrennt sortieren diff --git a/02_advanced/uebungen/u29_stream/index.js b/02_advanced/uebungen/u29_stream/index.js index ca3e922..6891431 100644 --- a/02_advanced/uebungen/u29_stream/index.js +++ b/02_advanced/uebungen/u29_stream/index.js @@ -8,9 +8,13 @@ const gzipCompressor = zlib.createGzip(); const inputStream = fs.createReadStream('data/products.html'); const outputStream = fs.createWriteStream('data/products.html.gz'); -inputStream.on('data', (data) => { - console.log('Pakete (data chunks) werden geladen: ', data.length); - outputStream.write(zlib.gzipSync(data)); +inputStream.on('data', (chunk) => { + console.log('Pakete (data chunks) werden geladen: ', chunk.length); + // outputStream.write(zlib.gzipSync(data)); +}); + +outputStream.on('finish', () => { + console.log('Process finished'); }); inputStream.pipe(gzipCompressor).pipe(outputStream); @@ -21,3 +25,13 @@ inputStream.pipe(gzipCompressor).pipe(outputStream); // TIPP: Um eine Datei päckchenweise lesen- und schreiben zu können, gibt es für das fs Modul die Methoden createReadStream und createWriteStream. // ÜBUNG BEREITS GELÖST!!! + +// Die wichtigsten WritableStream-Events im Überblick + +// - 'finish': Feuert, nachdem stream.end() aufgerufen wurde und alle gepufferten Daten erfolgreich auf das Ziellaufwerk geschrieben wurden. + +// - 'close': Feuert, wenn der zugrundeliegende File Descriptor / die Ressource vollständig geschlossen wurde. + +// - 'drain': Feuert, wenn der interne Puffer voll war (write() gab false zurück) und nun wieder bereit für neue Daten ist. + +// - 'error': Feuert, wenn beim Schreiben ein Fehler auftritt (z. B. fehlende Schreibrechte oder volle Festplatte). diff --git a/02_advanced/uebungen/u32_os-info/index.js b/02_advanced/uebungen/u32_os-info/index.js index 9bef6b1..478300a 100644 --- a/02_advanced/uebungen/u32_os-info/index.js +++ b/02_advanced/uebungen/u32_os-info/index.js @@ -1,3 +1,58 @@ +import os from 'node:os'; + +console.log(os.platform()); +console.log(os.cpus().length); + +console.log(`I am running on a machine with ${os.platform()} and ${os.cpus().length} cores.`); +console.log(`I am running on a machine with ${os.type()} and ${os.cpus().length} cores.`); +console.log(`I am running on a machine with ${os.version()} and ${os.cpus().length} cores.`); + +// Weitere Informationen zum Betriebssystem +console.log('\n--- Betriebssystem ---'); +console.log('Systemtyp:', os.type()); +console.log('Systemversion:', os.release()); +console.log('Architektur von Node.js:', os.arch()); +console.log('Computername:', os.hostname()); + +// os.cpus() liefert Informationen zu den logischen CPU-Kernen. +const cpus = os.cpus(); +console.log('\n--- Prozessor ---'); +console.log('Logische CPU-Kerne:', cpus.length); +console.log('CPU-Modell:', cpus[0]?.model ?? 'Unbekannt'); + +// Die Speicherangaben kommen in Bytes. 1024 ** 3 Bytes entsprechen einem GiB. +const totalMemory = os.totalmem(); +const freeMemory = os.freemem(); +const usedMemory = totalMemory - freeMemory; + +function formatMemory(bytes) { + return `${(bytes / 1024 ** 3).toFixed(2)} GiB`; +} + +console.log('\n--- Arbeitsspeicher ---'); +console.log('Gesamt:', formatMemory(totalMemory)); +console.log('Frei:', formatMemory(freeMemory)); +console.log('Belegt:', formatMemory(usedMemory)); + +// os.uptime() gibt die Laufzeit des Betriebssystems in Sekunden zurück. +const uptime = os.uptime(); +const hours = Math.floor(uptime / 3600); +const minutes = Math.floor((uptime % 3600) / 60); +console.log(`\nSystemlaufzeit: ${hours} Stunden und ${minutes} Minuten`); + +console.log('\n--- Benutzer und Verzeichnisse ---'); +console.log('Benutzername:', os.userInfo().username); +console.log('Home-Verzeichnis:', os.homedir()); +console.log('Temporäres Verzeichnis:', os.tmpdir()); + +// Jede Netzwerkschnittstelle kann mehrere IPv4- und IPv6-Adressen haben. +console.log('\n--- Netzwerkschnittstellen ---'); +for (const [name, addresses] of Object.entries(os.networkInterfaces())) { + for (const address of addresses ?? []) { + console.log(`${name}: ${address.address} (${address.family}${address.internal ? ', intern' : ''})`); + } +} + // Übung 32: Information zum Betriebssystem und der Anzahl der vorhandenen CPUs // Im Kontext einer Monitoring-Lösung benötigt ein Kunde eine kleine CLI (Command Line Interface)-Anwendung, die es erlaubt, das aktuelle Betriebssystem und die Anzahl der CPUs auf dem jeweiligen Rechner zu ermitteln. diff --git a/02_advanced/unterricht/tag18/01_csv-to-html/index.js b/02_advanced/unterricht/tag18/01_csv-to-html/index.js index f33e264..0461338 100644 --- a/02_advanced/unterricht/tag18/01_csv-to-html/index.js +++ b/02_advanced/unterricht/tag18/01_csv-to-html/index.js @@ -5,7 +5,15 @@ import color from 'chalk'; // VARS ========= const STOCK_WARN_AMOUNT = 5; -const data = fs.readFileSync('data/products.csv', 'utf-8'); +let data = ''; + +try { + data = fs.readFileSync('data/products.csv', 'utf-8'); +} catch (error) { + console.log(color.red(error)); + // Beendet den Prozess erfolgreich (Code 0) + process.exit(0); +} const products = data.split('\n'); const headerAr = products.shift().split(/\s*,\s*/); // => [ 'Code', 'Short Description', 'Tagline', 'Quantity', 'Price' ] @@ -60,9 +68,7 @@ const writeHtmlDocument = (content = '') => { const listItems = products .filter((row) => row !== '') // leere String Einträge rausfiltern - .map((row) => { - return recordToHtml(row); - }); + .map(recordToHtml); // Funktionsreferenz const htmlList = `
    ${listItems.join('')}
`;