├── src ├── assets │ ├── styles │ │ ├── sidebar.css │ │ ├── newdefault.css │ │ ├── lecture_header.css │ │ ├── homepage.css │ │ ├── layout.css │ │ └── index.css │ ├── favicon.ico │ ├── homepage │ │ ├── swoosh.png │ │ ├── bg.afdesign │ │ └── bg.svg │ ├── scripts │ │ ├── get_highlights.jl │ │ ├── sidebar.js │ │ ├── get_subjects.jl │ │ └── search.js │ ├── favicon.svg │ ├── julia-logo-color.svg │ └── julia-logo-dark.svg ├── index.jlmd ├── netlify.toml ├── _includes │ ├── md.jlmd │ ├── welcome.jlmd │ └── layout.jlhtml ├── _data │ ├── tracks.jl │ ├── sidebar.jl │ ├── course_info.jl │ └── homepage.jl ├── mod3_publish_website │ ├── setup_server.md │ ├── precompute_output.md │ └── deploy_static.md ├── logistics.md ├── search.md ├── cheatsheets.md ├── mod1_setup_website │ ├── working_locally.md │ ├── getting_started.md │ └── basic_info.md ├── mod2_add_material │ ├── add_markdown.md │ └── add_pluto.jl ├── installation.md └── homework │ └── hw1.jl ├── .gitattributes ├── Procfile ├── .gitignore ├── extra_outputs └── index.html ├── .vscode ├── tasks.json ├── extensions.json └── settings.json ├── README.md ├── pluto-deployment-environment ├── PlutoDeployment.toml ├── Project.toml └── Manifest.toml ├── generate.jl ├── .github └── workflows │ ├── pr_comment.yml │ ├── preview_cleanup.yml │ ├── KeepCacheFresh.yml │ └── ExportNotebooks.yml ├── tools └── update_notebook_packages.jl ├── LICENSE.md ├── Dockerfile ├── develop.jl ├── Website maintenance.md └── PlutoPages.jl /src/assets/styles/sidebar.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | page/* linguist-vendored 2 | * text=auto -------------------------------------------------------------------------------- /src/index.jlmd: -------------------------------------------------------------------------------- 1 | --- 2 | tags: ["homepage"] 3 | layout: "welcome.jlmd" 4 | --- 5 | -------------------------------------------------------------------------------- /src/netlify.toml: -------------------------------------------------------------------------------- 1 | [[headers]] 2 | for = "/*" 3 | [headers.values] 4 | Access-Control-Allow-Origin = "*" 5 | -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuliaPluto/computational-thinking-template/HEAD/src/assets/favicon.ico -------------------------------------------------------------------------------- /src/assets/homepage/swoosh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuliaPluto/computational-thinking-template/HEAD/src/assets/homepage/swoosh.png -------------------------------------------------------------------------------- /src/assets/homepage/bg.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuliaPluto/computational-thinking-template/HEAD/src/assets/homepage/bg.afdesign -------------------------------------------------------------------------------- /src/_includes/md.jlmd: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "layout.jlhtml" 3 | --- 4 | 5 |
6 |
7 | $(content) 8 |
9 |
-------------------------------------------------------------------------------- /src/_data/tracks.jl: -------------------------------------------------------------------------------- 1 | [ 2 | "julia" => "💻 Julia programming", 3 | "material" => "Material development", 4 | "setup" => "Website maintenance" 5 | ] -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: julia --project="pluto-deployment-environment" -e "import PlutoSliderServer; PlutoSliderServer.run_directory(\".\"; port=$PORT , host=\"0.0.0.0\")" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | reduced_phil.png 5 | notebooks/week9/testCSVwrite.csv 6 | 7 | _cache 8 | _site 9 | generation_report.html 10 | src/week9/testCSVwrite.csv 11 | -------------------------------------------------------------------------------- /src/_data/sidebar.jl: -------------------------------------------------------------------------------- 1 | [ 2 | "welcome" => "Welcome", 3 | "module1" => "Module 1: Website setup", 4 | "module2" => "Module 2: Adding course material", 5 | "module3" => "Module 3: Publishing your website" 6 | ] -------------------------------------------------------------------------------- /extra_outputs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/mod3_publish_website/setup_server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Setup a server for your website" 3 | order: 3 4 | chapter: 3 5 | section: 3 6 | layout: "md.jlmd" 7 | tags: ["module3", "track_setup", "deploy", "server", "dynamic", "droplet"] 8 | --- 9 | 10 | COMING SOON 11 | 12 | -------------------------------------------------------------------------------- /src/mod3_publish_website/precompute_output.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Precompute the pluto notebooks" 3 | order: 2 4 | chapter: 3 5 | section: 2 6 | layout: "md.jlmd" 7 | tags: ["module3", "track_setup", "track_julia", "deploy", "precompute", "Pluto", "PlutoSliderServer"] 8 | --- 9 | 10 | COMING SOON -------------------------------------------------------------------------------- /src/logistics.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Class logistics" 3 | tags: ["welcome"] 4 | order: 1 5 | layout: "md.jlmd" 6 | --- 7 | 8 | 14 | 15 | # Course logistics 16 | 17 | Describe here the logistics of your class. -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "PlutoPages: run development server", 8 | "type": "shell", 9 | "command": "julia develop.jl", 10 | "group": "build" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /src/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Search results" 3 | tags: [] 4 | layout: "md.jlmd" 5 | --- 6 | 7 | 8 |
9 |
10 |

Search

11 | 17 | 18 |

Results

19 |
20 | Loading... 21 |
22 | 23 | -------------------------------------------------------------------------------- /src/cheatsheets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Cheatsheets" 3 | tags: ["welcome"] 4 | order: 3 5 | layout: "md.jlmd" 6 | --- 7 | 8 | # Cheatsheets 9 | 10 | - [Getting Started with Julia - live](/basic_syntax/). 11 | - [Fastrack to Julia](https://juliadocs.github.io/Julia-Cheat-Sheet/) cheatsheet. 12 | - [MATLAB-Julia-Python comparative cheatsheet](https://cheatsheets.quantecon.org/) by [QuantEcon group](https://quantecon.org) 13 | - [Plots.jl cheatsheet](https://github.com/sswatson/cheatsheets/blob/master/plotsjl-cheatsheet.pdf) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computational thinking template 2 | 3 |

4 | Go to template website :balloon:
5 | template includes instructions for how to start editing to shape to your own needs :rocket: 6 |

7 | 8 | This repository is a template to build a website like the [Computational thinking course](https://computationalthinking.mit.edu/) tought at MIT. 9 | 10 | **Note**: This is an early experiment and very WIP; use at your own risk. 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "esbenp.prettier-vscode", 8 | "julialang.language-julia", 9 | ], 10 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 11 | "unwantedRecommendations": [ 12 | 13 | ] 14 | } -------------------------------------------------------------------------------- /src/_data/course_info.jl: -------------------------------------------------------------------------------- 1 | Dict( 2 | "course_name" => "Name of your course", 3 | "course_subtitle" => "a short catchy phrase about your course", 4 | "code" => "code of your course", 5 | "semester" => "Fall 20XX", 6 | "authors" => [ 7 | "First author name" => "first author homepage link", 8 | "Second author name" => "second author homepage link" 9 | ], 10 | "institution" => "Your university (or similar) name", 11 | "institution_logo" => "name of your institution logo file, e.g. `logo.svg`. Place this under `assets`", 12 | "repo" => "link to the repository of the source code" 13 | ) -------------------------------------------------------------------------------- /pluto-deployment-environment/PlutoDeployment.toml: -------------------------------------------------------------------------------- 1 | [Export] 2 | baked_state = false 3 | baked_notebookfile = false 4 | offer_binder = true 5 | ignore_cache = [ 6 | "index.jl", 7 | ] 8 | create_index = false 9 | exclude = [ 10 | # these are in the repo but not used on the website 11 | "tools/*", 12 | "PlutoPages.jl", 13 | ] 14 | 15 | [SliderServer] 16 | port = 8080 17 | host = "0.0.0.0" 18 | exclude=[ 19 | # these are in the repo but not used on the website 20 | "tools/*", 21 | "PlutoPages.jl", 22 | 23 | # notebooks not interactive 24 | 25 | # don't run homeworks 26 | "*/hw*.jl", 27 | ] 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.jlmd": "markdown", 4 | "*.jlhtml": "html", 5 | }, 6 | 7 | "prettier.printWidth": 160, 8 | "prettier.tabWidth": 4, 9 | "prettier.semi": false, 10 | "prettier.quoteProps": "consistent", 11 | "prettier.singleQuote": false, 12 | 13 | "editor.formatOnSave": false, 14 | "[javascript]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode", 16 | "editor.formatOnSave": true 17 | }, 18 | "[css]": { 19 | "editor.defaultFormatter": "esbenp.prettier-vscode", 20 | "editor.formatOnSave": true 21 | } 22 | } -------------------------------------------------------------------------------- /src/_includes/welcome.jlmd: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "layout.jlhtml" 3 | --- 4 | 5 | 6 | 7 | 10 | 11 | $(isempty(get(metadata["homepage"], "disclaimer", "")) ? nothing : @htl("""""")) 12 | 13 |
14 | $(Base.include(@__MODULE__, joinpath(@__DIR__, "..", "assets", "scripts", "get_highlights.jl"))) 15 | $(Base.include(@__MODULE__, joinpath(@__DIR__, "..", "assets", "scripts", "get_subjects.jl"))) 16 |
-------------------------------------------------------------------------------- /src/assets/scripts/get_highlights.jl: -------------------------------------------------------------------------------- 1 | if isempty(get(metadata["homepage"], "highlights", [])) 2 | nothing 3 | else 4 | highlights = [ 5 | @htl(""" 6 |
7 |
8 |

$(x["name"])

9 |

$(x["text"])

10 |
11 |
12 | 13 |
14 |
15 | """) for x in metadata["homepage"]["highlights"] 16 | ] 17 | 18 | @htl(""" 19 |
20 |

Highlights

21 |
22 | $(highlights) 23 |
24 |
25 | """) 26 | end -------------------------------------------------------------------------------- /generate.jl: -------------------------------------------------------------------------------- 1 | import Pluto 2 | 3 | s = Pluto.ServerSession() 4 | 5 | # s.options.server.disable_writing_notebook_files = true 6 | s.options.server.launch_browser = false 7 | 8 | @info "PlutoPages: Starting..." 9 | nb = Pluto.SessionActions.open(s, joinpath(@__DIR__, "PlutoPages.jl"); run_async=false) 10 | @info "PlutoPages: Finished. Analyzing result..." 11 | 12 | write("generation_report.html", Pluto.generate_html(nb)) 13 | 14 | failed = filter(c -> c.errored, nb.cells) 15 | 16 | for c in failed 17 | println(stderr, "Cell errored: ", c.cell_id) 18 | println(stderr) 19 | show(stderr, MIME"text/plain"(), c.output.body) 20 | println(stderr) 21 | println(stderr) 22 | end 23 | 24 | Pluto.SessionActions.shutdown(s, nb) 25 | 26 | if !isempty(failed) 27 | exit(1) 28 | end 29 | -------------------------------------------------------------------------------- /.github/workflows/pr_comment.yml: -------------------------------------------------------------------------------- 1 | name: PR Comment # Write a comment in the PR with a link to the preview of the given website 2 | on: 3 | pull_request: 4 | types: [opened, reopened] 5 | jobs: 6 | pr_comment: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Create PR comment 10 | if: github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name # if this is a pull request build AND the pull request is NOT made from a fork 11 | uses: thollander/actions-comment-pull-request@71efef56b184328c7ef1f213577c3a90edaa4aff 12 | with: 13 | message: 'Once the build has completed, you can preview your PR at this URL: https://${{ github.event.pull_request.base.repo.owner.login }}.github.io/${{ github.event.pull_request.base.repo.name }}/previews/PR${{ github.event.number }}/' 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/preview_cleanup.yml: -------------------------------------------------------------------------------- 1 | # from https://github.com/CliMA/ClimaTimeSteppers.jl 2 | name: Site Preview Cleanup 3 | 4 | on: 5 | pull_request: 6 | types: [closed] 7 | 8 | jobs: 9 | doc-preview-cleanup: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout gh-pages branch 13 | uses: actions/checkout@v2 14 | with: 15 | ref: gh-pages 16 | - name: Delete preview and history + push changes 17 | run: | 18 | if [ -d "previews/PR$PRNUM" ]; then 19 | git config user.name "Documenter.jl" 20 | git config user.email "documenter@juliadocs.github.io" 21 | git rm -rf "previews/PR$PRNUM" 22 | git commit -m "delete preview" 23 | git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree}) 24 | git push --force origin gh-pages-new:gh-pages 25 | fi 26 | env: 27 | PRNUM: ${{ github.event.number }} 28 | -------------------------------------------------------------------------------- /tools/update_notebook_packages.jl: -------------------------------------------------------------------------------- 1 | if !isdir("pluto-deployment-environment") || length(ARGS) != 1 2 | error(""" 3 | Run me from the root of the repository directory, using: 4 | 5 | julia tools/update_notebook_packages.jl 6 | 7 | Where is one of: PATCH, MINOR, MAJOR 8 | """) 9 | end 10 | 11 | if VERSION < v"1.6.0-aaa" 12 | @error "Our website needs to be generated with Julia 1.6. Go to julialang.org/downloads to install it." 13 | end 14 | 15 | import Pkg 16 | Pkg.activate("./pluto-deployment-environment") 17 | Pkg.instantiate() 18 | 19 | import Pluto 20 | 21 | flatmap(args...) = vcat(map(args...)...) 22 | 23 | 24 | all_files_recursive = flatmap(walkdir("src")) do (root, _dirs, files) 25 | joinpath.((root,), files) 26 | end 27 | 28 | all_notebooks = filter(Pluto.is_pluto_notebook, all_files_recursive) 29 | 30 | level = getfield(Pkg, Symbol("UPLEVEL_$(ARGS[1])")) 31 | 32 | for n in all_notebooks 33 | @info "Updating" n 34 | Pluto.update_notebook_environment(n; backup=false, level) 35 | end 36 | -------------------------------------------------------------------------------- /src/assets/styles/newdefault.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,500;0,700;1,500;1,700&display=swap"); 2 | @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"); 3 | @import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"); 4 | @import url("https://fonts.googleapis.com/css2?family=Vollkorn:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); 5 | 6 | html { 7 | box-sizing: border-box; 8 | font-size: 17px; 9 | /* color: #3c3c3c; */ 10 | } 11 | 12 | body { 13 | /* background: #f1e7e7; */ 14 | font-family: "Open Sans", sans-serif; 15 | overflow-wrap: break-word; 16 | } 17 | main h1 { 18 | font-family: "Vollkorn", serif; 19 | font-weight: 800; 20 | font-style: italic; 21 | margin-block-end: 0.5em; 22 | font-size: 2.5rem; 23 | margin-block-start: 0; 24 | letter-spacing: -0.2px; 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/styles/lecture_header.css: -------------------------------------------------------------------------------- 1 | .lecture-header { 2 | background: #282936; 3 | color: white; 4 | padding: 1rem; 5 | /* min-height: 500px; */ 6 | /* width: 100%; */ 7 | display: block; 8 | border-radius: 1rem; 9 | margin: 1rem; 10 | } 11 | 12 | .lecture-header * { 13 | color: white; 14 | } 15 | 16 | .lecture-header, 17 | .lecture-header h1 { 18 | font-family: Vollkorn, serif; 19 | font-weight: 700; 20 | font-feature-settings: "lnum", "pnum"; 21 | } 22 | 23 | .lecture-header .number { 24 | font-style: italic; 25 | font-size: 1.5rem; 26 | opacity: 0.8; 27 | } 28 | 29 | .lecture-header h1 { 30 | text-align: center; 31 | font-size: 2rem; 32 | } 33 | .lecture-header .video > div { 34 | display: flex; 35 | justify-content: center; 36 | overflow: hidden; 37 | max-width: 400px; 38 | margin: 0 auto; 39 | } 40 | .lecture-header .video iframe, 41 | .lecture-header .video lite-youtube { 42 | /* max-width: 400px; */ 43 | aspect-ratio: 16/9; 44 | flex: 1 1 auto; 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/KeepCacheFresh.yml: -------------------------------------------------------------------------------- 1 | name: Keep caches fresh 2 | on: 3 | schedule: 4 | - cron: "5 4 1/4 * *" # every 4 days 5 | 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: ⏱ Cache notebook states 11 | uses: actions/cache@v2 12 | with: 13 | path: _cache 14 | key: ${{ runner.os }}-pluto_state_cache-v3-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }}-${{ github.run_id }} 15 | restore-keys: | 16 | ${{ runner.os }}-pluto_state_cache-v3-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }} 17 | 18 | - name: ⏱ Cache .julia 19 | uses: actions/cache@v2 20 | with: 21 | path: ~/.julia 22 | key: ${{ runner.os }}-dotjulia-v1-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }}-${{ github.run_id }} 23 | restore-keys: | 24 | ${{ runner.os }}-dotjulia-v1-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }} 25 | 26 | -------------------------------------------------------------------------------- /pluto-deployment-environment/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | BetterFileWatching = "c9fd44ac-77b5-486c-9482-9798bd063cc6" 3 | CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" 4 | Deno_jll = "04572ae6-984a-583e-9378-9577a1c2574d" 5 | Gumbo = "708ec375-b3d6-5a57-a7ce-8257bf98657a" 6 | HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" 7 | JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 8 | LRUCache = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" 9 | Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" 10 | MarkdownLiteral = "736d6165-7244-6769-4267-6b50796e6954" 11 | Memoize = "c03570c3-d221-55d1-a50c-7939bbd78826" 12 | Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 13 | Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781" 14 | PlutoHooks = "0ff47ea0-7a50-410d-8455-4348d5de0774" 15 | PlutoLinks = "0ff47ea0-7a50-410d-8455-4348d5de0420" 16 | PlutoSliderServer = "2fc8631c-6f24-4c5b-bca7-cbb509c42db4" 17 | PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 18 | ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c" 19 | ThreadsX = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d" 20 | URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 21 | Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 22 | YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" 23 | -------------------------------------------------------------------------------- /src/assets/scripts/sidebar.js: -------------------------------------------------------------------------------- 1 | const sidebar = document.querySelector("#pages-sidebar") 2 | const layout = document.querySelector("#pages-layout") 3 | const navtoggle = document.querySelector("#toggle-nav") 4 | 5 | document.querySelector("#toggle-nav").addEventListener("click", function (e) { 6 | console.log(e) 7 | layout.classList.toggle("pages_show_sidebar") 8 | e.stopPropagation() 9 | }) 10 | 11 | window.addEventListener("click", function (e) { 12 | if (!sidebar.contains(e.target) && !navtoggle.contains(e.target)) { 13 | layout.classList.remove("pages_show_sidebar") 14 | } 15 | }) 16 | 17 | document.querySelectorAll(".track-chooser select").forEach((trackSelect) => { 18 | const ontrack = () => { 19 | let track = trackSelect.value 20 | 21 | localStorage.setItem("chosen track", track) 22 | 23 | let lectures_homeworks = Array.from(sidebar.querySelectorAll(".lecture,.homework")) 24 | 25 | lectures_homeworks.forEach((el) => { 26 | let intrack = track === "" || el.classList.contains(`tag_track_${track}`) || el.classList.contains(`tag_welcome`) 27 | el.classList.toggle("not_in_track", !intrack) 28 | }) 29 | } 30 | 31 | trackSelect.value = localStorage.getItem("chosen track") 32 | ontrack() 33 | trackSelect.addEventListener("change", ontrack) 34 | }) 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | My license here: 2 | 3 | 4 | 5 | 6 | This repository was generated from https://github.com/JuliaPluto/computational-thinking-template which is licensed as follows: 7 | 8 | Copyright 2023 Luca Ferranti, Fons van der Plas and the MIT Computational Thinking team: computationalthinking.mit.edu 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | -------------------------------------------------------------------------------- /src/mod3_publish_website/deploy_static.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Deploy your website as static" 3 | order: 1 4 | chapter: 3 5 | section: 1 6 | layout: "md.jlmd" 7 | tags: ["module3", "track_setup", "deploy", "netlify", "github actions", "github pages"] 8 | --- 9 | 10 | 11 | ## Deploying with github pages 12 | 13 | Deploying your website as static page with github pages is a breeze. 14 | 15 | Whenever you push to main, the website will be deployed to a branch called `gh-pages`. All you need to do is go to your repository and from `Settings > Pages` choose to deploy from `gh-pages` branch, as the following picture shows. 16 | 17 | 18 | ![](https://user-images.githubusercontent.com/49938764/249790280-d9c46b7f-eecd-42aa-8e51-ce44dfdfce58.png) 19 | 20 | After that, the website will be available at 21 | 22 | ``` 23 | https://yourusername.github.io/your-repository-name 24 | ``` 25 | 26 | Note that this is a **static** webpage, so sliders will not work. Students will still be able to play with interactivity by downloading the notebook or running it on binder. 27 | 28 | If you want interactivity to work on the webpage, you can either 29 | 30 | 1. [Precompute the notebooks outputs](https://juliapluto.github.io/computational-thinking-template/mod3_publish_website/precompute_output/) (experimental) 31 | 32 | or 33 | 34 | 2. [Run your own server](https://juliapluto.github.io/computational-thinking-template/mod3_publish_website/setup_server/) -------------------------------------------------------------------------------- /src/assets/scripts/get_subjects.jl: -------------------------------------------------------------------------------- 1 | let 2 | sections = metadata["sidebar"] 3 | sections = [ 4 | @htl(""" 5 | $([ 6 | let 7 | input = other_page.input 8 | output = other_page.output 9 | 10 | name = get(output.frontmatter, "title", basename(input.relative_path)) 11 | desc = get(output.frontmatter, "description", nothing) 12 | tags = get(output.frontmatter, "tags", String[]) 13 | 14 | image = get(output.frontmatter, "image", nothing) 15 | 16 | class = [ 17 | "no-decoration", 18 | ("tag_$(replace(x, " "=>"_"))" for x in tags)..., 19 | ] 20 | 21 | image === nothing || isempty(image) ? nothing : @htl(""" 22 |

$(name)

