Page abstraction
All checks were successful
CI / Check typos (push) Successful in 10s
CI / Check links (push) Successful in 34s
CI / Clippy (push) Successful in 41s
CI / Build and test (push) Successful in 2m4s
CI / Build container (push) Successful in 3m15s

This commit is contained in:
2025-11-04 08:55:14 -08:00
parent acc057e4cb
commit 4504a88f4b
20 changed files with 522 additions and 233 deletions

View File

@@ -0,0 +1,57 @@
use assetserver::Asset;
use maud::html;
use crate::{
components::{md::Markdown, misc::Backlinks},
page::{Page, PageMetadata},
routes::assets::{Image_Betalupi, Image_Icon},
};
pub fn page() -> Page {
Page {
meta: PageMetadata {
title: "What's a \"betalupi?\"".into(),
author: Some("Mark".into()),
description: None,
image: Some(Image_Icon::URL.into()),
},
generate_html: Box::new(|_page| {
html! {
(Backlinks(&[("/", "home")], "whats-a-betalupi"))
(Markdown(MD))
img alt="betalupi map" class="image" src=(Image_Betalupi::URL) {}
}
}),
..Default::default()
}
}
const MD: &str = r#"[es]: https://github.com/endless-sky/endless-sky
[*Stellaris*]: https://www.paradoxinteractive.com/games/stellaris/about
[Arabic]: https://en.wikipedia.org/wiki/List_of_Arabic_star_names
[wiki-betalupi]: https://en.wikipedia.org/wiki/Beta_Lupi
# What's a "betalupi?"
Beta Lupi is a solar system on the [_Endless Sky_][es] galaxy map,
which is the first place I look whenever I need to name a server.
Stellar names (especially those of [Arabic] origin) make pretty good hostnames: they're meaningless (in English), they sound interesting, and the "hyperlanes" that connect them in titles like [_Endless Sky_][es] and [*Stellaris*] look a lot like a network topology.
Beta Lupi also happens to be a real star in the southern constellation of Lupus ([wiki][wiki-betalupi]), but that's not particularly important.
A snippet of the [_Endless Sky_][es] map is below.
<br/>
**In other words:** Try finding a `.com` domain that...
- Isn't already taken
- Doesn't sound awful
- Isn't owned by a scalper that's selling it for $300"
<br/>
"#;

View File

