From 7fabb9420d0ba001af209afc5093158871e0aef0 Mon Sep 17 00:00:00 2001 From: Buutti Education <> Date: Fri, 25 Jul 2025 08:57:26 +0000 Subject: [PATCH] Initial commit --- .scripts/.gitattributes | 1 + .scripts/buildHTMLslides.bat | 11 ++ .scripts/buildPDFslides.bat | 11 ++ .scripts/convertAndReplaceAll.bat | 32 +++++ .scripts/convertPptxToMd.bat | 3 + .scripts/generateREADME.py | 52 ++++++++ .scripts/removeHtmls.bat | 5 + .scripts/removeLinebreaks.sh | 10 ++ .scripts/renamePptx.sh | 11 ++ .scripts/replace.sh | 18 +++ .themes/buutti.css | 63 +++++++++ .vscode/markdown.code-snippets | 207 ++++++++++++++++++++++++++++++ .vscode/settings.json | 14 ++ README.md | 26 ++++ example-lecture-slides.html | 112 ++++++++++++++++ example-lecture.md | 85 ++++++++++++ imgs/.gitkeep | 0 imgs/buuttilogo.png | Bin 0 -> 1541 bytes solutions/.gitkeep | 0 19 files changed, 661 insertions(+) create mode 100644 .scripts/.gitattributes create mode 100644 .scripts/buildHTMLslides.bat create mode 100644 .scripts/buildPDFslides.bat create mode 100644 .scripts/convertAndReplaceAll.bat create mode 100644 .scripts/convertPptxToMd.bat create mode 100644 .scripts/generateREADME.py create mode 100644 .scripts/removeHtmls.bat create mode 100644 .scripts/removeLinebreaks.sh create mode 100644 .scripts/renamePptx.sh create mode 100644 .scripts/replace.sh create mode 100644 .themes/buutti.css create mode 100644 .vscode/markdown.code-snippets create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 example-lecture-slides.html create mode 100644 example-lecture.md create mode 100644 imgs/.gitkeep create mode 100644 imgs/buuttilogo.png create mode 100644 solutions/.gitkeep diff --git a/.scripts/.gitattributes b/.scripts/.gitattributes new file mode 100644 index 0000000..8218efd --- /dev/null +++ b/.scripts/.gitattributes @@ -0,0 +1 @@ +*.sh eol=lf \ No newline at end of file diff --git a/.scripts/buildHTMLslides.bat b/.scripts/buildHTMLslides.bat new file mode 100644 index 0000000..c4bfb46 --- /dev/null +++ b/.scripts/buildHTMLslides.bat @@ -0,0 +1,11 @@ +for /d %%A in (.\*) do ( + set "except=" + if /i "%%~nxA" == "temp" set "except=1" + if /i "%%~nxA" == "_site" set "except=1" + if /i "%%~nxA" == ".jekyll-cache" set "except=1" + if not defined except ( + for %%j in (%%A\*.md) do ( + marp %%j -o %%~pj%%~nj-slides.html --html true + ) + ) +) diff --git a/.scripts/buildPDFslides.bat b/.scripts/buildPDFslides.bat new file mode 100644 index 0000000..545efa3 --- /dev/null +++ b/.scripts/buildPDFslides.bat @@ -0,0 +1,11 @@ +for /d %%A in (.\*) do ( + set "except=" + if /i "%%~nxA" == "temp" set "except=1" + if /i "%%~nxA" == "_site" set "except=1" + if /i "%%~nxA" == ".jekyll-cache" set "except=1" + if not defined except ( + for %%j in (%%A\*.md) do ( + marp %%j -o %%~pj%%~nj.pdf --html true + ) + ) +) diff --git a/.scripts/convertAndReplaceAll.bat b/.scripts/convertAndReplaceAll.bat new file mode 100644 index 0000000..a455c59 --- /dev/null +++ b/.scripts/convertAndReplaceAll.bat @@ -0,0 +1,32 @@ +wsl bash renamePptx.sh +call convertPptxToMd.bat +REN img imgs + +chcp 65001 + +wsl bash replace.sh "![](img%%5C" "![](imgs/" +wsl bash replace.sh "\." "." +wsl bash replace.sh "\," "," +wsl bash replace.sh "\!" "!" +wsl bash replace.sh "\-" "-" +wsl bash replace.sh "\_" "_" +wsl bash replace.sh "\*" "*" +wsl bash replace.sh "\#" "#" +wsl bash replace.sh "\\+" "+" +wsl bash replace.sh "\(" "(" +wsl bash replace.sh "\)" ")" +wsl bash replace.sh "\{" "{" +wsl bash replace.sh "\}" "}" +wsl bash replace.sh "\[" "[" +wsl bash replace.sh "\]" "]" +wsl bash replace.sh "_[" "[" +wsl bash replace.sh ")_" ")" +wsl bash replace.sh "”" "\"" +wsl bash replace.sh "“" "\"" +wsl bash replace.sh "’" "'" +wsl bash replace.sh "‘" "'" + +wsl bash replace.sh "\\\\" "\\" +wsl bash replace.sh "\<" "<" + +wsl bash removeLinebreaks.sh \ No newline at end of file diff --git a/.scripts/convertPptxToMd.bat b/.scripts/convertPptxToMd.bat new file mode 100644 index 0000000..f2e50e2 --- /dev/null +++ b/.scripts/convertPptxToMd.bat @@ -0,0 +1,3 @@ +for %%j in (.\*.pptx) do ( + pptx2md --disable-color "%%j" -o "%%~pj%%~nj.md" +) \ No newline at end of file diff --git a/.scripts/generateREADME.py b/.scripts/generateREADME.py new file mode 100644 index 0000000..bdac9ee --- /dev/null +++ b/.scripts/generateREADME.py @@ -0,0 +1,52 @@ +import os +import re +from pathlib import Path + +def get_first_title(md_path): + with open(md_path, 'r', encoding='utf-8') as file: + for line in file: + match = re.match(r'^#\s+(.*)', line.strip()) + if match: + return match.group(1) + return "Untitled" + +def extract_leading_number(filename): + match = re.match(r'^(\d{1,2})[_\- ]', filename) + return match.group(1) if match else None + +def generate_markdown_table(directory): + entries = [] + for filename in os.listdir(directory): + if filename.endswith('.md'): + number = extract_leading_number(filename) + if filename == 'README.md': + continue # Skip README + filepath = os.path.join(directory, filename) + title = get_first_title(filepath) + if number is None: + entries.append((None, " ", title, filename)) + else: + entries.append((int(number), number, title, filename)) + + entries.sort(key=lambda x: (x[0] == None, x[0] if x[0] != None else x[2].lower())) + + table = ["| # | Lecture | Slides |", "|:------|:-----|:------|"] + for _, number, title, filename in entries: + table.append(f"| {number} | [{title}]({filename}) | [Download slides]({Path(filename).stem}-slides.html?raw=1) |") + + return '\n'.join(table) + +def main(): + directory = "./../" # current directory, or change to any other path + output_file = directory + "README.md" + table_md = generate_markdown_table(directory) + + with open(output_file, 'a', encoding='utf-8') as f: + f.write("# Contents\n\n") + f.write(table_md) + f.write("\n") + + print(f"Index written to {output_file}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/.scripts/removeHtmls.bat b/.scripts/removeHtmls.bat new file mode 100644 index 0000000..63d5351 --- /dev/null +++ b/.scripts/removeHtmls.bat @@ -0,0 +1,5 @@ +for /D %%i in (.\*) do ( + for %%j in (%%i\*.md) do ( + del %%~pj%%~nj.html + ) +) diff --git a/.scripts/removeLinebreaks.sh b/.scripts/removeLinebreaks.sh new file mode 100644 index 0000000..4cbe3a3 --- /dev/null +++ b/.scripts/removeLinebreaks.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +for file in *.md; do + perl -0777 -i -pe ' + s/\r\n/\n/g; # Normalize Windows line endings to Unix + s/(?:[ \t]*\n){2,}/\n\n/g; # Collapse multiple blank lines (even with whitespace) + ' "$file" +done + +echo "Collapsed extra blank lines." \ No newline at end of file diff --git a/.scripts/renamePptx.sh b/.scripts/renamePptx.sh new file mode 100644 index 0000000..3c1f736 --- /dev/null +++ b/.scripts/renamePptx.sh @@ -0,0 +1,11 @@ +for f in *.pptx; do + name="${f%.*}" # strip extension + ext="${f##*.}" # get extension + newname=$(echo "$name" \ + | tr '[:upper:]' '[:lower:]' \ + | tr ' ' '-' \ + | sed 's/&/and/g' \ + | tr -d '.,()' # remove dots, commas, and parentheses + ) + mv -- "$f" "$newname.$ext" +done \ No newline at end of file diff --git a/.scripts/replace.sh b/.scripts/replace.sh new file mode 100644 index 0000000..2d8538f --- /dev/null +++ b/.scripts/replace.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +SEARCH="$1" +REPLACE="$2" + +for file in *.md; do + SEARCH="$SEARCH" REPLACE="$REPLACE" perl -i -pe ' + BEGIN { + $search = quotemeta($ENV{"SEARCH"}); + $replace = $ENV{"REPLACE"}; + $replace =~ s/\\/\\\\/g; # escape backslashes in replacement + $replace =~ s/\$/\\\$/g; # escape $ in replacement + } + s/$search/$replace/g; + ' "$file" +done + +echo "Literal replacement complete." \ No newline at end of file diff --git a/.themes/buutti.css b/.themes/buutti.css new file mode 100644 index 0000000..b4e1310 --- /dev/null +++ b/.themes/buutti.css @@ -0,0 +1,63 @@ +/* buutti.css */ +/* @theme buutti */ + +@import "default"; + +.columns { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; +} +.columns12 { + display: grid; + grid-template-columns: 1fr 2fr; + gap: 1rem; +} +.columns21 { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 1rem; +} +.columns32 { + display: grid; + grid-template-columns: 3fr 2fr; + gap: 1rem; +} +.columns23 { + display: grid; + grid-template-columns: 2fr 3fr; + gap: 1rem; +} +.columns111 { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 1rem; +} +.centered { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; +} +.tableborderless td, th { + border: none!important; + border-collapse: collapse; +} + +section.extra { + background-color: #5d275d; + background-image: linear-gradient(to bottom, #401a40, #1d0c1d); + color: white; +} +section.extra a { + color: rgb(145, 255, 209); +} + +section.exercise { + background-color: #29366f; + background-image: linear-gradient(to bottom, #20636a, #173742); + color: white; +} +section.exercise a { + color: rgb(211, 173, 255); +} diff --git a/.vscode/markdown.code-snippets b/.vscode/markdown.code-snippets new file mode 100644 index 0000000..0aedd00 --- /dev/null +++ b/.vscode/markdown.code-snippets @@ -0,0 +1,207 @@ +{ + "python code block" : { + "scope": "markdown", + "prefix": "py", + "body": [ + "```python", + "$0", + "```" + ], + "description": "Python code block" + }, + "cpp code block" : { + "scope": "markdown", + "prefix": "cpp", + "body": [ + "```cpp", + "$0", + "```" + ], + "description": "C++ code block" + }, + "csharp code block" : { + "scope": "markdown", + "prefix": "cs", + "body": [ + "```csharp", + "$0", + "```" + ], + "description": "C# code block" + }, + "js code block" : { + "scope": "markdown", + "prefix": "js", + "body": [ + "```js", + "$0", + "```" + ], + "description": "JavaScript code block" + }, + "ts code block" : { + "scope": "markdown", + "prefix": "ts", + "body": [ + "```ts", + "$0", + "```" + ], + "description": "TypeScript code block" + }, + "html code block" : { + "scope": "markdown", + "prefix": "html", + "body": [ + "```html", + "$0", + "```" + ], + "description": "HTML code block" + }, + "css code block" : { + "scope": "markdown", + "prefix": "css", + "body": [ + "```css", + "$0", + "```" + ], + "description": "CSS code block" + }, + "powershell code block" : { + "scope": "markdown", + "prefix": "ps", + "body": [ + "```powershell", + "$0", + "```" + ], + "description": "PowerShell code block" + }, + "bash code block" : { + "scope": "markdown", + "prefix": "bash", + "body": [ + "```bash", + "$0", + "```" + ], + "description": "bash code block" + }, + "sql code block" : { + "scope": "markdown", + "prefix": "sql", + "body": [ + "```sql", + "$0", + "```" + ], + "description": "SQL code block" + }, + "inline code" : { + "scope": "markdown", + "prefix": "c", + "body": [ + "`$0`", + ], + "description": "Inline code block" + }, + "extra slide" : { + "scope": "markdown", + "prefix": "extra", + "body": [ + "## Extra: $0", + "", + ], + "description": "Extra slide colors" + }, + "exercise slide" : { + "scope": "markdown", + "prefix": "exercise", + "body": [ + "## Exercise $0.", + "", + ], + "description": "Exercise slide colors" + }, + "marp front matter" : { + "scope": "markdown", + "prefix": "marp", + "body" : [ + "---", + "marp: true", + "paginate: true", + "math: mathjax", + "theme: buutti", + "title: N. $0", + "---", + "", + "# $0", + "", + "", + "" + ] + }, + "marp columns" : { + "scope": "markdown", + "prefix": "column", + "body" : [ + "
", + "
", + "$0", + "
", + "
", + "", + "
", + "
", + ] + }, + "marp columns start" : { + "scope": "markdown", + "prefix": "startcol", + "body" : [ + "
", + "
", + ] + }, + "marp columns middle" : { + "scope": "markdown", + "prefix": "midcol", + "body" : [ + "
", + "
", + ] + }, + "marp columns end" : { + "scope": "markdown", + "prefix": "endcol", + "body" : [ + "
", + "
", + ] + }, + "marp centered" : { + "scope": "markdown", + "prefix": "centered", + "body" : [ + "
", + "$0", + "
", + ] + }, + "em dash" : { + "scope": "markdown", + "prefix": "em", + "body" : [ + "—", + ] + }, + "marp footer" : { + "scope": "markdown", + "prefix": "footer", + "body" : [ + "" + ] + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..89ea4d9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "markdown.marp.themes": ["./.themes/buutti.css"], + "saveAndRun": { + "commands": [ + { + "match": "\\.md$", + "notMatch": "README\\.md$", + "cmd": "marp \"${fileDirname}\\${fileBasename}\" -o \"${fileDirname}\\${fileBasenameNoExt}-slides.html\" --html true --theme \"${fileDirname}\\.themes\\buutti.css\"", + "useShortcut": false, + "silent": false + }, + ] + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2d9702 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Contents + +Material completion denoted with 🌑🌘🌗🌖🌕 . + +| # | Lecture | Materials | Exercises | +| ---: | ------------------------------------- | --------: | --------: | +| 1 | [Example Lecture](example-lecture.md) | 🌕 | 🌕 | + + +## Repository notes (remove before publishing) + +- After reading, remove [example-lecture.md](./example-lecture.md), [example-lecture-slides.html](./example-lecture-slides.html) and [buuttilogo.png](./imgs/buuttilogo.png) +- See [Markdown code snippets](.vscode/markdown.code-snippets) for autocomplete stuff. +- Remove the .gitkeep files from imgs and solutions folders after adding new files to those folders. + +## Running scripts to convert lectures to MD + +Note: These instructions are for a Windows PC with WSL installed + +1) Install `pptx2md`: in an admin powershell, run `pip install pptx2md` +2) copy `.pptx` lecture slides to `.scripts` folder +3) In the `.scripts` folder, run `.\convertAndReplaceAll.bat` +4) If everything went ok, move the generated `.md` files and the `imgs` folder to the root folder +5) Remove .pptx files and the example lecture and its slides html +7) In the `.scripts` folder, run `python generateREADME.py` +8) Remove everything else from README than the generated table \ No newline at end of file diff --git a/example-lecture-slides.html b/example-lecture-slides.html new file mode 100644 index 0000000..dcc8159 --- /dev/null +++ b/example-lecture-slides.html @@ -0,0 +1,112 @@ +N. Example Lecture
+