23 | 24 |
""") 25 | end for other_page in collections[section_id].pages 26 | ]) 27 | """) 28 | for (section_id, section_name) in sections 29 | ] 30 | 31 | isempty(sections) ? nothing : @htl("""
32 |

Subjects

33 |
34 | $(sections) 35 |
36 |
37 | """) 38 | end -------------------------------------------------------------------------------- /src/mod1_setup_website/working_locally.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working locally" 3 | order: 3 4 | chapter: 1 5 | section: 3 6 | layout: "md.jlmd" 7 | image: "https://user-images.githubusercontent.com/49938764/249456721-2ff021b2-326d-443d-a3ac-b433692647e0.png" 8 | tags: ["module1", "track_setup", "track_julia", "PlutoSliderServer", "pluto"] 9 | --- 10 | 11 | ## Working locally 12 | 13 | Open this repository in VS Code, and install the recommended extensions. 14 | 15 | To start running the development server, open the VS Code *command palette* (press `Cmd+Shift+P`), and search for **`Tasks: Run Task`**, then **`PlutoPages: run development server`**. The first run can take some time, as it builds up the notebook outputs cache. Leave it running. 16 | 17 | This will start two things in parallel: the PlutoPages.jl notebook (which generates the website), and a static file server (with Deno_jll). It will open two tabs in your browser: one is the generation dashboard (PlutoPages), the other is the current site preview (Deno_jll). 18 | 19 | Whenever you edit a file, PlutoPages will automatically regenerate! Refresh your browser tab. If it does not pick up the change, go to the generation dashboard and click the "Read input files again" button. 20 | 21 | **Note!**: This workflow is recommended for writing static content, styles, and for site maintenance. But for writing Pluto notebooks, it's best to prepare the notebook first, and then run the site (because it re-runs the entire notebook on any change). -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Hi there! 2 | 3 | # This Dockerfile does _not_ run the Pluto notebooks. You can _not_ use it to work on the homework exercises. Instead, take a look at our website to learn how to get started with Pluto: http://computationalthinking.mit.edu . If you want to run a Pluto Container (e.g. for homework) take a look here: https://github.com/JuliaPluto/docker-stacks 4 | 5 | # This is an internal Dockerfile for the Pluto "@bind server" for the course website. It runs all the sliders, buttons and camera inputs, so that you can interact with them directly on the website, without having to wait for binder or a local Pluto session. 6 | # Take a look at https://github.com/JuliaPluto/PlutoSliderServer.jl for more info. 7 | 8 | # -fonsi 9 | 10 | FROM julia:1.8.2 11 | 12 | # HTTP port 13 | EXPOSE 1234 14 | RUN apt-get update -y && apt-get upgrade -y 15 | # add a new user called "pluto" 16 | RUN useradd -ms /bin/bash pluto 17 | # set the current directory 18 | WORKDIR /home/pluto 19 | # run the rest of commands as pluto user 20 | USER pluto 21 | # copy the contents of the github repository into /home/pluto 22 | COPY --chown=pluto . ${HOME} 23 | 24 | 25 | # Initialize the julia project environment that will be used to run the bind server. 26 | RUN julia --project=${HOME}/pluto-deployment-environment -e "import Pkg; Pkg.instantiate(); Pkg.precompile()" 27 | 28 | # The "default command" for this docker thing. 29 | CMD ["julia", "--project=/home/pluto/pluto-deployment-environment", "-e", "import PlutoSliderServer; PlutoSliderServer.run_directory(\".\"; SliderServer_port=1234 , SliderServer_host=\"0.0.0.0\")"] -------------------------------------------------------------------------------- /src/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/_data/homepage.jl: -------------------------------------------------------------------------------- 1 | Dict( 2 | "title" => @htl("Computational thinking website template"), 3 | 4 | # # add a disclaimer to the course webpage. Remove it if you dont want to include it. 5 | "disclaimer" => md""" 6 | This template will allow you to build a website like the **Computational thinking with Julia** class tought at MIT. 7 | Use it to harness the power of Julia and Pluto in your own teaching and enhance students learning experience. 8 | """, 9 | 10 | # Highlights the key features of your class to make it more engaging. Remove it if you dont want to include it. 11 | "highlights" => [ 12 | Dict("name" => "Easy to customise", 13 | "text" => md"Let the template automate all of the website development and infrastructure, so that you can focus on the most important thing: 14 | **easily develop your lesson materials!**", 15 | "img" => "https://user-images.githubusercontent.com/6933510/168320383-a401459b-97f5-41df-bc7b-ebe76e4886cc.png" 16 | ), 17 | Dict("name" => "Revolutionary interactivity with Pluto.jl", 18 | "text" => md""" 19 | Thanks to Pluto.jl, the website is built using real code, and instead of a book, we have a series of interactive notebooks. 20 | **On the website, students can play with sliders, buttons and images to interact with our simulations.** 21 | You can even go further, and modify and run any code on our website! 22 | """, 23 | "img" => "https://user-images.githubusercontent.com/6933510/136196607-16207911-53be-4abb-b90e-d46c946e6aaf.gif" 24 | ), 25 | Dict("name" => "Learn Julia", 26 | "text" => md""" 27 | In literature it's not enough to just know the technicalities of grammar. 28 | In music it's not enough to learn the scales. The goal is to communicate experiences and emotions. 29 | For a computer scientist, it's not enough to write a working program, 30 | the program should be written with beautiful high level abstractions that speak to your audience. 31 | **Julia is designed with this purpose in mind, use it in your teaching to harness its power.** 32 | """, 33 | "img" => "https://user-images.githubusercontent.com/6933510/136203632-29ce0a96-5a34-46ad-a996-de55b3bcd380.png" 34 | ) 35 | ] 36 | ) -------------------------------------------------------------------------------- /src/mod1_setup_website/getting_started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting started" 3 | order: 1 4 | chapter: 1 5 | section: 1 6 | layout: "md.jlmd" 7 | image: "https://user-images.githubusercontent.com/49938764/249456747-c93b41a0-308a-4ad4-9afb-6ce3309633d1.png" 8 | tags: ["module1", "track_setup", "teaching", "repository structure"] 9 | --- 10 | 11 | ## Fork the template 12 | 13 | Go to the [template repository](https://github.com/juliapluto/computational-thinking-template) and click `Use this template` on the top-right corner. This will fork the repository under your github profile. 14 | 15 | ![](https://user-images.githubusercontent.com/49938764/249456747-c93b41a0-308a-4ad4-9afb-6ce3309633d1.png) 16 | 17 | ## Folder structure 18 | 19 | Let us have a look at what this repository looks like. The most important folder, where you will be mainly working is `src`. Here you will place all your lecture materials. So let us take a closer look at this. 20 | 21 | Opening the `src` folder, you will see the following 22 | 23 | - `_data` folder: here you will place metadata about your website (university name, class semester, define tracks, etc.), more on this in the next lesson. 24 | - `_include`: This folder contains the layout templates that are used to generate the final pages on your website. Unless you want to tweak the layout, you will not need to modify this. 25 | - `assets`: in this folder you can place all attachements, such as your university logo and other pictures. The folder also contains the CSS and scripts used to render the website. 26 | 27 | That was for the "infrastructure part" of the website, the rest is content! To add new pages to your website, simply them under the `src` folder. You can group them in subfolders, as done in this template, but that is not a strict requirement. 28 | 29 | When downloading this template, you will get the following material: 30 | 31 | - **`installation.md`**: this page contains instructions on how to install Julia and Pluto. If you find it useful, you may keep it as is, or edit to match your wanted installation instructions. 32 | - **`cheatsheets.md`**: contains a list of julia related resources. Again, you can keep it or remove it. 33 | - **`logistics.md`**: empty markdown page, where you can describe the logistics of your class 34 | - **`index.jlmd`**: this is used to render the homepage. **Do not remove or modify this!** 35 | - **`search.md`**: this is used to render the search tab on the sidebar, do not modify or remove this file. 36 | 37 | The remaining folders 38 | 39 | - `mod1_setup_website` 40 | - `mod2_add_material` 41 | - `mod3_publish_website` 42 | - `homework` 43 | 44 | are placeholder samples, used to showcase what a deployed website looks like. As a bonus, these placeholder files actually document how to use this template. You can read it and see what the final result looks like on the [template webpage](https://juliapluto.github.io/computational-thinking-template). 45 | 46 | When starting adding your course material, you will most likely want to remove these. -------------------------------------------------------------------------------- /.github/workflows/ExportNotebooks.yml: -------------------------------------------------------------------------------- 1 | name: Export Pluto notebooks & Deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | concurrency: 11 | group: export 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | build-and-deploy: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout source 19 | uses: actions/checkout@v2 20 | 21 | - name: 🙌 Install Julia 22 | uses: julia-actions/setup-julia@v1 23 | with: 24 | version: "1.8" 25 | 26 | - name: ⏱ Cache notebook states 27 | uses: actions/cache@v2 28 | with: 29 | path: _cache 30 | key: ${{ runner.os }}-pluto_state_cache-v3-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }}-${{ github.run_id }} 31 | restore-keys: | 32 | ${{ runner.os }}-pluto_state_cache-v3-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }} 33 | 34 | - name: ⏱ Cache .julia 35 | uses: actions/cache@v2 36 | with: 37 | path: ~/.julia 38 | key: ${{ runner.os }}-dotjulia-v1-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }}-${{ github.run_id }} 39 | restore-keys: | 40 | ${{ runner.os }}-dotjulia-v1-${{ hashFiles('**/Project.toml', '**/Manifest.toml') }} 41 | 42 | - name: 🪴 Generate site 43 | run: julia --project=pluto-deployment-environment -e ' 44 | import Pkg; 45 | Pkg.instantiate(); 46 | 47 | include("./generate.jl")' 48 | 49 | 50 | - name: 📰 Upload site generation report 51 | uses: actions/upload-artifact@v2 52 | if: always() 53 | with: 54 | path: generation_report.html 55 | 56 | - name: 🚀 Deploy to GitHub Pages (main) 57 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 58 | uses: JamesIves/github-pages-deploy-action@releases/v3 59 | with: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | BRANCH: gh-pages 62 | FOLDER: _site 63 | CLEAN_EXCLUDE: | 64 | previews/* 65 | 66 | - name: Deploy PR preview 67 | if: github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name # if this build is a PR build and the PR is NOT from a fork 68 | uses: JamesIves/github-pages-deploy-action@releases/v3 69 | with: 70 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 71 | BRANCH: gh-pages 72 | FOLDER: _site 73 | TARGET_FOLDER: "previews/PR${{ github.event.number }}" # The website preview is going to be stored in the previews subfolder -------------------------------------------------------------------------------- /src/mod2_add_material/add_markdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Add markdown files" 3 | order: 1 4 | chapter: 2 5 | section: 1 6 | layout: "md.jlmd" 7 | tags: ["module2", "track_material", "markdown", "frontmatter"] 8 | --- 9 | 10 | ## Add markdown files 11 | 12 | If your lecture does not need to run code or use interactivity. You can write it as a markdown file. 13 | 14 | As an extra twist, you can evaluate julia code inside a `\$` symbol. For example, 15 | 16 | ```julia 17 | \$(1 + 1) 18 | ``` 19 | will become 20 | 21 | $(1 + 1) 22 | 23 | ## Add Front-matter 24 | 25 | For each file, markdown or pluto, you will need to add a *front-matter*, which specifies the page metadata. For markdown files, the front-matter is specified at the top of the file between three dashes `---`. For example, the front-matter of this file is 26 | 27 | ``` 28 | --- 29 | title: "Add markdown file" 30 | order: 1 31 | chapter: 2 32 | section: 1 33 | layout: "md.jlmd" 34 | tags: ["module2", "track_material", "markdown", "frontmatter"] 35 | --- 36 | ``` 37 | 38 | You will need to specify the following attributes 39 | 40 | - **`title`**: title of the page 41 | - **`order`**: the position of the page in the module on the sidebar. **Hint!**: You can also use fractional numbers, e.g. `1.5`. This can be handy for homeworks, so you can include the homework between the first and second lesson without messing up lessons counting. 42 | - **`layout`**: set to `"md.jlmd"`, unless you are using some custom layout 43 | - **`chapter`** and **`section`** (optional): used to number the page. If for example `chapter=1` and `section=2`, the page will be displayed as `1.2` on the sidebar and page header. 44 | - **`image`** (optional): link to summarizing image to display in the `subjects` section on the homepage. If left empty, the page wont be included in the subjects section. If no page has an `image` field in the front-matter, the subjects section is not displayed. 45 | - **`description`** (optional): short description of the notebook 46 | - **`youtube_id`** (optional): youtube id of the video associated with the page. If included, the page header will embed the youtube video. 47 | - **`homework_number`**: needed only for homeworks, the number of the homework 48 | - **`tags`**: list of keywords for the page. It should at least include the module name, as defined in `_data/sidebar.jl` to include the page in the sidebar. You can also associate pages to a given track by adding the track id, prefixed with `track_` to the tags. For example, if you want to include the page in the julia track, add `track_julia` in the tags list. 49 | 50 | 51 | ## Markdown 101 52 | 53 | If you are not familiar with markdown, you can see for example [here](https://www.markdowntutorial.com/). Here is a quick and dirty cheatsheet 54 | 55 | 1. Use `#` for headers, for example 56 | 57 | ```markdown 58 | # Header 59 | ## Subheader 60 | ### Sub-sub-header 61 | ``` 62 | 63 | 2. You can create links with the syntax 64 | 65 | ```markdown 66 | [text](adddress) 67 | ``` 68 | 69 | For example the link to the mardown tutorial above was typed as 70 | 71 | ```markdown 72 | [here](https://www.markdowntutorial.com/) 73 | ``` 74 | 75 | 3. You can insert pictures with the syntax 76 | 77 | ```markdown 78 | ![optional alternative text](link-to-picture) 79 | ``` 80 | 81 | for example 82 | 83 | ``` 84 | ![](https://raw.githubusercontent.com/JuliaLang/julia-logo-graphics/master/images/julia-logo-color.png) 85 | ``` 86 | 87 | will give 88 | 89 | ![](https://raw.githubusercontent.com/JuliaLang/julia-logo-graphics/master/images/julia-logo-color.png) -------------------------------------------------------------------------------- /develop.jl: -------------------------------------------------------------------------------- 1 | cd(@__DIR__) 2 | notebook_path = joinpath(@__DIR__, "PlutoPages.jl") 3 | 4 | @assert VERSION >= v"1.6.0" 5 | 6 | begin 7 | begin 8 | begin 9 | # copy paste from pluto source code 10 | function detectwsl() 11 | Sys.islinux() && 12 | isfile("/proc/sys/kernel/osrelease") && 13 | occursin(r"Microsoft|WSL"i, read("/proc/sys/kernel/osrelease", String)) 14 | end 15 | 16 | function open_in_default_browser(url::AbstractString)::Bool 17 | try 18 | if Sys.isapple() 19 | Base.run(`open $url`) 20 | true 21 | elseif Sys.iswindows() || detectwsl() 22 | Base.run(`powershell.exe Start "'$url'"`) 23 | true 24 | elseif Sys.islinux() 25 | Base.run(`xdg-open $url`) 26 | true 27 | else 28 | false 29 | end 30 | catch ex 31 | false 32 | end 33 | end 34 | end 35 | end 36 | end 37 | 38 | 39 | 40 | import Pkg 41 | Pkg.activate("./pluto-deployment-environment") 42 | Pkg.instantiate() 43 | import Pluto 44 | import Deno_jll 45 | 46 | 47 | pluto_port_channel = Channel{UInt16}(1) 48 | function on_event(e::Pluto.ServerStartEvent) 49 | put!(pluto_port_channel, e.port) 50 | end 51 | function on_event(e) 52 | # ignore 53 | end 54 | 55 | req_s = false 56 | 57 | # We create a session: 58 | sesh = Pluto.ServerSession(options=Pluto.Configuration.from_flat_kwargs(; 59 | # workspace_use_distributed=false, 60 | # disable_writing_notebook_files=true, 61 | auto_reload_from_file=true, 62 | launch_browser=false, 63 | on_event, 64 | require_secret_for_access=req_s, 65 | require_secret_for_open_links=req_s 66 | )) 67 | 68 | notebook_launch_task = @async Pluto.SessionActions.open(sesh, notebook_path; run_async=true) 69 | 70 | @info "Pluto app: Starting server..." 71 | 72 | println("Ignore the message \"Go to ... in your browser\":") 73 | pluto_server_task = @async Pluto.run(sesh) 74 | 75 | pluto_port = take!(pluto_port_channel) # This waits for the server to get ready 76 | @info "Pluto app: waiting for notebook to launch..." 77 | notebook = fetch(notebook_launch_task) # This waits for the notebook to finish 78 | 79 | output_dir = joinpath(@__DIR__, "_site") 80 | 81 | dev_server_port = rand(40507:40999) 82 | 83 | 84 | dev_server_task = @async run(`$(Deno_jll.deno()) run --allow-read --allow-net https://deno.land/std@0.102.0/http/file_server.ts --cors --port $(dev_server_port) $(output_dir)`) # <=v"0.102.0" because of https://github.com/denoland/deno_std/issues/2251 85 | 86 | sleep(.5) 87 | 88 | ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) 89 | @info "Press Ctrl+C multiple times to exit" 90 | 91 | isolated_cell_ids = [ 92 | "cf27b3d3-1689-4b3a-a8fe-3ad639eb2f82" 93 | "7f7f1981-978d-4861-b840-71ab611faf74" 94 | "7d9cb939-da6b-4961-9584-a905ad453b5d" 95 | "4e88cf07-8d85-4327-b310-6c71ba951bba" 96 | "079a6399-50eb-4dee-a36d-b3dcb81c8456" 97 | "b0006e61-b037-41ed-a3e4-9962d15584c4" 98 | "06edb2d7-325f-4f80-8c55-dc01c7783054" 99 | "e0a25f24-a7de-4eac-9f88-cb7632de09eb" 100 | ] 101 | 102 | isolated_cell_query = join("&isolated_cell_id=$(i)" for i in isolated_cell_ids) 103 | 104 | dev_server_url = "http://localhost:$(dev_server_port)/" 105 | pluto_server_url = "http://localhost:$(pluto_port)/edit?id=$(notebook.notebook_id)$(isolated_cell_query)" 106 | 107 | @info """ 108 | 109 | ✅✅✅ 110 | 111 | Ready! To see the website, visit: 112 | ➡️ $(dev_server_url) 113 | 114 | To inspect the generation process, go to: 115 | ➡️ $(pluto_server_url) 116 | 117 | ✅✅✅ 118 | 119 | """ 120 | 121 | 122 | 123 | open_in_default_browser(dev_server_url) 124 | open_in_default_browser(pluto_server_url) 125 | 126 | wait(dev_server_task) 127 | wait(pluto_server_task) -------------------------------------------------------------------------------- /src/mod1_setup_website/basic_info.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fill course basic information" 3 | order: 2 4 | chapter: 1 5 | section: 2 6 | layout: "md.jlmd" 7 | image: "https://user-images.githubusercontent.com/49938764/249464984-ae268773-b804-459a-9c33-ed2839802ad8.png" 8 | tags: ["module1", "track_setup", "teaching", "metadata"] 9 | --- 10 | 11 | ## Add basic information 12 | 13 | If you look at the homepage of the template website, you will see it has a bunch of placeholder text, such as "name of your course", "a short catchy phrase" etc. 14 | 15 | To customize this, you will need to customize the *metadata* of the website. That is, add basic info for your class. 16 | 17 | To do so, you will need to fill the info in the files under the folder `src/_data`. Let us analyze these one by one. 18 | 19 | ## course_info.jl 20 | 21 | This file contains a julia `Dict` with the basic info of the class. For each key (`course_name`, `course_subtitle`, etc.) replace the corresponding placeholder with an appropriate text for your class. 22 | 23 | When filling the `institution_logo` data with the name of your university logo file, do not forget to actually put the file under `src/assets`. 24 | 25 | Authors are listed as a vector of pairs, where the first element is the author name and the second is their homepage address. If you dont have a homepage address for the author, put an empty string `""`. 26 | 27 | ## `homepage.jl` 28 | 29 | This file contains metadata for the info displayed in the homepage, particularly 30 | 31 | - **`title`**: the title displayed on top of the homepage 32 | - **`disclaimer`**: the disclaimer displayed below the title. If you don't want a disclaimer, you can remove this entry. 33 | - **`highlights`**: in this entry you can specify the highlights of your class, which will be displayed on the homepage. This entry should be a vector of highlights. Each entry in the vector should be a dict with the following fields 34 | - **`name`**: the title of the highlight 35 | - **`text`**: short description of the highlight 36 | - **`img`**: link to an image summarizing the highlight 37 | 38 | ## `sidebar.jl` 39 | 40 | In this file you can specify the sidebar of the website. All lecture materials will be grouped in *modules* in the sidebar, which are defined in this file. 41 | 42 | The modules in the file are specified as a vector of pairs, in the form 43 | 44 | ```julia 45 | module_id => module_title 46 | ``` 47 | 48 | for example 49 | 50 | ```julia 51 | "module1" => "Week 1: Introduction to the class" 52 | ``` 53 | 54 | To link a file to a module, you will need to add the module identifier in the page tags. For more info about this, see [Add frontmatter](https://juliapluto.github.io/computational-thinking-template/add_markdown) 55 | 56 | ## `tracks.jl` 57 | 58 | In this file you will specify tracks. Tracks can be used to group lectures across modules, e.g. if they have a commmon theme. When a track is selected on the sidebar, only the pages 59 | belonging to that track will be highlighted. 60 | 61 | Similar to modules, tracks are stored in a vector of pairs in the form 62 | 63 | ```julia 64 | track_id => track_title 65 | ``` 66 | 67 | for example 68 | 69 | ```julia 70 | "julia" => "💻 Julia programming" 71 | ``` 72 | 73 | To link a file to a track, you will need to add the track id, prefixed with `track_`, to the tags of the page. For example, to add a lesson to the julia track defined above, you would add the tag `track_julia` to the tags of that lesson file. 74 | 75 | ## License 76 | 77 | Choosing an appropriate license is important to make your material properly reusable. 78 | 79 | - For text, popular licenses are [Creative Commons](https://creativecommons.org/about/cclicenses/), for example [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) 80 | 81 | - For code, an [OSI open source license](https://opensource.org/licenses/) is recommended. For example [MIT](https://opensource.org/license/mit/) or [Apache 2.0](https://opensource.org/license/apache-2-0/) license. 82 | 83 | To add the license, open the file `LICENSE.md` and replace the text 84 | 85 | ``` 86 | 87 | ``` 88 | 89 | with your license(s). -------------------------------------------------------------------------------- /src/assets/homepage/bg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Website maintenance.md: -------------------------------------------------------------------------------- 1 | # Website maintenance 2 | 3 | This document describes how the website works. 4 | 5 | # Overview 6 | 7 | This is the source code for the computational thinking website! It uses a site generation system inspired by [https://www.11ty.dev/](https://www.11ty.dev/), but there are only three template systems: 8 | - **`.jlhtml` files** are rendered by [HypertextLiteral.jl](https://github.com/JuliaPluto/HypertextLiteral.jl) 9 | - **`.jlmd` files** are rendered by [MarkdownLiteral.jl](https://github.com/JuliaPluto/MarkdownLiteral.jl) 10 | - **`.jl` files** are rendered by [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) 11 | 12 | The `/src/` folder is scanned for files, and all files are turned into HTML pages. 13 | 14 | Paths correspond to URLs. For example, `src/data_science/pca.jl` will become available at `https://computationalthinking.mit.edu/data_science/pca/`. For files called *"index"*, the URL will point to its parent, e.g. `src/docs/index.jlmd` becomes `https://computationalthinking.mit.edu/docs/`. Remember that changing URLs is very bad! You can't share this site with your friends if the links break. 15 | 16 | > **To add something to our website, just create a new file!** Fons will be happy to figure out the technical bits. 17 | 18 | You can generate & preview the website locally (more on this later), and we have a github action generating the website when we push to the `Fall23` branch. The result (in the `Fall23-output` branch) is deployed with GitHub Pages. 19 | 20 | # Content 21 | 22 | ## Literal templates 23 | We use *Julia* as our templating system! Because we use HypertextLiteral and MarkdownLiteral, you can write regular Markdown files and HTML files, but you can also include `$(interpolation)` to spice up your documents! For example: 24 | 25 | ```markdown 26 | # Hey there! 27 | 28 | This is some *text*. Here is a very big number: $(1 + 1). 29 | ``` 30 | 31 | Besides small inline values, you can also write big code blocks, with `$(begin ... end)`, and you can output HTML. Take a look at some of our files to learn more! 32 | 33 | ## Pluto notebooks 34 | 35 | Pluto notebooks will be rendered to HTML and included in the page. What you see is what you get! 36 | 37 | On a separate system, we are running a PlutoSliderServer that is synchronized to the `Fall23` brach. This makes our notebooks interactive! 38 | 39 | Notebook outputs are **cached** (for a long time) by the file hash. This means that a notebook file will only ever run once, which makes it much faster to work on the website. If you need to re-run your notebook, add a space somewhere in the code :) 40 | 41 | ## `.css`, `.html`, `.gif`, etc 42 | 43 | Web assets go through the system unchanged. 44 | 45 | # Front matter 46 | 47 | Like many SSG systems, we use [*front matter*](https://www.11ty.dev/docs/data-frontmatter/) to add metadata to pages. In `.jlmd` files, this is done with a front matter block, e.g.: 48 | ```markdown 49 | --- 50 | title: "🌼 How to install" 51 | description: "Instructions to install Pluto.jl" 52 | tags: ["docs", "introduction"] 53 | layout: "md.jlmd" 54 | --- 55 | 56 | # Let's install Pluto 57 | 58 | here is how you do it 59 | ``` 60 | 61 | Every page **should probably** include: 62 | - *`title`*: Will be used in the sidebar, on Google, in the window header, and on social media. 63 | - *`description`*: Will be used on hover, on Google, and on social media. 64 | - *`tags`*: List of *tags* that are used to create collections out of pages. Our sidebar uses collections to know which pages to list. (more details in `sidebar data.jl`) 65 | - *`layout`*: The name of a layout file in `src/_includes`. For basic Markdown or HTML, you probably want `md.jlmd`. For Pluto, you should use `layout.jlhtml`. 66 | 67 | ## How to write front matter 68 | For `.jlmd` files, see the example above. 69 | 70 | For `.jl` notebooks, use the [Frontmatter GUI](https://github.com/fonsp/Pluto.jl/pull/2104) built into Pluto. 71 | 72 | For `.jlhtml`, we still need to figure something out 😄. 73 | 74 | # Running locally 75 | 76 | ## Developing *content, styles, etc.* 77 | 78 | Open this repository in VS Code, and install the recommended extensions. 79 | 80 | To start running the development server, open the VS Code *command palette* (press `Cmd+Shift+P`), and search for **`Tasks: Run Task`**, then **`PlutoPages: run development server`**. The first run can take some time, as it builds up the notebook outputs cache. Leave it running. 81 | 82 | This will start two things in parallel: the PlutoPages.jl notebook (which generates the website), and a static file server (with Deno_jll). It will open two tabs in your browser: one is the generation dashboard (PlutoPages), the other is the current site preview (Deno_jll). 83 | 84 | Whenever you edit a file, PlutoPages will automatically regenerate! Refresh your browser tab. If it does not pick up the change, go to the generation dashboard and click the "Read input files again" button. 85 | 86 | This workflow is recommended for writing static content, styles, and for site maintenance. But for writing Pluto notebooks, it's best to prepare the notebook first, and then run the site (because it re-runs the entire notebook on any change). 87 | 88 | ## Developing PlutoPages itself 89 | 90 | 91 | You need to manually run the notebook with Pluto: 92 | 1. Go to this folder, and run `julia --project=pluto-deployment-environment`. Then `import Pkg; Pkg.instantiate();`. 93 | 1. `import Pluto; Pluto.run()` and open the `PlutoPages.jl` notebook in this repository. The first run can take some time, as it builds up the notebook outputs cache. Leave it running. 94 | 2. In a second terminal, go to this folder, and run `julia --project=pluto-deployment-environment`, then: 95 | ```julia 96 | import Deno_jll 97 | run(`$(Deno_jll.deno()) run --allow-read --allow-net https://deno.land/std@0.102.0/http/file_server.ts _site`) 98 | ``` 99 | 3. Go to the URL printed to your terminal. 100 | 4. Whenever you edit a file, PlutoPages will automatically regenerate! Refresh your browser tab. If it does not pick up the change, go to the generation dashboard and click the "Read input files again" button. 101 | 102 | # PlutoPages.jl? 103 | 104 | The PlutoPages.jl is still in experimental stage, and I'm not sure if the Julia community is waiting for another SSG system. So right now it's sort of released in secret. If you use it, be sure to respect our LICENSE and be sure to share your feedback with fons@plutojl.org! Bug reports welcome. 105 | -------------------------------------------------------------------------------- /src/assets/julia-logo-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/julia-logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/scripts/search.js: -------------------------------------------------------------------------------- 1 | const root_href = document.head.querySelector("link[rel='root']").getAttribute("href") 2 | 3 | const minby = (arr, fn) => arr.reduce((a, b) => (fn(a) < fn(b) ? a : b)) 4 | const maxby = (arr, fn) => arr.reduce((a, b) => (fn(a) > fn(b) ? a : b)) 5 | const range = (length) => [...Array(length).keys()] 6 | 7 | const sortby = (arr, fn) => arr.sort((a, b) => fn(a) - fn(b)) 8 | 9 | const setup_search_index = async () => { 10 | const search_data_href = document.head.querySelector("link[rel='pp-search-data']").getAttribute("href") 11 | console.log(search_data_href) 12 | 13 | const search_data = await (await fetch(search_data_href)).json() 14 | window.search_data = search_data 15 | 16 | console.log(search_data) 17 | 18 | // create a search bar powered by lunr 19 | // const search_bar = document.createElement('div') 20 | // search_bar.id = 'search-bar' 21 | // search_bar.innerHTML = ` 22 | // 23 | //
24 | // ` 25 | // document.body.appendChild(search_bar) 26 | 27 | // create a search index 28 | const before = Date.now() 29 | const search_index = window.lunr(function () { 30 | this.ref("url") 31 | 32 | this.field("title", { boost: 10 }) 33 | this.field("tags", { boost: 5 }) 34 | this.field("text") 35 | this.metadataWhitelist = ["position"] 36 | search_data.forEach(function (doc) { 37 | this.add(doc) 38 | }, this) 39 | }) 40 | const after = Date.now() 41 | console.info(`lunr: Indexing ${search_data.length} documents took ${after - before}ms`) 42 | window.search_index = search_index 43 | 44 | return { search_data, search_index } 45 | } 46 | 47 | const excerpt_length = 200 48 | const excerpt_padding = 50 49 | 50 | const init_search = async () => { 51 | const query = new URLSearchParams(window.location.search).get("q") 52 | console.warn({ query }) 53 | 54 | document.querySelector(".search-bar.big input").value = query 55 | 56 | const { search_data, search_index } = await setup_search_index() 57 | 58 | if (query) { 59 | const results = search_index.search(query) 60 | console.log(results) 61 | 62 | const search_results = document.getElementById("search-results") 63 | 64 | if (results.length !== 0) { 65 | search_results.innerHTML = "" 66 | results.forEach((result) => { 67 | const { url, title, tags, text } = search_data.find((doc) => doc.url === result.ref) 68 | const result_div = document.createElement("a") 69 | result_div.classList.add("search-result") 70 | result_div.innerHTML = ` 71 |