@@ -0,0 +1,254 @@
use assetserver::Asset;
use maud::html;
use crate::{
components::{md::Markdown, misc::Backlinks},
page::{Page, PageMetadata},
routes::assets::Image_Icon,
};
pub fn page() -> Page {
Page {
meta: PageMetadata {
title: "Mark's Handouts".into(),
author: Some("Mark".into()),
description: None,
image: Some(Image_Icon::URL.into()),
},
generate_html: Box::new(|_page| {
html! {
(Backlinks(&[("/", "home")], "handouts"))
(Markdown(MD_A))
}
}),
..Default::default()
}
}
const MD_A: &str = r#"# Mark's Handouts
[ORMC]: https://circles.math.ucla.edu/circles
This page lists all the handouts I've written for my classes at the [ORMC],
arguably the best math circle in the western world. We teach students mathematics
far beyond the regular school curriculum, much like [AOPS](https://artofproblemsolving.com)
and the [BMC](https://mathcircle.berkeley.edu).
<br></br>
{style(color_var:pink) For my students: } \
Don't look at solutions we haven't discussed,
and don't start any handouts before class. That spoils all the fun!
{style(color_var:green) For everyone else:} \
If you're using any of these, please let me know---especially \
if you find errors, mistakes, or a poorly designed section. \
Such things must be fixed! { include(email_beta) }
<br></br>
## Overview & Context
Our classes are two hours long, with a ten-minute break in between. The lessons below
are written with this in mind.\
I do not expect the average student to finish all problems during this two-hour session.
If the class finishes early, the lesson is either too short or too easy.
<br></br>
<hr></hr>
<br></br>
## Warm-Ups
Students never show up on time. Some come early, some come late. Warm-ups
are my solution to this problem: we hand these out as students walk in,
giving them something to do until we can start the lesson.
<ul id="handout-ul-Warm-Ups" class="handout-ul"></ul>
<script>
fetch("https://git.betalupi.com/api/packages/Mark/generic/ormc-handouts/latest/index.json")
.then(res => res.json())
.then(out => {
out = out.sort((a, b) => (
a["title"].toLowerCase() < b["title"].toLowerCase()
));
out.forEach(element => {
if (element["group"] != "Warm-Ups") { return }
// Handout title
const title = document.createElement("span");
const title_a = document.createElement("strong");
title_a.appendChild(document.createTextNode(element["title"] + " "));
title.appendChild(title_a)
title.classList.add("handout-li-title");
// Handout title
const desc = document.createElement("span");
desc.appendChild(document.createTextNode(element["description"]));
desc.classList.add("handout-li-desc");
const handout_link = element["handout"];
const solutions_link = element["solutions"];
const links = document.createElement("span");
links.classList.add("handout-li-links");
const h = document.createElement("a");
h.appendChild(document.createTextNode("handout"))
h.href = handout_link;
if (solutions_link === null) {
links.appendChild(document.createTextNode("[ "));
links.appendChild(h);
links.appendChild(document.createTextNode(" ]"));
} else {
var s = document.createElement("a");
s.appendChild(document.createTextNode("solutions"))
s.href = solutions_link;
links.appendChild(document.createTextNode("[ "));
links.appendChild(h);
links.appendChild(document.createTextNode(" | "));
links.appendChild(s);
links.appendChild(document.createTextNode(" ]"));
}
// Add to main list
const item = document.createElement("li");
item.appendChild(title)
item.appendChild(links);
//item.appendChild(desc)
const list = document.getElementById("handout-ul-Warm-Ups");
list.insertBefore(item, list.children[0]);
})}
)
.catch(err => {
// Print fallback link if we failed to load json index
console.log(err)
const title = document.createElement("span");
const title_a = document.createElement("strong");
title_a.appendChild(document.createTextNode("Error: "));
title.appendChild(title_a)
title.appendChild(document.createTextNode("failed to load handouts, something broke."))
title.classList.add("handout-li-title");
const fallback = "https://git.betalupi.com/Mark/-/packages/generic/ormc-handouts/latest";
const link = document.createElement("a");
link.href = fallback
link.appendChild(document.createTextNode("ormc-handouts"));
const item_a = document.createElement("li");
item_a.appendChild(title)
const item_b = document.createElement("li");
item_b.appendChild(document.createTextNode("Fallback link: "))
item_b.appendChild(link)
const list = document.getElementById("handout-ul-Warm-Ups");
list.insertBefore(item_b, list.children[0]);
list.insertBefore(item_a, list.children[0]);
});
</script>
## Advanced
The highest level of the ORMC, and the group I spend most of my time with.
Students in ORMC Advanced are in high school, which means
they're ~14-18 years old.
<ul id="handout-ul-Advanced" class="handout-ul"></ul>
<script>
fetch("https://git.betalupi.com/api/packages/Mark/generic/ormc-handouts/latest/index.json")
.then(res => res.json())
.then(out => {
out = out.sort((a, b) => (
a["title"].toLowerCase() < b["title"].toLowerCase()
));
out.forEach(element => {
if (element["group"] != "Advanced") { return }
// Handout title
const title = document.createElement("span");
const title_a = document.createElement("strong");
title_a.appendChild(document.createTextNode(element["title"] + " "));
title.appendChild(title_a)
title.classList.add("handout-li-title");
// Handout title
const desc = document.createElement("span");
desc.appendChild(document.createTextNode(element["description"]));
desc.classList.add("handout-li-desc");
const handout_link = element["handout"];
const solutions_link = element["solutions"];
const links = document.createElement("span");
links.classList.add("handout-li-links");
const h = document.createElement("a");
h.appendChild(document.createTextNode("handout"))
h.href = handout_link;
if (solutions_link === null) {
links.appendChild(document.createTextNode("[ "));
links.appendChild(h);
links.appendChild(document.createTextNode(" ]"));
} else {
var s = document.createElement("a");
s.appendChild(document.createTextNode("solutions"))
s.href = solutions_link;
links.appendChild(document.createTextNode("[ "));
links.appendChild(h);
links.appendChild(document.createTextNode(" | "));
links.appendChild(s);
links.appendChild(document.createTextNode(" ]"));
}
// Add to main list
const item = document.createElement("li");
item.appendChild(title)
item.appendChild(links);
//item.appendChild(desc)
const list = document.getElementById("handout-ul-Advanced");
list.insertBefore(item, list.children[0]);
})}
)
.catch(err => {
// Print fallback link if we failed to load json index
console.log(err)
const title = document.createElement("span");
const title_a = document.createElement("strong");
title_a.appendChild(document.createTextNode("Error: "));
title.appendChild(title_a)
title.appendChild(document.createTextNode("failed to load handouts, something broke."))
title.classList.add("handout-li-title");
const fallback = "https://git.betalupi.com/Mark/-/packages/generic/ormc-handouts/latest";
const link = document.createElement("a");
link.href = fallback
link.appendChild(document.createTextNode("ormc-handouts"));
const item_a = document.createElement("li");
item_a.appendChild(title)
const item_b = document.createElement("li");
item_b.appendChild(document.createTextNode("Fallback link: "))
item_b.appendChild(link)
const list = document.getElementById("handout-ul-Advanced");
list.insertBefore(item_b, list.children[0]);
list.insertBefore(item_a, list.children[0]);
});
</script>
"#;

View File

@@ -0,0 +1,45 @@
Also see [what's a "betalupi?"](/whats-a-betalupi)
## Pages
- [Handouts](/handouts): Math circle lessons I've written
- [Links](/links): Interesting parts of the internet
<hr style="margin-top: 8rem; margin-bottom: 8rem"/>
## Projects
- **RedoxOS**, a general-purpose, microkernel-based operating system written in Rust. _{ style(color_var:grey) [enthusiast] }_
- { style(color_var:grey) Status: } { style(color_var:yellow) Passive. }
- { style(color_var:grey) Website: } [:fa-link: redox-os.org](https://www.redox-os.org/)
<br/>
- **Tectonic**, the LaTeX engine that is pleasant to use.
Experimental, but fully functional. _{ style(color_var:grey) [co-maintainer] }_
- { style(color_var:grey) Status: } { style(color_var:yellow) Passive. } [Typst](https://github.com/typst/typst) is better.
- { style(color_var:grey) Main repo: } [:fa-github: Tectonic](https://github.com/tectonic-typesetting/tectonic)
- { style(color_var:grey) Bundle tools: } [:fa-github: tectonic-texlive-bundles](https://github.com/tectonic-typesetting/tectonic-texlive-bundles)
<br/>
- **Daisy**, a pretty TUI scientific calculator. _{style(color_var:grey) [author] }_
- {style(color_var:grey) Status: } {style(color_var:orange) Done. } Used this to learn Rust. [Numbat](https://numbat.dev) is better.
- {style(color_var:grey) Repository: } [:fa-github: rm-dr/daisy](https://github.com/rm-dr/daisy)
- {style(color_var:grey) Website: } [:fa-link: daisy.betalupi.com](https://daisy.betalupi.com) (WASM demo)
<br/>
- **Lamb**, a lambda calculus engine. _{style(color_var:grey) [author] }_
- {style(color_var:grey) Status: } {style(color_var:orange) Done. } Fun little project.
- {style(color_var:grey) Repository: } [:fa-github: rm-dr/lamb](https://github.com/rm-dr/lamb)
- {style(color_var:grey) PyPi: } [:fa-python: lamb-engine](https://pypi.org/project/lamb-engine)
<br/>

View File

@@ -0,0 +1,75 @@
use assetserver::Asset;
use maud::html;
use crate::{
components::{
fa::FAIcon,
mangle::{MangledBetaEmail, MangledGoogleEmail},
md::Markdown,
misc::FarLink,
},
page::{Page, PageMetadata},
routes::assets::{Image_Cover, Image_Icon},
};
pub fn page() -> Page {
Page {
meta: PageMetadata {
title: "Betalupi: About".into(),
author: Some("Mark".into()),
description: Some("Description".into()),
image: Some(Image_Icon::URL.into()),
},
generate_html: Box::new(move |_page| {
html! {
h2 id="about" { "About" }
div {
img
src=(Image_Cover::URL)
style="float:left;margin:10px 10px 10px 10px;display:block;width:25%;"
{}
div style="margin:2ex 1ex 2ex 1ex;display:inline-block;overflow:hidden;width:60%;" {
"Welcome, you've reached Mark's main page. Here you'll find"
" links to various projects I've worked on."
ul {
li { (MangledBetaEmail {}) }
li { (MangledGoogleEmail {}) }
li {
(
FarLink(
"https://github.com/rm-dr",
html!(
(FAIcon::Github)
"rm-dr"
)
)
)
}
li {
(
FarLink(
"https://git.betalupi.com",
html!(
(FAIcon::Git)
"git.betalupi.com"
)
)
)
}
}
}
br style="clear:both;" {}
}
(Markdown(include_str!("index.md")))
}
}),
..Default::default()
}
}

View File

@@ -0,0 +1,126 @@
# Bookmarks
This is a heavily opinionated bookmarks toolbar.
<hr style="margin-top: 8rem; margin-bottom: 8rem"></hr>
## Podcasts
- :star: [Darknet Diaries](https://darknetdiaries.com/): A perennial classic.
- [Art of Manliness](https://www.artofmanliness.com/podcast/): Philosophy, literaure, psychology.
- [The Overanalyzers](https://www.theoveranalyzers.com/): Amateur podcasters talk amateur psychology. This is a complement---they're _very_ good!
- [Rust in Production](https://corrode.dev/podcast/): Operations, Rust, and modern tech.
- :star: [On the Metal](https://onthemetal.transistor.fm/): Quality stories from quality engineers.
- [Security Cryptography Whatever](https://securitycryptographywhatever.com/): Modern cryptography, for those who understand the underlying theory.
## Essays
- [Real Programmers don't use Pascal](https://www.ee.torontomu.ca/~elf/hack/realmen.html)
- [A Mathematician's Lament](/files/lockhart.pdf)
- :star: [The Jargon File](http://www.catb.org/jargon/)
## Textbooks
- :star: [OpenLogic](https://openlogicproject.org/): The gold standard
- [Operating Systems: from 0 to 1](https://github.com/tuhdo/os01)
- [Operating Systems: Three Easy Pieces](https://pages.cs.wisc.edu/~remzi/OSTEP/)
- [Crafting Interpreters](https://craftinginterpreters.com/contents.html)
- [An Introduction to Mathematical Cryptography](https://link.springer.com/book/10.1007/978-0-387-77993-5)
- [Stories about Maxima and Minima](https://archive.org/details/storiesaboutmaxi0000tikh)
## Miscellanea
- [Hackaday](https://hackaday.com/)
- [Grumpy Website](https://grumpy.website/): Daily design crimes
- :star: [ZSA Voyager](https://www.zsa.io/voyager): World's best keyboard
- [Nikita Prokopov](https://tonsky.me/)
- [Faster Than Lime](https://fasterthanli.me/)
- [Pepper & Carrot](https://www.peppercarrot.com/): The open-source webcomic
- [User Friendly](https://en.wikipedia.org/wiki/User_Friendly): Old-school. Offline and archived.
- [PhD Comics](https://phdcomics.com/): Quality academic humor. Discontinued.
- :star: [Spintronics](https://store.upperstory.com/collections/spintronics/products/spintronics-act-one): Mechanical circuits. Very clever toy.
- :star: [Turing Tumble](https://store.upperstory.com/collections/turing-tumble-game/products/turing-tumble): Modern Dr. Nim
<hr style="margin-top: 8rem; margin-bottom: 8rem"></hr>
## Tools
- :star: [Numbat](https://numbat.dev/)
- [MxToolbox](https://mxtoolbox.com/)
- [Brainfuck Interpreter](https://copy.sh/brainfuck/)
- [Compiler Explorer](https://godbolt.org/)
- [Monkeytype](https://monkeytype.com/)
- :star: [TLDR](https://tldr.sh/)
- [TOS;DR](https://tosdr.org/)
- [Regexr](https://regexr.com/)
- [Choose a License](https://choosealicense.com/)
- [DeepL](https://www.deepl.com/translator)
- [ShuffleCake](https://shufflecake.net/)
- [Zola](https://www.getzola.org/): Static site generator
- [Presenterm](https://github.com/mfontanini/presenterm)
- [mprocs](https://github.com/pvolok/mprocs): Simpler tmux
- [mask](https://github.com/jacobdeichert/mask)
- [gitui](https://github.com/gitui-org/gitui): git tui
- [tokei](https://github.com/XAMPPRocky/tokei): count lines of code
- [delta](https://github.com/dandavison/delta): pretty pager for diffs
- [dust](https://github.com/dandavison/delta): `du`, but better
## Math Resources
- [Quantum Quest](https://www.quantum-quest.org/)
- [The Natural Number Game](https://www.ma.imperial.ac.uk/~buzzard/xena/natural_number_game/)
- [Intro to Lambda Calculus](https://www.driverlesscrocodile.com/technology/lambda-calculus-for-people-a-step-behind-me-1/)
- [FSM Simulator](https://ivanzuzak.info/noam/webapps/fsm_simulator/)
- [Euclidea](https://www.euclidea.xyz/)
- [Problems.ru](https://problems.ru/)
## OS Dev Resources
- [OS Dev Wiki](https://wiki.osdev.org/Expanded_Main_Page)
- [Nand2Tetris](https://www.nand2tetris.org/course)
- :star: [Writing an OS in Rust](https://os.phil-opp.com/)
- [x86 Assembly Guide](https://www.cs.virginia.edu/~evans/cs216/guides/x86.html)
- [Writing a simple x86 Bootloader](https://www.alanfoster.me/posts/writing-a-bootloader/)
- [FDC Programming](http://www.brokenthorn.com/Resources/OSDev20.html)
- [CS77 at Bristol College](http://www.c-jump.com/CIS77/CIS77syllabus.htm)
## Misc Resources
- [Learn OpenGL](https://learnopengl.com/)
- [Learn WGPU](https://sotrh.github.io/learn-wgpu)
- [WGPU Fundamentals](https://webgpufundamentals.org/)
- [Acko](https://acko.net/)
- [Bezier Info](https://pomax.github.io/bezierinfo/)
- [SHA256 Algorithm](https://sha256algorithm.com/)
- [ML Playground](https://ml-playground.com/)
- [Learn you some Erlang](https://learnyousomeerlang.com/)
- [Learn you a Haskell](https://learnyouahaskell.github.io/)
- [Teach yourself CS](https://teachyourselfcs.com/)
- [The Architecture of Open Source Applications](http://aosabook.org/en/index.html)
- [wtfjs](https://github.com/denysdovhan/wtfjs): js [wat](https://www.destroyallsoftware.com/talks/wat)s
## Reference
- [DevHints](https://devhints.io/)
- [OverAPI](https://overapi.com/)
- [TSConfig Cheat Sheet](https://www.totaltypescript.com/tsconfig-cheat-sheet)
- [Makefile Tutorial](https://makefiletutorial.com/)
- [The Pinouts Book](https://pinouts.org/)
- [Laws of UX](https://lawsofux.com/)
## Rust
- [Understanding Memory Ordering in Rust](https://emschwartz.me/understanding-memory-ordering-in-rust/)
- [Unfair Rust Quiz](https://this.quiz.is.fckn.gay/): wtfjs, but in Rust.
<hr style="margin-top: 8rem; margin-bottom: 8rem"></hr>
## Misc
- [Slide Rule Collection](https://www.followingtherules.info/)
- [MK-61 Command Reference](http://www.thimet.de/CalcCollection/Calculators/Elektronika-MK-61/CmdRef.html)
- [Why Privacy Matters](https://www.ted.com/talks/glenn_greenwald_why_privacy_matters)
- [Papers we Love](https://paperswelove.org/)
- [Grug Brain Dev](https://grugbrain.dev/)
- [Zen of Python](https://peps.python.org/pep-0020/)
- [The XY Problem](https://xyproblem.info/)

View File

@@ -0,0 +1,35 @@
use assetserver::Asset;
use maud::html;
use crate::{
components::{md::Markdown, misc::Backlinks},
page::{Page, PageMetadata},
routes::assets::Image_Icon,
};
pub fn page() -> Page {
Page {
meta: PageMetadata {
title: "Links".into(),
author: Some("Mark".into()),
description: None,
image: Some(Image_Icon::URL.into()),
},
generate_html: Box::new(|_page| {
html! {
(Backlinks(&[("/", "home")], "links"))
(Markdown(include_str!("links.md")))
}
}),
..Default::default()
}
}
/*
Dead links:
https://www.commitstrip.com/en/
http://www.3dprintmath.com/
*/

View File

@@ -0,0 +1,4 @@
pub mod betalupi;
pub mod handouts;
pub mod index;
pub mod links;