Example Lecture

+
+
+

Section

+
    +
  • This line appears instantly
  • +
+
    +
  • This line appears by pressing spacebar (preferred)
  • +
  • This line has an inline code variable
  • +
+
    +
  1. This line appears instantly
  2. +
+
    +
  1. This line appears by pressing spacebar
  2. +
+
+
+

Code and maths

+
    +
  • code code code:
    console.log("Here's a syntax-highlighted JavaScript code block");
    +console.log("Remember indentation so it's revealed after the bullet point.");
    +
    +
  • +
  • This line has an inline LaTeX maths equation
  • +
  • Here's a maths block:
  • +
+

Footers are exclusive to presentation; they are not shown in the webpage markdown document
+
+
+

Columns

+
+
+

+
    +
  • Basic image example
  • +
+
+
+

+
    +
  • Wider image
  • +
+
+
+
    +
  • This line is outside the columns and goes from left all the way to the right
  • +
+
+
+

Columns 2

+
+
+
    +
  • Another column example with a wider left panel
  • +
+
+
+
    +
  • Change class name to change proportions
  • +
  • If suitable proportions not available, add to buutti.css
  • +
+
+
+
+
+

Setup

+ +
+
\ No newline at end of file diff --git a/example-lecture.md b/example-lecture.md new file mode 100644 index 0000000..6c11c6d --- /dev/null +++ b/example-lecture.md @@ -0,0 +1,85 @@ +--- +marp: true +paginate: true +math: mathjax +theme: buutti +title: N. Example Lecture +--- + +# Example Lecture + + + + +## Section + +- This line appears instantly +* This line appears by pressing spacebar (preferred) +* This line has an inline code `variable` +1. This line appears instantly +2) This line appears by pressing spacebar + +## Code and maths + +* code code code: + ```js + console.log("Here's a syntax-highlighted JavaScript code block"); + console.log("Remember indentation so it's revealed after the bullet point."); + ``` +* This line has an inline LaTeX maths equation $c = \frac{a^2}{\sqrt{b}}$ +* Here's a maths block: + +$$ +F(x) = \int_a^b f(x) dx +$$ + + + +## Columns + +
+
+ +![](imgs/buuttilogo.png) + +* Basic image example + +
+
+ +![width:800px](imgs/buuttilogo.png) +* Wider image + +
+
+ +* This line is outside the columns and goes from left all the way to the right + +## Columns 2 + +
+
+ +* Another column example with a wider left panel + +
+
+ +* Change `class` name to change proportions +* If suitable proportions not available, add to `buutti.css` + +
+
+ +## Setup + +* In VS Code, install the extensions + * [Marp for VS code](https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode) + * So you can see the slideshow preview when editing. + * [Markdown all in one](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) + * [Markdown table formatter](https://marketplace.visualstudio.com/items?itemName=fcrespo82.markdown-table-formatter) + * *Right click > Format document* makes tables pretty + * [Save and run](https://marketplace.visualstudio.com/items?itemName=wk-j.save-and-run) + * An HTML version of the lecture is created on save + * See [settings.json](./.vscode/settings.json) + * Add filenames to `notMatch` if a HTML on save is not needed \ No newline at end of file diff --git a/imgs/.gitkeep b/imgs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/imgs/buuttilogo.png b/imgs/buuttilogo.png new file mode 100644 index 0000000000000000000000000000000000000000..8c3557824987085f6e4e335fead43d172a6a32cf GIT binary patch literal 1541 zcmV+g2KxDlP)(OoSekO#CLahT3TA4pPy`OY=VM<E-o%NH#gYW*y-u%wzjs+%*;kcM)ULYk&%%c930lx)>Bhc5)u+6B_$~-DROdh zGcz-LdwW1u2HF4s1x`ssK~#90?VagjsxS~nLAh9Psbbx0YioV~SG;O1%w!kC((;|3 zWCoHPKnXDh0RR910000000000000000002*#Pgi@m!>PzZPKt{+;nBSO^>KZnyyT@ zfr{1u6|Dg(S_4$H2B>HaP|+HoqBTH8Yk-P+n58`x>AVQhsZb{Nda|vxCh~fqm*$7H zUP*P1&V^quIbU9?@h?;}DMB4h(I)*0jhgGj(8^%F4TFA~a+5|7vD6gWg$$XNI z5m{V>;pW*(V@hJY15*`!TJT3zoU>vt%_#*`2sC$LK!wQ0OM^-P6|Hdr6)vf@02K;m zUfOgoP@%$0o9+cFRLIYVHP9gy?k1YKMRiC;G9HhUB?;MFwp{2-7tGX4tL~#EDju!r zH$$U}D{IYOUIiE4t8b^Ailm=Y+jzBuif6kDx)(O)w%srl4NQ6~r=kfeRuKfuMFV#z zs3>5Uh1a?}0Tl&fs$%H1@-9F{!9KJfqC%j8@YHB~p@PtCd!d2=6>ij^f)+xBp6XQ` zNLhDP&@m{7POL@+9TaKcaT_WMsEIZ|;=NW{jW(!QnN*wxIoX64Wuz$I*e4seEIg+1 zbFz~utvyYgC<|l5(I24&D!2*p2sCfNiVdWc-D#WJ;s33eU3Zz^4H(phQM_pd$RXE^R z#qLv+2Nibwst8w_yed?zvy7%Jvoq`4)6MZ*NC#5hu7$DT=#S7!6=9~%t3riv2x%N# zJ2Kl5715V6uLcz@nZ8_`icLRZuz65dGG!iA*eO3U`-AWaIaTICg`G#I8C>A6Ek+J` zP@%wwiUV_zIpjfw0v{@PSG_spL4{>6Z|V@cih%wwDT?iRP@&*BUFK-sxjU$s(bm1& z^Pr*}4l05jR6qq(2tdW3Rl$D*4iz^XRGet*R4RBsv98Ux(x(%?Ho`kpeB+>k&SKuZ zDDrrd2g;I6tAhRJA1X{L7IbNYr7ADKRIbp1qBACR>xhK!>Fp0HOe$j5wRxAY-(Jwi zM?Qd6F1T;;vS35H;$_hl6)SbN_47iEx4955J>kQd zsfdM-l8&fYYb*LLKh~K$L%iv5#JeDW+UGAizIbXUROm%qFv?KG4^1+p52Sze+!q%f zW{Z&gdKK2Y{mQ=1%81_6-`M*HW&DZy@39kK`j!^NNg+d81DcLuRi`5Qf&Nl=UTnS- zor+1{MB@C-kBJ#!J5szp%YUB&u<=Jaxe;QtOhx0000000000 r00000000000000000000Xe0jt##v;W`1Ep~00000NkvXXu0mjf0@20| literal 0 HcmV?d00001 diff --git a/solutions/.gitkeep b/solutions/.gitkeep new file mode 100644 index 0000000..e69de29