From 6567b4e9666dad5c3ef116ab9a7816571ff8877f Mon Sep 17 00:00:00 2001 From: Adam Skotarczak Date: Wed, 28 May 2025 11:56:44 +0000 Subject: [PATCH 1/5] add-plesk-login --- dokus/plesk/plesk-benutzer-schon-vorhanden.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 dokus/plesk/plesk-benutzer-schon-vorhanden.md diff --git a/dokus/plesk/plesk-benutzer-schon-vorhanden.md b/dokus/plesk/plesk-benutzer-schon-vorhanden.md new file mode 100644 index 0000000..f5ff62a --- /dev/null +++ b/dokus/plesk/plesk-benutzer-schon-vorhanden.md @@ -0,0 +1,31 @@ +# Plesk ausgesperrt bei Rechnerwechsel + +**Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70 + +Bei Plesk gibt es manchmal die gloreiche Meldung: + +> Sie konnten nicht angemeldet werden. +Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.` + +Ärgerlich wenn das gerade der Adminzugang ist. +Falls Du gerade noch SSH Zugang hast dann: + +login und wechsel zum root, anschliessend: + + ```bash + plesk db "DELETE FROM sessions WHERE login = 'admin';" + ``` + +oder + + ```bash + mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';" + ``` + +anschliessend: + + ```bash + systemctl restart psa + ``` + +und dann ganz normal Login wie gewohnt. From beb1c8c9ed06e763dac22135d0b82959f367ef7b Mon Sep 17 00:00:00 2001 From: "Adam Skotarczak (DEVELOP-WSL)" Date: Tue, 3 Jun 2025 23:34:49 +0200 Subject: [PATCH 2/5] js-ts + tools --- .gitignore | 1 + README.md | 23 +- dokus/js-ts/js-ts-dialekte.md | 345 ++++++++++++++ package-lock.json | 499 +++++++++++++++++++- package.json | 18 +- tools/collector/config.jsonc | 9 +- tools/collector/link_collector.js | 188 ++++++++ tools/collector/processed.log | 2 + tools/src/collector/config.jsonc.template | 16 + tools/{ => src}/collector/link_collector.ts | 13 +- tools/src/fscopy.ts | 80 ++++ tools/src/fsdel.ts | 41 ++ tsconfig.json | 11 + 13 files changed, 1225 insertions(+), 21 deletions(-) create mode 100644 dokus/js-ts/js-ts-dialekte.md create mode 100644 tools/collector/link_collector.js create mode 100644 tools/src/collector/config.jsonc.template rename tools/{ => src}/collector/link_collector.ts (95%) create mode 100644 tools/src/fscopy.ts create mode 100644 tools/src/fsdel.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 6148b02..8ea5748 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode/ node_modules/ +dist/ diff --git a/README.md b/README.md index e547849..ec582fd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,10 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr - [Markdown](#markdown) - [Mermaid](#mermaid) - [Server](#server) + - [Plesk](#plesk) - [Webserver](#webserver) + - [Programmierung](#programmierung) + - [ts - js - node](#ts---js---node) - [Neue Dokumente](#neue-dokumente) --- @@ -28,14 +31,14 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr ### AsciiDoc -- [Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md) +- [Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md) --- ### Git - [Artikel: git](dokus/git/git.md) - - [SSH-Zugriff auf Git-Repository in WSL einrichten](dokus/git/git-ssh-remote.md) + - [SSH-Zugriff auf Git-Repository in WSL einrichten](dokus/git/git-ssh-remote.md) - [Git – Remote-Branches: Häufige Aufgaben und Lösungen](dokus/git/git-remote-branch.md) ### Markdown @@ -46,14 +49,24 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr ### Server +#### Plesk + +- [Plesk ausgesperrt bei Rechnerwechsel](dokus/plesk/plesk-benutzer-schon-vorhanden.md) + #### Webserver -- [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](dokus/apache-plesk/lets-encrypt-plesk.md) +- [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](dokus/apache-plesk/lets-encrypt-plesk.md) --- +### Programmierung + +#### ts - js - node + +- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md) + ## Neue Dokumente -> führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) aus um nach neuen Dateien zu suchen! +> führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) oder `npm run scan` aus um nach neuen Dateien zu suchen! -**NEUE EINTRÄGE AUS './tools/collector/link_collector.py'->** +**NEUE EINTRÄGE AUS 'link_collector'->** diff --git a/dokus/js-ts/js-ts-dialekte.md b/dokus/js-ts/js-ts-dialekte.md new file mode 100644 index 0000000..b629570 --- /dev/null +++ b/dokus/js-ts/js-ts-dialekte.md @@ -0,0 +1,345 @@ +# Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration + +## ✨ Ziel dieses Dokuments + +Diese Anleitung richtet sich an Anfänger, die lernen wollen, wann sie welchen JavaScript-Dialekt (CommonJS vs. ESM) verwenden sollten, wie sie TypeScript korrekt konfigurieren und worauf sie bei modernen Projekten achten müssen. + +## Inhalt + +- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](#einstieg-in-javascript-dialekte-und-typescript-konfiguration) + - [✨ Ziel dieses Dokuments](#-ziel-dieses-dokuments) + - [Inhalt](#inhalt) + - [🔢 Begriffe erklärt](#-begriffe-erklärt) + - [JavaScript-Dialekte (Modulsysteme)](#javascript-dialekte-modulsysteme) + - [Was ist TypeScript?](#was-ist-typescript) + - [🔍 Wann verwende ich was?](#-wann-verwende-ich-was) + - [🔧 TypeScript richtig konfigurieren](#-typescript-richtig-konfigurieren) + - [📦 Was ist ESM?](#-was-ist-esm) + - [✅ Wann kann/sollte/muss man **ESM** verwenden?](#-wann-kannsolltemuss-man-esm-verwenden) + - [🟢 **Du kannst ESM verwenden**, wenn](#-du-kannst-esm-verwenden-wenn) + - [🟡 **Du solltest ESM verwenden**, wenn](#-du-solltest-esm-verwenden-wenn) + - [🔴 **Du musst ESM verwenden**, wenn](#-du-musst-esm-verwenden-wenn) + - [⚙️ TypeScript-Konfiguration für ESM](#️-typescript-konfiguration-für-esm) + - [📌 Merkmale von ESM](#-merkmale-von-esm) + - [⚠️ Besonderheiten und Stolperfallen](#️-besonderheiten-und-stolperfallen) + - [✅ Fazit ESM](#-fazit-esm) + - [🌐 CommonJS-Konfiguration CJS (Alternative)](#-commonjs-konfiguration-cjs-alternative) + - [📦 Was ist CommonJS?](#-was-ist-commonjs) + - [✅ Wann kann/sollte/muss man **CommonJS** verwenden?](#-wann-kannsolltemuss-man-commonjs-verwenden) + - [🟢 **Du kannst CJS verwenden**, wenn](#-du-kannst-cjs-verwenden-wenn) + - [🟡 **Du solltest CJS verwenden**, wenn](#-du-solltest-cjs-verwenden-wenn) + - [🔴 **Du musst CJS verwenden**, wenn](#-du-musst-cjs-verwenden-wenn) + - [⚙️ TypeScript-Konfiguration für CJS](#️-typescript-konfiguration-für-cjs) + - [📌 Merkmale von CommonJS](#-merkmale-von-commonjs) + - [✅ Fazit CommonJS](#-fazit-commonjs) + - [📄 Fazit: Empfehlungen](#-fazit-empfehlungen) + - [📁 Dateiendungen in Node.js](#-dateiendungen-in-nodejs) + - [⚠️ Typische Fehler vermeiden](#️-typische-fehler-vermeiden) + - [🚀 CLI-Build-Tipps (tsc)](#-cli-build-tipps-tsc) + - [📍 Weiterführende Themen](#-weiterführende-themen) + +--- + +## 🔢 Begriffe erklärt + +### JavaScript-Dialekte (Modulsysteme) + +| Name | Kürzel | Typ | Verwendung heute | +| ------------------ | ------ | ----------- | ----------------------- | +| CommonJS | CJS | `require()` | Ältere Node.js-Projekte | +| ECMAScript Modules | ESM | `import` | Browser, moderne Tools | + +- **CommonJS:** Nutzt `require()` und `module.exports`. Standard bis Node 12. +- **ESM:** Nutzt `import`/`export`. Standard im Browser und in Node ab Version 14+. + +### Was ist TypeScript? + +TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird. + +--- + +## 🔍 Wann verwende ich was? + +| Ziel | Modulformat | Empfehlung | Grund | +| -------------------------- | ------------ | -------------- | ------------------------------------------ | +| 📅 Moderne Webanwendung | ESM | Ja | Browser erwartet ESM | +| 📄 Node.js CLI-Tool | ESM oder CJS | Beides möglich | ESM zukunftssicher, CJS maximal kompatibel | +| 🔐 Legacy-Node-Integration | CJS | Ja | Viele NPM-Pakete sind CJS-only | +| 🔌 Electron Renderer | ESM | Ja (Pflicht) | Chromium-only, kein CJS | +| 🔁 Vite/Webpack-Projekt | ESM | Ja | Toolchain basiert auf ESM | + +--- + +## 🔧 TypeScript richtig konfigurieren + +Eine vollständige Zusammenfassung zu **ESM (ECMAScript Modules)** – wann du es **verwenden kannst**, **solltest** oder **musst**, sowie alle wesentlichen technischen Eigenschaften. Stil und Umfang entsprechen exakt der vorherigen CommonJS-Zusammenfassung. + +--- + +### 📦 Was ist ESM? + +**ESM (ECMAScript Modules)** ist das moderne Modulsystem von JavaScript: + +- verwendet `import`/`export`-Syntax +- wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt +- ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.) + +```js +// ESM-Stil +import fs from 'node:fs/promises'; +export function read(path) { + return fs.readFile(path, 'utf-8'); +} +``` + +--- + +### ✅ Wann kann/sollte/muss man **ESM** verwenden? + +#### 🟢 **Du kannst ESM verwenden**, wenn + +- du mit **modernen Node.js-Versionen (v16+)** arbeitest +- du ein **Frontend-Tool** oder ein **Browser-kompatibles Projekt** baust +- du Tree-Shaking oder Dynamic `import()` nutzen willst +- du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort) + +#### 🟡 **Du solltest ESM verwenden**, wenn + +| Situation | Grund | +| ------------------------------------------------------------------- | ---------------------------- | +| 🌐 Du entwickelst Webanwendungen mit Vite, Nuxt, Webpack o. ä. | Diese Tools basieren auf ESM | +| 💡 Du möchtest moderne Syntax und Tooling nutzen | ESM ist Standard | +| 🔄 Du willst `import()` dynamisch verwenden | Nur in ESM verfügbar | +| 📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte | Zukunftssicherheit | +| 🧩 Du verwendest Deno, Bun oder moderne Plattformen | ESM only | + +#### 🔴 **Du musst ESM verwenden**, wenn + +- du im **Browser** arbeitest (ohne Bundler) → dort ist `import` Pflicht +- du in **Electron-Renderer-Prozessen** arbeitest +- du ein Projekt hast mit `"type": "module"` und `.js`-Dateien → dann interpretiert Node sie nur als ESM +- du ESM-only-Dependencies nutzt (z. B. `chalk@5`, `node-fetch@3`) + +--- + +### ⚙️ TypeScript-Konfiguration für ESM + +```jsonc +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + } +} +``` + +Und in der `package.json`: + +```json +{ + "type": "module" +} +``` + +**Wichtig:** Ohne `"type": "module"` behandelt Node deine `.js`-Dateien **nicht als ESM**, sondern als CommonJS. + +--- + +### 📌 Merkmale von ESM + +| Merkmal | ESM | +| ------------------------- | -------------------------------------------- | +| Import-Syntax | `import`, `export` | +| Export-Syntax | `export default`, `export {...}` | +| Dateiendung `.js` | **.js** nur mit `"type": "module"` | +| `.mjs` | explizit ESM | +| `__dirname`, `__filename` | ❌ nicht vorhanden, nur via `import.meta.url` | +| Dynamische Imports | ✅ `await import('...')` | +| Tree Shaking | ✅ möglich | +| Browser-kompatibel | ✅ nativ | +| CommonJS-Interop | ❗ mit Einschränkungen (`createRequire`) | + +--- + +### ⚠️ Besonderheiten und Stolperfallen + +| Problem | Lösung | +| --------------------------------------------- | ------------------------------------------- | +| ❌ `__dirname`/`__filename` fehlen | nutze `import.meta.url` + `fileURLToPath()` | +| ❌ `require()` nicht verfügbar | verwende `import`, oder `createRequire()` | +| ❌ `.js` muss beim Import angegeben werden | z. B. `import './utils.js'` | +| ❌ viele alte Pakete sind nicht ESM-kompatibel | ggf. CommonJS verwenden | + +--- + +### ✅ Fazit ESM + +> **ESM ist der offizielle Standard für moderne JavaScript-Entwicklung** – sowohl im Browser als auch in modernen Node.js-Umgebungen. + +Du solltest ESM verwenden, wenn du: + +- neue Projekte startest, +- moderne Toolchains nutzt, +- oder langfristige Kompatibilität willst. + +In Zweifelsfällen gilt: **Wenn du mit aktuellen Tools und Node-Versionen arbeitest, nimm ESM.** +Nur bei Problemen mit alten Paketen oder Tooling solltest du temporär auf CommonJS zurückfallen. + +--- + +## 🌐 CommonJS-Konfiguration CJS (Alternative) + +### 📦 Was ist CommonJS? + +**CommonJS (CJS)** ist das ursprüngliche Modulsystem von Node.js: + +- verwendet `require()` zum Importieren +- verwendet `module.exports` oder `exports` zum Exportieren +- keine native Unterstützung für `import`/`export` +- funktioniert nur in Node.js (nicht im Browser ohne Bundler) + +```js +// CommonJS-Stil +const fs = require('fs'); +module.exports = { read: fs.readFileSync }; +``` + +--- + +### ✅ Wann kann/sollte/muss man **CommonJS** verwenden? + +#### 🟢 **Du kannst CJS verwenden**, wenn + +- du ein CLI-Tool oder Node.js-Skript erstellst +- du maximale **Kompatibilität** ohne ESM-Komplikationen willst +- du keine modernen ESM-Features brauchst +- du auf Build-Tools verzichtest und direkt `.js`-Dateien startest + +#### 🟡 **Du solltest CJS verwenden**, wenn + +| Situation | Grund | +| ------------------------------------------------------------------- | ------------------------------------------------------ | +| 🔄 Du arbeitest mit älteren Node.js-Versionen (z. B. v12 oder v10) | ESM ist dort nicht stabil | +| 📦 Du nutzt NPM-Pakete, die **kein ESM unterstützen** | `require()` wird erwartet | +| 🧪 Du verwendest alte Tools, Tests oder Konfigurationen | z. B. alte `mocha`, `gulpfile.js`, `webpack.config.js` | +| 🧱 Du brauchst direkten Zugriff auf `__dirname`, `__filename` | Diese fehlen in ESM | +| 📜 Du möchtest `.js`-Dateien ohne `.mjs` oder `type: module` nutzen | CommonJS macht keine Vorgaben für Dateiendungen | + +#### 🔴 **Du musst CJS verwenden**, wenn + +- das Node.js-Modul, das du importieren willst, **nur `module.exports` exportiert** (kein ESM-Support) +- dein Projekt oder Tool **nicht mit ESM kompatibel ist** (ältere Tooling oder NPM-Module) +- du `require()` oder dynamisches Laden (`require(dynamicPath)`) verwendest, was in ESM nicht geht + +--- + +### ⚙️ TypeScript-Konfiguration für CJS + +```jsonc +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true + } +} +``` + +Und in der `package.json`: + +```json +{ + "type": "commonjs" +} +``` + +**Hinweis:** Das `"type"`-Feld ist für Node wichtig, nicht für TypeScript. + +--- + +### 📌 Merkmale von CommonJS + +| Merkmal | CommonJS | +| ------------------------- | -------------------------- | +| Import-Syntax | `require()` | +| Export-Syntax | `module.exports = …` | +| Dateiendung | `.js` (keine `.mjs` nötig) | +| Direkt ausführbar | ✅ Ohne zusätzliche Flags | +| `__dirname`, `__filename` | ✅ verfügbar | +| Browserkompatibilität | ❌ Nur mit Bundler möglich | +| Dynamische Importe | ✅ `require(dynamicPath)` | +| Tree Shaking | ❌ nicht möglich | + +--- + +### ✅ Fazit CommonJS + +> **CommonJS ist stabil, weit verbreitet und maximal kompatibel.** +> Wenn du **einfach nur ein Node-Tool oder CLI-Skript baust** und keine besonderen Build-Prozesse oder Browser-Kompatibilität brauchst: **Nutze CommonJS.** + +Für moderne ESM-Projekte im Web oder wenn du zukunftssicher entwickeln willst, solltest du auf ESM setzen – aber CJS bleibt in vielen Fällen die einfachste und robusteste Wahl. + +--- + +## 📄 Fazit: Empfehlungen + +- **Neue Projekte:** Nutze ESM mit `"type": "module"` +- **Bestehende Tools nutzen `require()`?** Dann CJS +- **Browser + Node gemeinsam nutzen?** ESM-only + klare Trennung von `shared/`, `client/`, `server/` +- **Tooling wie Vite, Nuxt, Webpack?** Immer ESM + +--- + +## 📁 Dateiendungen in Node.js + +| Dateiendung | Verhalten | +| ----------- | ------------------- | +| `.js` | Hängt von `type` ab | +| `.mjs` | Immer ESM | +| `.cjs` | Immer CommonJS | + +--- + +## ⚠️ Typische Fehler vermeiden + +- **`SyntaxError: Cannot use import statement outside a module`** + → `type` fehlt in `package.json` + +- **`Cannot find module` bei relativen Imports** + → `.js` fehlt am Ende beim ESM-Import + +- **`__dirname` ist not defined** + → Du nutzt ESM, verwende `import.meta.url` + +--- + +## 🚀 CLI-Build-Tipps (tsc) + +```bash +npx tsc # Kompiliert Projekt laut tsconfig.json +chmod +x dist/index.js # Macht CLI-Datei ausführbar +``` + +Header für CLI-Datei: + +```ts +#!/usr/bin/env node +``` + +--- + +## 📍 Weiterführende Themen + +- Dual-Exports für NPM (ESM + CJS gleichzeitig) +- "exports"-Feld in `package.json` +- Tools wie `tsup`, `vite`, `esbuild` als Alternativen zu `tsc` +- Einstieg in CLI-Tools: `commander`, `yargs`, `chalk`, `ora` diff --git a/package-lock.json b/package-lock.json index e40ff16..096f533 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,502 @@ { - "name": "adminslog", + "name": "tools", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "tools", + "version": "1.0.0", "dependencies": { "fs": "^0.0.1-security", "path": "^0.12.7", - "process": "^0.11.10" + "process": "^0.11.10", + "typescript": "^5.8.3" + }, + "bin": { + "link-collector": "dist/index.js" }, "devDependencies": { - "@types/node": "^22.15.21" + "@types/node": "^22.15.29", + "esbuild": "^0.25.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, "node_modules/@types/node": { - "version": "22.15.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", - "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==", + "version": "22.15.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz", + "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==", "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, "node_modules/fs": { "version": "0.0.1-security", "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", @@ -54,6 +528,19 @@ "node": ">= 0.6.0" } }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", diff --git a/package.json b/package.json index e567063..3dbe6c7 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,24 @@ { + "name": "tools", + "version": "1.0.0", + "type": "module", + "bin": { + "link-collector": "./dist/index.js" + }, + "scripts": { + "build": "tsc", + "postbuild": "node tools/dist/fscopy.js -s tools/dist/collector/link_collector.js -t tools/collector/link_collector.js && npm run clean", + "scan": "node tools/collector/link_collector.js", + "clean": "node ./tools/dist/fsdel.js ./tools/dist/collector/link_collector.js" + }, "dependencies": { "fs": "^0.0.1-security", "path": "^0.12.7", - "process": "^0.11.10" + "process": "^0.11.10", + "typescript": "^5.8.3" }, "devDependencies": { - "@types/node": "^22.15.21" + "@types/node": "^22.15.29", + "esbuild": "^0.25.5" } } diff --git a/tools/collector/config.jsonc b/tools/collector/config.jsonc index 402a4d6..befa901 100644 --- a/tools/collector/config.jsonc +++ b/tools/collector/config.jsonc @@ -1,8 +1,8 @@ { // Verzeichnis relativ zum Script, das durchsucht wird -"root_dirs": [ - "dokus" -], + "root_dirs": [ + "dokus" + ], // Nur Dateien mit dieser Endung (wird erweitert) "extensions": [".md"], @@ -10,6 +10,7 @@ // Zielpfad für die Linkausgabe (Markdown-Datei) "output_file": "README.md", - // Optional: Log für bereits verarbeitete Dateien + // Optional: Log für bereits verarbeitete Dateien. Dateien die dort + // enthalten sind, werden nicht nochmals verabeitet. "processed_log": "processed.log" } diff --git a/tools/collector/link_collector.js b/tools/collector/link_collector.js new file mode 100644 index 0000000..5515134 --- /dev/null +++ b/tools/collector/link_collector.js @@ -0,0 +1,188 @@ +#!/usr/bin/env node +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +class ScriptInfo { + static dir() { + return path.dirname(__filename); + } + static cwd() { + return process.cwd(); + } +} +class ConfigLoader { + static load(filename = 'config.jsonc') { + const configPath = path.join(ScriptInfo.dir(), filename); + if (!fs.existsSync(configPath)) { + console.error(` ⚠ Konfigurationsdatei nicht gefunden: ${configPath}`); + process.exit(1); + } + const raw = fs.readFileSync(configPath, 'utf8'); + const clean = raw + .split('\n') + .filter(line => !line.trim().startsWith('//')) + .join(''); + return JSON.parse(clean); + } +} +class ArgParser { + static parse() { + const argv = process.argv.slice(2); + const result = { scan: null, ignore: [], reset: false, hilfe: false }; + while (argv.length) { + const arg = argv.shift(); + if (!arg) + break; + if (arg === '-h' || arg === '--hilfe') { + result.hilfe = true; + } + else if (arg === '--reset') { + result.reset = true; + } + else if ((arg === '-s' || arg === '--scan') && argv.length) { + result.scan = argv.shift().split(',').map(x => x.trim()).filter(Boolean); + } + else if ((arg === '-x' || arg === '--ignore') && argv.length) { + result.ignore = argv.shift().split(',').map(x => x.trim()).filter(Boolean); + } + else { + console.warn(` ⚠ Unbekannter Parameter: ${arg}`); + result.hilfe = true; + break; + } + } + return result; + } + static showHelp() { + console.log(` +(C) 2025 - Adam Skotarczak (ionivation.com) + +🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link. +Verwendung: ts-node link_collector.ts [OPTIONEN] + + -s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad) + -x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen + --reset Löscht das Logfile 'processed.log' und beendet sich + -h, --hilfe Zeigt diese Hilfe + +Beispiel: + ts-node link_collector.ts -s docs,notes -x "docs/alt" +`); + } +} +class FileScanner { + static *find(rootDirs, ignoreDirs, extensions) { + for (const root of rootDirs) { + const absRoot = path.resolve(root); + const stack = [absRoot]; + while (stack.length) { + const current = stack.pop(); + const rel = path.relative(ScriptInfo.cwd(), current).replace(/\\/g, '/'); + if (ignoreDirs.some(ignored => rel.startsWith(ignored))) + continue; + const entries = fs.readdirSync(current, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(current, entry.name); + if (entry.isDirectory()) { + stack.push(fullPath); + } + else if (extensions.some(ext => entry.name.endsWith(ext))) { + yield fullPath; + } + } + } + } + } +} +class TitleExtractor { + static extract(filepath) { + try { + const content = fs.readFileSync(filepath, 'utf8'); + for (const line of content.split('\n')) { + if (line.trim().startsWith('#')) { + return line.replace(/^#+/, '').trim(); + } + } + } + catch (e) { + console.error(`⚠ Fehler beim Lesen von ${filepath}: ${e}`); + } + return path.basename(filepath, path.extname(filepath)); + } +} +class ProcessedLog { + constructor(filename) { + this.logPath = path.join(ScriptInfo.dir(), filename); + this.entries = new Set(); + this.load(); + } + load() { + if (!fs.existsSync(this.logPath)) + return; + const lines = fs.readFileSync(this.logPath, 'utf8').split('\n').map(x => x.trim()).filter(Boolean); + this.entries = new Set(lines.map(p => p.replace(/\\/g, '/'))); + } + has(posixPath) { + return this.entries.has(posixPath); + } + update(newPaths) { + const content = newPaths.map(p => p.replace(/\\/g, '/')).join('\n') + '\n'; + fs.appendFileSync(this.logPath, content, 'utf8'); + } + reset() { + if (fs.existsSync(this.logPath)) { + fs.unlinkSync(this.logPath); + console.log('🧹 Logfile gelöscht:', this.logPath); + } + else { + console.log('ℹ Logfile existierte nicht:', this.logPath); + } + } +} +class MarkdownAppender { + static append(outputFile, links) { + const content = links.join('\n') + '\n'; + fs.appendFileSync(outputFile, content, 'utf8'); + } +} +// Einstiegspunkt +function main() { + const config = ConfigLoader.load(); + const args = ArgParser.parse(); + if (args.hilfe) { + ArgParser.showHelp(); + return; + } + const log = new ProcessedLog(config.processed_log || 'processed.log'); + if (args.reset) { + log.reset(); + return; + } + const cwd = ScriptInfo.cwd(); + const outputFile = path.resolve(cwd, config.output_file || 'output.md'); + const rootDirs = (args.scan || config.root_dirs || []).map(d => path.resolve(d)); + const ignoreDirs = (args.ignore || []).map(d => path.relative(cwd, path.resolve(d)).replace(/\\/g, '/')); + const extensions = config.extensions || ['.md']; + const newLinks = []; + const newProcessed = []; + for (const absPath of FileScanner.find(rootDirs, ignoreDirs, extensions)) { + const relPath = path.relative(cwd, absPath).replace(/\\/g, '/'); + if (path.resolve(absPath) === outputFile || log.has(relPath)) + continue; + const title = TitleExtractor.extract(absPath); + newLinks.push(`- [${title}](${relPath})`); + newProcessed.push(relPath); + } + if (newLinks.length > 0) { + MarkdownAppender.append(outputFile, newLinks); + log.update(newProcessed); + console.log(`✔ ${newLinks.length} neue Links hinzugefügt.`); + } + else { + console.log(' ℹ Keine neuen Dateien gefunden.'); + } +} +main(); diff --git a/tools/collector/processed.log b/tools/collector/processed.log index 08295b7..b12e0f4 100644 --- a/tools/collector/processed.log +++ b/tools/collector/processed.log @@ -3,3 +3,5 @@ dokus/asciidoc/asciidoctor-theme-bug-workaround.md dokus/git/git-remote-branch.md dokus/git/git-ssh-remote.md dokus/git/git.md +dokus/plesk/plesk-benutzer-schon-vorhanden.md +dokus/js-ts/js-ts-dialekte.md diff --git a/tools/src/collector/config.jsonc.template b/tools/src/collector/config.jsonc.template new file mode 100644 index 0000000..befa901 --- /dev/null +++ b/tools/src/collector/config.jsonc.template @@ -0,0 +1,16 @@ +{ + // Verzeichnis relativ zum Script, das durchsucht wird + "root_dirs": [ + "dokus" + ], + + // Nur Dateien mit dieser Endung (wird erweitert) + "extensions": [".md"], + + // Zielpfad für die Linkausgabe (Markdown-Datei) + "output_file": "README.md", + + // Optional: Log für bereits verarbeitete Dateien. Dateien die dort + // enthalten sind, werden nicht nochmals verabeitet. + "processed_log": "processed.log" +} diff --git a/tools/collector/link_collector.ts b/tools/src/collector/link_collector.ts similarity index 95% rename from tools/collector/link_collector.ts rename to tools/src/collector/link_collector.ts index 96a13cd..c058ef4 100644 --- a/tools/collector/link_collector.ts +++ b/tools/src/collector/link_collector.ts @@ -1,8 +1,13 @@ -#!/usr/bin/env ts-node +#!/usr/bin/env node -import * as fs from 'fs'; -import * as path from 'path'; -import * as process from 'process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); type Config = { root_dirs?: string[]; diff --git a/tools/src/fscopy.ts b/tools/src/fscopy.ts new file mode 100644 index 0000000..4006c70 --- /dev/null +++ b/tools/src/fscopy.ts @@ -0,0 +1,80 @@ +#!/usr/bin/env ts-node + +/** + * Robust plattformunabhängiger Dateikopierer + * Verwendung: node fscopy.ts -s -t + * Optionen: -h | --help + */ + +import * as fs from "fs"; +import * as path from "path"; + +function showHelp(): void { + console.log(` +Copy Files with node.js +Verwendung: + node fscopy.ts -s -q + +Parameter: + -s, --source Pfad zur Quelldatei (z.B. static/.htaccess) + -t, --target Pfad zur Zieldatei (z.B. dist/app/.htaccess) + -h, --help Diese Hilfe anzeigen +`); + process.exit(0); +} + +function parseArgs(): { source: string; ziel: string } { + const args = process.argv.slice(2); + let source = ""; + let ziel = ""; + + for (let i = 0; i < args.length; i++) { + switch (args[i]) { + case "-s": + case "--source": + source = args[++i]; + break; + case "-t": + case "--target": + ziel = args[++i]; + break; + case "-h": + case "--help": + showHelp(); + break; + default: + console.error(`Unbekannter Parameter: ${args[i]}`); + showHelp(); + } + } + + if (!source || !ziel) { + console.error("❌ Quelle und Ziel müssen angegeben werden."); + showHelp(); + } + + return { source, ziel }; +} + +function copyFile(source: string, ziel: string): void { + const zielVerzeichnis = path.dirname(ziel); + fs.mkdir(zielVerzeichnis, { recursive: true }, (mkdirErr) => { + if (mkdirErr) { + console.error(`❌ Zielverzeichnis konnte nicht erstellt werden: ${mkdirErr.message}`); + process.exit(1); + } + + fs.copyFile(source, ziel, (copyErr) => { + if (copyErr) { + console.error(`❌ Fehler beim Kopieren: ${copyErr.message}`); + process.exit(1); + } + + console.log(`✔ Datei erfolgreich kopiert: ${source} → ${ziel}`); + }); + }); +} + +// Ausführung +const { source, ziel } = parseArgs(); +copyFile(source, ziel); diff --git a/tools/src/fsdel.ts b/tools/src/fsdel.ts new file mode 100644 index 0000000..85e192c --- /dev/null +++ b/tools/src/fsdel.ts @@ -0,0 +1,41 @@ +#!/usr/bin/env ts-node + +import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Löscht eine Datei am angegebenen Pfad. + * + * @param filePath - Pfad zur Datei, die gelöscht werden soll + */ +function deleteFile(filePath: string): void { + const resolvedPath = path.resolve(filePath); + + if (!fs.existsSync(resolvedPath)) { + console.error(`❌ Datei nicht gefunden: ${resolvedPath}`); + process.exit(1); + } + + try { + fs.unlinkSync(resolvedPath); + console.log(`✔ Datei gelöscht: ${resolvedPath}`); + } catch (err) { + console.error(`❌ Fehler beim Löschen: ${(err as Error).message}`); + process.exit(1); + } +} + +// Kommandozeilenargumente +const [, , arg] = process.argv; + +if (!arg || arg === '-h' || arg === '--help') { + console.log(`Verwendung: + ts-node delete.ts + +Beispiel: + ts-node delete.ts ./log/output.txt`); + process.exit(0); +} + +// Datei löschen +deleteFile(arg); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..341a94a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "outDir": "./tools/dist", + "rootDir": "./tools/src", + "strict": true + }, + "include": ["tools/src"] +} From e8e3f349d41214b839ca8afc4f54f17b8d527898 Mon Sep 17 00:00:00 2001 From: "Adam Skotarczak (DEVELOP)" Date: Sun, 8 Jun 2025 10:59:15 +0200 Subject: [PATCH 3/5] gewindetabelle etc. --- README.md | 11 +++- dokus/mechanik/gewindetabellen.md | 64 +++++++++++++++++++ dokus/plesk/plesk-benutzer-schon-vorhanden.md | 43 +++++++++---- tools/collector/processed.log | 1 + 4 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 dokus/mechanik/gewindetabellen.md diff --git a/README.md b/README.md index ec582fd..8a67186 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr - [Git](#git) - [Markdown](#markdown) - [Mermaid](#mermaid) + - [Mechanik](#mechanik) - [Server](#server) - [Plesk](#plesk) - [Webserver](#webserver) @@ -45,7 +46,13 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr #### Mermaid -- [mermaidPockedGuide](https://dns.lan:3000/realAscot/mermaidPockedGuide/src/branch/main/README.md) **EXTERN** +- [mermaidPockedGuide](https://local.ionivation.com/realAscot/mermaidPockedGuide) **EXTERN** 🚀 + +### Mechanik + +- [Gewindetabellen](dokus/mechanik/gewindetabellen.md) + +--- ### Server @@ -65,6 +72,8 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr - [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md) +--- + ## Neue Dokumente > führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) oder `npm run scan` aus um nach neuen Dateien zu suchen! diff --git a/dokus/mechanik/gewindetabellen.md b/dokus/mechanik/gewindetabellen.md new file mode 100644 index 0000000..6bde09d --- /dev/null +++ b/dokus/mechanik/gewindetabellen.md @@ -0,0 +1,64 @@ +# Gewindetabellen + +## 📏 **Praxis-Gewindetabelle (zöllig, G = BSPP)** + +| Gewindebezeichnung | ⌀ Außengewinde (mm) | ⌀ Innengewinde (mm) | Typische Anwendung | +| ------------------ | ------------------- | ------------------- | ---------------------------------- | +| **G 1/8"** | \~9,7 mm | \~8,5 mm | Druckluft, Manometer | +| **G 1/4"** | \~13,2 mm | \~11,5 mm | Kleingeräte, Kaffeemaschinen | +| **G 3/8"** | \~16,6 mm | \~14,5 mm | Geräteventile, Mini-Zulaufschlauch | +| **G 1/2"** | \~20,95 mm | \~18,6 mm | Wasserhahn, Spülarmatur | +| **G 3/4"** | \~26,4 mm | \~24,0 mm | Waschmaschine, Gartenschlauch | +| **G 1"** | \~33,25 mm | \~30,3 mm | Gartenwasserleitungen, Heizkreise | +| **G 1 1/4"** | \~41,9 mm | \~38,8 mm | Hausanschluss, Regenwassernutzung | + +--- + +### 📌 Hinweise + +- Die Werte sind **gemittelte Praxiswerte**. Es gibt leichte Toleranzen je nach Hersteller. +- Es handelt sich um **zylindrische Whitworth-Rohrgewinde (BSPP / G)**, **nicht kegelig**. +- Zur **Identifikation** reicht in der Regel eine Schieblehre und ein Blick in diese Tabelle. +- Die Angabe „Zoll“ hat **nichts** mit dem Außendurchmesser zu tun – das ist reine Gewindeklassifizierung aus der Rohrnorm. + +--- + +Klar – hier kommt eine **praxisorientierte Bohrtabelle für metrische ISO-Gewinde (M-Gewinde)** von **M1 bis M12**, wie sie beim Innengewindeschneiden (z. B. per Hand mit Schneideisen oder Gewindebohrer) verwendet wird. + +--- + +## 📏 **Bohrtabelle für metrische ISO-Regelgewinde (M-Gewinde nach DIN 13-1)** + +| Gewinde | Steigung (mm) | Kernloch-Ø (mm) (Bohrerdurchmesser) | Hinweis | +| ------- | ------------- | ----------------------------------- | ---------------------- | +| M1 | 0.25 | 0.75 | selten, Feinmechanik | +| M1.2 | 0.25 | 0.95 | z. B. Elektronik | +| M1.6 | 0.35 | 1.25 | sehr fein | +| M2 | 0.4 | 1.6 | Standard M2 | +| M2.5 | 0.45 | 2.05 | beliebt bei Modellbau | +| M3 | 0.5 | 2.5 | sehr verbreitet | +| M4 | 0.7 | 3.3 | Klassiker | +| M5 | 0.8 | 4.2 | oft bei Maschinen | +| M6 | 1.0 | 5.0 | Standardgröße | +| M7 | 1.0 | 6.0 | eher selten | +| M8 | 1.25 | 6.8 | Standard M8 | +| M9 | 1.25 | 7.8 | Sondermaß | +| M10 | 1.5 | 8.5 | Maschinenbau | +| M11 | 1.5 | 9.5 | selten | +| M12 | 1.75 | 10.2 | oft für tragende Teile | + +--- + +### 📌 Hinweise Bohrtabelle + +- Dies sind die **Regelgewinde** – bei **Feingewinden** (z. B. M10x1) brauchst du kleinere Bohrer. +- Werte gelten für **100 % Gewindeüberdeckung**. In der Praxis reicht oft eine leicht größere Bohrung für leichtere Schnitte (z. B. bei Alu oder weichen Werkstoffen). +- Bei harter Werkstoffwahl ggf. Spiralbohrer vorher anspitzen oder mit Zentrierbohrer vorbohren. + +--- + +### 🧰 Beispiel zur Borhtabelle + +Du willst ein **M6-Gewinde** schneiden? → **5,0 mm Bohrer** nehmen → dann Gewindebohrer M6 einsetzen. + +--- diff --git a/dokus/plesk/plesk-benutzer-schon-vorhanden.md b/dokus/plesk/plesk-benutzer-schon-vorhanden.md index f5ff62a..5b29c73 100644 --- a/dokus/plesk/plesk-benutzer-schon-vorhanden.md +++ b/dokus/plesk/plesk-benutzer-schon-vorhanden.md @@ -1,31 +1,52 @@ # Plesk ausgesperrt bei Rechnerwechsel +## Inhalt + +- [Plesk ausgesperrt bei Rechnerwechsel](#plesk-ausgesperrt-bei-rechnerwechsel) + - [Inhalt](#inhalt) + - [Problembeschreibung](#problembeschreibung) + - [Workarround](#workarround) + - [Nachhaltige Lösung des Problems](#nachhaltige-lösung-des-problems) + +## Problembeschreibung + +Es kommt öfter vor, das ich aus der Plesk Weboberfläche automatisch ausgeloggt werde und ein erneuter Login anschliessend nicht mehr möglich ist. +Die genaue Ursache ist mir nicht eindeutig bekannt aber ich vermute das im Browser irgendwelche Sessions gelöscht werden. +Als erstes habe ich in meinem Brave-Browser den Schutz für explizit diese Seite deaktiviert. +Um mich wieder einloggen zu können, muss ich die Session auf dem Server von hand aus der Datenbank löschen. + +### Workarround + **Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70 Bei Plesk gibt es manchmal die gloreiche Meldung: -> Sie konnten nicht angemeldet werden. -Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.` +> Sie konnten nicht angemeldet werden. +> **Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.** Ärgerlich wenn das gerade der Adminzugang ist. Falls Du gerade noch SSH Zugang hast dann: -login und wechsel zum root, anschliessend: +login und wechsel zum root, anschliessend: - ```bash +```bash plesk db "DELETE FROM sessions WHERE login = 'admin';" - ``` +``` -oder +**oder** - ```bash +```bash mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';" - ``` +``` anschliessend: - ```bash +```bash systemctl restart psa - ``` +``` -und dann ganz normal Login wie gewohnt. +und dann ganz normal Login wie gewohnt. + +### Nachhaltige Lösung des Problems + +aktuell nicht bekannt! diff --git a/tools/collector/processed.log b/tools/collector/processed.log index b12e0f4..1bca6e8 100644 --- a/tools/collector/processed.log +++ b/tools/collector/processed.log @@ -5,3 +5,4 @@ dokus/git/git-ssh-remote.md dokus/git/git.md dokus/plesk/plesk-benutzer-schon-vorhanden.md dokus/js-ts/js-ts-dialekte.md +dokus/mechanik/gewindetabellen.md From 6a3ae701f6ef138db7c0b3ed0fc813f40cdae83a Mon Sep 17 00:00:00 2001 From: "Adam Skotarczak (DEVELOP)" Date: Sun, 15 Jun 2025 11:28:30 +0200 Subject: [PATCH 4/5] v0.1.0 --- CHANGELOG.md | 10 ++ LICENSE | 2 +- README.md | 84 +++++++++++- VERSION | 2 + dokus/helix__editor_einfuehrung_de.md | 182 ++++++++++++++++++++++++++ dokus/windows/desktop_ini.md | 177 +++++++++++++++++++++++++ media/realAscotLogo_128x128.png | Bin 0 -> 23656 bytes tools/collector/processed.log | 12 +- 8 files changed, 460 insertions(+), 9 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 VERSION create mode 100644 dokus/helix__editor_einfuehrung_de.md create mode 100644 dokus/windows/desktop_ini.md create mode 100644 media/realAscotLogo_128x128.png diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ca6828b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +- **25/06/15** - commit: v0.1.0 + - **Hinzugefügt:** + - [X] helix + - [x] desktop.ini + +--- + +- **initial commit** diff --git a/LICENSE b/LICENSE index 8643c86..b3ad055 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1 @@ -(C) - 2025 Adam Skotarczak +(C) 2025 - Adam Skotarczak führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) oder `npm run scan` aus um nach neuen Dateien zu suchen! diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..b3e7542 --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +0.1.0 +15.06.2025 \ No newline at end of file diff --git a/dokus/helix__editor_einfuehrung_de.md b/dokus/helix__editor_einfuehrung_de.md new file mode 100644 index 0000000..ada335b --- /dev/null +++ b/dokus/helix__editor_einfuehrung_de.md @@ -0,0 +1,182 @@ +# Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch) + +## Inhalt + +- [Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)](#helix-editor--ein-umfassender-einstieg-für-anfänger-deutsch) + - [Inhalt](#inhalt) + - [✨ Was ist Helix?](#-was-ist-helix) + - [🔧 Installation](#-installation) + - [Linux (Fedora, Arch, Debian)](#linux-fedora-arch-debian) + - [GitHub Release (empfohlen für aktuellste Version)](#github-release-empfohlen-für-aktuellste-version) + - [📁 Erstes Projekt starten](#-erstes-projekt-starten) + - [Beispiel: Rust-Projekt](#beispiel-rust-projekt) + - [Beispiel: JavaScript-Projekt](#beispiel-javascript-projekt) + - [⌨ Bedienkonzept von Helix](#-bedienkonzept-von-helix) + - [Modale Steuerung (ähnlich wie Vim)](#modale-steuerung-ähnlich-wie-vim) + - [Wechsel der Modi](#wechsel-der-modi) + - [⚖️ Wichtige Tastenkombinationen](#️-wichtige-tastenkombinationen) + - [🪨 Sprachserver (LSP)](#-sprachserver-lsp) + - [Rust](#rust) + - [JavaScript/TypeScript](#javascripttypescript) + - [C / C++](#c--c) + - [⚖️ LSP-Befehle in Helix](#️-lsp-befehle-in-helix) + - [📂 Konfiguration](#-konfiguration) + - [Beispiel-Inhalt](#beispiel-inhalt) + - [🌍 Weitere Ressourcen](#-weitere-ressourcen) + +## ✨ Was ist Helix? + +Helix ist ein moderner, terminalbasierter Code-Editor mit Fokus auf Produktivität, Effizienz und minimalistische Bedienung. Er verwendet **modale Eingabe** (wie Vim), bietet jedoch eine eigene, einsteigerfreundlichere Philosophie mit moderner Technologie wie **LSP**, **Tree-sitter**, und Syntax-Highlighting direkt aus dem Terminal. + +--- + +## 🔧 Installation + +### Linux (Fedora, Arch, Debian) + +```bash +# Fedora +sudo dnf install helix + +# Arch (via pacman) +sudo pacman -S helix + +# Debian/Ubuntu (nur in neueren Versionen oder via GitHub) +``` + +### GitHub Release (empfohlen für aktuellste Version) + +1. Gehe zu: [https://github.com/helix-editor/helix/releases](https://github.com/helix-editor/helix/releases) +2. Lade das passende Paket für dein System herunter +3. Entpacken: + +```bash +tar -xvf helix-*-x86_64-linux.tar.xz +sudo cp helix-*/helix/hx /usr/local/bin/ +``` + +--- + +## 📁 Erstes Projekt starten + +### Beispiel: Rust-Projekt + +```bash +cargo new hallo_helix +cd hallo_helix +hx src/main.rs +``` + +### Beispiel: JavaScript-Projekt + +```bash +mkdir node_hello && cd node_hello +echo 'console.log("Hallo, Welt!");' > index.js +hx index.js +``` + +--- + +## ⌨ Bedienkonzept von Helix + +### Modale Steuerung (ähnlich wie Vim) + +- **Normalmodus**: Standardmodus zum Navigieren und Bearbeiten +- **Einfügemodus (Insert)**: `i` drücken zum Schreiben +- **Auswahlmodus (Select)**: `v` für Zeichenweise, `V` für Zeilenweise Auswahl + +### Wechsel der Modi + +| Modus | Taste | Funktion | +| ----------- | ----- | ----------------------- | +| Normal | `Esc` | Zur Steuerung & Befehle | +| Insert | `i` | Einfügen / Tippen | +| Select | `v` | Auswahl ab Cursor | +| Line-Select | `V` | Ganze Zeile auswählen | + +--- + +## ⚖️ Wichtige Tastenkombinationen + +| Tastenkombi | Bedeutung | +| ----------- | --------------------------------- | +| `:w` | Datei speichern | +| `:q` | Editor beenden | +| `:wq` | Speichern und beenden | +| `g g` | Zum Anfang der Datei | +| `G` | Zum Ende der Datei | +| `d d` | Aktuelle Zeile löschen | +| `u` | Letzte Änderung rückgängig machen | +| `space + /` | Fuzzy-Dateisuche starten | +| `space + g` | Git-Diff anzeigen | + +--- + +## 🪨 Sprachserver (LSP) + +Helix erkennt automatisch den Dateityp und startet den passenden Sprachserver: + +### Rust + +```bash +rustup component add rust-analyzer +``` + +### JavaScript/TypeScript + +```bash +npm install -g typescript typescript-language-server +``` + +### C / C++ + +```bash +sudo dnf install clang clang-tools-extra +``` + +--- + +## ⚖️ LSP-Befehle in Helix + +| Taste | Bedeutung | +| ----- | ------------------------------- | +| `g d` | Gehe zur Definition | +| `g r` | Gehe zu Referenzen | +| `K` | Hover-Info anzeigen (Typ, Doku) | +| `=` | Formatieren | + +--- + +## 📂 Konfiguration + +Helix-Konfiguration liegt unter: + +```bash +~/.config/helix/config.toml +``` + +Zum Öffnen: + +```bash +:config-open +``` + +### Beispiel-Inhalt + +```toml +theme = "base16_default_dark" + +[keys.normal] +"C-s" = ":w" +"C-q" = ":wq" +``` + +--- + +## 🌍 Weitere Ressourcen + +- Offizielle Seite: [https://helix-editor.com](https://helix-editor.com) +- GitHub: [https://github.com/helix-editor/helix](https://github.com/helix-editor/helix) +- Tastenkombis: [https://docs.helix-editor.com/](https://docs.helix-editor.com/) + +--- diff --git a/dokus/windows/desktop_ini.md b/dokus/windows/desktop_ini.md new file mode 100644 index 0000000..0668abc --- /dev/null +++ b/dokus/windows/desktop_ini.md @@ -0,0 +1,177 @@ +# Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows + +*2025 - Adam Skotarczak* + +Die `desktop.ini`-Datei ist eine wichtige, jedoch wenig bekannte Datei in Windows, die zur Konfiguration und Anpassung von Ordnern verwendet wird. Sie ermöglicht es Benutzern, das Erscheinungsbild und Verhalten von Ordnern anzupassen, indem sie Einstellungen wie Symbole, Tooltips und Ordnerspezifikationen definiert. In diesem Artikel werden wir die Funktionsweise der `desktop.ini`-Datei ausführlich erklären und alle Optionen und Attribute vorstellen, die in dieser Datei verwendet werden können. + +## Inhaltsverzeichnis + +- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](#einführung-in-die-desktopini-datei-verwendung-und-anpassung-von-ordnern-in-windows) + - [Inhaltsverzeichnis](#inhaltsverzeichnis) + - [Was ist die `desktop.ini`-Datei?](#was-ist-die-desktopini-datei) + - [Grundlegende Struktur der `desktop.ini`](#grundlegende-struktur-der-desktopini) + - [Wichtige Optionen und Attribute](#wichtige-optionen-und-attribute) + - [Optionen in der `[General]`-Sektion](#optionen-in-der-general-sektion) + - [Optionen in der `[View]`-Sektion](#optionen-in-der-view-sektion) + - [Optionen in der `[Icon]`-Sektion](#optionen-in-der-icon-sektion) + - [Optionen in der `[LocalizedFileNames]`-Sektion](#optionen-in-der-localizedfilenames-sektion) + - [Optionen in der `[ShellClassInfo]`-Sektion](#optionen-in-der-shellclassinfo-sektion) + - [Kommentare in der `desktop.ini`](#kommentare-in-der-desktopini) + - [Die Bedeutung von Attributen und Rechten der `desktop.ini`](#die-bedeutung-von-attributen-und-rechten-der-desktopini) + - [Rechte für die `desktop.ini` unter Windows setzen](#rechte-für-die-desktopini-unter-windows-setzen) + - [Verwendung der `desktop.ini` auf NAS-Laufwerken](#verwendung-der-desktopini-auf-nas-laufwerken) + - [Fazit](#fazit) + +## Was ist die `desktop.ini`-Datei? + +Die `desktop.ini`-Datei ist eine Systemdatei in Microsoft Windows, die zur Anpassung von Ordnersymbolen, Tooltips und anderen Ordnerattributen verwendet wird. Diese Datei ermöglicht es, das Aussehen und Verhalten eines Ordners zu verändern, ohne dass zusätzliche Software erforderlich ist. Sie befindet sich normalerweise im Ordner, für den sie Einstellungen vornimmt, und beeinflusst nur diesen Ordner. + +## Grundlegende Struktur der `desktop.ini` + +Die `desktop.ini`-Datei ist eine INI-Datei, die aus verschiedenen Sektionen und Key-Value-Paaren besteht. Sie enthält spezifische Anweisungen für den Ordner, in dem sie sich befindet. Die wichtigsten Sektionen sind: + +- `[General]`: Enthält grundlegende Informationen zum Ordner, wie den Namen und den Tooltip. +- `[View]`: Steuert die Anzeigeeinstellungen des Ordners. +- `[Icon]`: Definiert das Symbol des Ordners. +- `[LocalizedFileNames]`: Bietet die Möglichkeit, Ordnernamen in verschiedenen Sprachen anzuzeigen. +- `[ShellClassInfo]`: Beinhaltet erweiterte Einstellungen für den Ordner, wie das Symbol und zusätzliche Eigenschaften. + +## Wichtige Optionen und Attribute + +### Optionen in der `[General]`-Sektion + +- **`Name`**: Der Name des Ordners, der im Windows Explorer angezeigt wird. + + ```ini + Name=Mein Ordner + ``` + +- **`InfoTip`**: Ein Tooltip, der angezeigt wird, wenn der Benutzer mit der Maus über den Ordner fährt. + + ```ini + InfoTip=Dies ist ein wichtiger Ordner. + ``` + +### Optionen in der `[View]`-Sektion + +- **`Mode`**: Bestimmt die Ansicht des Ordners. Mögliche Werte: + - `0`: Liste + - `1`: Details + - `2`: Große Symbole + - `3`: Kleine Symbole + + ```ini + Mode=2 ; Setze den Ordner auf "Große Symbole" + ``` + +- **`FolderType`**: Bestimmt den Typ des Ordners, z. B. `Documents`, `Music`, `Pictures`. + + ```ini + FolderType=Documents ; Ordnertyp auf Dokumente setzen + ``` + +- **`IconAreaImage`**: Setzt ein Hintergrundbild für den Ordnerbereich. + + ```ini + IconAreaImage=C:\Bilder\Hintergrund.png + ``` + +### Optionen in der `[Icon]`-Sektion + +- **`IconFile`**: Der Pfad zu einer Datei, die das Ordnersymbol enthält (z. B. `.ico`, `.dll`, `.exe`). + + ```ini + IconFile=C:\Windows\System32\shell32.dll + ``` + +- **`IconIndex`**: Der Index des Symbols in der Datei, wenn mehrere Symbole in einer Datei vorhanden sind. + + ```ini + IconIndex=5 + ``` + +### Optionen in der `[LocalizedFileNames]`-Sektion + +- **`@`**: Erlaubt die Anzeige von Ordnernamen in verschiedenen Sprachen. + + ```ini + [LocalizedFileNames] + @="Projektordner" + ``` + +### Optionen in der `[ShellClassInfo]`-Sektion + +- **`NoSharing`**: Verhindert die Freigabe des Ordners über das Netzwerk. + + ```ini + NoSharing=1 ; Verhindert die Netzwerkfreigabe + ``` + +- **`ConfirmFileOp`**: Steuert, ob eine Bestätigung beim Kopieren von Dateien erforderlich ist. + + ```ini + ConfirmFileOp=0 ; Keine Bestätigung erforderlich + ``` + +- **`InfoTip`**: Eine zusätzliche Option zur Festlegung eines Tooltips. + + ```ini + InfoTip=Dieser Ordner enthält Projektdateien. + ``` + +- **`IconFile` und `IconIndex`**: Wiederholung der Optionen zur Festlegung des Ordnersymbols. + + ```ini + IconFile=C:\Windows\System32\shell32.dll + IconIndex=5 + ``` + +## Kommentare in der `desktop.ini` + +In der `desktop.ini`-Datei können **Kommentare** durch das Hinzufügen eines **Semikolons (`;`)** am Anfang einer Zeile eingefügt werden. Alles, was nach einem Semikolon in einer Zeile steht, wird von Windows ignoriert und dient lediglich der Dokumentation. + +Beispiel: + + ```ini + ; Dies ist ein Kommentar + [.ShellClassInfo] + IconFile=C:\Windows\System32\shell32.dll + IconIndex=23 + ``` + +## Die Bedeutung von Attributen und Rechten der `desktop.ini` + +Die `desktop.ini`-Datei muss bestimmte **Dateiattribute** besitzen, damit sie korrekt funktioniert: + +- **Schreibgeschützt (`+r`)**: Verhindert, dass die Datei überschrieben wird. +- **Versteckt (`+h`)**: Stellt sicher, dass die Datei im Windows Explorer nicht angezeigt wird. +- **System (`+s`)**: Kennzeichnet die Datei als Systemdatei, sodass Windows sie als Konfigurationsdatei erkennt. + +Die `desktop.ini`-Datei sollte auch die entsprechenden **Dateisystemrechte** haben, um sicherzustellen, dass sie nicht versehentlich gelöscht oder verändert wird. + +## Rechte für die `desktop.ini` unter Windows setzen + +Damit die `desktop.ini`-Datei korrekt funktioniert, müssen unter Windows bestimmte **Dateirechte und Attribute** gesetzt werden: + +- **Schreibschutz setzen**: Um zu verhindern, dass die Datei überschrieben wird, kann das Schreibschutz-Attribut aktiviert werden. Dies kann über die Eingabeaufforderung mit dem Befehl `attrib +r desktop.ini` erreicht werden. + +- **Versteckt setzen**: Damit die Datei im Explorer nicht angezeigt wird, muss das versteckte Attribut gesetzt werden. Dies kann mit `attrib +h desktop.ini` erfolgen. + +- **Systemdateiattribut setzen**: Um die Datei als Systemdatei zu kennzeichnen, sodass Windows sie korrekt als Konfigurationsdatei behandelt, muss das Systemattribut gesetzt werden. Verwenden Sie dazu `attrib +s desktop.ini`. + +Die richtigen Attribute können alle auf einmal gesetzt werden, indem Sie den folgenden Befehl verwenden: + +```cmd +attrib +r +h +s desktop.ini +``` + +## Verwendung der `desktop.ini` auf NAS-Laufwerken + +Die `desktop.ini`-Datei kann auch auf **NAS-Laufwerken** verwendet werden, solange das Laufwerk ein **Windows-kompatibles Dateisystem** wie **NTFS** verwendet. Es gibt jedoch einige wichtige Aspekte zu beachten: + +- Das NAS muss ein unterstütztes Dateisystem verwenden. +- Die Berechtigungen für die Datei und die Ordnersichtbarkeit müssen so konfiguriert werden, dass Windows sie korrekt lesen kann. + +## Fazit + +Die `desktop.ini`-Datei ist ein mächtiges Werkzeug zur Anpassung von Ordnern in Windows. Sie ermöglicht es, das Aussehen und Verhalten von Ordnern zu verändern, ohne zusätzliche Software zu benötigen. Durch die Verwendung von Kommentaren und Attributen können Benutzer ihre Ordnerspezifikationen einfach und effektiv anpassen. Ob auf lokalen Laufwerken oder NAS-Systemen – die `desktop.ini` bleibt eine vielseitige Lösung für die Ordneranpassung in Windows. diff --git a/media/realAscotLogo_128x128.png b/media/realAscotLogo_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..eeeebaacfa981925b72952069a6ae761207188e2 GIT binary patch literal 23656 zcmV*pKt{ibP)5#Q0b-Isv*>y5s;+rB^Ed6C zKlXRNs>U~Yz_#wSF!elo)ZI0mbN1S6z3YA7wGMpi<69r!`uK~ml6?c-YM z{rxzpnA}R7BzV40x6`qWMm29X8XHTCiyM3P?dyEt&;PjdtpNBY`grnFpY^(t=GYr5 zl}hMoPn6a~QAn0%7;Dg4qm;7780&eupQXvWH#Rn3`>Buo<=~t7b@Bco9RA@Op8TXJ zs=TpLs|L5+dJD5VcMyajN`(F(1}v2*qEd+@&oViF;#BR#sk8sQQc2DMZ~kU}ZS+5c z0GQsn=bfOQbk%_aWLeJg@+xz4bF8he({8s}T3lj%V}o|5%gWk1Prdai2!{2I)-6$` z_WPGFo$q}s0G^;9`>r~COQqI$>-6-bs#L0ES&HXrM4;F0k)#Ppk}w#=#Df7Q&sg8s z;QH&Y<>;|fkrivtoH%;dw*ue^`Z2Y0&pVZH{nb|=#18_jH6%$wzdt}J1;&!58F`*# zj3Li*I^8Z&6tQz=LM|^Z9~qmN`29=g&vw5VUmx{Ne*16swD+AeGc)9QPL`&aJO^6< zAg#&r46PI*LY8G1Yr(>W^B0+&oh6E*=16nm$G(*To|v`&w}B_^-Mh!#b^(Qur?pp|<$ln9~(1MHpM!NT(Dk*Hev-G#Y}gKuSkC&VI>jfyr~yG(jm%nxoYeu&*bzB#@ex&*}bp%Rt9(id_478 zcSMzX^Nwn@_V2AR2PP*c3Bw3uEJ_6JX^b(55|TJU1eDfzo`v!cojd(aLlXV}P6R#qsn1kdmcMdreDYr+a(aDr^*0{7|MQQ1 zgCtL6^6ZWvth~bWyq9Y2O=f8#BaH@O7y=N60VX#XYiKr`2+-+t@H`)_6&3-3TD3~A zKOhKvwDt&sfWy}w=H!W!EUv8DAPC}qzyFEN^|e1RCi~E*KlZ`?H~gG$d*<%R=^a1b z7-?27&s}`emp=3HrGJnCaLo-j?eW9PJ8QMtcU*huko4okwtIu5-P-)ae!u&s`#=Aw zOaHs?efINT9BgcCJSzw*uL`5^rGiY2jWuP@p518WksHJE(xOB6xgpCls+9`HSUgXo zwIk}wLZe=%(`obASC6yN?$|WTmRp+}f407| z@;~eK`WHU>{`Y48r|0|P?|Fs4zP|Bel}ham^~T7^$VgL^lEvla#eeqE_xu5AwYnCAJSYBG@p+}FAB&qGk zgOj~p_YXU**1PYy>w_1+_Br4D^yl1Isn!3Jr~PL(8+C5H@d!_T@{{<&7w==E)y_9t zt+y{OEd0{v?)pIgn>qk?A2>7`RcgN(1kpd;vuBr@oSvcE?hwZVYPA~s_V45Hp+kK2 ztB>*UW5=zCoZj4Ae{(z-G{P|YK@qvJR;{Rg`}Q(AHiosZytGKW)g}x>;v~lRe3Ce( zQmxSI_3(XeBa07z77kudJUx% zK@hTI#|%4XchK+kxpe6g$4;CfH+dr1&#bR+{?YpS>id09bp-voFp7RYP1ES=s}2wZ zAwd{0Ha5nSZn%!+|6w~A^dFd?pMTY7KlWG0zbOOYz~LKi^}X;tzVBai^HXjn z%MIO5ha^d;L=oE4SPRXO5e^st0X*MhZFQA2Nf^Wf zv{HE5BZ?x@EM+hl;Au^6OquGlG{f_Kln85UYh-D{%E~gmZkHq;&}cT(O(C>AV zG?~yMvS;sJ;y5OW6N12}(Ws-e$DxB)6NLd^_|li{+UDlQ(&dGpXpT1D^S(d&!*7lN zm_2Y%`Cjmoo*(|&V=x#XK&4hCO_Gwt@w7*7as-ODE+Gg*(ln#r?XtPK&g#kvNfHx<5l0S&yy|7U ztzVsxKl$@h_OtiRiw-Bx#CR5T(%CHBdnikYyRou~Fhd z%+&N0Gt<*lsuj+kzsT7$XYo8;249wDC?yzc$_F-i$qdt_;bANW{n zsa7iFCPyiaC?O0&vOFV8Qt~{<^E|rUE=nu3_D~`ilOsyudoEpzh1@vGcX?@n#l;1z zu>?Vg_B{4X2tV@!0e4&_M5`wuYT9`6+4A}MI`4SbgFJL>m2R)gj-9jY-n*ZXkr6!4 z$15^amZqQtB?_$-X_`@QG)R*Kr8PkiP_5O7LigC$R@X3jPE@IorYUKfl%*(+69DRs zIwK<^96ES4t7~gK{OD2J>2~jHZLI&mT_5_4!I+t)WQA$nM>vaab9(kU* z!_RWZy&Fpq1{mWG-S<7x)baD4r|^6aYr*91>n#?gq{to`tR*uBljrpNJiCEpKhsAmkL9HWPMth~F$S$YL>w-t)vDwsC(m+{Bta=b5SJ;k4Bzv>TH+)D9QkCe zMZ{&l{-BSshAhnxrKr}btgWtrQe1QJDmFGZD{-7Wf5)ypZ$EeXgn2>*z{T@tsZ>W^ zY>hcwtvU4UYNy3o>s}z=Bg=BEvE*4=CMHj7ci_e%fc8ABb>ElgIce(n{BBX(j~#uC zjkPsA?Le9mcks6yGQ8zSa{H=lH)OnXo}|@hWx??AM@RYDyLR)5rBOb!*yO}{P1NmE z(;2m3gGTpJdFsJ2?!5De?c>XZ`IsoGva!C-xihCR*5GLuoV99=EKRZ2oljO|xNfhD z)(TO|VHJchbfwN1gNW-oL=?t4exl#+W344g5<0yen;RP}udKwIt&QK9zi{q}6#xKX zRJ}@+Jik_}Axfc?LTOcyE>4llGbhDbaIIV%69hh$YK1gONeh5Sar=GWCrdLH7ZpapfK6UdBdv>KlQ9Odk1GFZ*|yMHQaZq%9}s4oBw%cf>eiSt?|Qv zMO)*;7wQaF4V6KkiVsz}%tU%jo_o`NZhQJ(dtot_jgC;M)@W^Ra`yB|j5WlAglesZ z@B3(_5#=P7Cw$+Id<$g{a*L3FMj&t z?|DLM0ZQx052GIl{6H#2JxpMY z7tYb`w9&qgUm$F!Zdv}tOJm;nvXmR;EV{i$y9FmNX#VS$cJLn_oM9=eqP2&`G8pvn zJP)Nbl}d%jI(0sNA|h;c@%sZRRZBHJ%dDJ{7eDtVyZ_qV^6=4BjQBK0nzUOjE}TCL z))IyhX_gTLKGr&{lbf7)5EDirw(uT=QAnQWMY&5+O1sw3_X{%0!!Q0ke|f=fuCKps zVgADXPsjim9h=xRme*pfSF6=A*0?O7RB>p6Qi>$Wij?T1L}9TQ4eCrf3#VIMu-7S9i< zR%@)Uu5#wo2|VAUQmK}JRB%{Dl(;UT_;=59I3mxD3qs#7v%oNmv^F+aSzF6C)>nRV zb$OxngbaXQx81MSM_z8N-O(H!B@6<0=*5k-#*k(iVHlvblVpP^EYhL-x+Fn- z`EvxmL&~BQ);I`$XeQ@Ze<-^#j_3G_?bO?bYUFvgR-^E3vgDc zR7uj5YPCis3}_ePkWvcmd#u)627&%}l#ldP_X0bfWG1fXE%7Qf(trSrd;RinTdW~bpPS79p zzdSuL_M2x;KR%t{|0i;ARH@x0aBCD*@I1f3d4g7|Xx{`8mkG2|B_kLFAuB7(oIZJi zEXxSP2q{oDSSp_37rrm%mtNemhx0ix8(lV5;nDK}@4Ro8cOIRhWkZxwu01OPDhxv? zZlA>#-GwkV+N9s_VR1daQi>o9IUCn_|Ct(LCnoCks8kFUwPYvb<8tTIud+AXw3icS z)}-4P{2(LR7&GYoGP$`0E5AR<&{+i{lV{j z?(UD>{e<=d_(9n8!|3JJsDk$NRu7z;5*USHSTK4yd6to-8K+JjXMKH@Fsh(E&oOXH zz#3lh%!If6lQz$+Unbbxl-7pj(xT#hU!CHYKR?6SxK;u$8D<*`T1!!zjYHxE72=E` zDM1iojDez5A)vK~A4c4_TIUO=Jeo-le-KNxVu_NAvd_C9-~NJY$pW88PV~{9M;KMG z2xm{9Bux{-C?X6)tTm)*2G%;Rz|$yE#pf)>TE@o55nz3@W!G1i-n6_hfA$F-0JVDa zi0An)pO~0LX=ljrJWUveDCPdIwIa(h^4zeozQ)D#=g`{2^MkG4+T`3goAQ?L+vNMM zS)|!sXVA`BT7}P@ZSsb@XZhq}gD6zoe67#oy7T&3Yx#-icX`8W_Sl)dA)mXyD}uX$ z|M7=ne&UCA+t?cU>ZufCoNMU!f3e9AfB$}a^7saeEiFn3N_%v4mAmE|T)ZrVtu~QK zsMie9-~zWk`5>!VXpf(ZMMMaKkf>6n)!Jn4;&~eNkrMN0tx#Hnv1ME6`@ZulT9}xe zWd8CZ{eJ)6g}L+hJz)c2VtU7P5Y_&)5=A4UV`HVd=0Kn#H-`Se^}cbEu(q$V_q#S*B|U!X#^dbTTj$i} zL>@UK?yzueYY+rnNNRlWY?XK|V`R`~YRV_b=eX*|!~F5b)+Ea?*qN%QaXJpbi;_Us|eT-~EU!zMQ*NlKn)Byr4z^Jg&z*A5k~+^yPecWq?<{e z!y_vVe*9wx_=8i^1W^U8^e}Vs+^GShfsv-&V0PS;T)o1I9c)TfGOIw8xRMfBgH5_J z(eNA^u$Jp5QphdjiQs3_>-Fe$JM?>9vZ5swapfh9BJLebaA8?6S%P#f$n}S{9kPOD zs@3kLZZw)$ga_~cGOKHA3hg_ozHqg z1;EsfT{C_V{^t1Dm}t)<%d!%brHSjiqcEi3>vQ(Z89d)Fd*f265-I57v&kef#K;l`xXpX%S0nXS3)LgKE8HAHR&5h8t%|{G=0Rn zKVQ8gA&jsj13NN0!S3BVIdteC2M-=#Y;*);9BB1Dk9aV^_k4_}u;L*mL4w3lzy&L5 ztwZ@*91B{nHy9hA;E@L(V0Cr5Bz*?`zROw#`L(jLOs!U9YI5A0oS1&cQ=ffj_=E`n zrTw>ho;OviHyjfd1O?c!#7RsThIG1ZE?v6lv~um(xZ#0YJG|5G&v{}|8d5#Me77J? zuqCNuti>9`?rO*SVk}FSxbcu{vC=eUx|ty+x3zqQ9aA~h!t<`m@H7w)nDA3OR>@sp zRQiNfU+A^CW{0sWD{EX{Sme_DA{HS{6XG}~&2q9Vb%9;Pt<6$PnwA^|2!5esxCjHK z9O|E#oaV%_qntWeUZA!2 z{X2K=6q9F&2x*oUEtxY>v|B9}FJC6`gW{M$utiTy$(UJVoOp!68ZaicS(Xp0NuePO z1)>CsP4R=jB5|G42(rGBavx|DFPP@ zoo>INZ=Dof3=-ifAWtDnMe?kWs2v@gW+_>k7S5!EG)~A+2g_d-Z-98=rXn?azJT?BC^C{hg18@7i}&H8b+t^+sJ)D^>da zK3Sd>M2JBvO`c~gE-auu-)RAbd}fq3r$;${>=;29F+M&)5Cj-& zX}3Gnfw{RkZoc^@PM^OxHa<1|df+vGZ!uc2&e&}Qa$88qE_;Yr$dch# zUipz5?64_ION8O!Dvp_tWim$qGTq^EAff^!t6zpTEGZHyxo` zsr=~e&wb%-e=h@IYRB$_o*(?|jvYHtBIL%IIN~IB&RS8dtSp!AT;ximKm4;2DXzOv z+$ltg7R)4Kike}qC5{vFJa+-)?jtsL+&an>x`Qgk9;~&wu`;Az^UOkKux22D)mkCB zxPP}6OYRbnF{r}ERhFfq%|zhK7bp1emz(_Mr<>gWm0BU^y4r8Dj32pefvL@9l1`6L z+&|6-J~Kw^!Xnf256Wx4FU0eG#wI2?cJwg@g8`j(hb+tJ_xfa6#^r?t!YHEIsQb;a z@qhoq?|hm1dsPCiJ@ORR*4BSL^!;kB)}Ytxmi&H}JC9$hwMoC{$#2V;z zq2J5#2YqZVt^~vo_YI!TF!ZoCLKRsm3`2JB*-fj}!3xg8Cc>XA&7xPN%nmMC9S4vk z3A3_>O+C)33Hz_VvRA5=h~0bc=eC&+2O7&*GeQuA^!t70E?wf9!-w%auf!W^nle9s znOkqUnO3*=oXhib{|I>R-|XYpX@evt>tg zso#_qtL<$dP`;q8zR#rvxZH6zuWdiV-R>fgmODOQeAM0ixr+N>Oe}8DiF)^M#vW*8laW2t6?I;!4e~uUawz1?kvqfIrmbYJ7cPH z(Tfy#CNDD0#=6C(8I$`a*gI+H_Y;P}BW{8K z(c0DP;S(4JLgB4bf)!Dsv`1k)!W3mfYh8|incTRWUHsmmPT^QTmyxvRp|oF27iGoc zlk(@PVfHHU0|K5Jj-5FGn;?7#)S|5+_2XGiGo*khB;bs3Ga?YY4h-i*AdD8XQ^Qq5%&gOak@i-p*QEOx4kyf-G~lq}%PWyu8fP(h|LHhbRo`^?HRh+Qa6Cg@t)kv3vn* z_}S-m`M;jAfm$1&MDP#XXz%Gx$ZLLeo{S;Q>i$0@gp?GlAC?#0n)0gWrW|Y}RI6i% z)Eu4_1xkZ8pq%E948sMBvVwR8U=&cwit@w`zYK-NL&N|nRst(1vBhK%HglZ>3S&dt zGF3Uhk@5b!=lQ@Vmq4~$K-*hDt%M|r>32H(`m^Tjx8G(sGq2_2$0m69=?Sd%OF*0( zLo(pbPwr_mT`Fz64c)@p8Q+4Gp0nc@2Du0TZy6QXNFHk6rf~y?C$Sh+w+JZTDt=+z$aL2k=m^|6Ui`$9Mzmt5C<+x zDFuE7v*!-(+oX*}Sse()TJukv~O=Xda5@2;2T7o`+& z?AqpPtxlZ8v^F={IXla)-FwRUh)T6WlBU#aHR3oaR8z&y9Xl9lHrcy(x3kg32@gN= z2#*{+kz71`=KA|S_sP?LBM_)We~&eWco1{+vEkUhCGdSr;bM)#(6L=vwne&N(VnK= z+H|+yy4(NU-F@0?hUz|#pS$NORx;r&{y96n<0QB5ze@hV`Unn;Wm#Ul@J_mY`}eQf z=hRlkE?aT~-9D^$Ak7NE;J&SB8Eu&WtOX@dj1iOxLBtfIlVh2%TbRNWOq2_PA^^2B zuR8Y*RH}-J(F{NNAWs{)j^F-;>-dphIZkc`tQ5c77DABan(>sqQ_%M`fA!@`v6R9+ z&VIkg$jAsun$hnM5P@p7#`&{nn3|d)2m^w^r`PS_2R_|S7g35{w~Oa_EG{l`_S`v+ z9X&>Kw8?05ltTv(^1#E7`BA0%3jR0y4*!n8BMHRK~K zq6!V7xWz+6YI6|Z+B~&lGfPt^92ku`a#+~4=NLCn2|x2gJ9*20TR>@5PAfUi!SI4> z`-Gv-vCW93uIm7du^5vxK0Z#rSW}lIZayLmL&B)S#>N_xQ!~Y5b90b_K#^&|(%RfC zy@mbDecJ6d)oO)(yLU>v)&7pZQ2=!NgJ(vSdZk)*p7%U+6FYg45`FE_?YCYHi2wi~ z07*naRQJ%z1%X$nej-AernHLNZ_B0~K5^0Kd9%Xw(Pe(;6`37mNOQ9*{S5o5uV|sD z&jwqjaGU46@W2|T?{3RV=JA#_5L1&8$AAzn$n7C_QoS?Htyp<5in7Rh9dEeR$m zfZcGhl-=eA7(SUi&loj5Ue}xF**asVe~RxsGHZXgYGt+S#>C3*z*=tI+eIsQ=uFK8 zrLm-G%t&K|Uawzx2Q0g0cT%ZV-3AliV|96%@$pIeSw<9vSc@yci0g_9&x45L3k2wO zx-2X%GCeg#6rQ{FnRmWu>~o*^==wJl0G=0omoYg(5RzvZd7c%%HOJ{EY2wzd6)l+7 zj`Y!@$kODBUVm5`S}NjCk2Z+Y7Q2_%rCEVXIec+xl=nOkqO^52+YH%0s7cDsYTsSN zn(&U#?cnn(BOnQts`CRVwNjuv%}ErUX&N!IcER({T(sJVz6itsw(4}oddGaKZ|-UATrd?RJ}Px5LOtvlx=u8a~PL43)cfdt+mhdc9Uo zPxZS!rl%$eqbN#N^A`Yr@^uHm{;RH%IFmbS)mmxLu;@ZSah|p$Nl{u8g&~7DE-h0a zbi3X1;#oVa$AXCB)0-ol__FZUJ2%-mi~X&y&hX#AQV}oESHRPuurn6sNNTY@EO-?@ zbi9h^D?C3a<_WUW^f}}W27{zT*2cKyPfFAlC}10jP&~fvsbct;Z80mb^$P}NhM1X| z=F;3et+2`QwGD0>WK>#n>>IB-KEW8C^`x8^-LaEtHf^&WaJhwi<&=l`j`6f6Cy5j4 zjT+YCIw-9jds<|Ps8VHd;WE`~t$ZBT7(^**wHn=Sw-`(b9AQ-iZoA!f9Tk?5#>k8Q z-vZ!&%O?-|@g8gJLC^EZb0@!UP2#%RMM0(v4?al}lGM3;`hz}pTk0LkrXt|^0duCx zYEOtfwZR@ zxKdVRf#v08_UxV&YwewPzU1Zl>&^g!IC)l74V35m#Bp4#SQ)-(7V+JTUYcg~`hB!= zX3027==b}jyLE`hhd^!UhxdG+3mZP0t%U2Z$?=tt7PrwB%-mK$NGa#y`J$9Aq+m_o;x)Xh?5wlJghG$F<`CL zDl1&fmidc@yFWb7Lbt(RoZ8J-;|3x^r`;y1L{zFZ;yC8^Yjgh9_iC=*HBBcO=VQkW zzxjI?NQ}i;Aq*oHFJES6$4-~w;@G|3aZ(CZQ52R0n)`Q4uiIsMdJ-@2_sm^5cNK8* z>k0rrh@NJxTcaMw33)NiI{XEL{s7PS$|)DGnChuS75d#ysm?hdw*{iC9a6rUqbpTb zTM5@Exjgq4Wk2y1D;A4li}4%w`rG^W;SIJ$y&tCPA?T9g@Qjn@w*gAS_Gq+Qt$<6L zMK&3(gc-VbhW##z z@b6wa&(1ty@!rSq75tN%pKAG`N%^(^dKnQ#7**(Y+E_c|vXv0z06}Jn=(_5rUaU-?XZl=BHwe#E*hh^w= zIc?>~h4?I;592?91+`i-6U`11eHCSUlO*zuPV1MvxL$NJ0Dz z)A&}pr}P#K%L~KOvLzxEKiZTTMZ|Fjs@McFG>ock9tI4BWv%cC07wC1aaQuEQbYUx z6*P9ORwvCevOFivGQQ*5O=_(k^KqSj@)x)Bb02&f$+3Io_I(SkQW=Bid9>P_E?9GC zT^qzPK^VGmbnVvJDN&?Jx-AzvEF~B!QFQy)RRZ?z-8(wS?6q3!a;wL1aB+w*-HH?K z1~{u#27>_#N~A7DcAyR!wyZ<7N9Fjgg8b{6(vCaT8W^Llfh&;2dakYX&)Uby6uFcmvgM= zZOOdDPC^5j``yZJS;pP4M?oTLb;WfP5e7vIXN|$LhNm6Qhg$_@rIT>+59 z$(TWVn;Yu{K|rNiEnYZFr4lhH)V|@V3fqP!ToVnW*)@p1NLmv(Y zc>KkwQJTRT`&Z6U@v&imL=jAnj$!TO*S7KHEpl$#t&A?)sNZcpdkOkVm2q1a-~t=0 z6?~iXx__#8(T$-U3+kfrzy?_Dkp&el3`Xt$xa$J%{qVA=vhUs!uFQ}}7y@K#-H^vN zT;XJ6Q)alG&5XDGNXI@Y?8#&IWgMP5#hp)7VXw#O)2HYUQX9vEN58HBSXf**+Z>(v73KMFT)aFllhZR) ztIp-p?e-k#P_7M26SqZc==bY(yJf96X1JQ&Wq~wJ866v=({AGjZshA|I>H;j;&I1x zpNX0k-v=EE8(CByw}`!h%Nf@G@_-R{LkhrGrhbt!fZSu2EfBa3G1@fYcYm_OQ^(uL zg|;|rn!D|yA@Jd#R`N^V_98noxyQcaT^D3~Seh~eZHv1Cu@B4DHoRiRA~)_ydCRMN z?Ci|R+!@QCJvzeS3tev9f4_A5n!7Jf@du|HXit@;%JY0W?G|Y|1vq8U%@vpumw_9x zH`bE&`AEI!3g*D9PVg->c zKcSRvVpTeY3iWVU+lTHWD+PKlDC5F^|Jpk@xGh?SO-rX^IdvY+FImzYw7|@m<@#$Z zW9f(G)wjOb-uFOYzwmG@ph^xwZOc_MTtS~@{P0UWruU44j@$w>i}-oRzG&uzjBc!O zW?u0tAD`vk<$IUmy1hzNVes`ofenxr0pKNZdkEcn(_~euu$jCCMdTAj} z+#p1~R%4^6^ShgdH@>37jaOG}CzzJ^e6h#x{dr1K%mhSAh?BHfo}kd%NCT(YO9|F& z**!Rh-YuDMHFWrOd7km+ABJ5AXY9g8B(M9;`Lcb)TGBM-cYnIh$n*%GKLPK2_cA7T zE8lLPShF@Zg1}eTYrOX36D;LHi7)m@m!Iz}@toT%^)q+LE1!D{UwFut9>k%grBt5n zkWozep2kV8ZdS1>5UYIWc<#4lFyG-T3lVR;dpBo$5n(9XgeuwkS%t$$X(x9&Ae|%1 zr_<@uY>trUIdQRJB+YVGS65kBSi}pwez)8H=jTry`|p2aOIT}j?GufWk=wNwy|>%# z91!M@9UlHvBs&@l{PeT0wsT8LK75ZMOH(}G z$M+2Ve!pn7w$*b{_(9-$ePi)N@P;uV)(SXN=g>`T494W_Sv=1zW2a<&*M6&{B6+cQ z$Qnz-#2nc;ZKp#;clV)!A9jJ`#hHi#Ga2%>KbvM)wyl3S( z@9y>OOLJoxo0uq=K~-+P7;d++)-owQ78&JdzPOv`jd%Iw(G&7rx9;JCpK-yGCJCPB zF*`d;nmO}kUc8-4R=j`DP^^<}G|$$bwiZPU17|RRJOgYdHg{Ah)@l42OO{%(xdksT zp1K8N@vXJwNFFr!^7()$(onRPCN~6r$p4t1;a%s)(Msb50a`gUq6+g0hSHiYR*B=R zeBS)%{?Z)FHk=}&@O+IL(xXEOy#T9PYl31$-k?7ydVe=^-s^Q34aQ4#HceBaAYw2W zkmWgXJh;c2^p%${p1b^aW(wU{Uu%txjeoDP_R%DX4|#g)4Hn!E-8xb@fUPy0UKCz% zUCKXyQIEr>jWIAKU6eFSjXckDR@c_Idh3#S*;Y-hDeYX=0tS&{vDDC#Z3@NB8s`SK z!#94|7CMF1zW@?fe!kojAw!#(MGv=@6j>+=BTNvMH*`zpwwRKv8uot5iu=GX_8Sa| zso`@}%3&0n=fxU4x7&C~o(-2v-f>I7*vtr@{#=XImc`Qwo0~#qbo?>IUSD5J#wK^HDW%A=v=mZQfxN?lpBE86biB%V)aJzp&Y*yW zHMsV`fPeYjP5#UKUAr_qz#$+TvM@@Cb5svgxOFe`(6BL_F*MeoMVAK6k_Il)=Wy*> zZk#}3hpdR*8VwoR(Cv2Wk*#%ZrSqq3$F@2OhQyM+68$4qtg*$`P$|oVr(Klgh5k_T z6c|iy%Pu9)4dZ^s+g=-U%l;-}5;k9Ykl*=GpZEOb1vhP#IzL9UIYJUA^an9f6rr`I z*Xw=V?``xA+rpJnb~_sw7X1HU;HcqY4ZnM{!Tc9Ax13E#b5Lab<3W!fd(MXao|^(O zXwceub##CfZ`y%qP+BgmdHjoi-=#1RZ@tE9Xx?;_JVp%LszQmvx9LOfu@EYa~w%zx#_dW~Q59jkTghY~q>$ zt3;%*FyXuTb;+_5&w<`KgVQeDCO&1=D+=gd+kLaDV9x- zj5IJN$K=K~YPI#pEdvO)Qwlnw5YKJ)>h=4j;ld6fn$}3Mg+@g2wqujrGB@DbiJXeR zCBj$-?(y{&Zy)=SU@TVLZO^y7enZ%FrL2!FriY7`jO{)@VY=%4oXP{sHk{$+4&Cn! z>=s}v_7o0FiLW(-L4v1MLGN1fd<$XNA`yu(#hO}B%Hy-A>pXaA=pz)gGFT%et8I(+ zH#1<2h}Ixhc-nyu(|Zkjjwm>8m^l<$26Ix8nhnEIF(xn8)p+y=F~(ZrL4wjEON*<$ z$1MP|JYN*ih3Cysi9(Vj#nbM6cuLu{6l)4orh+i4@JJl-$ov*ZKkW0joVi=A;FkWd zMc%tR@-?*EHot*;QW`C`^ds0j=eai|R4ZFqL`uVno9ea(6r=1IfwjKb@>mQfOlC zdb8O2-fQKn^BwzxzqBOIJNPxYVdx_$-dEsV7j|x=rniWy;n%y7`E9d{#SqKS=s6C| zwB#QjKFv#B>obzA%EqeU1E18AE06NKvO^}&Y?({#6}~<@9PmXf)H|{K%4=rr zAAPVT2;8_U<<(Ewr0&N4sRxB}SOnU_hH!9TsjhT+^DpePKlkg4vf1AfjFhqb!gsgq z$k_$)=8n@(XT;i>@({~5#aK6yoNv`BQOf-uC1~ZGKHJyUS#ZeSZoNiXp7A?houVQ! zPgz=^*?{>>_@hT>IlbypZ}+wGw}MV6W?8Le&H`w$%uMG|Y^@D9tZw>R+hkbKe1EvJ0)o^CnDWv}oB*m47h z-S&yB7#B+ySNKOem3;3{*0CzYuC&RP5+~U!c+$=>UUXY-Km4UcwAS2vsm9K+4%Y>X zJj1KXU2nbG#&IIHkb-^NC%Sw=vQ=ou!vFkK;|dvh%UxEONVf@qT5>|qq5sSpJh5a( zl|wIkcTKUr(Wc$)qqN%@=y@JFHQw;>9%diuvwu`L*{jj@tB!jpb|Q%g-A>QF2U6nv znbw$YZKVGAl>iZ0v9_%880(to+!zAi$Mf7K?=5T9b_ceUTK&+w_hT=P`M;mpvO&Kk zHWx&kxpeWm(BAdgXsak}_XD^c0p*BrX%0cG#Vz>C=ax{Hmx{Iu7FV#BSCJ!!u=S%4 z%WJ=ThkWE-x551P&yKQpWPmjpd)jBIFP@d^wnSzv3^Lg4z$Y$F@QG7CqD|>HRANfO z%3TgA#IJ<+|LfT9-@hAFr68B!(e+XJ#kZa0!jj>_+%h90btcBgSXo=gs^MgmqEfA~ zq3S%4xXf7&(-v+c<*DLLHUhWtObo{4*<%ksY9F@%NRp)O`C;*f4UWu+2_* zC}2zL(BZ>eI(PE%2>`8Rb2zWA3kPr%x;;PbPKVLaQCh7{R}zP+8x~L8lBXmSMkB*- zeeVX>c`cUb;3LN(-g18(Q<6H)O`|=zVp4dBqK0ua>>jkzWHx5B=Jfs3VUr*Ke6{Sg zloF(vPk7h)99#J5wRSo?N)bd=-hC+|JMUK6OBr;6C=utA#B3q|5(I8*RSSVgwsj{%UcnkSo(L+~@PJdMkWKb|2sWyqo#64;#)cJ1wQ#?Ug}q@*M4{lFwkcAPYs3r)0TX#NliA zW|&&5g~x42(4lLtm3m|3g|7a&mMu;aw?skdatz8TUxufQ#Y~tUxd{K|zMcHryLWNo zJb2{XlTGqKyISz<#jd~Nok70#zu_>~aPU+3>q8s|CsTZZm0rN&8%{vI&>0-BzKFc!FBq^OkZqmpnuQYhmqf^{>QlXbG zamx`?wzf{^uti6$3PH?0&Pt_17zU+|;CarC?cS%zC#qClaO17F@BKRufJ4_@D{GtW zw}eskUo=OXgi%-yh@@#klEhB@(3&ucu)wIFvDOBfJ|9{h<eqcx%+s!6$SbvSY+ z+eWvxzsN&}jl)<@i|{;Mio#eJmjnUMuGH*y>DX@55$yJ*Q^+>|V2Ln`eT245yVlrk z?%LrdkfFJ?*mT0yV5*xhbcf{!zS{xpd-QtUD^}iko<|T>*-Sj>x2QF?g4u5CZc0a# zwPac9#>0}dd^a^!V4O6Kx$(#iD5ZBz&CGt}mS@~C^LJJP4qtnNtgdhTS`bD*7X|^< zYMnGo-P@t4EvKw8hHkgZR*Q$0H1q4iRfCLoyn5Ys*Nt4)$QYow=RsW>GKPEn zk4$B};yab~LM7|%kl*+pNvYPQ?v1|DO39YL&tQx6{<*VN1mTOFnq0vV$~Mx7ZLSl0 zWl7lXCEPwYu*GTFQZANlt!J5~WO!hLHMV4WM0t4L*6w4wtp!#}uu74}In%Wq!7rzj zC@gfc%@&ts?%hp1tr_(DL{WuquSX@S&}y}rn4IF7&v-ib-gp0XV`CHVyZQF#eES1m z_{_%NDggHG+b=8Y8~-+ps;{fpYBU-nbi17`(nBlaI4K`!zu#wKd>m1V%ZbNl&V^Vz z;Hv2bnXSV765Ku4;K56(*u>$q?{C|a@`mqPwGESsXjq%B@>Vm2h$S=DO+pLoZbY`` zAxddHt;mbp`l00!KD5+u^s?GU8Enf2rFf&Z%%Zl?8^nGsS7EmTrbz3msKF%x#0>KSCY!XH!Fhp{+9K9==IBs10Rlqslv|~$1z&F4Psg; z2JwJKy~d@B7pO!bw?F+h?)lsopFTc5`Ik4`^wjTs?7@56f8zk?$LY_7QT6pv6v^o5 z7@bbXEmO*K{9+t@I3F;ia6QjM|F8DGJjk-EKJPor-QLpuUib9gGnyGj%ScFQi6jaw z$e0Qat|9^@kT?X}I58=klyMeU#V!bnA#t!xa8TI=HrR2+b|7FDlN3e-m`G?TQAjdK zvq&@3Gu_ks+wZ&Y-FvqDan8N(wOmO`pc!DSJJp&}kJQtB@44sve&6p~D1+tvSsI|%xcoZ2CH_>_ml^NTlgDRFo&I;9UJiM^7-=ZQp1etKuM9?Gg20f&F@X2@fbnWW4nj-kTDK`(M5G3 zl|&eX@MMY`mir`Ug{}9g6Qt%W6FuH^jC_v(7)=SB>sfLC7)2D>ydi6gYaoTd?A$y& z&oA%*TLW;EqY%kph%gLs;>1ZT?_b89cf1;pKK{hrGjsEQe&>(<#G4-e`j-bUdI8j@ z=YEoT!3POIrlzKlBngyO;A|9jXtyTmJb(xoAxN_nwOS3kySw0?hevuI9_c#M28>y@ zxC!3duIZyBBt%4U|3lOGtCkN?R&1+Vf?%^tP;VL>^tSL**VeKA#t?t<bP;LIDvH zeEl&_M#sx&Co1%g1<+$42m>HMjB`kJ*#y=l#Q7ydLrQ@l3=2l~z)fFmZD1pKm6V{2 zVS8%}lv3RJnpfkYhaY|Yz?cUB{M?IP0EXaoBFlJfcFqPiI~y~=qJTy3~O(E-aX{+Y&JGW&are#36vhWh~;h}+7RfmP9h&_ z=G{G&eoHsvv zA0vPK*(MBF;VJ?ryDOC|;N0dBN~I7*p)DpE1*q*fbpG`Xu(`1b0$_S-602+dcU=Ff zTYv34Pd~Bwq85Ob;#mS~UKEBUXSrgajY26bxtLS?4SCM}69!Pu&(G%`GNH#9zhul2 zkhtwwBh$I5CMEO*rXB8uGjj=2o>Slq)fH3QO02a7KsoWoFqlrfd(N^jOMuea*b{-*t#I z%;hL4C@C<#Zy%^*VcD!fo4!uM5HeFm4397ZO4&@NR=b0K+(X>!b|$B4jTgNGP-7l6 z#>jpg^HNkUxLK6aBIn2Y=Gh2!z#s~3{CnJwarhMnapJ_uk>JwFupBRI^q95l^pv|X zWQ=~2a|^hS-+8KrU%s)0M~-V;xd6=9B`VLKg-c&`CRGL@&;S4&0!c(cR1l-V9L7Mu zB7lUv&@v|9p2wO4`@QZ_q?s{v5^lhhDPWKRtuD~l1fM!Nhi|OdImsB=ccf|_Yv}+3 z&q%!Xx;~m&h>!p24DP+@jJf5`edJB|OqkDp%@BM3TlbPM2mu0Q0k0cSQ}I6y9~T2alyVvuSMs zYb8r1V|46+5{xY8Nj}FIEtK&Mi81%z=jfXrEeJA>DLN8~(tr>^mH}Z1bWDIxAD_lU zTNc$c4l&G~N5=)M<1FPWB$!ZG_2L#9c^}P3$EG1K)Y@5$T=@|`ddfr9WO(C& z6bB~++C%FmUA)D5bc_(!7J|IcBi=Zlf)U8%$VQF~WX5Wi(YC=TK)D@2bu`Cg-wpA# zjk3!hrXaaU%w-_vb;h_dItO}o1#sd#!R^;j{Q5ua;6}D%;sMClA9A`%M=Ot_$mS~< zjllPj34!4-1@}0HgQ1TF-`K?R(h@c|H%EHGv33U|)QjYF{XJ`A%vQ!7>HsnDsE>j1 z@R{`zus*Kxv@YX?CqU8f@0FSD+5X4OqV{Z07_VDMK?Bce=Gdc&bS|Z2oE)Ub9yWpJ z=YGSgxObXz{Ml1=D0PNhu>hVI1hmnZ zrV=R4{Vi(B5r)8UFerd4&KNRhEl(*$KaN2eHN9@{PrffCaBcOh zi7FGH^8M)MEK3oDHtAD{tl;mlV!KoDg8&AsNCw~D+QESX%UHj#F{0m&1Qhv;YY|dO z3YGUBUZKtvzoWM<7nKr1KsiUr51_Tey-RJ}btpzT1fEYOaQ{Ogq?Gu@8#|b*8AKs5 zUp&2!eEy8BUw-BG4)#qLlqU#&;Y;&qDS|tyJ-qq47}W^qu`+)3f7d~%lZ%ZVCHbb2 z^YKL{u)Mq<GEL1^^x@>}ixz zn3-8ZG8iHV>{!_Me3!JIy2Mp02Ma^%&s;8-L8+zapE-RRX_~Ih&CY*){rs8lZy3ZG z{cnH~{Wvc4e}q^%IHA;yNiA1RWCB|0f-y`eu|72i_B)?l>>>3M7zDn7=K*rCN90pX z)l8n_OX*&RPj`$k%8S~h78o3v1+HBN_AgOT=OMUMGq~jtaN}Wv={aVBD`G!?!+zlE zg9aXDV3c983S6^baLXZsBL`_QAjX>#t>53aw;8{8bL(q=m39w`Nm?QAIS3lU}RKoXtOitENDn$sw z(2{N~;}@Ri+v9^<8oqY0wjTr*rR5wO>+4WT37Msze96YaB1=C>2(|I*V_f~QItj|{ z1k8mv85nS8;nR)HEnIo!5$A_*Z{&Sf4sq8+%UoCk`Sim9w!ghb{>5Dhx%MC_Jo)&T z!BYMg7Emu4;rB(mNJh#58jR|PyhWtcxlWDg7Dk65byxx^%&(|N49itOV=al25<%eO zy6ayFKM2u}W29+{POFLY=T?xW8P?a%V{LT>LS)$4-oeh!4sL(-Yp{R+eh_E;pxn%W z5>^;l)az3=;vNLj(e5)LiZ^|jS|270zib= zMsFwmc-GpG_@gr-g#?!rLhNGU;<|7`F-|g(h$05oaHeg2^4=jj?rub!8b<`-G@sfL(MP zlo4=B4AEqq;SEY18bOFPailo_qcJ@_1CdDxA<^x$(P%W_dp@F41t12DTX*kMC!fXA z@)ZC9R?eQq{QLseRxj*fDk&|YmBzxtBDm)xNi5cHi#waTnxlQYyE_n4I9~+I6VT2f z6okU}{dAZnAACtEVVzcEP^#A7&$;(oNgRi6+3r#0!Wd$-HjFbeJG%fWWYI08=@4hm zuHfpcj-cD^B29-_Yf|iVfg4^Wv2ZpuuR1JM zC{57m1Dt~N2l+^kAX65+@%2b+P65ONpg#my-$1%$q%<%X+7H3?XoOtQ|4b3)1Q-mG zK02Kaf*>3-xTMZG-Fo(2SUm?R77;BiA&%oh^^`M=q)@2UYw&}>>ixse@+*=Ak?T4J z!vW5%tiTwfq*6m;3?YCbl=fgu4=`QMz0F>y^|9@Z)yH3QPGHh&{oc}nLx0-X-K_^f z5E4zQ{eD~pp`3HZ8DmUqyu$#0uhVH^VzO2gO?E!uVRLf}*Ij!QPd)uKzH~0ck$N9D z@C|(Qb=zdvmU!|^fX{xD+J{O4dCVAdQylkR;RgXqrHb>h%OIshw-=*a zF5${6kKp8qlla}gs^bl?Bo<~2DStKGn0@34hXg7dM5`}P5P zDl`wSdW2BBZ9cvp;EL%1^uWVsPcU2kP>St@;+}bhPdrg8#<$0|INp2|ICu@iFa3VW zm@&(qf~w|PHO86q0icEUfjbCTo4p)~G_{Uud-aSO9_LtCTm)qd182L-DFP zo<&;I4{xup{>AqCDqf1~C6A6x`kii6p8PpK2p?>>TAnT9EKriiv~Fx}VQFy@Q&ZE} zY&P&m=fZ-9O>@9yk91oX`gc?OyD1z*@-tg&g2gH@JppW#141Y%b|6W8T)8m7*`NY2 zUM!sbQv_FCMez6+gQ7?n5{8)?P@88+zz88@9e^9tnw(`wXyM?MOUR{CBPUW?BwnHv zg-8YiR4V1sgivWL>|eAq6)90FMMzUi1W`(&TCG9|fo8J>ZPcTbn)khw&+DRuM-Td) zV?tyf0)TG21t}yvj~8tlAp{$nn>cv*FmiaA73tx0oXm?neY;vNLt~sRjH2x8` zMH-v}1IB?B=nY zvVv5aa|kD@)sdsQR;btOc9vq5*N{@96qOJJJ|-q7k!2aSwzfbhX=T~)9T!&4q(Afv z002BjKcJO-B26>Iy^eJk&Cg9`GX*y{HgMBTHzJBkc7$0x7+QG!=OgE#^CUDQ0}o3_ z%ePc_MoVqLInWrgJ+2{DZd=HN?X`sG)EaxqaV8NVu+f3WjHrJGWRFNi7o^Rl+WVkBlo!VSq*R9Zct+lVFZzloyTpL^U_2URzrOWlV{5`16~q|Npk`hh_nE+Kr)- z^6h|W_4_fBqz|JtJdcAoX_+<#=U3No^ypDkCnm=p{0JDyAC^?Q*oKt@V62K~99RO% zOv8_Wm2HM`a)Cz;7=v-SR?gSR+RqtBEiP0(#EyI^2pK1{j7G_}_!CkhN&4`7A2;1} zGp44eiZh=UEMxnzxU_^QDnW=0yNz84ks%BtL{VfHgtl=!Hb=lBpS#;Oif)kfKeBf2 z`OjR8=XB8)fU5^ii7b65rA&6(O`C|BrUixcZu_L7m|-TzZ@( zdyWb|=4QK|@4vu9*uHT~(+0i|oI1ny1U_+U(LJLu5_AxY9GX2Qh4vq*u=9rN57L4` zN+~I@2hKTG&z(U!9AaZ*6RWGMc;)ps;M(i1bF3Z99W0efxZ>a;gkc1wH8$4QvAwwg zr4%M>HDu202~M7t42B?-pxtVrKNvuY>?>gy{OZMeMi+Gf*m|J*d68wm4iI!ZE!z?~ zqNe4?**AN2Z4Fr_aP?JJW3pB&#s-8?1b$FBi4jKKz{C{4U<}I4;KTRz@#EJG@Wh!2 zkDg;Ao*#f9B=CI@)hBxv4j}}Dx!Gi)>Y+Hh%dl}eGymn?8TmIq6Tu_8C`bt*;GPfe z`FQTsajcy?gDg$)%rnoRR4(JSue}G;)6#r622c4KXmR3 z2p9~8LnKLp+1Xjl&&{FLZacY{F8EdU{~>!YfH&PF@!@+Lm>u@;m){L>|07e7W8#4O z{+7Z&y}O5iYW%@tlQ`d^MMeMm-McpAEqUUx7#%LT$$j<@8bCH z4|^o%mRUuPEnc%MMPqjdrE(cbl3+L-V*i0F5XXH8DKH!)SX(_0>4GBaQ_~27z%D$u z^W>Sv!@&@ZMgt&-2mRigw${%-cQKz0zZ46g*J;YIJo!#d)X}6LUl&FtR4Y}aSvDpJ z9q|mB%_f2%z^iV!0dYUZ>E};FOFM*;F2Ff&|K9uh1aCOJi<2jS&plJe7uQP#A!4~| z@cw%f++1s6?Huqw&P?E;(-dUPLdWM6jA>KjAT2|RP^^@M_=6RW|8-$V-h81C6UmW2 zk&e!JLOd{P^M6*)oyBCW4zsv~!C-()WZ2o-LelSpGKN~Mj;K`HV-%SaJ&6n8Z1fvo zoSSZ^_0P7~&p&aopUoxN0j#V!&4Q?M1*PncQmF*Sz2a@l2_lqHL}BEDDKm7sU3i>h z|Na9A0w3K@x5)9!6}JaXAE(!V-+p2mPsR4;G6MYb*QR*y-)QMr0Q zV{Ct|KIQTT$sRv|aTTw2Mhj`0q1)}k4?@h(&mr)A#QlDe&-+x<$78!?3|%NRKyXtv z#ZO(cgL5kypMH7*zw>MzJ1Qt9fB^8?MS%z2x{FXKGCugmva$j z`2ZG#B89Yzz$KlgW=HC6AGU1BM3q(g7v)H06clwEP#H$e^(HdOWgNe!nozTYpq7+ z3(D9Y*lo4;bC&NWovHGL0pmOd%RdY`J|9@?!qlCuMx(;^ErgbP_0%$2qC^7+;l0P3%hjN|HLm+LT;a! zs1-Kng`LV6yJy65F@*;a#%2TgS=(&3FdPnX#eoBuo0~JaH?|y7gD01BuJ73M~_~EYIVX2 zSglvisL#)l#j&yRi5-G{I>qv^NtRd#+ii+ZJUWHvdfuLgt{q4eMI}s6Ps0xa$B7(i z{w+m|kE(n3P;F4=NFOMieV%qYKE~|=*G}oHr0q1S)iPSG_M{ZzfyVa6@JId#7$nIY zq5NvjIAAoCcC&G*EUaqagr?MuQ7sXYyCIQ*aS$>Aam62_tcZt|#^CwWXW@Aq*WYkG z7^OIM>N&JpZ73x{hz+AOPWcNMv`mB#ew*XYb3;@@if=Unv=CYOT9GNlFg;aAxm>X% zOt)w~Ctc6=5V=R<9u<%~@3q$8+{WqUKa(EY`lL%_m&$SihQlG|=NG`a7skELH2@y_ zkzW8($wiNOJWW$bslYw%0;H@^BJ!OZR?hS>K;ZjD5QK$8v92IeD#u{5e-^r*b(9@wYo0I+iXd!43Hou2&5aExt%t)T{y?wO+WL`S z0K-9I!l?WOsiaRCe@)VliOm`E3c+Mv<=fA5DCfz~sAb$_X@*v-fiz3q+hyN4?s;}H z$hjj)+9VPy!6FbspwsE1*=&I^hI+k@$y&{YKoCq%Pa}*LuSB`u*)a&)IwYh<2W5-qdtk4kHJS0=p2wL0ma30Q08AH3(LZ{OK2-)rT zdvDuVJ^Rgz{cH#>@l~qS-pW1y_Xsc*l}ebHtRZl-^xSd8^SzN}91I5iK056d3}B>` zAON9^p4Erc-I7^$ReQ%Yty=a`wDN3~i7V+?63;0GQC$-pfv29I;3=@5Bz3E0~y= zgy;Eg7BIBip)p1X@hPLlFZVjF0verL*zd*t-ffI||9}wkCQ9kDF`zKos%Jb8VN`KWyeQ-nt<_hg$o|Olye~I)HVeAe z-10%ho%VfR5dJPDbk_4c%+4<$3`2X=WGR}>hIN?L>bMZ;J9jrPJbtO4!w+l$i~yp^ z*L!~O2}&e10B!{k z8l%a+nRx^*&^n*Ioh7%~88^D`z2;F?xTivE6&IU#~VbTS<4-8e<&8fs6d>&&1iE6<@784Zu^<<=WA6a>Jeq$3Z-Or-^`q| zhqqL%yrs+Auq?|8#!-&>2SJD^3Q>wmIDYa32+S&@xa#clC%hm+666&gci_MqHc9&?i z+vvyLU)x?k_wO&adqgki1puu-4nPi)r0C_Dn=C5lVL;va@B0C$1EI8Y4KJ5UXt!I? zN)3z=pS&Dz(Pg~=`n~pXrQ|Usr3+S;kW#o{OS=PzOt=U++Xhl<;pkdz(&76CQi?C^ zY^-m-ya0X#FDcUpDC1^0=ofac9_K|eM-JcSe1V)*WB}|oc3@ykKkk0?a=ky7{Q{^? z)V`#ZTp1)bTTg2XJ2R&@DCA+uY5G{LUVrp*y*~th1FllF_AmV) z`b}tEgpCw$`gm3V#`PftJP1sd4&Kt<-TM6HdT;pOgar@;!2?31b Date: Sun, 15 Jun 2025 12:09:34 +0200 Subject: [PATCH 5/5] v0.2.0 --- CHANGELOG.md | 8 +- README.md | 26 ++- VERSION | 2 +- dokus/git/git-submodule-leitfaden.md | 203 ++++++++++++++++++++++++ dokus/rust/rust-offline-installation.md | 152 ++++++++++++++++++ dokus/rust/rust-toolchain-msvc.md | 152 ++++++++++++++++++ tools/collector/processed.log | 3 + 7 files changed, 539 insertions(+), 7 deletions(-) create mode 100644 dokus/git/git-submodule-leitfaden.md create mode 100644 dokus/rust/rust-offline-installation.md create mode 100644 dokus/rust/rust-toolchain-msvc.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ca6828b..461d258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog -- **25/06/15** - commit: v0.1.0 +- **25/06/15** - commit: v0.2.0 + - **Hinzugefügt:** + - [X] git submodule erstellt + - [X] Rust Toolchain Einrichtung + - [X] Rust offline-installation + +- **25/06/15** - commit: v0.1.0 - **Hinzugefügt:** - [X] helix - [x] desktop.ini diff --git a/README.md b/README.md index 9bc64df..a57f0fc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@ ![Logo Adam Skotarczak](./media/realAscotLogo_128x128.png) -Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebrauch. Ausserdem befinden sich hier auch viele Artikel die von mir noch nicht vollständig verwertet worden sind. +Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebrauch. +Ausserdem befinden sich hier auch viele Artikel die von mir noch nicht vollständig verwertet worden sind. +Die Artikel sind auch zur Vorbereitung für neue Artikel auf vorgesehen. + +**origin:** ## Inhalt @@ -22,6 +26,7 @@ Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebr - [Webserver](#webserver) - [Windows](#windows) - [Programmierung](#programmierung) + - [Rust](#rust) - [ts - js - node](#ts---js---node) - [Projektinhalt](#projektinhalt) - [Neue Dokumente](#neue-dokumente) @@ -57,6 +62,7 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt - [Artikel: git](dokus/git/git.md) - [SSH-Zugriff auf Git-Repository in WSL einrichten](dokus/git/git-ssh-remote.md) - [Git – Remote-Branches: Häufige Aufgaben und Lösungen](dokus/git/git-remote-branch.md) + - [Git-Submodule: Der umfassende Praxisleitfaden](dokus/git/git-submodule-leitfaden.md) ### Markdown @@ -90,6 +96,13 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt ### Programmierung +#### Rust + +- [Rust-Toolchain mit MSVC unter Windows einrichten](dokus/rust/rust-toolchain-msvc.md) +- [Erstellung eines Installationsmediums für Rust + MSVC (Offline)](dokus/rust/rust-offline-installation.md) + +--- + #### ts - js - node - [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md) @@ -102,9 +115,6 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt ```plaintext 📁 ./ -├── 📁 .vscode -│ ├── 📄 cspell.json -│ └── 📄 settings.json ├── 📁 dokus │ ├── 📁 apache-plesk │ │ └── 📄 lets-encrypt-plesk.md @@ -113,6 +123,7 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt │ ├── 📁 git │ │ ├── 📄 git-remote-branch.md │ │ ├── 📄 git-ssh-remote.md +│ │ ├── 📄 git-submodule-leitfaden.md │ │ └── 📄 git.md │ ├── 📁 js-ts │ │ └── 📄 js-ts-dialekte.md @@ -120,6 +131,9 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt │ │ └── 📄 gewindetabellen.md │ ├── 📁 plesk │ │ └── 📄 plesk-benutzer-schon-vorhanden.md +│ ├── 📁 rust +│ │ ├── 📄 rust-offline-installation.md +│ │ └── 📄 rust-toolchain-msvc.md │ ├── 📁 windows │ │ └── 📄 desktop_ini.md │ └── 📄 helix__editor_einfuehrung_de.md @@ -142,12 +156,14 @@ Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Pyt │ ├── 📄 fscopy.ts │ └── 📄 fsdel.ts ├── 📄 .gitignore +├── 📄 CHANGELOG.md ├── 📄 LICENSE ├── 📄 package-lock.json ├── 📄 package.json ├── 📄 README.md ├── 📄 scan.cmd -└── 📄 tsconfig.json +├── 📄 tsconfig.json +└── 📄 VERSION ``` --- diff --git a/VERSION b/VERSION index b3e7542..88c8879 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -0.1.0 +0.2.0 15.06.2025 \ No newline at end of file diff --git a/dokus/git/git-submodule-leitfaden.md b/dokus/git/git-submodule-leitfaden.md new file mode 100644 index 0000000..678d0c7 --- /dev/null +++ b/dokus/git/git-submodule-leitfaden.md @@ -0,0 +1,203 @@ +# Git-Submodule: Der umfassende Praxisleitfaden + +## Inhalt + +- [Git-Submodule: Der umfassende Praxisleitfaden](#git-submodule-der-umfassende-praxisleitfaden) + - [Inhalt](#inhalt) + - [🔰 Was ist ein Git-Submodul?](#-was-ist-ein-git-submodul) + - [🧱 Grundlagen](#-grundlagen) + - [📌 `.gitmodules`](#-gitmodules) + - [🧠 Merksatz](#-merksatz) + - [🛠️ Submodul hinzufügen](#️-submodul-hinzufügen) + - [🔄 Submodule aktualisieren](#-submodule-aktualisieren) + - [📥 Klonen mit Submodulen](#-klonen-mit-submodulen) + - [Methode 1: Inklusive Submodule](#methode-1-inklusive-submodule) + - [Methode 2: Nachträglich initialisieren](#methode-2-nachträglich-initialisieren) + - [🔃 Submodul-Synchronisation](#-submodul-synchronisation) + - [📂 Weitere Remotes im Submodul](#-weitere-remotes-im-submodul) + - [❗ Stolperfallen und Besonderheiten](#-stolperfallen-und-besonderheiten) + - [🔄 Remote-URL wechseln](#-remote-url-wechseln) + - [🚀 Push \& Pull Verhalten](#-push--pull-verhalten) + - [🧼 Submodul löschen](#-submodul-löschen) + - [🧰 Best Practices](#-best-practices) + - [📎 Nützliche Kommandos](#-nützliche-kommandos) + - [📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl](#-beispiel-gitmodules-mit-kommentierter-remote-auswahl) + - [🧭 Alternative: Subtree statt Submodul?](#-alternative-subtree-statt-submodul) + - [📚 Fazit](#-fazit) + - [🔗 Weiterführende Links](#-weiterführende-links) + +--- + +## 🔰 Was ist ein Git-Submodul? + +Ein **Submodul** ist ein Git-Repository innerhalb eines anderen Git-Repositories. Es erlaubt, einen festen Commit eines externen Repositories als Teilprojekt einzubinden, ohne dessen Dateien direkt zu übernehmen. + +Beispielhafte Struktur: + +```plaintext +hauptprojekt/ +├── .gitmodules +├── modul1/ ← eingebundenes Submodul +└── modul2/ +``` + +## 🧱 Grundlagen + +### 📌 `.gitmodules` + +Diese Datei beschreibt Pfad und Remote-URL aller eingebundenen Submodule: + +```ini +[submodule "modul1"] + path = modul1 + url = git@github.com:user/modul1.git +``` + +### 🧠 Merksatz + +> Submodule sind **Pointer auf einen bestimmten Commit** eines anderen Repositories. + +## 🛠️ Submodul hinzufügen + +```bash +git submodule add +git commit -m "📦 Submodul hinzugefügt" +``` + +Beispiel: + +```bash +git submodule add git@github.com:user/libmath.git extern/libmath +``` + +Erzeugt: + +- `.gitmodules` +- Verzeichniseintrag im Git-Index +- Initialer Checkout des Submoduls (HEAD auf Remote-Commit) + +## 🔄 Submodule aktualisieren + +```bash +cd extern/libmath +git pull origin main +cd ../.. +git add extern/libmath +git commit -m "🔄 Submodul libmath aktualisiert" +``` + +> Nur das **Hauptrepo speichert den Commit-Zeiger**, nicht den Submodul-Inhalt selbst. + +## 📥 Klonen mit Submodulen + +### Methode 1: Inklusive Submodule + +```bash +git clone --recurse-submodules +``` + +### Methode 2: Nachträglich initialisieren + +```bash +git clone +git submodule update --init +``` + +## 🔃 Submodul-Synchronisation + +Wenn sich `.gitmodules` ändert (z. B. Remote-URL): + +```bash +git submodule sync +``` + +## 📂 Weitere Remotes im Submodul + +```bash +cd modul1 +git remote add backup git@backup.server:repo.git +``` + +> Diese Remotes sind **lokal**, nicht versioniert. `.gitmodules` kennt nur den Haupt-Remote. + +## ❗ Stolperfallen und Besonderheiten + +| Problem | Erklärung | +|--------|-----------| +| Submodul wird nicht mitgeclont | `--recurse-submodules` vergessen | +| Änderungen im Submodul nicht sichtbar | Submodul-Commit im Hauptrepo nicht geupdated | +| `.gitmodules` zeigt nicht funktionierende URL | z. B. lokale URL nach GitHub-Push – muss angepasst werden | +| Submodul zeigt „detached HEAD“ | normaler Zustand, wenn Submodul auf festen Commit gesetzt ist | + +## 🔄 Remote-URL wechseln + +```bash +# In .gitmodules ändern oder per Befehl: +git config -f .gitmodules submodule.modul1.url git@github.com:newuser/libmath.git +git submodule sync +``` + +## 🚀 Push & Pull Verhalten + +| Aktion | Wirkung | +|---------------------|---------| +| `git push` im Hauptrepo | Pusht nur Zeiger auf Submodul-Commit | +| `git push` im Submodul | Muss separat erfolgen | +| `git pull` im Hauptrepo | Holt *nicht* automatisch neuen Submodul-Stand | + +## 🧼 Submodul löschen + +```bash +# Schritt 1: Entfernen +git submodule deinit -f pfad/zum/modul +git rm -f pfad/zum/modul +rm -rf .git/modules/pfad/zum/modul +git commit -m "❌ Submodul entfernt" +``` + +## 🧰 Best Practices + +- **Nur stabile Submodul-Commits einchecken**, keine laufenden Branches. +- **Submodule niemals blind aktualisieren** – Änderungen genau prüfen. +- **Remote-Umschaltung dokumentieren oder automatisieren**, z. B. per Script. +- **Submodule klein halten** – große, tief verschachtelte Strukturen vermeiden. +- Für wiederverwendbare Bibliotheken oder Assets ideal (CAD, Snippets, Markdown, etc.). + +## 📎 Nützliche Kommandos + +```bash +git submodule status # Überblick über alle Submodule +git submodule update --init # Submodule initial holen +git submodule update --remote # Auf neuesten Remote-Stand updaten +git config -f .gitmodules ... # .gitmodules direkt bearbeiten +``` + +## 📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl + +```ini +[submodule "modul1"] + path = modul1 + url = ssh://git@local.example.com:2222/myorg/modul1.git + # url = git@github.com:myorg/modul1.git +``` + +## 🧭 Alternative: Subtree statt Submodul? + +Subtree ist einfacher zu verwalten, aber: + +- kein fester Commit-Zeiger, +- kein Remote-Wechsel ohne Umweg, +- gemergte Historie im Hauptrepo. + +**Submodul = getrennte Repos** +**Subtree = eingemergter Inhalt** + +## 📚 Fazit + +Git-Submodule sind mächtig, aber erfordern **Disziplin und Überblick**. Für wiederverwendbare Komponenten, zentral gepflegte Inhalte oder externe Bibliotheken sind sie oft die bessere Wahl als Duplikate oder Copy-Paste. + +## 🔗 Weiterführende Links + +- [Git Book: Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) +- [git-scm Doku: submodule](https://git-scm.com/docs/git-submodule) +- [Vergleich Submodule vs. Subtree](https://www.atlassian.com/git/tutorials/git-submodule) diff --git a/dokus/rust/rust-offline-installation.md b/dokus/rust/rust-offline-installation.md new file mode 100644 index 0000000..0239b63 --- /dev/null +++ b/dokus/rust/rust-offline-installation.md @@ -0,0 +1,152 @@ +# Erstellung eines Installationsmediums für Rust + MSVC (Offline) + +Dieser Artikel beschreibt, wie du ein **vollständiges Installationsmedium** für die **Rust-Toolchain mit MSVC** unter Windows vorbereitest, damit du Rust auf anderen Rechnern **ohne Internetzugang** einrichten kannst. + +--- + +## Ziel + +Ein USB-Stick oder Offline-Verzeichnis mit: + +- Rust-Installer (offlinefähig) +- Visual Studio Build Tools (komplett inkl. MSVC) +- Optional: vorkompilierte Ziel-Toolchains + +--- + +## 1. Rust Offline-Installer vorbereiten + +### 1.1 Rustup Offline-Installer besorgen + +Gehe auf: + + https://forge.rust-lang.org/infra/release-archives.html + +Lade von dort: + +- `rust--x86_64-pc-windows-msvc.msi` +- `cargo--x86_64-pc-windows-msvc.msi` (optional) + +Oder direkt über: + + https://static.rust-lang.org/dist/ + +### 1.2 Installation ohne Internet + +Auf dem Zielrechner: + +- Führe `.msi`-Datei lokal aus +- Setze den `Path` manuell oder automatisch via Skript + +--- + +## 2. Visual Studio Build Tools offline installieren + +### 2.1 Installer herunterladen + +Lade den **Visual Studio Installer** von: + + https://visualstudio.microsoft.com/de/visual-cpp-build-tools/ + +Starte dann: + +```cmd +vs_BuildTools.exe --layout C:\VSOffline --lang de-DE +``` + +Dieser Befehl erstellt einen vollständigen Offline-Installer im Verzeichnis `C:\VSOffline`. + +### 2.2 Auswahl der Workloads + +Wähle beim interaktiven Download (GUI oder CLI): + +- **C++ Build Tools** +- Workload-Komponenten: + - MSVC v14.x (x64/x86) + - Windows 10/11 SDK + - CMake-Tools (optional) + +> 💡 Achtung: Download-Größe ca. 4–6 GB! + +### 2.3 Installation auf Zielsystem (Offline) + +Auf dem Zielrechner: + +```cmd +C:\VSOffline\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait +``` + +Alternativ über `vs_setup.exe`, je nach Version. + +--- + +## 3. Optional: Toolchains, Crates & Targets vorbereiten + +Falls du zusätzliche Targets (z. B. Linux oder ARM) brauchst: + +### 3.1 Ziel-Toolchain lokal laden + +```cmd +rustup target add x86_64-unknown-linux-gnu --print +``` + +Lade die `.tar.gz` von: + + https://static.rust-lang.org/dist/ + +Speichere diese im `dist/`-Ordner und installiere offline via: + +```cmd +rustup toolchain link +``` + +--- + +## 4. Automatisierung via USB-Stick + +### Dateistruktur auf Stick + +```text +USB-STICK/ +├── rust/ +│ └── rust-1.xx.x-x86_64-pc-windows-msvc.msi +├── vsbuildtools/ +│ └── setup + Offline-Daten +├── install.cmd +``` + +### Beispiel `install.cmd` + +```cmd +@echo off +echo [1/2] Installiere Rust... +start /wait rust\rust-*.msi + +echo [2/2] Installiere Visual Studio Build Tools... +start /wait vsbuildtools\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait + +echo Fertig. Bitte PC neu starten! +pause +``` + +--- + +## 5. Validierung + +Nach der Offline-Installation auf Zielsystem: + +```cmd +cargo new testprojekt +cd testprojekt +cargo build --release +``` + +Ergebnis: + + target\release\testprojekt.exe + +--- + +## Fazit + +Mit dieser Methode kannst du eine vollständige Rust- und MSVC-Umgebung offline auf jedem Windows-System aufsetzen – ideal für abgeschottete Systeme ohne Internetverbindung. diff --git a/dokus/rust/rust-toolchain-msvc.md b/dokus/rust/rust-toolchain-msvc.md new file mode 100644 index 0000000..d4ea7bc --- /dev/null +++ b/dokus/rust/rust-toolchain-msvc.md @@ -0,0 +1,152 @@ +# Rust-Toolchain mit MSVC unter Windows einrichten + +Dieser Artikel beschreibt die vollständige Einrichtung einer produktionsfähigen Rust-Toolchain mit **MSVC (Microsoft Visual C++)** unter **Windows**, einschließlich Erstellung einer `.exe`-Datei aus einem Beispielprogramm. + +## Inhalt + +- [Rust-Toolchain mit MSVC unter Windows einrichten](#rust-toolchain-mit-msvc-unter-windows-einrichten) + - [Inhalt](#inhalt) + - [Voraussetzungen](#voraussetzungen) + - [1. Rust installieren](#1-rust-installieren) + - [2. Visual Studio Build Tools installieren](#2-visual-studio-build-tools-installieren) + - [Schritt-für-Schritt](#schritt-für-schritt) + - [3. Umgebungsvariablen setzen (optional)](#3-umgebungsvariablen-setzen-optional) + - [4. Beispielprojekt erstellen](#4-beispielprojekt-erstellen) + - [5. Projekt kompilieren](#5-projekt-kompilieren) + - [Debug-Build (schnell, nicht optimiert)](#debug-build-schnell-nicht-optimiert) + - [Release-Build (optimiert, kleine `.exe`)](#release-build-optimiert-kleine-exe) + - [6. Optional: `.exe` testen](#6-optional-exe-testen) + - [7. Troubleshooting](#7-troubleshooting) + - [8. Alternative: Toolchain in einem Offline-Installer vorbereiten](#8-alternative-toolchain-in-einem-offline-installer-vorbereiten) + - [Zusammenfassung](#zusammenfassung) + - [Weiterführende Themen](#weiterführende-themen) + +--- + +## Voraussetzungen + +- Windows 10 oder 11 (64 Bit) +- Administratorrechte +- Mindestens 2 GB freier Speicherplatz + +## 1. Rust installieren + +Lade das offizielle Rust-Installationsprogramm herunter und führe es aus: + + + +Beim Setup: + +- **Toolchain wählen**: `default host triple: x86_64-pc-windows-msvc` +- Folge dem Assistenten, um `rustc`, `cargo` und `rustup` zu installieren. + +Verifiziere die Installation: + +```shell +rustc --version +cargo --version +``` + +## 2. Visual Studio Build Tools installieren + +Die Rust-Toolchain mit MSVC benötigt den **"C++ Build Tools"**-Teil von Visual Studio. + +### Schritt-für-Schritt + +1. Lade den **Visual Studio Installer**: + - + +2. Wähle bei der Installation: + - ✅ **C++ Build Tools** + - Und in der rechten Spalte: + - ✅ "MSVC v14.x - VS 2022 C++ x64/x86-Buildtools" + - ✅ "Windows 10 SDK" oder "Windows 11 SDK" (je nach Zielsystem) + - ✅ "C++ CMake-Tools für Windows" (optional für CMake-Projekte) + +3. Installiere alles und starte das System neu, falls verlangt. + +## 3. Umgebungsvariablen setzen (optional) + +Falls du die Buildtools über Kommandozeile verwenden willst, öffne: + +```cmd +"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat" +``` + +Das setzt temporär alle notwendigen Umgebungsvariablen für den Build-Prozess. + +## 4. Beispielprojekt erstellen + +```cmd +cargo new hello_world +cd hello_world +``` + +Beispielcode in `src/main.rs`: + +```rust +fn main() { + println!("Hallo Welt – kompiliert mit MSVC!"); +} +``` + +## 5. Projekt kompilieren + +### Debug-Build (schnell, nicht optimiert) + +```cmd +cargo build +``` + +### Release-Build (optimiert, kleine `.exe`) + +```cmd +cargo build --release +``` + +Die fertige `.exe` liegt unter: + + .\target\release\hello_world.exe + +## 6. Optional: `.exe` testen + +```cmd +.\target\release\hello_world.exe +``` + +## 7. Troubleshooting + +- **Fehlermeldung `link.exe not found`?** + → Build-Tools sind nicht korrekt installiert (siehe Schritt 2) + +- **Fehlermeldung zu fehlendem SDK?** + → Stelle sicher, dass du das passende Windows SDK mit installiert hast + +- **MSVC und GNU Toolchain gleichzeitig installiert?** + → Du kannst über `rustup` zwischen beiden wechseln: + +```cmd +rustup show +rustup default stable-x86_64-pc-windows-msvc +``` + +## 8. Alternative: Toolchain in einem Offline-Installer vorbereiten + +Wenn du das Setup auf mehreren Rechnern ohne Internetzugang durchführen möchtest, siehe [separater Artikel zur Erstellung eines Installationsmediums](./rust-offline-installation.md). + +## Zusammenfassung + +| Komponente | Aufgabe | +|------------------|----------------------------------| +| Rustup | Verwaltung von Toolchains | +| Cargo | Buildsystem und Paketmanager | +| MSVC Build Tools | C++-Compiler/Linker für Windows | +| `vcvars64.bat` | Aktiviert Build-Umgebung | +| `cargo build` | Erstellt `.exe` mit Rust und MSVC | + +## Weiterführende Themen + +- Einbindung von Ressourcen und Icons in die `.exe` +- Verwendung von `cc`/`bindgen` für C-Bindings +- Cross-Kompilierung mit `x86_64-pc-windows-gnu` oder Linux-Zielsystemen +- Automatisierter Build via Makefile oder PowerShell diff --git a/tools/collector/processed.log b/tools/collector/processed.log index 1ba696b..c8810d1 100644 --- a/tools/collector/processed.log +++ b/tools/collector/processed.log @@ -8,3 +8,6 @@ dokus/git/git-ssh-remote.md dokus/git/git.md dokus/asciidoc/asciidoctor-theme-bug-workaround.md dokus/apache-plesk/lets-encrypt-plesk.md +dokus/git/git-submodule-leitfaden.md +dokus/rust/rust-toolchain-msvc.md +dokus/rust/rust-offline-installation.md