72 |

73 |

74 | ` 75 | console.log(root_href) 76 | result_div.querySelector(".title").innerText = title 77 | result_div.href = new URL(url, new URL(root_href, window.location.href)).href 78 | result_div.querySelector(".tags").innerText = tags.join(", ") 79 | result_div.querySelector(".snippet").innerText = text.substring(0, excerpt_length) + "..." 80 | 81 | const text_match_positions = Object.values(result?.matchData?.metadata ?? {}) 82 | .flatMap((z) => z?.text?.position ?? []) 83 | .sort(([a, _a], [b, _b]) => a - b) 84 | const title_match_positions = Object.values(result?.matchData?.metadata ?? {}) 85 | .flatMap((z) => z?.title?.position ?? []) 86 | .sort(([a, _a], [b, _b]) => a - b) 87 | 88 | console.error(title_match_positions) 89 | if (title_match_positions.length > 0) { 90 | const strong_el = document.createElement("strong") 91 | strong_el.innerText = title 92 | result_div.querySelector(".title").innerHTML = `` 93 | result_div.querySelector(".title").appendChild(strong_el) 94 | } 95 | 96 | if (text_match_positions.length > 0) { 97 | // console.log(text_match_positions) 98 | // console.log(find_longest_run(text_match_positions, 50)) 99 | // console.log(find_longest_run(text_match_positions, 100)) 100 | // console.log(find_longest_run(text_match_positions, 200)) 101 | // console.log(find_longest_run(text_match_positions, 300)) 102 | // console.log(find_longest_run(text_match_positions, 400)) 103 | 104 | const [start_index, num_matches] = find_longest_run(text_match_positions, excerpt_length) 105 | 106 | const excerpt_start = text_match_positions[start_index][0] 107 | const excerpt_end = excerpt_start + excerpt_length 108 | 109 | const highlighted_ranges = text_match_positions.slice(start_index, start_index + num_matches) 110 | 111 | const elements = highlighted_ranges.flatMap(([h_start, h_length], i) => { 112 | const h_end = h_start + h_length 113 | const word = text.slice(h_start, h_end) 114 | const filler = text.slice(h_end, highlighted_ranges[i + 1]?.[0] ?? excerpt_end) 115 | const word_el = document.createElement("strong") 116 | word_el.innerText = word 117 | return [word_el, filler] 118 | }) 119 | 120 | const snippet_p = result_div.querySelector(".snippet") 121 | snippet_p.innerHTML = `` 122 | ;["...", text.slice(excerpt_start - excerpt_padding, excerpt_start).trimStart(), ...elements, "..."].forEach((el) => snippet_p.append(el)) 123 | } 124 | 125 | // text_match_positions.slice(start_index, start_index + num_matches).forEach(([start, length]) => { 126 | 127 | search_results.appendChild(result_div) 128 | }) 129 | } else { 130 | search_results.innerText = `No results found for "${query}"` 131 | } 132 | } 133 | } 134 | 135 | const count = (arr, fn) => arr.reduce((a, b) => fn(a) + fn(b), 0) 136 | 137 | const find_longest_run = (/** @type{Array<[number, number]>} */ positions, max_dist) => { 138 | const legal_run_size = (start_index) => 139 | positions.slice(start_index).filter(([start, length]) => start + length < positions[start_index][0] + max_dist).length 140 | 141 | console.warn(range(positions.length).map(legal_run_size)) 142 | 143 | const best_start = maxby(range(positions.length), legal_run_size) 144 | const best_length = legal_run_size(best_start) 145 | return [best_start, best_length] 146 | } 147 | 148 | window.init_search = init_search 149 | -------------------------------------------------------------------------------- /src/assets/styles/homepage.css: -------------------------------------------------------------------------------- 1 | @import url("newdefault.css"); 2 | 3 | body { 4 | background: url("../homepage/bg.svg"); 5 | background-color: hsl(231deg 14% 57%); 6 | background-size: cover; 7 | backdrop-filter: blur(3vw); 8 | } 9 | main h1 { 10 | font-family: "Vollkorn", serif; 11 | font-weight: 800; 12 | font-style: italic; 13 | margin-block-end: 0.5em; 14 | font-size: 3rem; 15 | margin-block-start: 0; 16 | border-bottom: 5px solid #74747414; 17 | letter-spacing: -0.2px; 18 | color: #424250; 19 | padding: 0px 10px; 20 | text-shadow: 7px 5px 0px #e5dbb8; 21 | } 22 | 23 | a { 24 | text-decoration: none; 25 | /* background: #f3f3ff; */ 26 | /* border: 3px solid; */ 27 | color: black; 28 | /* border-bottom: 0.2em solid rgba(0, 0, 0, 0.3); */ 29 | } 30 | .homepage a:not(.no-decoration) { 31 | background-position: 0 0.83em; 32 | background-repeat: repeat-x; 33 | background-size: 2px 8px; 34 | background-image: linear-gradient(to bottom, rgba(165, 213, 235, 0.3) 33%, rgba(165, 213, 235, 0.3)); 35 | /* text-shadow: 2px 2px white, 2px -2px white, -2px 2px white, -2px -2px white; */ 36 | transition: background-position 50ms linear, background-size 50ms linear; 37 | } 38 | 39 | a:hover { 40 | background-position: 0 0em; 41 | background-size: 2px auto; 42 | } 43 | 44 | div.banner { 45 | min-height: 20rem; 46 | display: grid; 47 | place-items: center; 48 | } 49 | 50 | div.banner h1 { 51 | transform: perspective(187px) rotate3d(0, 2, 0, 0deg); 52 | font-family: "Alegreya", sans-serif; 53 | background: #000000ad; 54 | padding: 0.2em 0.5em; 55 | margin: 0px 10px; 56 | border-radius: 0.4em; 57 | transition: transform 200ms ease-in-out; 58 | color: #ffffffc7; 59 | font-style: normal; 60 | border: none; 61 | backdrop-filter: blur(6px); 62 | /* flex: 1 1 auto; */ 63 | /* display: block; */ 64 | } 65 | div.banner h1 strong { 66 | color: white; 67 | } 68 | 69 | div.banner:hover h1 { 70 | /* transform: perspective(187px) rotate3d(0, 2, 0, 3deg) scale(1.05); */ 71 | } 72 | 73 | #title { 74 | background-image: url("../homepage/swoosh.png"); 75 | 76 | background-size: cover; 77 | image-rendering: pixelated; 78 | } 79 | 80 | img.logo { 81 | position: absolute; 82 | top: 5px; 83 | left: 5px; 84 | z-index: 10; 85 | height: 2rem; 86 | background: #ffffff96; 87 | padding: 3px; 88 | } 89 | 90 | .twocols { 91 | column-count: 2; 92 | color: #fffffff7; 93 | background: linear-gradient(155deg, #7c7e87, #5a594a); 94 | } 95 | 96 | main { 97 | /* background: white; */ 98 | padding: 1em; 99 | max-width: 86rem; 100 | z-index: -1; 101 | margin: 3em auto 0 auto; 102 | padding-bottom: 5rem !important; 103 | } 104 | main > div { 105 | z-index: 4; 106 | background: white; 107 | padding: 2rem; 108 | margin-block-end: 5rem; 109 | border-radius: 1rem; 110 | box-shadow: 0px 6px 7px #1c12120d; 111 | 112 | max-width: 700px; 113 | margin-left: auto; 114 | margin-right: auto; 115 | } 116 | 117 | main > div.wide { 118 | max-width: unset; 119 | } 120 | 121 | main > div:last-of-type { 122 | margin-block-end: 0px; 123 | } 124 | main > div > *:last-child, 125 | main > div > .contain > *:last-child { 126 | margin-block-end: 0px; 127 | margin-bottom: 0em; 128 | } 129 | main thingy { 130 | background: #ff00005e; 131 | width: 300vw; 132 | border-radius: 50%; 133 | height: 60vh; 134 | display: block; 135 | /* position: unset; */ 136 | z-index: -4; 137 | /* transform: translate(10px, -64px); */ 138 | /* transform: rotate(11deg); */ 139 | } 140 | .asdf { 141 | position: absolute; 142 | transform: translate(-); 143 | overflow: hidden; 144 | max-width: 100vw; 145 | } 146 | .contain { 147 | max-width: 700px; 148 | margin-left: auto; 149 | margin-right: auto; 150 | } 151 | 152 | blockquote { 153 | border-left: 0.6em solid #b97777; 154 | padding: 0.5em 1em; 155 | max-width: 30em; 156 | font-style: italic; 157 | background: #f9f9f9; 158 | font-size: 1rem; 159 | margin: 0 auto; 160 | } 161 | 162 | blockquote.banner { 163 | margin-top: -46px; 164 | font-style: unset; 165 | font-size: 1rem; 166 | border-radius: 0.5em; 167 | box-shadow: 0px 3px 17px #0000001a; 168 | } 169 | 170 | .pillars { 171 | display: flex; 172 | flex-direction: row; 173 | justify-content: space-between; 174 | overflow-x: auto; 175 | } 176 | 177 | .pillars > div { 178 | color: white; 179 | padding: 1em; 180 | background: #434366; 181 | min-height: 300px; 182 | flex: 1 1 33%; 183 | margin: 0px 10px; 184 | } 185 | 186 | .scrolly { 187 | /* max-height: 20em; */ 188 | /* overflow-y: auto; */ 189 | } 190 | .pillars > div ul { 191 | padding-left: 0.6rem; 192 | } 193 | .pillars > div li { 194 | list-style: "- "; 195 | margin-bottom: 0.3rem; 196 | margin-right: 0.5rem; 197 | } 198 | .pillars > div li::marker { 199 | color: rgba(255, 255, 255, 0.4); 200 | } 201 | 202 | .subjects { 203 | display: grid; 204 | grid-template-columns: repeat(3, auto); 205 | grid-gap: 1rem; 206 | /* display: flex; */ 207 | /* flex-wrap: wrap; */ 208 | } 209 | 210 | @media (max-width: 1350px) { 211 | .subjects { 212 | grid-template-columns: repeat(2, auto); 213 | } 214 | } 215 | @media (max-width: 850px) { 216 | .subjects { 217 | grid-template-columns: repeat(1, auto); 218 | } 219 | } 220 | 221 | @media (min-width: 1250px) { 222 | .subjectscontainer { 223 | display: flex; 224 | flex-direction: row; 225 | margin-block-start: 5rem; 226 | } 227 | 228 | .subjectscontainer h1 { 229 | flex-shrink: 0; 230 | position: sticky; 231 | top: 100px; 232 | align-self: flex-start; 233 | margin-block-start: 0px; 234 | /* padding-right: 0; */ 235 | margin-right: 1em; 236 | } 237 | } 238 | 239 | .subjects > a { 240 | display: block; 241 | border: 7px solid #c19d1c1f; 242 | min-height: 200px; 243 | min-width: min(90vw, 188px); 244 | padding: 1em; 245 | border-radius: 1em; 246 | transition: transform 100ms ease-in-out; 247 | /* width: 27%; */ 248 | box-shadow: 0px 6px 7px #1c12120d; 249 | } 250 | 251 | .subjects > a:hover { 252 | transform: scale(1.05); 253 | } 254 | 255 | .subjects > a img { 256 | max-width: 100%; 257 | width: 100%; 258 | } 259 | section { 260 | display: flex; 261 | flex-direction: row; 262 | background: linear-gradient(145deg, #a6b8ef, #daeaff); 263 | padding: 1em; 264 | background-repeat: repeat-x; 265 | border-radius: 1em; 266 | margin-bottom: 2em; 267 | } 268 | 269 | .shadow, 270 | section { 271 | box-shadow: 0px 6px 9px #0606060f; 272 | padding: 1rem; 273 | border-radius: 1rem; 274 | } 275 | 276 | @media (max-width: 500px) { 277 | section { 278 | flex-direction: column; 279 | } 280 | } 281 | 282 | section > div { 283 | flex: 1 1 60%; 284 | } 285 | 286 | section > div.content { 287 | margin-right: 1em; 288 | } 289 | section > div.preview { 290 | flex: 0 1 40%; 291 | } 292 | 293 | section > div.preview > img { 294 | width: 100%; 295 | } 296 | 297 | .homepage, 298 | .banner { 299 | color: #3c3c3c; 300 | } 301 | -------------------------------------------------------------------------------- /src/assets/styles/layout.css: -------------------------------------------------------------------------------- 1 | /* COLOR */ 2 | 3 | #pages-layout { 4 | /* --bg-color: set by pluto */ 5 | --sidebar-bg: #fafafa; 6 | --sidebar-color: rgb(82, 82, 82); 7 | --sidebar-li-active-bg: rgb(235, 235, 235); 8 | --sidebar-li-hover-bg: rgb(247, 240, 190); 9 | } 10 | @media (prefers-color-scheme: dark) { 11 | #pages-layout { 12 | --sidebar-bg: #303030; 13 | --sidebar-color: rgb(255, 255, 255); 14 | --sidebar-li-active-bg: rgb(82, 82, 82); 15 | --sidebar-li-hover-bg: rgb(108, 94, 70); 16 | } 17 | } 18 | 19 | /* LAYOUT */ 20 | 21 | #pages-layout { 22 | display: flex; 23 | flex-direction: row; 24 | min-height: 100vh; 25 | align-items: stretch; 26 | } 27 | 28 | #pages-sidebar { 29 | font-family: system-ui, sans-serif; 30 | flex: 0 0 auto; 31 | width: 15rem; 32 | font-weight: 400; 33 | z-index: 1900; 34 | } 35 | 36 | #pages-content { 37 | display: block; 38 | flex: 1 1 auto; 39 | min-width: 0; 40 | } 41 | 42 | #pages-sidebar > div { 43 | margin: 1rem; 44 | margin-right: 0; 45 | padding: 0.5rem; 46 | /* padding-bottom: 2rem; */ 47 | border-radius: 1rem; 48 | background: var(--sidebar-bg); 49 | color: var(--sidebar-color); 50 | } 51 | 52 | #toggle-nav { 53 | display: none; 54 | cursor: pointer; 55 | } 56 | 57 | /* SIDEBAR COLLAPSING */ 58 | 59 | #pages-content::after { 60 | content: ""; 61 | z-index: 23400; 62 | touch-action: none; 63 | pointer-events: none; 64 | position: fixed; 65 | top: 0; 66 | left: 0; 67 | right: 0; 68 | bottom: 0; 69 | transition: background-color 0.2s ease-out; 70 | } 71 | 72 | @media screen and (max-width: 768px) { 73 | #pages-layout { 74 | flex-direction: column; 75 | } 76 | #toggle-nav { 77 | display: inline-flex; 78 | align-self: start; 79 | border: none; 80 | background: none; 81 | } 82 | #toggle-nav::after { 83 | --size: 40px; 84 | content: " "; 85 | display: inline-block; 86 | width: var(--size); 87 | height: var(--size); 88 | background-image: url(https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/menu-outline.svg); 89 | background-size: var(--size) var(--size); 90 | filter: var(--image-filters); 91 | } 92 | #pages-sidebar { 93 | position: fixed; 94 | top: 0; 95 | bottom: 0; 96 | right: 100%; 97 | overflow-y: auto; 98 | transition: transform 300ms cubic-bezier(0.18, 0.89, 0.45, 1.12); 99 | } 100 | @media (prefers-reduced-motion) { 101 | #pages-sidebar { 102 | transition: none; 103 | } 104 | } 105 | 106 | .pages_show_sidebar #pages-sidebar { 107 | transform: translateX(100%); 108 | z-index: 23401; 109 | } 110 | .pages_show_sidebar #pages-content::after { 111 | display: block; 112 | background-color: rgba(0, 0, 0, 0.5); 113 | } 114 | } 115 | 116 | /* SIDEBAR */ 117 | 118 | #pages-sidebar { 119 | --child-padding: 0.2em 0.6em; 120 | --border-radius: 0.5em; 121 | } 122 | 123 | #pages-sidebar > div > ul { 124 | margin-block-start: 0px; 125 | margin-block-end: 0px; 126 | } 127 | 128 | #pages-sidebar li, 129 | #pages-sidebar ul { 130 | padding: 0px; 131 | list-style-type: none; 132 | } 133 | 134 | #pages-sidebar a { 135 | color: unset; 136 | text-decoration: none; 137 | } 138 | 139 | #pages-sidebar li li a, 140 | #pages-sidebar li h3 { 141 | border-radius: var(--border-radius); 142 | padding: var(--child-padding); 143 | } 144 | 145 | #pages-sidebar li h3 { 146 | color: var(--sidebar-accent-1); 147 | font-variant-caps: all-petite-caps; 148 | margin-block-start: 3rem; 149 | margin-block-end: 0; 150 | } 151 | 152 | #pages-sidebar li hr { 153 | margin: 3rem 1rem; 154 | /* border-color: red; */ 155 | border-style: solid; 156 | opacity: 0.2; 157 | } 158 | 159 | #pages-sidebar li:first-of-type h3 { 160 | margin-block-start: 0; 161 | } 162 | 163 | #pages-sidebar li, 164 | #pages-sidebar ul { 165 | display: flex; 166 | flex-direction: column; 167 | align-items: stretch; 168 | } 169 | 170 | #pages-sidebar li li.homework { 171 | padding-left: 1ch; 172 | /* background: yellow; */ 173 | } 174 | 175 | #pages-sidebar li li a { 176 | margin: 0.2em 0; 177 | } 178 | 179 | #pages-sidebar li li.homework a { 180 | /* background: #ffb60012; */ 181 | margin: 0.4em 0px; 182 | outline: 3px dashed #92929278; 183 | outline-offset: -1px; 184 | } 185 | 186 | /* #pages-sidebar li li.homework a::before { 187 | content: "👉 "; 188 | } */ 189 | 190 | #pages-sidebar li li span.entry-number { 191 | opacity: 0.6; 192 | } 193 | #pages-sidebar li li.homework span.entry-number { 194 | display: block; 195 | } 196 | 197 | #pages-sidebar li li.active a { 198 | background-color: var(--sidebar-li-active-bg); 199 | } 200 | #pages-sidebar li li:hover a { 201 | background-color: var(--sidebar-li-hover-bg); 202 | } 203 | #pages-sidebar li li.not_in_track { 204 | opacity: 0.4; 205 | } 206 | 207 | /* TRACK CHOOSER */ 208 | 209 | .track-chooser { 210 | margin-top: 3em; 211 | padding: 0.5em; 212 | border: 3px solid var(--track-bg-accent); 213 | background: var(--track-bg); 214 | color: var(--fg); 215 | border-radius: 0.3em; 216 | display: flex; 217 | flex-direction: column; 218 | align-items: center; 219 | } 220 | 221 | .track-chooser h2:not(#asdf) { 222 | font-weight: 900; 223 | font-family: sans-serif; 224 | font-style: normal; 225 | font-size: 1.2rem; 226 | margin-block-end: 0.3em; 227 | margin-block-start: 0; 228 | } 229 | 230 | .track-chooser label { 231 | display: contents; 232 | } 233 | 234 | .track-chooser select { 235 | max-width: 100%; 236 | } 237 | 238 | /* SIDEBAR LOGO */ 239 | 240 | #pages-sidebar .home_link img { 241 | height: 1.2em; 242 | width: 1.2em; 243 | } 244 | #pages-sidebar a.home_link { 245 | font-size: 1.7rem; 246 | padding: 0.3em; 247 | font-weight: 800; 248 | display: flex; 249 | flex-direction: row; 250 | align-items: center; 251 | gap: 0.5ch; 252 | } 253 | 254 | /* Markdown content */ 255 | 256 | .pages-markdown main { 257 | max-width: 700px; 258 | margin-left: auto; 259 | margin-right: auto; 260 | margin-top: 5rem; 261 | } 262 | 263 | /* footnote */ 264 | 265 | main { 266 | padding-bottom: 5rem !important; 267 | } 268 | 269 | .github-logo { 270 | width: 1em; 271 | } 272 | 273 | .page-foot { 274 | z-index: 4; 275 | background: white; 276 | padding: 2rem; 277 | border-radius: 1rem; 278 | box-shadow: 0px 0px 10px 5px #1c12120d; 279 | 280 | max-width: 700px; 281 | margin-left: auto; 282 | margin-right: auto; 283 | margin-block-end: 5rem; 284 | margin-bottom: 10em; 285 | } 286 | 287 | .page-foot a { 288 | text-decoration: none; 289 | /* background: #f3f3ff; */ 290 | /* border: 3px solid; */ 291 | color: black; 292 | /* border-bottom: 0.2em solid rgba(0, 0, 0, 0.3); */ 293 | } 294 | .page-foot a:not(.no-decoration) { 295 | background-position: 0 0.83em; 296 | background-repeat: repeat-x; 297 | background-size: 2px 8px; 298 | background-image: linear-gradient(to bottom, rgba(165, 213, 235, 0.3) 33%, rgba(165, 213, 235, 0.3)); 299 | /* text-shadow: 2px 2px white, 2px -2px white, -2px 2px white, -2px -2px white; */ 300 | transition: background-position 50ms linear, background-size 50ms linear; 301 | } 302 | 303 | .page-foot a:hover { 304 | background-position: 0 0em; 305 | background-size: 2px auto; 306 | } 307 | -------------------------------------------------------------------------------- /src/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Software installation" 3 | tags: ["welcome"] 4 | order: 2 5 | layout: "md.jlmd" 6 | youtube_id: "OOjKEgbt8AI" 7 | --- 8 | 9 | $( 10 | begin 11 | # these special elements will automatically update to read the latest Julia version. See the JavaScript snippet at the bottom of this page to see how it works! 12 | 13 | version = html"1.8.2" 14 | pkg_version = html"1.8" 15 | 16 | nothing 17 | end 18 | ) 19 | 20 | # First-time setup: Install Julia & Pluto 21 | 22 | \\ 23 | \\ 24 | \\ 25 | **Text and pictures version:** 26 | 27 | ## Step 1: Install Julia $version 28 | 29 | Go to [https://julialang.org/downloads](https://julialang.org/downloads) and download the current stable release, Julia $(version), using the correct version for your operating system (Linux x86, Mac, Windows, etc). 30 | 31 | ## Step 2: Run Julia 32 | 33 | After installing, **make sure that you can run Julia**. On some systems, this means searching for the "Julia $(version)" program installed on your computer; in others, it means running the command `julia` in a terminal. Make sure that you can execute `1 + 1`: 34 | 35 | ![image](https://user-images.githubusercontent.com/6933510/91439734-c573c780-e86d-11ea-8169-0c97a7013e8d.png) 36 | 37 | *Make sure that you are able to launch Julia and calculate `1+1` before proceeding!* 38 | 39 | ## Step 3: Install [`Pluto`](https://github.com/fonsp/Pluto.jl) 40 | 41 | Next we will install the [**Pluto**](https://github.com/fonsp/Pluto.jl), the notebook environment that we will be using during the course. Pluto is a Julia _programming environment_ designed for interactivity and quick experiments. 42 | 43 | Open the **Julia REPL**. This is the command-line interface to Julia, similar to the previous screenshot. 44 | 45 | Here you type _Julia commands_, and when you press ENTER, it runs, and you see the result. 46 | 47 | To install Pluto, we want to run a _package manager command_. To switch from _Julia_ mode to _Pkg_ mode, type `]` (closing square bracket) at the `julia>` prompt: 48 | 49 |

 50 | julia> ]
 51 | 
 52 | (@v$(pkg_version)) pkg>
 53 | 
54 | 55 | The line turns blue and the prompt changes to `pkg>`, telling you that you are now in _package manager mode_. This mode allows you to do operations on **packages** (also called libraries). 56 | 57 | To install Pluto, run the following (case sensitive) command to *add* (install) the package to your system by downloading it from the internet. 58 | You should only need to do this *once* for each installation of Julia: 59 | 60 |

 61 | (@v$(pkg_version)) pkg> add Pluto
 62 | 
63 | 64 | This might take a couple of minutes, so you can go get yourself a cup of tea! 65 | 66 | ![image](https://user-images.githubusercontent.com/6933510/91440380-ceb16400-e86e-11ea-9352-d164911774cf.png) 67 | 68 | You can now close the terminal. 69 | 70 | ## Step 4: Use a modern browser: Mozilla Firefox or Google Chrome 71 | We need a modern browser to view Pluto notebooks with. Firefox and Chrome work best. 72 | 73 | 74 | # Second time: _Running Pluto & opening a notebook_ 75 | Repeat the following steps whenever you want to work on a project or homework assignment. 76 | 77 | ## Step 1: Start Pluto 78 | 79 | Start the Julia REPL, like you did during the setup. In the REPL, type: 80 | ```julia 81 | julia> using Pluto 82 | 83 | julia> Pluto.run() 84 | ``` 85 | 86 | ![image](https://user-images.githubusercontent.com/6933510/91441094-eb01d080-e86f-11ea-856f-e667fdd9b85c.png) 87 | 88 | The terminal tells us to go to `http://localhost:1234/` (or a similar URL). Let's open Firefox or Chrome and type that into the address bar. 89 | 90 | ![image](https://user-images.githubusercontent.com/6933510/199279574-4b1d0494-2783-49a0-acca-7b6284bede44.png) 91 | 92 | > If you're curious about what a _Pluto notebook_ looks like, have a look at the **Featured Notebooks**. These notebooks are useful for learning some basics of Julia programming. 93 | > 94 | > If you want to hear the story behind Pluto, have a look a the [JuliaCon presentation](https://www.youtube.com/watch?v=IAF8DjrQSSk). 95 | 96 | If nothing happens in the browser the first time, close Julia and try again. And please let us know! 97 | 98 | ## Step 2a: Opening a notebook from the web 99 | 100 | This is the main menu - here you can create new notebooks, or open existing ones. Our homework assignments will always be based on a _template notebook_, available in this GitHub repository. To start from a template notebook on the web, you can _paste the URL into the blue box_ and press ENTER. 101 | 102 | For example, homework 0 is available [here](/hw0/). Go to this page, and on the top right, click on the button that says "Edit or run this notebook". From these instructions, copy the notebook link, and paste it into the box. Press ENTER, and select OK in the confirmation box. 103 | 104 | ![image](https://user-images.githubusercontent.com/6933510/91441968-6b750100-e871-11ea-974e-3a6dfd80234a.png) 105 | 106 | **The first thing we will want to do is to save the notebook somewhere on our own computer; see below.** 107 | 108 | ## Step 2b: Opening an existing notebook file 109 | When you launch Pluto for the second time, your recent notebooks will appear in the main menu. You can click on them to continue where you left off. 110 | 111 | If you want to run a local notebook file that you have not opened before, then you need to enter its _full path_ into the blue box in the main menu. More on finding full paths in step 3. 112 | 113 | ## Step 3: Saving a notebook 114 | We first need a folder to save our homework in. Open your file explorer and create one. 115 | 116 | Next, we need to know the _absolute path_ of that folder. Here's how you do that in [Windows](https://www.top-password.com/blog/copy-full-path-of-a-folder-file-in-windows/), [MacOS](https://www.josharcher.uk/code/find-path-to-folder-on-mac/) and [Ubuntu](). 117 | 118 | For example, you might have: 119 | 120 | - `C:\\Users\\fons\\Documents\\18S191_assignments\\` on Windows 121 | 122 | - `/Users/fons/Documents/18S191_assignments/` on MacOS 123 | 124 | - `/home/fons/Documents/18S191_assignments/` on Ubuntu 125 | 126 | Now that we know the absolute path, go back to your Pluto notebook, and at the top of the page, click on _"Save notebook..."_. 127 | 128 | ![image](https://user-images.githubusercontent.com/6933510/91444741-77fb5880-e875-11ea-8f6b-02c1c319e7f3.png) 129 | 130 | This is where you type the **new path+filename for your notebook**: 131 | 132 | ![image](https://user-images.githubusercontent.com/6933510/91444565-366aad80-e875-11ea-8ed6-1265ded78f11.png) 133 | 134 | Click _Choose_. 135 | 136 | ## Step 4: Sharing a notebook 137 | 138 | After working on your notebook (your code is autosaved when you run it), you will find your notebook file in the folder we created in step 3. This the file that you can share with others, or submit as your homework assignment to Canvas. 139 | 140 | 141 | 156 | -------------------------------------------------------------------------------- /src/assets/styles/index.css: -------------------------------------------------------------------------------- 1 | /* a minimalist set of CSS resets */ 2 | 3 | @import url("https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css"); 4 | @import url("lecture_header.css"); 5 | @import url("newdefault.css"); 6 | 7 | /* @import url('https://cdn.jsdelivr.net/gh/fonsp/Pluto.jl@0.18.0/frontend/vollkorn.css'); */ 8 | /* @import url('https://fonts.googleapis.com/css2?family=Jaldi:wght@400;700&display=swap'); */ 9 | /* @import url('https://fonts.googleapis.com/css2?family=Jaldi:wght@400;700&family=Work+Sans:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700;1,800;1,900&family=Yantramanav:wght@400;500;700;900&display=swap'); */ 10 | 11 | *, 12 | *:before, 13 | *:after { 14 | box-sizing: inherit; 15 | } 16 | 17 | :root { 18 | --system-fonts: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", 19 | "Segoe UI Symbol", system-ui, sans-serif; 20 | --system-fonts-mono: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 21 | 22 | --fg: #000; 23 | --faded-1: #858585; 24 | --faded-2: rgb(161, 161, 161); 25 | --sidebar-accent-1: #c89393; 26 | --search-bg: hsl(78deg 10% 85%); 27 | --search-bg-accent: #f4f4f5; 28 | 29 | --track-bg: hsl(56 50% 94% / 1); 30 | --track-bg-accent: #a3987c; 31 | } 32 | 33 | @media (prefers-color-scheme: dark) { 34 | :root { 35 | --fg: #ddd; 36 | --faded-1: #b3b3b3; 37 | --faded-2: #999999; 38 | 39 | --sidebar-accent-1: #d0a493; 40 | --search-bg: #363b33; 41 | --search-bg-accent: #4d6542; 42 | 43 | --track-bg: #545346; 44 | --track-bg-accent: #dad1b9; 45 | } 46 | } 47 | 48 | /* adjust typography defaults */ 49 | body { 50 | margin: 0; 51 | padding: 0; 52 | /* font-family: Noto; */ 53 | /* font-family: sans-serif; */ 54 | /* font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; */ 55 | width: 100vw; 56 | overflow-x: hidden; 57 | background: hsl(235deg 19% 16%); 58 | color: var(--pluto-output-color); 59 | 60 | /* background: url(bg.svg); */ 61 | /* background-color: hsl(231deg 14% 57%); */ 62 | /* background-size: cover; */ 63 | word-break: break-word; 64 | } 65 | 66 | .pages-markdown p, 67 | .pages-markdown ol { 68 | line-height: 1.5; 69 | } 70 | 71 | .pages-markdown h1, 72 | .pages-markdown h2 { 73 | font-weight: 800; 74 | } 75 | 76 | .pages-markdown h1, 77 | .pages-markdown h2, 78 | .pages-markdown h3, 79 | .pages-markdown h4, 80 | .pages-markdown h5, 81 | .pages-markdown h6 { 82 | color: var(--pluto-output-h-color); 83 | } 84 | 85 | pre { 86 | tab-size: 4; 87 | white-space: pre-wrap; 88 | word-break: break-word; 89 | } 90 | 91 | pre, 92 | code { 93 | font-family: var(--system-fonts-mono); 94 | } 95 | 96 | /* images and videos max out at full width */ 97 | img, 98 | video { 99 | height: auto; 100 | max-width: 100%; 101 | } 102 | 103 | a { 104 | font-weight: 500; 105 | text-decoration: none; 106 | } 107 | .pages-markdown a, 108 | .pages-markdown a:visited { 109 | color: #4674bc; 110 | } 111 | a:hover { 112 | text-decoration: underline; 113 | } 114 | h1 a, 115 | h2 a, 116 | h3 a { 117 | font-weight: inherit; 118 | } 119 | 120 | a.arrow::after { 121 | content: " →"; 122 | } 123 | card-text > a.arrow { 124 | margin-top: auto; 125 | } 126 | 127 | /* SIDEBAR LOGO */ 128 | 129 | a.pluto_home_link img { 130 | height: 1.2em; 131 | width: 1.2em; 132 | } 133 | a.pluto_home_link { 134 | font-size: 1.7em; 135 | font-weight: 800; 136 | color: inherit; 137 | padding: 0.3em; 138 | display: flex; 139 | flex-direction: row; 140 | align-items: center; 141 | gap: 0.5ch; 142 | } 143 | 144 | .sidebar-about .logos { 145 | display: flex; 146 | flex-direction: row; 147 | gap: 1em; 148 | padding: 1em; 149 | align-items: center; 150 | } 151 | 152 | .sidebar-about .logos picture { 153 | flex: 1 1 auto; 154 | min-width: 0; 155 | height: auto; 156 | object-fit: contain; 157 | } 158 | 159 | .sidebar-about .course-numbers { 160 | opacity: 0.6; 161 | } 162 | .sidebar-about .course-numbers > span { 163 | font-family: var(--system-fonts-mono); 164 | font-size: 0.9em; 165 | } 166 | .sidebar-about .course-numbers::before { 167 | /* content: " | "; */ 168 | } 169 | 170 | .semester-details, 171 | .authors { 172 | border-radius: var(--border-radius); 173 | padding: var(--child-padding); 174 | } 175 | .semester-details > a { 176 | font-weight: 700; 177 | } 178 | 179 | #pages-sidebar h1 { 180 | font-size: 1.4rem; 181 | margin-block-end: 0px; 182 | margin: 0; /* line-height: 1; */ 183 | } 184 | 185 | #pages-sidebar h2 { 186 | font-size: 1rem; 187 | font-weight: 500; 188 | font-style: italic; 189 | opacity: 0.8; 190 | margin-block-start: 0.2em; 191 | } 192 | 193 | .authors { 194 | color: var(--faded-2); 195 | } 196 | .authors { 197 | color: var(--faded-2); 198 | } 199 | #pages-sidebar .authors > a { 200 | color: var(--fg); 201 | } 202 | 203 | .search-result strong { 204 | --bg-color: #73731e94; 205 | background: var(--bg-color); 206 | outline: 0.15em solid var(--bg-color); 207 | border-radius: 0.1em; 208 | } 209 | 210 | #pages-sidebar .search-bar form { 211 | display: flex; 212 | flex-direction: row; 213 | } 214 | #pages-sidebar .search-bar input[type="search"] { 215 | flex: 1 1 auto; 216 | min-width: 0px; 217 | } 218 | 219 | a.search-result, 220 | a.search-result:visited { 221 | color: inherit; 222 | display: block; 223 | text-decoration: none; 224 | background: var(--search-bg); 225 | padding: 0.7rem; 226 | margin: 2rem 1rem 2rem 0rem; 227 | --br: 0.4em; 228 | border-radius: var(--br); 229 | position: relative; 230 | } 231 | 232 | .search-result h3 { 233 | margin-block-start: 0; 234 | } 235 | 236 | .search-result .tags { 237 | opacity: 0.6; 238 | font-family: var(--system-fonts-mono); 239 | } 240 | 241 | a.search-result::before { 242 | content: ""; 243 | display: block; 244 | position: absolute; 245 | z-index: -1; 246 | --off: -3px; 247 | top: var(--off); 248 | right: var(--off); 249 | left: var(--off); 250 | bottom: var(--off); 251 | background: var(--search-bg-accent); 252 | transform: rotate(356.9deg) translate(0px, 0px); 253 | border-radius: var(--br); 254 | } 255 | 256 | .student-feedback .card { 257 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); 258 | margin: 1rem 0rem; 259 | border-radius: 0.4rem; 260 | padding: 0.2rem 1rem; 261 | } 262 | 263 | @media (prefers-color-scheme: dark) { 264 | .student-feedback .card { 265 | background: #4b4b4b; 266 | } 267 | } 268 | .student-feedback .card-container { 269 | padding: 4px 16px; 270 | } 271 | .student-feedback .card-container::after, 272 | .student-feedback .row::after { 273 | content: ""; 274 | clear: both; 275 | display: table; 276 | } 277 | .student-feedback .semester { 278 | opacity: 0.6; 279 | } 280 | .student-feedback .feedback { 281 | /* margin-top: 0.5em; */ 282 | } 283 | 284 | .student-feedback { 285 | margin-bottom: 4rem; 286 | } 287 | 288 | blockquote.twitter-tweet { 289 | margin: 0rem; 290 | } 291 | 292 | /* modify Pluto's styles to avoid a visual glitch. This will make the header always display fixed at the top. */ 293 | 294 | body:not(.asdfsdfa) pluto-editor:not(.asdffdas) header#pluto-nav { 295 | position: fixed; 296 | top: 0; 297 | left: 56px; 298 | right: 56px; 299 | z-index: 1998; 300 | width: auto; 301 | border-radius: 0 0 10px 10px; 302 | } 303 | 304 | /* Make space for the Pluto header */ 305 | body.binder:not(.offer_binder) { 306 | padding-top: 60px; 307 | } 308 | 309 | /* Another strategy: leave the header in place but make the export menu hidden when it is not opened. */ 310 | /* 311 | header.show_export aside#export { 312 | visibility: initial; 313 | } 314 | 315 | aside#export { 316 | visibility: hidden; 317 | } */ 318 | -------------------------------------------------------------------------------- /src/_includes/layout.jlhtml: -------------------------------------------------------------------------------- 1 | $(begin 2 | import Pluto 3 | "The contents of `` from a Pluto HTML export." 4 | const pluto_head = let 5 | default = Pluto.generate_html(; 6 | pluto_cdn_root=Pluto.PLUTO_VERSION < v"0.19" ? "https://cdn.jsdelivr.net/gh/fonsp/Pluto.jl@9ca70c36/frontend/" : nothing) 7 | m = match(r"(.*)"s, default) 8 | reduce([ 9 | # r""s 10 | r"" 11 | r"" 12 | r"" 13 | r"" 14 | ]; init=m[1]) do s,r 15 | replace(s, r => "") 16 | end |> HTML 17 | end 18 | 19 | f(x,y) = get(page.output.frontmatter, x, y) 20 | 21 | function section_number(frontmatter) 22 | ch = get(frontmatter, "chapter", nothing) 23 | se = get(frontmatter, "section", nothing) 24 | 25 | isnothing(ch) || isnothing(se) ? nothing : "$(ch).$(se)" 26 | end 27 | 28 | nothing 29 | end) 30 | 31 | 32 | $(f("title", splitext(basename(page.input.relative_path))[1])) — $(metadata["course_info"]["course_name"]) 33 | $(let d = f("description", nothing) 34 | if d !== nothing 35 | @htl("""""") 36 | end 37 | end) 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | $(pluto_head) 60 | 61 | 62 | 63 |
64 | 65 | 167 |
168 | $(isempty(f("title", "")) ? nothing : @htl("""
169 | $(if !isempty(f("homework_number", "")) 170 | @htl("""

Homework $(f("homework_number", ""))

""") 171 | elseif !isempty(f("chapter", "")) && !isempty(f("section", "")) 172 | @htl("""

Section $(f("chapter", "-")).$(f("section", "-"))

""") 173 | else 174 | nothing 175 | end) 176 |

$( 177 | f("title", basename(page.input.relative_path)) 178 | )

179 | 180 | $(!isempty(f("youtube_id", "")) ? @htl(""" 181 |
182 | 183 |

Lecture Video

184 |
185 | 186 |
187 |
188 | """) : nothing) 189 |
""")) 190 | $(content) 191 |
192 | 196 |
197 |
198 |
199 | 200 | 201 | -------------------------------------------------------------------------------- /src/homework/hw1.jl: -------------------------------------------------------------------------------- 1 | ### A Pluto.jl notebook ### 2 | # v0.19.25 3 | 4 | #> [frontmatter] 5 | #> homework_number = "1" 6 | #> order = "2.5" 7 | #> title = "sample homework" 8 | #> tags = ["module2", "track_julia", "track_material", "homeworks", "pluto", "PlutoTeachingTools"] 9 | #> layout = "layout.jlhtml" 10 | #> description = "sample howework" 11 | 12 | using Markdown 13 | using InteractiveUtils 14 | 15 | # ╔═╡ 75b9bee9-7d03-4c90-b828-43e9e946517b 16 | using PlutoTeachingTools, PlutoUI 17 | 18 | # ╔═╡ e022e3ce-15d1-11ee-2c26-a506ce7d9895 19 | md""" 20 | # Sample Homework 21 | 22 | This notebook showcases some of the features of [`PlutoTeachingTools.jl`](https://github.com/JuliaPluto/PlutoTeachingTools.jl) and how to use these to write homework assignment in Pluto. 23 | """ 24 | 25 | # ╔═╡ 2504b43f-f435-4dc6-8fe1-ce2df23ccfc1 26 | tip(md"""For a deeper tour of `PlutoTeachingTools.jl`, check their [documentation](https://juliapluto.github.io/PlutoTeachingTools.jl/example.html)""") 27 | 28 | # ╔═╡ 98c25807-6acd-4d79-8b6d-a335f7d8395a 29 | md""" 30 | ## Useful functionalities 31 | 32 | `PlutoTeachingTools.jl` has some functions like `correct`, `still_missing`, here a few demoes 33 | """ 34 | 35 | # ╔═╡ 4a6009fb-337e-4246-a086-a1571915bfef 36 | correct() 37 | 38 | # ╔═╡ 48090c34-8972-4ace-b9fc-d34fb609c4f9 39 | still_missing() 40 | 41 | # ╔═╡ 71f176dd-27d7-4856-be4f-23c2a8815f24 42 | keep_working() 43 | 44 | # ╔═╡ 520d73e9-0a29-4a00-9812-307e80cc061c 45 | keep_working(md"you can also give custom text to the boxes") 46 | 47 | # ╔═╡ c52bc95d-d195-48c9-92f2-fa6970387940 48 | hint(md"this is a hint, hover the box to unblur the text") 49 | 50 | # ╔═╡ f31da618-dd0c-4adb-a8ba-924a5722848c 51 | md""" 52 | ## Exercise 1: a simple exercise 53 | 54 | Replace missing with the value `1`. 55 | """ 56 | 57 | # ╔═╡ 0d208bc6-88fa-43b8-9b33-a6453ec23a71 58 | x = missing 59 | 60 | # ╔═╡ 60c02a2a-1ea6-4629-842e-a00e45673ef1 61 | if ismissing(x) 62 | still_missing() 63 | elseif x == 1 && x isa Int 64 | correct() 65 | elseif x == 1 && !(x isa Int) 66 | b1 = almost(md"""Your variable has the right value, but it's not quite the right answer. Read carefully the instructions""") 67 | b2 = hint(md"""What type should the value of x be?""") 68 | md""" 69 | $b1 70 | $b2 71 | """ 72 | else 73 | keep_working(md"""That is not the right answer! Keep trying!""") 74 | end 75 | 76 | # ╔═╡ 110bcb95-04c2-4e5c-94ef-3c402eabf235 77 | md""" 78 | here is a short demo of how it looks like when the student tries to solve the exercise 79 | """ 80 | 81 | # ╔═╡ 18014fde-b056-42f1-9dc8-f0b935a8630c 82 | Resource("https://user-images.githubusercontent.com/49938764/249749643-8cc12de3-2b50-4182-b95d-686c2c18332c.mov", :width => 500, :autoplay => "", :loop => "") 83 | 84 | # ╔═╡ 9f1cc6fd-d3ac-41a1-a761-897f421ce2f0 85 | md""" 86 | ## Exercise 2 87 | 88 | Write a function called `myfun` that takes as input an integer and returns its square. 89 | 90 | Define a variable called `y` and assign `myfun(3)` to it. 91 | """ 92 | 93 | # ╔═╡ d56b3483-c1c8-4f31-929f-3d6e2b1124f4 94 | let 95 | if !@isdefined(myfun) 96 | func_not_defined(:myfun) 97 | else 98 | test_values = [1, 2, 3, 4, 5] 99 | msg1 = correct() 100 | for t in test_values 101 | if myfun(t) != t^2 102 | msg1 = keep_working(md"Test failed for input $t, expected $(t^2), but got $(myfun(t))") 103 | break 104 | end 105 | end 106 | msg1 107 | end 108 | end 109 | 110 | # ╔═╡ 10fc3ffd-e4ec-40ab-b645-769d376794fe 111 | if !@isdefined(y) 112 | var_not_defined(:y) 113 | elseif y == 9 114 | correct() 115 | else 116 | keep_working(md"Evaluated expression y = $y is incorrect.") 117 | end 118 | 119 | # ╔═╡ 9e18fc7b-758a-4a63-8550-e04296cbea04 120 | md""" 121 | and here is a quick demo of the exercise in action 122 | """ 123 | 124 | # ╔═╡ 2fde68f8-7705-4e6f-84e4-27d720e7ab95 125 | Resource("https://user-images.githubusercontent.com/49938764/249748007-d0b2d773-6b21-49d4-89db-ad737af510fe.mov", :width => 500, :autoplay => "", :loop => "") 126 | 127 | # ╔═╡ 00000000-0000-0000-0000-000000000001 128 | PLUTO_PROJECT_TOML_CONTENTS = """ 129 | [deps] 130 | PlutoTeachingTools = "661c6b06-c737-4d37-b85c-46df65de6f69" 131 | PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 132 | 133 | [compat] 134 | PlutoTeachingTools = "~0.2.11" 135 | PlutoUI = "~0.7.51" 136 | """ 137 | 138 | # ╔═╡ 00000000-0000-0000-0000-000000000002 139 | PLUTO_MANIFEST_TOML_CONTENTS = """ 140 | # This file is machine-generated - editing it directly is not advised 141 | 142 | julia_version = "1.9.1" 143 | manifest_format = "2.0" 144 | project_hash = "525dcfd80d74b547385aa255d2a38f1acddad3f3" 145 | 146 | [[deps.AbstractPlutoDingetjes]] 147 | deps = ["Pkg"] 148 | git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" 149 | uuid = "6e696c72-6542-2067-7265-42206c756150" 150 | version = "1.1.4" 151 | 152 | [[deps.ArgTools]] 153 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 154 | version = "1.1.1" 155 | 156 | [[deps.Artifacts]] 157 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 158 | 159 | [[deps.Base64]] 160 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 161 | 162 | [[deps.CodeTracking]] 163 | deps = ["InteractiveUtils", "UUIDs"] 164 | git-tree-sha1 = "d730914ef30a06732bdd9f763f6cc32e92ffbff1" 165 | uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" 166 | version = "1.3.1" 167 | 168 | [[deps.ColorTypes]] 169 | deps = ["FixedPointNumbers", "Random"] 170 | git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" 171 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 172 | version = "0.11.4" 173 | 174 | [[deps.CompilerSupportLibraries_jll]] 175 | deps = ["Artifacts", "Libdl"] 176 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 177 | version = "1.0.2+0" 178 | 179 | [[deps.Dates]] 180 | deps = ["Printf"] 181 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 182 | 183 | [[deps.Distributed]] 184 | deps = ["Random", "Serialization", "Sockets"] 185 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 186 | 187 | [[deps.Downloads]] 188 | deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] 189 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 190 | version = "1.6.0" 191 | 192 | [[deps.FileWatching]] 193 | uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" 194 | 195 | [[deps.FixedPointNumbers]] 196 | deps = ["Statistics"] 197 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 198 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 199 | version = "0.8.4" 200 | 201 | [[deps.Formatting]] 202 | deps = ["Printf"] 203 | git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" 204 | uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" 205 | version = "0.4.2" 206 | 207 | [[deps.Hyperscript]] 208 | deps = ["Test"] 209 | git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" 210 | uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" 211 | version = "0.0.4" 212 | 213 | [[deps.HypertextLiteral]] 214 | deps = ["Tricks"] 215 | git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" 216 | uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" 217 | version = "0.9.4" 218 | 219 | [[deps.IOCapture]] 220 | deps = ["Logging", "Random"] 221 | git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" 222 | uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" 223 | version = "0.2.3" 224 | 225 | [[deps.InteractiveUtils]] 226 | deps = ["Markdown"] 227 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 228 | 229 | [[deps.JSON]] 230 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 231 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 232 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 233 | version = "0.21.4" 234 | 235 | [[deps.JuliaInterpreter]] 236 | deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] 237 | git-tree-sha1 = "6a125e6a4cb391e0b9adbd1afa9e771c2179f8ef" 238 | uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" 239 | version = "0.9.23" 240 | 241 | [[deps.LaTeXStrings]] 242 | git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" 243 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 244 | version = "1.3.0" 245 | 246 | [[deps.Latexify]] 247 | deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Printf", "Requires"] 248 | git-tree-sha1 = "8c57307b5d9bb3be1ff2da469063628631d4d51e" 249 | uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 250 | version = "0.15.21" 251 | 252 | [deps.Latexify.extensions] 253 | DataFramesExt = "DataFrames" 254 | DiffEqBiologicalExt = "DiffEqBiological" 255 | ParameterizedFunctionsExt = "DiffEqBase" 256 | SymEngineExt = "SymEngine" 257 | 258 | [deps.Latexify.weakdeps] 259 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 260 | DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" 261 | DiffEqBiological = "eb300fae-53e8-50a0-950c-e21f52c2b7e0" 262 | SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" 263 | 264 | [[deps.LibCURL]] 265 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 266 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 267 | version = "0.6.3" 268 | 269 | [[deps.LibCURL_jll]] 270 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 271 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 272 | version = "7.84.0+0" 273 | 274 | [[deps.LibGit2]] 275 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 276 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 277 | 278 | [[deps.LibSSH2_jll]] 279 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 280 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 281 | version = "1.10.2+0" 282 | 283 | [[deps.Libdl]] 284 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 285 | 286 | [[deps.LinearAlgebra]] 287 | deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] 288 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 289 | 290 | [[deps.Logging]] 291 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 292 | 293 | [[deps.LoweredCodeUtils]] 294 | deps = ["JuliaInterpreter"] 295 | git-tree-sha1 = "60168780555f3e663c536500aa790b6368adc02a" 296 | uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" 297 | version = "2.3.0" 298 | 299 | [[deps.MIMEs]] 300 | git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" 301 | uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" 302 | version = "0.1.4" 303 | 304 | [[deps.MacroTools]] 305 | deps = ["Markdown", "Random"] 306 | git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2" 307 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 308 | version = "0.5.10" 309 | 310 | [[deps.Markdown]] 311 | deps = ["Base64"] 312 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 313 | 314 | [[deps.MbedTLS_jll]] 315 | deps = ["Artifacts", "Libdl"] 316 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 317 | version = "2.28.2+0" 318 | 319 | [[deps.Mmap]] 320 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 321 | 322 | [[deps.MozillaCACerts_jll]] 323 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 324 | version = "2022.10.11" 325 | 326 | [[deps.NetworkOptions]] 327 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 328 | version = "1.2.0" 329 | 330 | [[deps.OpenBLAS_jll]] 331 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] 332 | uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" 333 | version = "0.3.21+4" 334 | 335 | [[deps.OrderedCollections]] 336 | git-tree-sha1 = "d321bf2de576bf25ec4d3e4360faca399afca282" 337 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 338 | version = "1.6.0" 339 | 340 | [[deps.Parsers]] 341 | deps = ["Dates", "PrecompileTools", "UUIDs"] 342 | git-tree-sha1 = "4b2e829ee66d4218e0cef22c0a64ee37cf258c29" 343 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 344 | version = "2.7.1" 345 | 346 | [[deps.Pkg]] 347 | deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 348 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 349 | version = "1.9.0" 350 | 351 | [[deps.PlutoHooks]] 352 | deps = ["InteractiveUtils", "Markdown", "UUIDs"] 353 | git-tree-sha1 = "072cdf20c9b0507fdd977d7d246d90030609674b" 354 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0774" 355 | version = "0.0.5" 356 | 357 | [[deps.PlutoLinks]] 358 | deps = ["FileWatching", "InteractiveUtils", "Markdown", "PlutoHooks", "Revise", "UUIDs"] 359 | git-tree-sha1 = "8f5fa7056e6dcfb23ac5211de38e6c03f6367794" 360 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0420" 361 | version = "0.1.6" 362 | 363 | [[deps.PlutoTeachingTools]] 364 | deps = ["Downloads", "HypertextLiteral", "LaTeXStrings", "Latexify", "Markdown", "PlutoLinks", "PlutoUI", "Random"] 365 | git-tree-sha1 = "88222661708df26242d0bfb9237d023557d11718" 366 | uuid = "661c6b06-c737-4d37-b85c-46df65de6f69" 367 | version = "0.2.11" 368 | 369 | [[deps.PlutoUI]] 370 | deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] 371 | git-tree-sha1 = "b478a748be27bd2f2c73a7690da219d0844db305" 372 | uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 373 | version = "0.7.51" 374 | 375 | [[deps.PrecompileTools]] 376 | deps = ["Preferences"] 377 | git-tree-sha1 = "9673d39decc5feece56ef3940e5dafba15ba0f81" 378 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 379 | version = "1.1.2" 380 | 381 | [[deps.Preferences]] 382 | deps = ["TOML"] 383 | git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" 384 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 385 | version = "1.4.0" 386 | 387 | [[deps.Printf]] 388 | deps = ["Unicode"] 389 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 390 | 391 | [[deps.REPL]] 392 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 393 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 394 | 395 | [[deps.Random]] 396 | deps = ["SHA", "Serialization"] 397 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 398 | 399 | [[deps.Reexport]] 400 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 401 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 402 | version = "1.2.2" 403 | 404 | [[deps.Requires]] 405 | deps = ["UUIDs"] 406 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 407 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 408 | version = "1.3.0" 409 | 410 | [[deps.Revise]] 411 | deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"] 412 | git-tree-sha1 = "1e597b93700fa4045d7189afa7c004e0584ea548" 413 | uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" 414 | version = "3.5.3" 415 | 416 | [[deps.SHA]] 417 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 418 | version = "0.7.0" 419 | 420 | [[deps.Serialization]] 421 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 422 | 423 | [[deps.Sockets]] 424 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 425 | 426 | [[deps.SparseArrays]] 427 | deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] 428 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 429 | 430 | [[deps.Statistics]] 431 | deps = ["LinearAlgebra", "SparseArrays"] 432 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 433 | version = "1.9.0" 434 | 435 | [[deps.SuiteSparse_jll]] 436 | deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] 437 | uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" 438 | version = "5.10.1+6" 439 | 440 | [[deps.TOML]] 441 | deps = ["Dates"] 442 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 443 | version = "1.0.3" 444 | 445 | [[deps.Tar]] 446 | deps = ["ArgTools", "SHA"] 447 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 448 | version = "1.10.0" 449 | 450 | [[deps.Test]] 451 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 452 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 453 | 454 | [[deps.Tricks]] 455 | git-tree-sha1 = "aadb748be58b492045b4f56166b5188aa63ce549" 456 | uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" 457 | version = "0.1.7" 458 | 459 | [[deps.URIs]] 460 | git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" 461 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 462 | version = "1.4.2" 463 | 464 | [[deps.UUIDs]] 465 | deps = ["Random", "SHA"] 466 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 467 | 468 | [[deps.Unicode]] 469 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 470 | 471 | [[deps.Zlib_jll]] 472 | deps = ["Libdl"] 473 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 474 | version = "1.2.13+0" 475 | 476 | [[deps.libblastrampoline_jll]] 477 | deps = ["Artifacts", "Libdl"] 478 | uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" 479 | version = "5.8.0+0" 480 | 481 | [[deps.nghttp2_jll]] 482 | deps = ["Artifacts", "Libdl"] 483 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 484 | version = "1.48.0+0" 485 | 486 | [[deps.p7zip_jll]] 487 | deps = ["Artifacts", "Libdl"] 488 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 489 | version = "17.4.0+0" 490 | """ 491 | 492 | # ╔═╡ Cell order: 493 | # ╠═75b9bee9-7d03-4c90-b828-43e9e946517b 494 | # ╟─e022e3ce-15d1-11ee-2c26-a506ce7d9895 495 | # ╟─2504b43f-f435-4dc6-8fe1-ce2df23ccfc1 496 | # ╟─98c25807-6acd-4d79-8b6d-a335f7d8395a 497 | # ╠═4a6009fb-337e-4246-a086-a1571915bfef 498 | # ╠═48090c34-8972-4ace-b9fc-d34fb609c4f9 499 | # ╠═71f176dd-27d7-4856-be4f-23c2a8815f24 500 | # ╠═520d73e9-0a29-4a00-9812-307e80cc061c 501 | # ╠═c52bc95d-d195-48c9-92f2-fa6970387940 502 | # ╟─f31da618-dd0c-4adb-a8ba-924a5722848c 503 | # ╠═0d208bc6-88fa-43b8-9b33-a6453ec23a71 504 | # ╠═60c02a2a-1ea6-4629-842e-a00e45673ef1 505 | # ╟─110bcb95-04c2-4e5c-94ef-3c402eabf235 506 | # ╟─18014fde-b056-42f1-9dc8-f0b935a8630c 507 | # ╟─9f1cc6fd-d3ac-41a1-a761-897f421ce2f0 508 | # ╠═d56b3483-c1c8-4f31-929f-3d6e2b1124f4 509 | # ╠═10fc3ffd-e4ec-40ab-b645-769d376794fe 510 | # ╟─9e18fc7b-758a-4a63-8550-e04296cbea04 511 | # ╟─2fde68f8-7705-4e6f-84e4-27d720e7ab95 512 | # ╟─00000000-0000-0000-0000-000000000001 513 | # ╟─00000000-0000-0000-0000-000000000002 514 | -------------------------------------------------------------------------------- /src/mod2_add_material/add_pluto.jl: -------------------------------------------------------------------------------- 1 | ### A Pluto.jl notebook ### 2 | # v0.19.25 3 | 4 | #> [frontmatter] 5 | #> chapter = 2 6 | #> section = 2 7 | #> order = 2 8 | #> image = "https://raw.githubusercontent.com/fonsp/Pluto.jl/580ab811f13d565cc81ebfa70ed36c84b125f55d/demo/plutodemo.gif" 9 | #> title = "Add Pluto notebooks" 10 | #> tags = ["module2", "track_julia", "track_material", "Pluto", "PlutoUI"] 11 | #> layout = "layout.jlhtml" 12 | 13 | using Markdown 14 | using InteractiveUtils 15 | 16 | # ╔═╡ 055ef0df-8ab8-4e54-a476-89d521f29ee0 17 | using PlutoTeachingTools, PlutoUI 18 | 19 | # ╔═╡ 4f643fd4-1e8d-4304-961b-a30a37a58de3 20 | TableOfContents() 21 | 22 | # ╔═╡ acdd466e-14f5-11ee-1921-93e6c67d7ec4 23 | md""" 24 | ## Add Pluto notebooks 25 | 26 | [Pluto.jl](https://plutojl.org/) is a revolutionary text-editor for reactive and interactive programming. 27 | 28 | To start creating a Pluto notebook, open a terminal and launch Julia, then do 29 | 30 | ```julia 31 | using Pluto; Pluto.run() 32 | ``` 33 | 34 | This will launch a Pluto session, where you can write your notebook. 35 | 36 | To add the front-matter, you can use Plut FrontmatterGUI, as the following short video clip shows. 37 | 38 | $(danger(md"For pluto notebooks, you will need to set layout to layout.jlhtml")) 39 | """ 40 | 41 | # ╔═╡ 832a1b2f-42dc-4a5d-9389-9f8f35a1759b 42 | html""" 43 | """ 46 | 47 | # ╔═╡ 8656f15c-a603-45f6-8ac6-4941580830e8 48 | md"""## Pluto 101 49 | 50 | Pluto is a notebook for Julia! It is **reactive**, **lightweight** and has **powerful interactivity tools**. This will allow you to make your lesson material more engaging for students. Here are a few highlights of Pluto. 51 | 52 | $(tip(md" To learn more, check out [Pluto featured notebooks](https://featured.plutojl.org/), the JuliaCon video at the beginning of this notebook, or the presentations at [PlutoCon 2021](https://www.youtube.com/playlist?list=PLP8iPy9hna6T5sNOTeGdiqygHe_09geEW).")) 53 | ### Writing code in Pluto 54 | 55 | In Pluto code is written in cells, to add some code, simply create a new cell and type in. Each cell should contain 1 julia expression (function definition, if-statement, variable assignment, etc.). 56 | 57 | ```julia 58 | if rand() > 0.5 59 | "hi" 60 | else 61 | "there" 62 | end 63 | ``` 64 | 65 | or 66 | 67 | ```julia 68 | a = 1 69 | ``` 70 | 71 | or 72 | 73 | ```julia 74 | function f() 75 | return rand() ^ 2 76 | end 77 | ``` 78 | 79 | **However**, multiple expressions in the same cell are not allowed, for example 80 | 81 | ```julia 82 | a = 1 83 | b = 2 84 | a + b 85 | ``` 86 | 87 | cannot be written in the same cell. You have two alternatives 88 | 89 | 1. Split it into multiple cells (recommended to make reactivity better). 90 | 2. Wrap your staments inside a `begin ... end` or `let ... end` block. The difference is that the latter introduces a local scope, hence variables defined inside `let` are not visibles from outside. 91 | 92 | ### Reactivity 93 | 94 | Pluto is reactive! This means that if you define a variable `a` in a cell, when you edit the variable value, all cells depending on that variable are automatically re-evaluated. A few notes 95 | 96 | 1. As mentioned above, better to have a single variable assignment per cell, this will make the dependency graph slimmer and reactivity smoother. 97 | 2. Code modifying a given variable should be in the same cell, i.e. you cannot have two cells modifying the same variable. 98 | 99 | Here is a summarizing demo 100 | 101 | """ 102 | 103 | # ╔═╡ ba9f13cc-bf18-4589-9e89-3d5c869e158f 104 | Resource("https://raw.githubusercontent.com/fonsp/Pluto.jl/580ab811f13d565cc81ebfa70ed36c84b125f55d/demo/plutodemo.gif", :width => 350) 105 | 106 | # ╔═╡ d97ae81e-fd53-4b0a-a990-abf173b0c1ab 107 | md""" 108 | ### Built-in environment 109 | 110 | Pluto is designed with reproducibility in mind! 111 | 112 | To use packages registered in the Julia general registry, just type `using MyPackage` in some cells, as done at the beginning of this notebook. Pluto will automatically download the package! 113 | 114 | The `Project.toml` and `Manifest.toml` (what Julia uses to record all libraries, their versions and dependencies) are stored inside the notebook, making it fully batteries included! 115 | 116 | $(Resource("https://user-images.githubusercontent.com/6933510/134823403-fbb79d7f-dd3e-4712-b5d5-b48ad0770f13.gif", :width => 400)) 117 | """ 118 | 119 | # ╔═╡ 177b8901-68ad-4319-b4fa-28fb30f3a731 120 | md""" 121 | ### Interactivity 122 | 123 | Pluto has great support to make your notebooks interactive! It allows you to associate variables with sliders and buttons that you can use to interactively change the result of the code. 124 | 125 | ![](https://user-images.githubusercontent.com/6933510/136196607-16207911-53be-4abb-b90e-d46c946e6aaf.gif) 126 | 127 | 128 | The easiest way to harness the power of Pluto interactivity is to use [PlutoUI.jl](https://github.com/juliapluto/PlutoUI.jl), which is showcased in the [next lecture](https://juliapluto.github.io/mod2_add_material/plutoui_showcase/). 129 | """ 130 | 131 | # ╔═╡ 00000000-0000-0000-0000-000000000001 132 | PLUTO_PROJECT_TOML_CONTENTS = """ 133 | [deps] 134 | PlutoTeachingTools = "661c6b06-c737-4d37-b85c-46df65de6f69" 135 | PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 136 | 137 | [compat] 138 | PlutoTeachingTools = "~0.2.11" 139 | PlutoUI = "~0.7.51" 140 | """ 141 | 142 | # ╔═╡ 00000000-0000-0000-0000-000000000002 143 | PLUTO_MANIFEST_TOML_CONTENTS = """ 144 | # This file is machine-generated - editing it directly is not advised 145 | 146 | julia_version = "1.9.1" 147 | manifest_format = "2.0" 148 | project_hash = "525dcfd80d74b547385aa255d2a38f1acddad3f3" 149 | 150 | [[deps.AbstractPlutoDingetjes]] 151 | deps = ["Pkg"] 152 | git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" 153 | uuid = "6e696c72-6542-2067-7265-42206c756150" 154 | version = "1.1.4" 155 | 156 | [[deps.ArgTools]] 157 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 158 | version = "1.1.1" 159 | 160 | [[deps.Artifacts]] 161 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 162 | 163 | [[deps.Base64]] 164 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 165 | 166 | [[deps.CodeTracking]] 167 | deps = ["InteractiveUtils", "UUIDs"] 168 | git-tree-sha1 = "d730914ef30a06732bdd9f763f6cc32e92ffbff1" 169 | uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" 170 | version = "1.3.1" 171 | 172 | [[deps.ColorTypes]] 173 | deps = ["FixedPointNumbers", "Random"] 174 | git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" 175 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 176 | version = "0.11.4" 177 | 178 | [[deps.CompilerSupportLibraries_jll]] 179 | deps = ["Artifacts", "Libdl"] 180 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 181 | version = "1.0.2+0" 182 | 183 | [[deps.Dates]] 184 | deps = ["Printf"] 185 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 186 | 187 | [[deps.Distributed]] 188 | deps = ["Random", "Serialization", "Sockets"] 189 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 190 | 191 | [[deps.Downloads]] 192 | deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] 193 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 194 | version = "1.6.0" 195 | 196 | [[deps.FileWatching]] 197 | uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" 198 | 199 | [[deps.FixedPointNumbers]] 200 | deps = ["Statistics"] 201 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 202 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 203 | version = "0.8.4" 204 | 205 | [[deps.Formatting]] 206 | deps = ["Printf"] 207 | git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" 208 | uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" 209 | version = "0.4.2" 210 | 211 | [[deps.Hyperscript]] 212 | deps = ["Test"] 213 | git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" 214 | uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" 215 | version = "0.0.4" 216 | 217 | [[deps.HypertextLiteral]] 218 | deps = ["Tricks"] 219 | git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" 220 | uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" 221 | version = "0.9.4" 222 | 223 | [[deps.IOCapture]] 224 | deps = ["Logging", "Random"] 225 | git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" 226 | uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" 227 | version = "0.2.3" 228 | 229 | [[deps.InteractiveUtils]] 230 | deps = ["Markdown"] 231 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 232 | 233 | [[deps.JSON]] 234 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 235 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 236 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 237 | version = "0.21.4" 238 | 239 | [[deps.JuliaInterpreter]] 240 | deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] 241 | git-tree-sha1 = "6a125e6a4cb391e0b9adbd1afa9e771c2179f8ef" 242 | uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" 243 | version = "0.9.23" 244 | 245 | [[deps.LaTeXStrings]] 246 | git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" 247 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 248 | version = "1.3.0" 249 | 250 | [[deps.Latexify]] 251 | deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Printf", "Requires"] 252 | git-tree-sha1 = "8c57307b5d9bb3be1ff2da469063628631d4d51e" 253 | uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 254 | version = "0.15.21" 255 | 256 | [deps.Latexify.extensions] 257 | DataFramesExt = "DataFrames" 258 | DiffEqBiologicalExt = "DiffEqBiological" 259 | ParameterizedFunctionsExt = "DiffEqBase" 260 | SymEngineExt = "SymEngine" 261 | 262 | [deps.Latexify.weakdeps] 263 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 264 | DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" 265 | DiffEqBiological = "eb300fae-53e8-50a0-950c-e21f52c2b7e0" 266 | SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" 267 | 268 | [[deps.LibCURL]] 269 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 270 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 271 | version = "0.6.3" 272 | 273 | [[deps.LibCURL_jll]] 274 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 275 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 276 | version = "7.84.0+0" 277 | 278 | [[deps.LibGit2]] 279 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 280 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 281 | 282 | [[deps.LibSSH2_jll]] 283 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 284 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 285 | version = "1.10.2+0" 286 | 287 | [[deps.Libdl]] 288 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 289 | 290 | [[deps.LinearAlgebra]] 291 | deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] 292 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 293 | 294 | [[deps.Logging]] 295 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 296 | 297 | [[deps.LoweredCodeUtils]] 298 | deps = ["JuliaInterpreter"] 299 | git-tree-sha1 = "60168780555f3e663c536500aa790b6368adc02a" 300 | uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" 301 | version = "2.3.0" 302 | 303 | [[deps.MIMEs]] 304 | git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" 305 | uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" 306 | version = "0.1.4" 307 | 308 | [[deps.MacroTools]] 309 | deps = ["Markdown", "Random"] 310 | git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2" 311 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 312 | version = "0.5.10" 313 | 314 | [[deps.Markdown]] 315 | deps = ["Base64"] 316 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 317 | 318 | [[deps.MbedTLS_jll]] 319 | deps = ["Artifacts", "Libdl"] 320 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 321 | version = "2.28.2+0" 322 | 323 | [[deps.Mmap]] 324 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 325 | 326 | [[deps.MozillaCACerts_jll]] 327 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 328 | version = "2022.10.11" 329 | 330 | [[deps.NetworkOptions]] 331 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 332 | version = "1.2.0" 333 | 334 | [[deps.OpenBLAS_jll]] 335 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] 336 | uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" 337 | version = "0.3.21+4" 338 | 339 | [[deps.OrderedCollections]] 340 | git-tree-sha1 = "d321bf2de576bf25ec4d3e4360faca399afca282" 341 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 342 | version = "1.6.0" 343 | 344 | [[deps.Parsers]] 345 | deps = ["Dates", "PrecompileTools", "UUIDs"] 346 | git-tree-sha1 = "4b2e829ee66d4218e0cef22c0a64ee37cf258c29" 347 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 348 | version = "2.7.1" 349 | 350 | [[deps.Pkg]] 351 | deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 352 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 353 | version = "1.9.0" 354 | 355 | [[deps.PlutoHooks]] 356 | deps = ["InteractiveUtils", "Markdown", "UUIDs"] 357 | git-tree-sha1 = "072cdf20c9b0507fdd977d7d246d90030609674b" 358 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0774" 359 | version = "0.0.5" 360 | 361 | [[deps.PlutoLinks]] 362 | deps = ["FileWatching", "InteractiveUtils", "Markdown", "PlutoHooks", "Revise", "UUIDs"] 363 | git-tree-sha1 = "8f5fa7056e6dcfb23ac5211de38e6c03f6367794" 364 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0420" 365 | version = "0.1.6" 366 | 367 | [[deps.PlutoTeachingTools]] 368 | deps = ["Downloads", "HypertextLiteral", "LaTeXStrings", "Latexify", "Markdown", "PlutoLinks", "PlutoUI", "Random"] 369 | git-tree-sha1 = "88222661708df26242d0bfb9237d023557d11718" 370 | uuid = "661c6b06-c737-4d37-b85c-46df65de6f69" 371 | version = "0.2.11" 372 | 373 | [[deps.PlutoUI]] 374 | deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] 375 | git-tree-sha1 = "b478a748be27bd2f2c73a7690da219d0844db305" 376 | uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 377 | version = "0.7.51" 378 | 379 | [[deps.PrecompileTools]] 380 | deps = ["Preferences"] 381 | git-tree-sha1 = "9673d39decc5feece56ef3940e5dafba15ba0f81" 382 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 383 | version = "1.1.2" 384 | 385 | [[deps.Preferences]] 386 | deps = ["TOML"] 387 | git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" 388 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 389 | version = "1.4.0" 390 | 391 | [[deps.Printf]] 392 | deps = ["Unicode"] 393 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 394 | 395 | [[deps.REPL]] 396 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 397 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 398 | 399 | [[deps.Random]] 400 | deps = ["SHA", "Serialization"] 401 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 402 | 403 | [[deps.Reexport]] 404 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 405 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 406 | version = "1.2.2" 407 | 408 | [[deps.Requires]] 409 | deps = ["UUIDs"] 410 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 411 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 412 | version = "1.3.0" 413 | 414 | [[deps.Revise]] 415 | deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"] 416 | git-tree-sha1 = "1e597b93700fa4045d7189afa7c004e0584ea548" 417 | uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" 418 | version = "3.5.3" 419 | 420 | [[deps.SHA]] 421 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 422 | version = "0.7.0" 423 | 424 | [[deps.Serialization]] 425 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 426 | 427 | [[deps.Sockets]] 428 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 429 | 430 | [[deps.SparseArrays]] 431 | deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] 432 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 433 | 434 | [[deps.Statistics]] 435 | deps = ["LinearAlgebra", "SparseArrays"] 436 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 437 | version = "1.9.0" 438 | 439 | [[deps.SuiteSparse_jll]] 440 | deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] 441 | uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" 442 | version = "5.10.1+6" 443 | 444 | [[deps.TOML]] 445 | deps = ["Dates"] 446 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 447 | version = "1.0.3" 448 | 449 | [[deps.Tar]] 450 | deps = ["ArgTools", "SHA"] 451 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 452 | version = "1.10.0" 453 | 454 | [[deps.Test]] 455 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 456 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 457 | 458 | [[deps.Tricks]] 459 | git-tree-sha1 = "aadb748be58b492045b4f56166b5188aa63ce549" 460 | uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" 461 | version = "0.1.7" 462 | 463 | [[deps.URIs]] 464 | git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" 465 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 466 | version = "1.4.2" 467 | 468 | [[deps.UUIDs]] 469 | deps = ["Random", "SHA"] 470 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 471 | 472 | [[deps.Unicode]] 473 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 474 | 475 | [[deps.Zlib_jll]] 476 | deps = ["Libdl"] 477 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 478 | version = "1.2.13+0" 479 | 480 | [[deps.libblastrampoline_jll]] 481 | deps = ["Artifacts", "Libdl"] 482 | uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" 483 | version = "5.8.0+0" 484 | 485 | [[deps.nghttp2_jll]] 486 | deps = ["Artifacts", "Libdl"] 487 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 488 | version = "1.48.0+0" 489 | 490 | [[deps.p7zip_jll]] 491 | deps = ["Artifacts", "Libdl"] 492 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 493 | version = "17.4.0+0" 494 | """ 495 | 496 | # ╔═╡ Cell order: 497 | # ╠═055ef0df-8ab8-4e54-a476-89d521f29ee0 498 | # ╠═4f643fd4-1e8d-4304-961b-a30a37a58de3 499 | # ╟─acdd466e-14f5-11ee-1921-93e6c67d7ec4 500 | # ╟─832a1b2f-42dc-4a5d-9389-9f8f35a1759b 501 | # ╟─8656f15c-a603-45f6-8ac6-4941580830e8 502 | # ╟─ba9f13cc-bf18-4589-9e89-3d5c869e158f 503 | # ╟─d97ae81e-fd53-4b0a-a990-abf173b0c1ab 504 | # ╟─177b8901-68ad-4319-b4fa-28fb30f3a731 505 | # ╟─00000000-0000-0000-0000-000000000001 506 | # ╟─00000000-0000-0000-0000-000000000002 507 | -------------------------------------------------------------------------------- /pluto-deployment-environment/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.8.5" 4 | manifest_format = "2.0" 5 | project_hash = "1897773a8065215ef94f8d665d12f3684212efac" 6 | 7 | [[deps.AbstractPlutoDingetjes]] 8 | deps = ["Pkg"] 9 | git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481" 10 | uuid = "6e696c72-6542-2067-7265-42206c756150" 11 | version = "1.1.4" 12 | 13 | [[deps.AbstractTrees]] 14 | git-tree-sha1 = "faa260e4cb5aba097a73fab382dd4b5819d8ec8c" 15 | uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" 16 | version = "0.4.4" 17 | 18 | [[deps.Adapt]] 19 | deps = ["LinearAlgebra", "Requires"] 20 | git-tree-sha1 = "76289dc51920fdc6e0013c872ba9551d54961c24" 21 | uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" 22 | version = "3.6.2" 23 | 24 | [[deps.ArgCheck]] 25 | git-tree-sha1 = "a3a402a35a2f7e0b87828ccabbd5ebfbebe356b4" 26 | uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" 27 | version = "2.3.0" 28 | 29 | [[deps.ArgTools]] 30 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 31 | version = "1.1.1" 32 | 33 | [[deps.Artifacts]] 34 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 35 | 36 | [[deps.BangBang]] 37 | deps = ["Compat", "ConstructionBase", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables"] 38 | git-tree-sha1 = "e28912ce94077686443433c2800104b061a827ed" 39 | uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" 40 | version = "0.3.39" 41 | 42 | [[deps.Base64]] 43 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 44 | 45 | [[deps.Baselet]] 46 | git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e" 47 | uuid = "9718e550-a3fa-408a-8086-8db961cd8217" 48 | version = "0.1.1" 49 | 50 | [[deps.BetterFileWatching]] 51 | deps = ["Deno_jll", "JSON"] 52 | git-tree-sha1 = "0d7ee0a1acad90d544fa87cc3d6f463e99abb77a" 53 | uuid = "c9fd44ac-77b5-486c-9482-9798bd063cc6" 54 | version = "0.1.5" 55 | 56 | [[deps.BitFlags]] 57 | git-tree-sha1 = "43b1a4a8f797c1cddadf60499a8a077d4af2cd2d" 58 | uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" 59 | version = "0.1.7" 60 | 61 | [[deps.CodeTracking]] 62 | deps = ["InteractiveUtils", "UUIDs"] 63 | git-tree-sha1 = "d730914ef30a06732bdd9f763f6cc32e92ffbff1" 64 | uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" 65 | version = "1.3.1" 66 | 67 | [[deps.CodecZlib]] 68 | deps = ["TranscodingStreams", "Zlib_jll"] 69 | git-tree-sha1 = "9c209fb7536406834aa938fb149964b985de6c83" 70 | uuid = "944b1d66-785c-5afd-91f1-9de20f533193" 71 | version = "0.7.1" 72 | 73 | [[deps.ColorTypes]] 74 | deps = ["FixedPointNumbers", "Random"] 75 | git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" 76 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 77 | version = "0.11.4" 78 | 79 | [[deps.CommonMark]] 80 | deps = ["Crayons", "JSON", "PrecompileTools", "URIs"] 81 | git-tree-sha1 = "532c4185d3c9037c0237546d817858b23cf9e071" 82 | uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" 83 | version = "0.8.12" 84 | 85 | [[deps.Compat]] 86 | deps = ["Dates", "LinearAlgebra", "UUIDs"] 87 | git-tree-sha1 = "7a60c856b9fa189eb34f5f8a6f6b5529b7942957" 88 | uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" 89 | version = "4.6.1" 90 | 91 | [[deps.CompilerSupportLibraries_jll]] 92 | deps = ["Artifacts", "Libdl"] 93 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 94 | version = "1.0.1+0" 95 | 96 | [[deps.CompositionsBase]] 97 | git-tree-sha1 = "802bb88cd69dfd1509f6670416bd4434015693ad" 98 | uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b" 99 | version = "0.1.2" 100 | 101 | [[deps.ConcurrentUtilities]] 102 | deps = ["Serialization", "Sockets"] 103 | git-tree-sha1 = "96d823b94ba8d187a6d8f0826e731195a74b90e9" 104 | uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" 105 | version = "2.2.0" 106 | 107 | [[deps.Configurations]] 108 | deps = ["ExproniconLite", "OrderedCollections", "TOML"] 109 | git-tree-sha1 = "62a7c76dbad02fdfdaa53608104edf760938c4ca" 110 | uuid = "5218b696-f38b-4ac9-8b61-a12ec717816d" 111 | version = "0.17.4" 112 | 113 | [[deps.ConstructionBase]] 114 | deps = ["LinearAlgebra"] 115 | git-tree-sha1 = "738fec4d684a9a6ee9598a8bfee305b26831f28c" 116 | uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" 117 | version = "1.5.2" 118 | 119 | [[deps.Crayons]] 120 | git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" 121 | uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" 122 | version = "4.1.1" 123 | 124 | [[deps.DataAPI]] 125 | git-tree-sha1 = "8da84edb865b0b5b0100c0666a9bc9a0b71c553c" 126 | uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" 127 | version = "1.15.0" 128 | 129 | [[deps.DataValueInterfaces]] 130 | git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" 131 | uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" 132 | version = "1.0.0" 133 | 134 | [[deps.Dates]] 135 | deps = ["Printf"] 136 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 137 | 138 | [[deps.DefineSingletons]] 139 | git-tree-sha1 = "0fba8b706d0178b4dc7fd44a96a92382c9065c2c" 140 | uuid = "244e2a9f-e319-4986-a169-4d1fe445cd52" 141 | version = "0.1.2" 142 | 143 | [[deps.Deno_jll]] 144 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 145 | git-tree-sha1 = "cd6756e833c377e0ce9cd63fb97689a255f12323" 146 | uuid = "04572ae6-984a-583e-9378-9577a1c2574d" 147 | version = "1.33.4+0" 148 | 149 | [[deps.Distributed]] 150 | deps = ["Random", "Serialization", "Sockets"] 151 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 152 | 153 | [[deps.Downloads]] 154 | deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] 155 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 156 | version = "1.6.0" 157 | 158 | [[deps.Expat_jll]] 159 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 160 | git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" 161 | uuid = "2e619515-83b5-522b-bb60-26c02a35a201" 162 | version = "2.4.8+0" 163 | 164 | [[deps.ExproniconLite]] 165 | deps = ["Pkg", "TOML"] 166 | git-tree-sha1 = "c2eb763acf6e13e75595e0737a07a0bec0ce2147" 167 | uuid = "55351af7-c7e9-48d6-89ff-24e801d99491" 168 | version = "0.7.11" 169 | 170 | [[deps.FileWatching]] 171 | uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" 172 | 173 | [[deps.FixedPointNumbers]] 174 | deps = ["Statistics"] 175 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 176 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 177 | version = "0.8.4" 178 | 179 | [[deps.FromFile]] 180 | deps = ["Downloads", "Requires"] 181 | git-tree-sha1 = "5df4ca248bed8c35164d6a7ae006073bbf8289ff" 182 | uuid = "ff7dd447-1dcb-4ce3-b8ac-22a812192de7" 183 | version = "0.1.5" 184 | 185 | [[deps.Future]] 186 | deps = ["Random"] 187 | uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" 188 | 189 | [[deps.FuzzyCompletions]] 190 | deps = ["REPL"] 191 | git-tree-sha1 = "e16dd964b4dfaebcded16b2af32f05e235b354be" 192 | uuid = "fb4132e2-a121-4a70-b8a1-d5b831dcdcc2" 193 | version = "0.5.1" 194 | 195 | [[deps.Git]] 196 | deps = ["Git_jll"] 197 | git-tree-sha1 = "51764e6c2e84c37055e846c516e9015b4a291c7d" 198 | uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" 199 | version = "1.3.0" 200 | 201 | [[deps.GitHubActions]] 202 | deps = ["JSON", "Logging"] 203 | git-tree-sha1 = "56e01ec63d13e1cf015d9ff586156eae3cc7cd6f" 204 | uuid = "6b79fd1a-b13a-48ab-b6b0-aaee1fee41df" 205 | version = "0.1.4" 206 | 207 | [[deps.Git_jll]] 208 | deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] 209 | git-tree-sha1 = "d8be4aab0f4e043cc40984e9097417307cce4c03" 210 | uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" 211 | version = "2.36.1+2" 212 | 213 | [[deps.Glob]] 214 | git-tree-sha1 = "97285bbd5230dd766e9ef6749b80fc617126d496" 215 | uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" 216 | version = "1.3.1" 217 | 218 | [[deps.Gumbo]] 219 | deps = ["AbstractTrees", "Gumbo_jll", "Libdl"] 220 | git-tree-sha1 = "a1a138dfbf9df5bace489c7a9d5196d6afdfa140" 221 | uuid = "708ec375-b3d6-5a57-a7ce-8257bf98657a" 222 | version = "0.8.2" 223 | 224 | [[deps.Gumbo_jll]] 225 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 226 | git-tree-sha1 = "29070dee9df18d9565276d68a596854b1764aa38" 227 | uuid = "528830af-5a63-567c-a44a-034ed33b8444" 228 | version = "0.10.2+0" 229 | 230 | [[deps.HTTP]] 231 | deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] 232 | git-tree-sha1 = "5e77dbf117412d4f164a464d610ee6050cc75272" 233 | uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" 234 | version = "1.9.6" 235 | 236 | [[deps.Hyperscript]] 237 | deps = ["Test"] 238 | git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9" 239 | uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" 240 | version = "0.0.4" 241 | 242 | [[deps.HypertextLiteral]] 243 | deps = ["Tricks"] 244 | git-tree-sha1 = "c47c5fa4c5308f27ccaac35504858d8914e102f9" 245 | uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" 246 | version = "0.9.4" 247 | 248 | [[deps.IOCapture]] 249 | deps = ["Logging", "Random"] 250 | git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" 251 | uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" 252 | version = "0.2.3" 253 | 254 | [[deps.InitialValues]] 255 | git-tree-sha1 = "4da0f88e9a39111c2fa3add390ab15f3a44f3ca3" 256 | uuid = "22cec73e-a1b8-11e9-2c92-598750a2cf9c" 257 | version = "0.3.1" 258 | 259 | [[deps.InteractiveUtils]] 260 | deps = ["Markdown"] 261 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 262 | 263 | [[deps.IteratorInterfaceExtensions]] 264 | git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" 265 | uuid = "82899510-4779-5014-852e-03e436cf321d" 266 | version = "1.0.0" 267 | 268 | [[deps.JLLWrappers]] 269 | deps = ["Preferences"] 270 | git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" 271 | uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" 272 | version = "1.4.1" 273 | 274 | [[deps.JSON]] 275 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 276 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 277 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 278 | version = "0.21.4" 279 | 280 | [[deps.JuliaInterpreter]] 281 | deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] 282 | git-tree-sha1 = "6a125e6a4cb391e0b9adbd1afa9e771c2179f8ef" 283 | uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" 284 | version = "0.9.23" 285 | 286 | [[deps.LRUCache]] 287 | git-tree-sha1 = "48c10e3cc27e30de82463c27bef0b8bdbd1dc634" 288 | uuid = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" 289 | version = "1.4.1" 290 | 291 | [[deps.LazilyInitializedFields]] 292 | git-tree-sha1 = "410fe4739a4b092f2ffe36fcb0dcc3ab12648ce1" 293 | uuid = "0e77f7df-68c5-4e49-93ce-4cd80f5598bf" 294 | version = "1.2.1" 295 | 296 | [[deps.LeftChildRightSiblingTrees]] 297 | deps = ["AbstractTrees"] 298 | git-tree-sha1 = "fb6803dafae4a5d62ea5cab204b1e657d9737e7f" 299 | uuid = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" 300 | version = "0.2.0" 301 | 302 | [[deps.LibCURL]] 303 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 304 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 305 | version = "0.6.3" 306 | 307 | [[deps.LibCURL_jll]] 308 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 309 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 310 | version = "7.84.0+0" 311 | 312 | [[deps.LibGit2]] 313 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 314 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 315 | 316 | [[deps.LibSSH2_jll]] 317 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 318 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 319 | version = "1.10.2+0" 320 | 321 | [[deps.Libdl]] 322 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 323 | 324 | [[deps.Libiconv_jll]] 325 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 326 | git-tree-sha1 = "c7cb1f5d892775ba13767a87c7ada0b980ea0a71" 327 | uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" 328 | version = "1.16.1+2" 329 | 330 | [[deps.LinearAlgebra]] 331 | deps = ["Libdl", "libblastrampoline_jll"] 332 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 333 | 334 | [[deps.Logging]] 335 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 336 | 337 | [[deps.LoggingExtras]] 338 | deps = ["Dates", "Logging"] 339 | git-tree-sha1 = "cedb76b37bc5a6c702ade66be44f831fa23c681e" 340 | uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" 341 | version = "1.0.0" 342 | 343 | [[deps.LoweredCodeUtils]] 344 | deps = ["JuliaInterpreter"] 345 | git-tree-sha1 = "60168780555f3e663c536500aa790b6368adc02a" 346 | uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" 347 | version = "2.3.0" 348 | 349 | [[deps.MIMEs]] 350 | git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" 351 | uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" 352 | version = "0.1.4" 353 | 354 | [[deps.MacroTools]] 355 | deps = ["Markdown", "Random"] 356 | git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2" 357 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 358 | version = "0.5.10" 359 | 360 | [[deps.Markdown]] 361 | deps = ["Base64"] 362 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 363 | 364 | [[deps.MarkdownLiteral]] 365 | deps = ["CommonMark", "HypertextLiteral"] 366 | git-tree-sha1 = "0d3fa2dd374934b62ee16a4721fe68c418b92899" 367 | uuid = "736d6165-7244-6769-4267-6b50796e6954" 368 | version = "0.1.1" 369 | 370 | [[deps.MbedTLS]] 371 | deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "Random", "Sockets"] 372 | git-tree-sha1 = "03a9b9718f5682ecb107ac9f7308991db4ce395b" 373 | uuid = "739be429-bea8-5141-9913-cc70e7f3736d" 374 | version = "1.1.7" 375 | 376 | [[deps.MbedTLS_jll]] 377 | deps = ["Artifacts", "Libdl"] 378 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 379 | version = "2.28.0+0" 380 | 381 | [[deps.Memoize]] 382 | deps = ["MacroTools"] 383 | git-tree-sha1 = "2b1dfcba103de714d31c033b5dacc2e4a12c7caa" 384 | uuid = "c03570c3-d221-55d1-a50c-7939bbd78826" 385 | version = "0.4.4" 386 | 387 | [[deps.MicroCollections]] 388 | deps = ["BangBang", "InitialValues", "Setfield"] 389 | git-tree-sha1 = "629afd7d10dbc6935ec59b32daeb33bc4460a42e" 390 | uuid = "128add7d-3638-4c79-886c-908ea0c25c34" 391 | version = "0.1.4" 392 | 393 | [[deps.Mmap]] 394 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 395 | 396 | [[deps.MozillaCACerts_jll]] 397 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 398 | version = "2022.2.1" 399 | 400 | [[deps.MsgPack]] 401 | deps = ["Serialization"] 402 | git-tree-sha1 = "fc8c15ca848b902015bd4a745d350f02cf791c2a" 403 | uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671" 404 | version = "1.2.0" 405 | 406 | [[deps.NetworkOptions]] 407 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 408 | version = "1.2.0" 409 | 410 | [[deps.OpenBLAS_jll]] 411 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] 412 | uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" 413 | version = "0.3.20+0" 414 | 415 | [[deps.OpenSSL]] 416 | deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] 417 | git-tree-sha1 = "51901a49222b09e3743c65b8847687ae5fc78eb2" 418 | uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" 419 | version = "1.4.1" 420 | 421 | [[deps.OpenSSL_jll]] 422 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 423 | git-tree-sha1 = "1aa4b74f80b01c6bc2b89992b861b5f210e665b5" 424 | uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" 425 | version = "1.1.21+0" 426 | 427 | [[deps.OrderedCollections]] 428 | git-tree-sha1 = "d321bf2de576bf25ec4d3e4360faca399afca282" 429 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 430 | version = "1.6.0" 431 | 432 | [[deps.PCRE2_jll]] 433 | deps = ["Artifacts", "Libdl"] 434 | uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" 435 | version = "10.40.0+0" 436 | 437 | [[deps.Parsers]] 438 | deps = ["Dates", "PrecompileTools", "UUIDs"] 439 | git-tree-sha1 = "a5aef8d4a6e8d81f171b2bd4be5265b01384c74c" 440 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 441 | version = "2.5.10" 442 | 443 | [[deps.Pkg]] 444 | deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 445 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 446 | version = "1.8.0" 447 | 448 | [[deps.Pluto]] 449 | deps = ["Base64", "Configurations", "Dates", "Distributed", "FileWatching", "FuzzyCompletions", "HTTP", "HypertextLiteral", "InteractiveUtils", "Logging", "LoggingExtras", "MIMEs", "Markdown", "MsgPack", "Pkg", "PrecompileSignatures", "REPL", "RegistryInstances", "RelocatableFolders", "SnoopPrecompile", "Sockets", "TOML", "Tables", "URIs", "UUIDs"] 450 | git-tree-sha1 = "c3127195e4d10d9de5aa7364b5924ae062dcad35" 451 | uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" 452 | version = "0.19.25" 453 | 454 | [[deps.PlutoHooks]] 455 | deps = ["InteractiveUtils", "Markdown", "UUIDs"] 456 | git-tree-sha1 = "072cdf20c9b0507fdd977d7d246d90030609674b" 457 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0774" 458 | version = "0.0.5" 459 | 460 | [[deps.PlutoLinks]] 461 | deps = ["FileWatching", "InteractiveUtils", "Markdown", "PlutoHooks", "Revise", "UUIDs"] 462 | git-tree-sha1 = "8f5fa7056e6dcfb23ac5211de38e6c03f6367794" 463 | uuid = "0ff47ea0-7a50-410d-8455-4348d5de0420" 464 | version = "0.1.6" 465 | 466 | [[deps.PlutoSliderServer]] 467 | deps = ["AbstractPlutoDingetjes", "Base64", "BetterFileWatching", "Configurations", "Distributed", "FromFile", "Git", "GitHubActions", "Glob", "HTTP", "JSON", "Logging", "Pkg", "Pluto", "SHA", "Sockets", "TOML", "TerminalLoggers", "UUIDs"] 468 | git-tree-sha1 = "2bca19d5d90959f6ffda8ec4bcfaa25ebf09b6b7" 469 | uuid = "2fc8631c-6f24-4c5b-bca7-cbb509c42db4" 470 | version = "0.3.25" 471 | 472 | [[deps.PlutoUI]] 473 | deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] 474 | git-tree-sha1 = "b478a748be27bd2f2c73a7690da219d0844db305" 475 | uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" 476 | version = "0.7.51" 477 | 478 | [[deps.PrecompileSignatures]] 479 | git-tree-sha1 = "18ef344185f25ee9d51d80e179f8dad33dc48eb1" 480 | uuid = "91cefc8d-f054-46dc-8f8c-26e11d7c5411" 481 | version = "3.0.3" 482 | 483 | [[deps.PrecompileTools]] 484 | deps = ["Preferences"] 485 | git-tree-sha1 = "9673d39decc5feece56ef3940e5dafba15ba0f81" 486 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 487 | version = "1.1.2" 488 | 489 | [[deps.Preferences]] 490 | deps = ["TOML"] 491 | git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" 492 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 493 | version = "1.4.0" 494 | 495 | [[deps.Printf]] 496 | deps = ["Unicode"] 497 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 498 | 499 | [[deps.ProgressLogging]] 500 | deps = ["Logging", "SHA", "UUIDs"] 501 | git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" 502 | uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" 503 | version = "0.1.4" 504 | 505 | [[deps.REPL]] 506 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 507 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 508 | 509 | [[deps.Random]] 510 | deps = ["SHA", "Serialization"] 511 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 512 | 513 | [[deps.Reexport]] 514 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 515 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 516 | version = "1.2.2" 517 | 518 | [[deps.Referenceables]] 519 | deps = ["Adapt"] 520 | git-tree-sha1 = "e681d3bfa49cd46c3c161505caddf20f0e62aaa9" 521 | uuid = "42d2dcc6-99eb-4e98-b66c-637b7d73030e" 522 | version = "0.1.2" 523 | 524 | [[deps.RegistryInstances]] 525 | deps = ["LazilyInitializedFields", "Pkg", "TOML", "Tar"] 526 | git-tree-sha1 = "ffd19052caf598b8653b99404058fce14828be51" 527 | uuid = "2792f1a3-b283-48e8-9a74-f99dce5104f3" 528 | version = "0.1.0" 529 | 530 | [[deps.RelocatableFolders]] 531 | deps = ["SHA", "Scratch"] 532 | git-tree-sha1 = "90bc7a7c96410424509e4263e277e43250c05691" 533 | uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" 534 | version = "1.0.0" 535 | 536 | [[deps.Requires]] 537 | deps = ["UUIDs"] 538 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 539 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 540 | version = "1.3.0" 541 | 542 | [[deps.Revise]] 543 | deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"] 544 | git-tree-sha1 = "feafdc70b2e6684314e188d95fe66d116de834a7" 545 | uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" 546 | version = "3.5.2" 547 | 548 | [[deps.SHA]] 549 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 550 | version = "0.7.0" 551 | 552 | [[deps.Scratch]] 553 | deps = ["Dates"] 554 | git-tree-sha1 = "30449ee12237627992a99d5e30ae63e4d78cd24a" 555 | uuid = "6c6a2e73-6563-6170-7368-637461726353" 556 | version = "1.2.0" 557 | 558 | [[deps.Serialization]] 559 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 560 | 561 | [[deps.Setfield]] 562 | deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] 563 | git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac" 564 | uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" 565 | version = "1.1.1" 566 | 567 | [[deps.SimpleBufferStream]] 568 | git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" 569 | uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" 570 | version = "1.1.0" 571 | 572 | [[deps.SnoopPrecompile]] 573 | deps = ["Preferences"] 574 | git-tree-sha1 = "e760a70afdcd461cf01a575947738d359234665c" 575 | uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" 576 | version = "1.0.3" 577 | 578 | [[deps.Sockets]] 579 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 580 | 581 | [[deps.SparseArrays]] 582 | deps = ["LinearAlgebra", "Random"] 583 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 584 | 585 | [[deps.SplittablesBase]] 586 | deps = ["Setfield", "Test"] 587 | git-tree-sha1 = "e08a62abc517eb79667d0a29dc08a3b589516bb5" 588 | uuid = "171d559e-b47b-412a-8079-5efa626c420e" 589 | version = "0.1.15" 590 | 591 | [[deps.StaticArraysCore]] 592 | git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" 593 | uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" 594 | version = "1.4.0" 595 | 596 | [[deps.Statistics]] 597 | deps = ["LinearAlgebra", "SparseArrays"] 598 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 599 | 600 | [[deps.StringEncodings]] 601 | deps = ["Libiconv_jll"] 602 | git-tree-sha1 = "33c0da881af3248dafefb939a21694b97cfece76" 603 | uuid = "69024149-9ee7-55f6-a4c4-859efe599b68" 604 | version = "0.3.6" 605 | 606 | [[deps.TOML]] 607 | deps = ["Dates"] 608 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 609 | version = "1.0.0" 610 | 611 | [[deps.TableTraits]] 612 | deps = ["IteratorInterfaceExtensions"] 613 | git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" 614 | uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" 615 | version = "1.0.1" 616 | 617 | [[deps.Tables]] 618 | deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] 619 | git-tree-sha1 = "1544b926975372da01227b382066ab70e574a3ec" 620 | uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" 621 | version = "1.10.1" 622 | 623 | [[deps.Tar]] 624 | deps = ["ArgTools", "SHA"] 625 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 626 | version = "1.10.1" 627 | 628 | [[deps.TerminalLoggers]] 629 | deps = ["LeftChildRightSiblingTrees", "Logging", "Markdown", "Printf", "ProgressLogging", "UUIDs"] 630 | git-tree-sha1 = "f133fab380933d042f6796eda4e130272ba520ca" 631 | uuid = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" 632 | version = "0.1.7" 633 | 634 | [[deps.Test]] 635 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 636 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 637 | 638 | [[deps.ThreadsX]] 639 | deps = ["ArgCheck", "BangBang", "ConstructionBase", "InitialValues", "MicroCollections", "Referenceables", "Setfield", "SplittablesBase", "Transducers"] 640 | git-tree-sha1 = "34e6bcf36b9ed5d56489600cf9f3c16843fa2aa2" 641 | uuid = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d" 642 | version = "0.1.11" 643 | 644 | [[deps.TranscodingStreams]] 645 | deps = ["Random", "Test"] 646 | git-tree-sha1 = "9a6ae7ed916312b41236fcef7e0af564ef934769" 647 | uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" 648 | version = "0.9.13" 649 | 650 | [[deps.Transducers]] 651 | deps = ["Adapt", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "Requires", "Setfield", "SplittablesBase", "Tables"] 652 | git-tree-sha1 = "25358a5f2384c490e98abd565ed321ffae2cbb37" 653 | uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999" 654 | version = "0.4.76" 655 | 656 | [[deps.Tricks]] 657 | git-tree-sha1 = "aadb748be58b492045b4f56166b5188aa63ce549" 658 | uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" 659 | version = "0.1.7" 660 | 661 | [[deps.URIs]] 662 | git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" 663 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 664 | version = "1.4.2" 665 | 666 | [[deps.UUIDs]] 667 | deps = ["Random", "SHA"] 668 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 669 | 670 | [[deps.Unicode]] 671 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 672 | 673 | [[deps.YAML]] 674 | deps = ["Base64", "Dates", "Printf", "StringEncodings"] 675 | git-tree-sha1 = "dbc7f1c0012a69486af79c8bcdb31be820670ba2" 676 | uuid = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" 677 | version = "0.4.8" 678 | 679 | [[deps.Zlib_jll]] 680 | deps = ["Libdl"] 681 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 682 | version = "1.2.12+3" 683 | 684 | [[deps.libblastrampoline_jll]] 685 | deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] 686 | uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" 687 | version = "5.1.1+0" 688 | 689 | [[deps.nghttp2_jll]] 690 | deps = ["Artifacts", "Libdl"] 691 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 692 | version = "1.48.0+0" 693 | 694 | [[deps.p7zip_jll]] 695 | deps = ["Artifacts", "Libdl"] 696 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 697 | version = "17.4.0+0" 698 | -------------------------------------------------------------------------------- /PlutoPages.jl: -------------------------------------------------------------------------------- 1 | ### A Pluto.jl notebook ### 2 | # v0.19.25 3 | 4 | using Markdown 5 | using InteractiveUtils 6 | 7 | # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). 8 | macro bind(def, element) 9 | quote 10 | local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end 11 | local el = $(esc(element)) 12 | global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) 13 | el 14 | end 15 | end 16 | 17 | # ╔═╡ b8024c95-6a63-4409-9c75-9bad6b301a92 18 | begin 19 | import Pkg 20 | Pkg.activate("./pluto-deployment-environment") 21 | 22 | import PlutoSliderServer 23 | import Pluto 24 | using MarkdownLiteral 25 | end 26 | 27 | # ╔═╡ d4cfce05-bae4-49ae-b26d-ce27171a3853 28 | using PlutoUI 29 | 30 | # ╔═╡ ce840b47-8406-48e6-abfb-1b00daab28dd 31 | using HypertextLiteral 32 | 33 | # ╔═╡ 7c53c1e3-6ccf-4804-8bc3-09126036608e 34 | using PlutoHooks 35 | 36 | # ╔═╡ 725cb996-68ac-4736-95ee-0a9754867bf3 37 | using BetterFileWatching 38 | 39 | # ╔═╡ 9d996c55-0e37-4ae9-a6a2-8c8761e8c6db 40 | using PlutoLinks 41 | 42 | # ╔═╡ c5a0b072-7f49-4c0c-855e-773cfc03d308 43 | TableOfContents(include_definitions=true) 44 | 45 | # ╔═╡ 644552c6-4e32-4caf-90ef-bee259977094 46 | import Logging 47 | 48 | # ╔═╡ 66c97351-2294-4ac2-a93a-f334aaee8f92 49 | import Gumbo 50 | 51 | # ╔═╡ bcbda2d2-90a5-43e6-8400-d5472578f86a 52 | import ProgressLogging 53 | 54 | # ╔═╡ cd576da6-59ae-4d1b-b812-1a35023b6875 55 | import ThreadsX 56 | 57 | # ╔═╡ 86471faf-af03-4f35-8b95-c4011ceaf7c3 58 | function progressmap_generic(mapfn, f, itr; kwargs...) 59 | l = length(itr) 60 | id = gensym() 61 | num_iterations = Threads.Atomic{Int}(0) 62 | 63 | function log(x) 64 | Threads.atomic_add!(num_iterations, x) 65 | Logging.@logmsg(ProgressLogging.ProgressLevel, "", progress=num_iterations[] / l, id=id) 66 | end 67 | 68 | log(0) 69 | 70 | output = mapfn(enumerate(itr); kwargs...) do (i,x) 71 | result = f(x) 72 | log(1) 73 | result 74 | end 75 | 76 | log(0) 77 | output 78 | end 79 | 80 | # ╔═╡ e0ae20f5-ffe7-4f0e-90be-168924526e03 81 | "Like `Base.map`, but with ProgressLogging." 82 | function progressmap(f, itr) 83 | progressmap_generic(map, f, itr) 84 | end 85 | 86 | # ╔═╡ d58f2a89-4631-4b19-9d60-5e590908b61f 87 | "Like `Base.asyncmap`, but with ProgressLogging." 88 | function progressmap_async(f, itr; kwargs...) 89 | progressmap_generic(asyncmap, f, itr; kwargs...) 90 | end 91 | 92 | # ╔═╡ 2221f133-e490-4e3a-82d4-bd1c6c979d1c 93 | "Like `ThreadsX.map`, but with ProgressLogging." 94 | function progressmap_threaded(f, itr; kwargs...) 95 | progressmap_generic(ThreadsX.map, f, itr; kwargs...) 96 | end 97 | 98 | # ╔═╡ 6c8e76ea-d648-449a-89de-cb6632cdd6b9 99 | md""" 100 | # Template systems 101 | 102 | A **template** system is will turn an input file (markdown, julia, nunjucks, etc.) into an (HTML) output. This architecture is based on [eleventy](https://www.11ty.dev/docs/). 103 | 104 | To register a template handler for a file extension, you add a method to `template_handler`, e.g. 105 | 106 | ```julia 107 | function template_handler( 108 | ::Val{Symbol(".md")}, 109 | input::TemplateInput 110 | )::TemplateOutput 111 | 112 | s = String(input.contents) 113 | result = run_markdown(s) 114 | 115 | return TemplateOutput(; 116 | contents=result.contents, 117 | front_matter=result.front_matter, 118 | ) 119 | end 120 | ``` 121 | 122 | See `TemplateInput` and `TemplateOutput` for more info! 123 | """ 124 | 125 | # ╔═╡ 4a2dc5a4-0bf2-4678-b984-4ecb7b397d72 126 | md""" 127 | ## `.jlhtml`: HypertextLiteral.jl 128 | """ 129 | 130 | # ╔═╡ b3ce7742-fb47-4c17-bac2-e6a7710eb1a1 131 | md""" 132 | ## `.md` and `.jlmd`: MarkdownLiteral.jl 133 | """ 134 | 135 | # ╔═╡ f4a4b741-8028-4626-9187-0b6a52f062b6 136 | import CommonMark 137 | 138 | # ╔═╡ 535efb29-73bd-4e65-8bbc-18b72ae8fe1f 139 | import YAML 140 | 141 | # ╔═╡ 90f0c676-b33f-441c-8ea6-d59c44a11547 142 | s_example = raw""" 143 | --- 144 | title: "Hello worfdsld!" 145 | description: "A longer description of the same thing" 146 | authors: ["Fonsi"] 147 | --- 148 | 149 | ### Hello there! 150 | 151 | My name is fons 152 | 153 |
    154 | $(map(1:num) do i 155 | @mdx ""\"
  • That's $i cool
  • ""\" 156 | end) 157 |
158 | 159 | Want to embed some cool HTML? *Easy!* Just type the HTML! **or markdown**, it's all the same!! 👀 160 | 161 | ```math 162 | \\sqrt{\\frac{1}{2}} 163 | ```` 164 | 165 | $(begin 166 | a = 1 167 | b = 2 168 | export b 169 | end) 170 | 171 | """ 172 | 173 | # ╔═╡ 5381e8b3-d4f9-4e58-8da3-f1ee0a9b7a6d 174 | @bind s TextField((70,20); default=s_example) 175 | 176 | # ╔═╡ 08b42df7-9120-4b42-80ee-8e438752b50c 177 | # s_result.exported 178 | 179 | # ╔═╡ adb1ddac-d992-49ca-820f-e1ed8ca33bf8 180 | md""" 181 | ## `.jl`: PlutoSliderServer.jl 182 | """ 183 | 184 | # ╔═╡ bb905046-59b7-4da6-97ad-dbb9055d823a 185 | const pluto_deploy_settings = PlutoSliderServer.get_configuration(PlutoSliderServer.default_config_path()) 186 | 187 | # ╔═╡ b638df55-fd74-4ae8-bdbd-ec7b18214b40 188 | function prose_from_code(s::String)::String 189 | replace(replace( 190 | replace( 191 | replace(s, 192 | # remove embedded project/manifest 193 | r"000000000001.+"s => ""), 194 | # remove cell delimiters 195 | r"^# [╔╟╠].*"m => ""), 196 | # remove some code-only punctiation 197 | r"[\!\#\$\*\+\-\/\:\;\<\>\=\(\)\[\]\{\}\:\@\_]" => " "), 198 | # collapse repeated whitespace 199 | r"\s+"s => " ") 200 | end 201 | 202 | # ╔═╡ 87b4431b-438b-4da4-9d06-79e7f3a2fe05 203 | prose_from_code(""" 204 | [xs for y in ab(d)] 205 | fonsi 206 | """) 207 | 208 | # ╔═╡ cd4e479c-deb7-4a44-9eb0-c3819b5c4067 209 | find(f::Function, xs) = for x in xs 210 | if f(x) 211 | return x 212 | end 213 | end 214 | 215 | # ╔═╡ 2e527d04-e4e7-4dc8-87e6-8b3dd3c7688a 216 | const FrontMatter = Dict{String,Any} 217 | 218 | # ╔═╡ a166e8f3-542e-4068-a076-3f5fd4daa61c 219 | Base.@kwdef struct TemplateInput 220 | contents::Vector{UInt8} 221 | relative_path::String 222 | absolute_path::String 223 | frontmatter::FrontMatter=FrontMatter() 224 | end 225 | 226 | # ╔═╡ 6288f145-444b-41cb-b9e3-8f273f9517fb 227 | begin 228 | Base.@kwdef struct TemplateOutput 229 | contents::Union{Vector{UInt8},String,Nothing} 230 | file_extension::String="html" 231 | frontmatter::FrontMatter=FrontMatter() 232 | search_index_data::Union{Nothing,String}=nothing 233 | end 234 | TemplateOutput(t::TemplateOutput; kwargs...) = TemplateOutput(; 235 | contents=t.contents, 236 | file_extension=t.file_extension, 237 | frontmatter=t.frontmatter, 238 | search_index_data=t.search_index_data, 239 | kwargs..., 240 | ) 241 | end 242 | 243 | # ╔═╡ ff55f7eb-a23d-4ca7-b428-ab05dcb8f090 244 | # fallback method 245 | function template_handler(::Any, input::TemplateInput)::TemplateOutput 246 | TemplateOutput(; 247 | contents=nothing, 248 | file_extension="nothing", 249 | ) 250 | end 251 | 252 | # ╔═╡ 692c1e0b-07e1-41b3-abcd-2156bda65b41 253 | """ 254 | Turn a MarkdownLiteral.jl string into HTML contents and front matter. 255 | """ 256 | function run_mdx(s::String; 257 | data::Dict{String,<:Any}=Dict{String,Any}(), 258 | cm::Bool=true, 259 | filename::AbstractString="unknown", 260 | ) 261 | # take a look at https://github.com/JuliaPluto/MarkdownLiteral.jl if you want to use it this too! 262 | 263 | # Just HTL, CommonMark parsing comes in a later step 264 | code = "@htl(\"\"\"$(s)\"\"\")" 265 | 266 | m = Module() 267 | Core.eval(m, :(var"@mdx" = var"@md" = $(MarkdownLiteral.var"@mdx"))) 268 | Core.eval(m, :(var"@htl" = $(HypertextLiteral.var"@htl"))) 269 | # Core.eval(m, :(setpage = $(setpage))) 270 | Core.eval(m, :(using Markdown, InteractiveUtils)) 271 | for (k,v) in data 272 | Core.eval(m, :($(Symbol(k)) = $(v))) 273 | end 274 | 275 | result = Base.include_string(m, code, filename) 276 | 277 | to_render, frontmatter = if !cm 278 | result, FrontMatter() 279 | else 280 | 281 | # we want to apply our own CM parser, so we do the MarkdownLiteral.jl trick manually: 282 | result_str = repr(MIME"text/html"(), result) 283 | cm_parser = CommonMark.Parser() 284 | CommonMark.enable!(cm_parser, [ 285 | CommonMark.AdmonitionRule(), 286 | CommonMark.AttributeRule(), 287 | CommonMark.AutoIdentifierRule(), 288 | CommonMark.CitationRule(), 289 | CommonMark.FootnoteRule(), 290 | CommonMark.MathRule(), 291 | CommonMark.RawContentRule(), 292 | CommonMark.TableRule(), 293 | CommonMark.TypographyRule(), 294 | # TODO: allow Julia in front matter by using Meta.parse as the TOML parser? 295 | # but you probably want to be able to use those variables inside the document, so they have to be evaluated *before* running the expr. 296 | CommonMark.FrontMatterRule(yaml=YAML.load), 297 | ]) 298 | 299 | ast = cm_parser(result_str) 300 | 301 | ast, CommonMark.frontmatter(ast) 302 | end 303 | 304 | contents = repr(MIME"text/html"(), to_render) 305 | 306 | # TODO: might be nice: 307 | # exported = filter(names(m; all=false, imported=false)) do s 308 | # s_str = string(s) 309 | # !(startswith(s_str, "#") || startswith(s_str, "anonymous")) 310 | # end 311 | 312 | (; 313 | contents, 314 | frontmatter, 315 | # exported, 316 | ) 317 | end 318 | 319 | # ╔═╡ 7717e24f-62ee-4852-9dec-d09b734d0693 320 | s_result = run_mdx(s; data=Dict("num" => 3)); 321 | 322 | # ╔═╡ 9f945292-ff9e-4f29-93ea-69b10fc4428d 323 | s_result.contents |> HTML 324 | 325 | # ╔═╡ 83366d96-4cd3-4def-a0da-16a22b40124f 326 | s_result.frontmatter 327 | 328 | # ╔═╡ 94bb6730-a4ad-42d2-aa58-41b70a15cd0e 329 | md""" 330 | ## `.css`, `.html`, `.js`, `.png`, etc: passthrough 331 | 332 | """ 333 | 334 | # ╔═╡ e15cf987-3615-4e96-8ccd-04cad3bcd48e 335 | function template_handler(::Union{ 336 | Val{Symbol(".css")}, 337 | Val{Symbol(".html")}, 338 | Val{Symbol(".js")}, 339 | Val{Symbol(".png")}, 340 | Val{Symbol(".svg")}, 341 | Val{Symbol(".gif")}, 342 | }, input::TemplateInput)::TemplateOutput 343 | 344 | TemplateOutput(; 345 | contents=input.contents, 346 | file_extension=lstrip(isequal('.'), splitext(input.relative_path)[2]), 347 | ) 348 | end 349 | 350 | # ╔═╡ 940f3995-1739-4b30-b8cf-c27a671043e5 351 | md""" 352 | ## Generated assets 353 | """ 354 | 355 | # ╔═╡ 5e91e7dc-82b6-486a-b745-34f97b6fb20c 356 | struct RegisteredAsset 357 | url::String 358 | relative_path::String 359 | absolute_path::String 360 | end 361 | 362 | # ╔═╡ 8f6393a4-e945-4f06-90f6-0a71f874c8e9 363 | import SHA 364 | 365 | # ╔═╡ 4fcdd524-86a8-4033-bc7c-4a7c04224eeb 366 | import Unicode 367 | 368 | # ╔═╡ 070c710d-3746-4706-bd03-b5b00a576007 369 | function myhash(data) 370 | s = SHA.sha256(data) 371 | string(reinterpret(UInt32, s)[1]; base=16, pad=8) 372 | end 373 | 374 | # ╔═╡ a5c22f80-58c7-4c63-95b8-ecb30bc896d0 375 | myhash(rand(UInt8, 50)) 376 | 377 | # ╔═╡ 750782a1-3aeb-4816-8f6a-ec31055373c1 378 | legalize(filename) = replace( 379 | Unicode.normalize( 380 | replace(filename, " " => "_"); 381 | stripmark=true) 382 | , r"[^\w-]" => "") 383 | 384 | # ╔═╡ f6b89b8c-3750-4dd2-940e-579be953c1c2 385 | legalize(" ëasdfa sd23__--f//asd f?\$%^&*() .") 386 | 387 | # ╔═╡ 29a81ad7-3803-4b7a-98ca-6e5b1077e1c7 388 | md""" 389 | # Input folder 390 | """ 391 | 392 | # ╔═╡ c52c9786-a25f-11ec-1fdc-9b13922d7ccb 393 | const dir = joinpath(@__DIR__, "src") 394 | 395 | # ╔═╡ cf27b3d3-1689-4b3a-a8fe-3ad639eb2f82 396 | md""" 397 | ## File watching 398 | """ 399 | 400 | # ╔═╡ 7f7f1981-978d-4861-b840-71ab611faf74 401 | @bind manual_update_trigger Button("Read input files again") 402 | 403 | # ╔═╡ e1a87788-2eba-47c9-ab4c-74f3344dce1d 404 | ignored_dirname(s; allow_special_dirs::Bool=false) = 405 | startswith(s, "_") && (!allow_special_dirs || s != "_includes") 406 | 407 | # ╔═╡ 485b7956-0774-4b25-a897-3d9232ef8590 408 | const this_file = split(@__FILE__, "#==#")[1] 409 | 410 | # ╔═╡ d38dc2aa-d5ba-4cf7-9f9e-c4e4611a57ac 411 | function ignore(abs_path; allow_special_dirs::Bool=false) 412 | p = relpath(abs_path, dir) 413 | 414 | # (_cache, _site, _andmore) 415 | any(x -> ignored_dirname(x; allow_special_dirs), splitpath(p)) || 416 | startswith(p, ".git") || 417 | startswith(p, ".vscode") || 418 | abs_path == this_file 419 | end 420 | 421 | # ╔═╡ 8da0c249-6094-49ab-9e59-d6e356818651 422 | dir_changed_time = let 423 | valx, set_valx = @use_state(time()) 424 | 425 | @info "Starting watch task" 426 | 427 | @use_task([dir]) do 428 | BetterFileWatching.watch_folder(dir) do e 429 | @debug "File event" e 430 | try 431 | is_caused_by_me = all(x -> ignore(x; allow_special_dirs=true), e.paths) 432 | 433 | if !is_caused_by_me 434 | @info "Reloading!" e 435 | set_valx(time()) 436 | end 437 | catch e 438 | @error "Failed to trigger" exception=(e,catch_backtrace()) 439 | end 440 | end 441 | end 442 | 443 | valx 444 | end 445 | 446 | # ╔═╡ 7d9cb939-da6b-4961-9584-a905ad453b5d 447 | allfiles = filter(PlutoSliderServer.list_files_recursive(dir)) do p 448 | # reference to retrigger when files change 449 | dir_changed_time 450 | manual_update_trigger 451 | 452 | !ignore(joinpath(dir, p)) 453 | end 454 | 455 | # ╔═╡ d314ab46-b866-44c6-bfca-9a413bc06514 456 | md""" 457 | # Output folder generation 458 | """ 459 | 460 | # ╔═╡ e01ebbab-dc9a-4aaf-ae16-200d171fcbd9 461 | const output_dir = mkpath(joinpath(@__DIR__, "_site")) 462 | 463 | # ╔═╡ 37b2cecc-e4c7-4b80-b7d9-71c68f3c0339 464 | 465 | 466 | # ╔═╡ 7a95681a-df77-408f-919a-2bee5afd7777 467 | """ 468 | This directory can be used to store cache files that are persisted between builds. Currently used as PlutoSliderServer.jl cache. 469 | """ 470 | const cache_dir = mkpath(joinpath(@__DIR__, "_cache")) 471 | 472 | # ╔═╡ f3d225b8-b9a5-4639-97eb-7785b1a78f5a 473 | md""" 474 | ## Running a dev web server 475 | """ 476 | 477 | # ╔═╡ c3a495c1-3e1f-42a1-ac08-8dc0b9175fe9 478 | # import Deno_jll 479 | 480 | # ╔═╡ 3b2d1919-41d9-4bba-9774-c8497bba5003 481 | # dev_server_port = 4507 482 | 483 | # ╔═╡ 6f7f66e8-ed10-4cc4-8672-a06861111aec 484 | # dev_server_url = "http://localhost:$(dev_server_port)/" 485 | 486 | # ╔═╡ d09ee809-33d8-44f8-aa7a-be4b3fdc21eb 487 | 488 | 489 | # ╔═╡ a0a80dce-2199-45b6-b4e9-d4168f520c85 490 | # @htl("
Go to $(dev_server_url) to preview the site.
") 491 | 492 | # ╔═╡ 4e88cf07-8d85-4327-b310-6c71ba951bba 493 | md""" 494 | ## Running the templates 495 | 496 | (This can take a while if you are running this for the first time with an empty cache.) 497 | """ 498 | 499 | # ╔═╡ f700357f-e21c-4d23-b56c-be4f9c90465f 500 | const NUM_PARALLEL_WORKERS = 4 501 | 502 | # ╔═╡ aaad71bd-5425-4783-952c-82e4d4fa7bb8 503 | md""" 504 | ## URL generation 505 | """ 506 | 507 | # ╔═╡ 76c2ac85-2e89-4396-a498-a4ceb1cc80bd 508 | Base.@kwdef struct Page 509 | url::String 510 | full_url::String 511 | input::TemplateInput 512 | output::TemplateOutput 513 | end 514 | 515 | # ╔═╡ a510857f-528b-43e8-be78-69e554d165a6 516 | function short_url(s::String) 517 | a = replace(s, r"index.html$" => "") 518 | isempty(a) ? "." : a 519 | end 520 | 521 | # ╔═╡ 1c269e16-65c7-47ae-aeab-001f1b205e14 522 | ishtml(output::TemplateOutput) = output.file_extension == "html" 523 | 524 | # ╔═╡ 898eb093-444c-45cf-88d7-3dbe9708ae31 525 | function final_url(input::TemplateInput, output::TemplateOutput)::String 526 | if ishtml(output) 527 | # Examples: 528 | # a/b.jl -> a/b/index.html 529 | # a/index.jl -> a/index.html 530 | 531 | in_dir, in_filename = splitdir(input.relative_path) 532 | in_name, in_ext = splitext(in_filename) 533 | 534 | if in_name == "index" 535 | joinpath(in_dir, "index.html") 536 | else 537 | joinpath(in_dir, in_name, "index.html") 538 | end 539 | else 540 | ext = lstrip(isequal('.'), output.file_extension) 541 | join((splitext(input.relative_path)[1], ".", ext)) 542 | end 543 | end 544 | 545 | # ╔═╡ 76193b12-842c-4b82-a23e-fb7403274234 546 | md""" 547 | ## Collections from `tags` 548 | """ 549 | 550 | # ╔═╡ 4f563136-fc7b-4322-92ba-78c0183c40cc 551 | struct Collection 552 | tag::String 553 | pages::Vector{Page} 554 | end 555 | 556 | # ╔═╡ 41ab51f9-0b33-4548-b08a-ad1ef7d38f1b 557 | function sort_by(p::Page) 558 | bn = basename(p.input.relative_path) 559 | num = get(p.output.frontmatter, "order", Inf) 560 | if num isa AbstractString 561 | num = tryparse(Float64, num) 562 | if isnothing(num) 563 | num = Inf 564 | end 565 | end 566 | return ( 567 | num, 568 | splitext(bn)[1] != "index", 569 | # TODO: sort based on dates if we ever need that 570 | bn, 571 | ) 572 | end 573 | 574 | # ╔═╡ b0006e61-b037-41ed-a3e4-9962d15584c4 575 | md""" 576 | ## Layouts 577 | """ 578 | 579 | # ╔═╡ f2fbcc70-a714-4eda-8786-7ee5692e3268 580 | with_doctype(p::Page) = Page(p.url, p.full_url, p.input, with_doctype(p.output)) 581 | 582 | # ╔═╡ 57fd383b-d791-4170-a353-f839356f9d7a 583 | with_doctype(output::TemplateOutput) = if ishtml(output) && output.contents !== nothing 584 | TemplateOutput(output; 585 | contents="" * String(output.contents) 586 | ) 587 | else 588 | output 589 | end 590 | 591 | # ╔═╡ 05f735e0-01cc-4276-a3f9-8420296e68be 592 | md""" 593 | ## Search index 594 | """ 595 | 596 | # ╔═╡ 1a303aa4-bed5-4d9b-855c-23355f4a88fe 597 | md""" 598 | ## Writing to the output directory 599 | """ 600 | 601 | # ╔═╡ 834294ff-9441-4e71-b5c0-edaf32d860ee 602 | import JSON 603 | 604 | # ╔═╡ eef54261-767a-4ce4-b549-0b1828379f7e 605 | SafeString(x) = String(x) 606 | 607 | # ╔═╡ cda8689d-9ae5-42c4-8e7e-715cf44c33bb 608 | SafeString(x::Vector{UInt8}) = String(copy(x)) 609 | 610 | # ╔═╡ 995c6810-8df2-483d-a87a-2277af0d43bd 611 | function template_handler( 612 | ::Union{Val{Symbol(".jlhtml")}}, 613 | input::TemplateInput)::TemplateOutput 614 | s = SafeString(input.contents) 615 | result = run_mdx(s; 616 | data=input.frontmatter, 617 | cm=false, 618 | filename=input.absolute_path, 619 | ) 620 | 621 | return TemplateOutput(; 622 | contents=result.contents, 623 | search_index_data=Gumbo.text(Gumbo.parsehtml(result.contents).root), 624 | frontmatter=result.frontmatter, 625 | ) 626 | end 627 | 628 | # ╔═╡ 7e86cfc7-5439-4c7a-9c3b-381c776d8371 629 | function template_handler( 630 | ::Union{ 631 | Val{Symbol(".jlmd")}, 632 | Val{Symbol(".md")} 633 | }, 634 | input::TemplateInput)::TemplateOutput 635 | s = SafeString(input.contents) 636 | result = run_mdx(s; 637 | data=input.frontmatter, 638 | filename=input.absolute_path, 639 | ) 640 | 641 | return TemplateOutput(; 642 | contents=result.contents, 643 | search_index_data=Gumbo.text(Gumbo.parsehtml(result.contents).root), 644 | frontmatter=result.frontmatter, 645 | ) 646 | end 647 | 648 | # ╔═╡ 4013400c-acb4-40fa-a826-fd0cbae09e7e 649 | reprhtml(x) = repr(MIME"text/html"(), x) 650 | 651 | # ╔═╡ 5b325b50-8984-44c6-8677-3c6bc5c2b0b1 652 | "A magic token that will turn into a relative URL pointing to the website root when used in output." 653 | const root_url = "++magic#root#url~$(string(rand(UInt128),base=62))++" 654 | 655 | # ╔═╡ 0d2b7382-2ddf-48c3-90c8-bc22de454c97 656 | """ 657 | ```julia 658 | register_asset(contents, original_name::String) 659 | ``` 660 | 661 | Place an asset in the `/generated_assets/` subfolder of the output directory and return a [`RegisteredAsset`](@ref) referencing it for later use. (The original filename will be sanitized, and a content hash will be appended.) 662 | 663 | To be used inside `process_file` methods which need to generate additional files. You can use `registered_asset.url` to get a location-independent href to the result. 664 | """ 665 | function register_asset(contents, original_name::String) 666 | h = myhash(contents) 667 | n, e = splitext(basename(original_name)) 668 | 669 | 670 | mkpath(joinpath(output_dir, "generated_assets")) 671 | newpath = joinpath(output_dir, "generated_assets", "$(legalize(n))_$(h)$(e)") 672 | write(newpath, contents) 673 | rel = relpath(newpath, output_dir) 674 | return RegisteredAsset(joinpath(root_url, rel), rel, newpath) 675 | end 676 | 677 | # ╔═╡ e2510a44-df48-4c05-9453-8822deadce24 678 | function template_handler( 679 | ::Val{Symbol(".jl")}, 680 | input::TemplateInput 681 | )::TemplateOutput 682 | 683 | 684 | if Pluto.is_pluto_notebook(input.absolute_path) 685 | temp_out = mktempdir() 686 | Logging.with_logger(Logging.NullLogger()) do 687 | PlutoSliderServer.export_notebook( 688 | input.absolute_path; 689 | Export_create_index=false, 690 | Export_cache_dir=cache_dir, 691 | Export_baked_state=false, 692 | Export_baked_notebookfile=false, 693 | Export_output_dir=temp_out, 694 | ) 695 | end 696 | d = readdir(temp_out) 697 | 698 | statefile = find(contains("state") ∘ last ∘ splitext, d) 699 | notebookfile = find(!contains("html") ∘ last ∘ splitext, d) 700 | 701 | reg_s = register_asset(read(joinpath(temp_out, statefile)), statefile) 702 | reg_n = register_asset(read(joinpath(temp_out, notebookfile)), notebookfile) 703 | 704 | # TODO these relative paths can't be right... 705 | h = @htl """ 706 | 713 | """ 714 | 715 | frontmatter = Pluto.frontmatter(input.absolute_path) 716 | 717 | return TemplateOutput(; 718 | contents = repr(MIME"text/html"(), h), 719 | search_index_data=prose_from_code(SafeString(input.contents)), 720 | frontmatter, 721 | ) 722 | else 723 | 724 | s = SafeString(input.contents) 725 | 726 | h = @htl """ 727 |
$(s)
728 | """ 729 | 730 | return TemplateOutput(; 731 | contents=repr(MIME"text/html"(), h), 732 | search_index_data=prose_from_code(s), 733 | ) 734 | end 735 | end 736 | 737 | # ╔═╡ 079a6399-50eb-4dee-a36d-b3dcb81c8456 738 | template_results = let 739 | # delete any old files 740 | for f in readdir(output_dir) 741 | rm(joinpath(output_dir, f); recursive=true) 742 | end 743 | 744 | # let's go! running all the template handlers 745 | progressmap_async(allfiles; ntasks=NUM_PARALLEL_WORKERS) do f 746 | absolute_path = joinpath(dir, f) 747 | 748 | input = TemplateInput(; 749 | contents=read(absolute_path), 750 | absolute_path, 751 | relative_path=f, 752 | frontmatter=FrontMatter( 753 | "root_url" => root_url, 754 | ), 755 | ) 756 | 757 | output = try 758 | template_handler(Val(Symbol(splitext(f)[2])), input) 759 | catch e 760 | @error "Template handler failed" f exception=(e,catch_backtrace()) 761 | rethrow() 762 | end 763 | 764 | input, output 765 | end 766 | end 767 | 768 | # ╔═╡ 318dc59e-15f6-4b25-bcf5-1ab6b0d87af7 769 | pages = Page[ 770 | let 771 | u = final_url(input, output) 772 | Page( 773 | short_url(u), u, input, output, 774 | ) 775 | end 776 | for (input, output) in template_results if output.contents !== nothing 777 | ] 778 | 779 | # ╔═╡ f93da14a-e4c8-4c28-ab01-4a5ba1a3cf47 780 | collections = let 781 | result = Dict{String,Set{Page}}() 782 | 783 | for page in pages 784 | for t in get(page.output.frontmatter, "tags", String[]) 785 | old = get!(result, t, Set{Page}()) 786 | push!(old, page) 787 | end 788 | end 789 | 790 | 791 | Dict{String,Collection}( 792 | k => Collection(k, sort(collect(v); by=sort_by)) for (k,v) in result 793 | ) 794 | end 795 | 796 | # ╔═╡ c2ee20be-16f5-47a8-851a-67a361bb0316 797 | """ 798 | ```julia 799 | process_layouts(page::Page)::Page 800 | ``` 801 | 802 | Recursively apply the layout specified in the frontmatter, returning a new `Page` with updated `output`. 803 | """ 804 | function process_layouts(page::Page)::Page 805 | output = page.output 806 | 807 | if haskey(output.frontmatter, "layout") 808 | @assert output.file_extension == "html" "Layout is not (yet) supported on non-HTML outputs." 809 | 810 | layoutname = output.frontmatter["layout"] 811 | @assert layoutname isa String 812 | layout_file = joinpath(dir, "_includes", layoutname) 813 | @assert isfile(layout_file) "$layout_file is not a valid layout path" 814 | 815 | 816 | content = if ishtml(output) 817 | HTML(SafeString(output.contents)) 818 | else 819 | output.contents 820 | end 821 | 822 | metadata = Dict() 823 | for data_file in readdir(joinpath(dir, "_data"); join=true) 824 | key = splitext(basename(data_file))[1] 825 | metadata[key] = include(data_file) 826 | end 827 | 828 | input = TemplateInput(; 829 | contents=read(layout_file), 830 | absolute_path=layout_file, 831 | relative_path=relpath(layout_file, dir), 832 | frontmatter=merge(output.frontmatter, 833 | FrontMatter( 834 | "content" => content, 835 | "page" => page, 836 | "collections" => collections, 837 | "root_url" => root_url, 838 | "metadata" => metadata 839 | ), 840 | ) 841 | ) 842 | 843 | result = template_handler(Val(Symbol(splitext(layout_file)[2])), input) 844 | 845 | @assert result.file_extension == "html" "Non-HTML output from Layouts is not (yet) supported." 846 | 847 | 848 | 849 | old_frontmatter = copy(output.frontmatter) 850 | delete!(old_frontmatter, "layout") 851 | new_frontmatter = merge(old_frontmatter, result.frontmatter) 852 | 853 | process_layouts(Page( 854 | page.url, 855 | page.full_url, 856 | page.input, 857 | TemplateOutput( 858 | result; 859 | search_index_data=output.search_index_data, 860 | frontmatter=new_frontmatter, 861 | ), 862 | )) 863 | else 864 | page 865 | end 866 | end 867 | 868 | # ╔═╡ 06edb2d7-325f-4f80-8c55-dc01c7783054 869 | rendered_results = progressmap(with_doctype ∘ process_layouts, pages) 870 | 871 | # ╔═╡ d8e9b950-6e71-40e2-bac1-c3ba85bc83ee 872 | collected_search_index_data = [ 873 | ( 874 | url=page.url::String, 875 | title=get( 876 | page.output.frontmatter, "title", 877 | splitext(basename(page.input.relative_path))[1] 878 | )::String, 879 | tags=get(page.output.frontmatter, "tags", String[]), 880 | text=page.output.search_index_data, 881 | ) 882 | for page in rendered_results if page.output.search_index_data !== nothing 883 | ] 884 | 885 | # ╔═╡ 1be06e4b-6072-46c3-a63d-aa95e51c43b4 886 | write( 887 | joinpath(output_dir, "pp_search_data.json"), 888 | JSON.json(collected_search_index_data) 889 | ) 890 | 891 | # ╔═╡ 9845db00-149c-45be-9e4f-55d1157afc87 892 | process_results = map(rendered_results) do page 893 | input = page.input 894 | output = page.output 895 | 896 | if output !== nothing && output.contents !== nothing 897 | 898 | # TODO: use front matter for permalink 899 | 900 | output_path2 = joinpath(output_dir, page.full_url) 901 | mkpath(output_path2 |> dirname) 902 | # Our magic root url: 903 | # in Julia, you can safely call `String` and `replace` on arbitrary, non-utf8 data :) 904 | write(output_path2, 905 | replace(SafeString(output.contents), root_url => relpath(output_dir, output_path2 |> dirname)) 906 | ) 907 | end 908 | end 909 | 910 | # ╔═╡ 70fa9af8-31f9-4e47-b36b-828c88166b3d 911 | md""" 912 | # Verify output 913 | """ 914 | 915 | # ╔═╡ d17c96fb-8459-4527-a139-05fdf74cdc39 916 | allfiles_output = let 917 | process_results 918 | PlutoSliderServer.list_files_recursive(output_dir) 919 | end 920 | 921 | # ╔═╡ 9268f35e-1a4e-414e-a7ea-3f5796e0bbf3 922 | allfiles_output2 = filter(allfiles_output) do f 923 | !startswith(f, "generated_assets") 924 | end 925 | 926 | # ╔═╡ e0a25f24-a7de-4eac-9f88-cb7632de09eb 927 | begin 928 | @assert length(allfiles_output2) ≥ length(pages) 929 | 930 | @htl(""" 931 | 936 | """) 937 | end 938 | 939 | # ╔═╡ Cell order: 940 | # ╠═b8024c95-6a63-4409-9c75-9bad6b301a92 941 | # ╠═c5a0b072-7f49-4c0c-855e-773cfc03d308 942 | # ╠═d4cfce05-bae4-49ae-b26d-ce27171a3853 943 | # ╠═644552c6-4e32-4caf-90ef-bee259977094 944 | # ╠═66c97351-2294-4ac2-a93a-f334aaee8f92 945 | # ╠═bcbda2d2-90a5-43e6-8400-d5472578f86a 946 | # ╠═cd576da6-59ae-4d1b-b812-1a35023b6875 947 | # ╟─e0ae20f5-ffe7-4f0e-90be-168924526e03 948 | # ╟─d58f2a89-4631-4b19-9d60-5e590908b61f 949 | # ╟─2221f133-e490-4e3a-82d4-bd1c6c979d1c 950 | # ╟─86471faf-af03-4f35-8b95-c4011ceaf7c3 951 | # ╟─6c8e76ea-d648-449a-89de-cb6632cdd6b9 952 | # ╠═a166e8f3-542e-4068-a076-3f5fd4daa61c 953 | # ╠═6288f145-444b-41cb-b9e3-8f273f9517fb 954 | # ╠═ff55f7eb-a23d-4ca7-b428-ab05dcb8f090 955 | # ╟─4a2dc5a4-0bf2-4678-b984-4ecb7b397d72 956 | # ╠═ce840b47-8406-48e6-abfb-1b00daab28dd 957 | # ╠═995c6810-8df2-483d-a87a-2277af0d43bd 958 | # ╟─b3ce7742-fb47-4c17-bac2-e6a7710eb1a1 959 | # ╠═f4a4b741-8028-4626-9187-0b6a52f062b6 960 | # ╠═535efb29-73bd-4e65-8bbc-18b72ae8fe1f 961 | # ╠═7e86cfc7-5439-4c7a-9c3b-381c776d8371 962 | # ╠═90f0c676-b33f-441c-8ea6-d59c44a11547 963 | # ╠═5381e8b3-d4f9-4e58-8da3-f1ee0a9b7a6d 964 | # ╠═9f945292-ff9e-4f29-93ea-69b10fc4428d 965 | # ╠═83366d96-4cd3-4def-a0da-16a22b40124f 966 | # ╠═08b42df7-9120-4b42-80ee-8e438752b50c 967 | # ╠═7717e24f-62ee-4852-9dec-d09b734d0693 968 | # ╠═692c1e0b-07e1-41b3-abcd-2156bda65b41 969 | # ╟─adb1ddac-d992-49ca-820f-e1ed8ca33bf8 970 | # ╠═e2510a44-df48-4c05-9453-8822deadce24 971 | # ╠═bb905046-59b7-4da6-97ad-dbb9055d823a 972 | # ╠═b638df55-fd74-4ae8-bdbd-ec7b18214b40 973 | # ╠═87b4431b-438b-4da4-9d06-79e7f3a2fe05 974 | # ╟─cd4e479c-deb7-4a44-9eb0-c3819b5c4067 975 | # ╠═2e527d04-e4e7-4dc8-87e6-8b3dd3c7688a 976 | # ╟─94bb6730-a4ad-42d2-aa58-41b70a15cd0e 977 | # ╠═e15cf987-3615-4e96-8ccd-04cad3bcd48e 978 | # ╟─940f3995-1739-4b30-b8cf-c27a671043e5 979 | # ╠═0d2b7382-2ddf-48c3-90c8-bc22de454c97 980 | # ╠═5e91e7dc-82b6-486a-b745-34f97b6fb20c 981 | # ╠═8f6393a4-e945-4f06-90f6-0a71f874c8e9 982 | # ╠═4fcdd524-86a8-4033-bc7c-4a7c04224eeb 983 | # ╟─070c710d-3746-4706-bd03-b5b00a576007 984 | # ╟─a5c22f80-58c7-4c63-95b8-ecb30bc896d0 985 | # ╟─750782a1-3aeb-4816-8f6a-ec31055373c1 986 | # ╟─f6b89b8c-3750-4dd2-940e-579be953c1c2 987 | # ╟─29a81ad7-3803-4b7a-98ca-6e5b1077e1c7 988 | # ╠═c52c9786-a25f-11ec-1fdc-9b13922d7ccb 989 | # ╠═7c53c1e3-6ccf-4804-8bc3-09126036608e 990 | # ╠═725cb996-68ac-4736-95ee-0a9754867bf3 991 | # ╠═9d996c55-0e37-4ae9-a6a2-8c8761e8c6db 992 | # ╟─cf27b3d3-1689-4b3a-a8fe-3ad639eb2f82 993 | # ╟─7f7f1981-978d-4861-b840-71ab611faf74 994 | # ╟─7d9cb939-da6b-4961-9584-a905ad453b5d 995 | # ╠═e1a87788-2eba-47c9-ab4c-74f3344dce1d 996 | # ╠═d38dc2aa-d5ba-4cf7-9f9e-c4e4611a57ac 997 | # ╠═485b7956-0774-4b25-a897-3d9232ef8590 998 | # ╠═8da0c249-6094-49ab-9e59-d6e356818651 999 | # ╟─d314ab46-b866-44c6-bfca-9a413bc06514 1000 | # ╠═e01ebbab-dc9a-4aaf-ae16-200d171fcbd9 1001 | # ╠═37b2cecc-e4c7-4b80-b7d9-71c68f3c0339 1002 | # ╟─7a95681a-df77-408f-919a-2bee5afd7777 1003 | # ╟─f3d225b8-b9a5-4639-97eb-7785b1a78f5a 1004 | # ╠═c3a495c1-3e1f-42a1-ac08-8dc0b9175fe9 1005 | # ╠═3b2d1919-41d9-4bba-9774-c8497bba5003 1006 | # ╠═6f7f66e8-ed10-4cc4-8672-a06861111aec 1007 | # ╠═d09ee809-33d8-44f8-aa7a-be4b3fdc21eb 1008 | # ╟─a0a80dce-2199-45b6-b4e9-d4168f520c85 1009 | # ╟─4e88cf07-8d85-4327-b310-6c71ba951bba 1010 | # ╠═f700357f-e21c-4d23-b56c-be4f9c90465f 1011 | # ╠═079a6399-50eb-4dee-a36d-b3dcb81c8456 1012 | # ╟─aaad71bd-5425-4783-952c-82e4d4fa7bb8 1013 | # ╠═76c2ac85-2e89-4396-a498-a4ceb1cc80bd 1014 | # ╠═898eb093-444c-45cf-88d7-3dbe9708ae31 1015 | # ╟─a510857f-528b-43e8-be78-69e554d165a6 1016 | # ╟─1c269e16-65c7-47ae-aeab-001f1b205e14 1017 | # ╟─318dc59e-15f6-4b25-bcf5-1ab6b0d87af7 1018 | # ╟─76193b12-842c-4b82-a23e-fb7403274234 1019 | # ╠═4f563136-fc7b-4322-92ba-78c0183c40cc 1020 | # ╠═f93da14a-e4c8-4c28-ab01-4a5ba1a3cf47 1021 | # ╠═41ab51f9-0b33-4548-b08a-ad1ef7d38f1b 1022 | # ╟─b0006e61-b037-41ed-a3e4-9962d15584c4 1023 | # ╠═c2ee20be-16f5-47a8-851a-67a361bb0316 1024 | # ╠═06edb2d7-325f-4f80-8c55-dc01c7783054 1025 | # ╟─f2fbcc70-a714-4eda-8786-7ee5692e3268 1026 | # ╟─57fd383b-d791-4170-a353-f839356f9d7a 1027 | # ╟─05f735e0-01cc-4276-a3f9-8420296e68be 1028 | # ╠═d8e9b950-6e71-40e2-bac1-c3ba85bc83ee 1029 | # ╟─1a303aa4-bed5-4d9b-855c-23355f4a88fe 1030 | # ╠═834294ff-9441-4e71-b5c0-edaf32d860ee 1031 | # ╠═1be06e4b-6072-46c3-a63d-aa95e51c43b4 1032 | # ╠═9845db00-149c-45be-9e4f-55d1157afc87 1033 | # ╟─eef54261-767a-4ce4-b549-0b1828379f7e 1034 | # ╟─cda8689d-9ae5-42c4-8e7e-715cf44c33bb 1035 | # ╟─4013400c-acb4-40fa-a826-fd0cbae09e7e 1036 | # ╟─5b325b50-8984-44c6-8677-3c6bc5c2b0b1 1037 | # ╟─70fa9af8-31f9-4e47-b36b-828c88166b3d 1038 | # ╠═d17c96fb-8459-4527-a139-05fdf74cdc39 1039 | # ╠═9268f35e-1a4e-414e-a7ea-3f5796e0bbf3 1040 | # ╠═e0a25f24-a7de-4eac-9f88-cb7632de09eb 1041 | --------------------------------------------------------------------------------