site

files for beauhilton.com
git clone https://git.beauhilton.com/site.git
Log | Files | Refs

commit 5a4b9d42e275e1afa3ab32dd7796748c637b89e5
parent bfd3ecaa0d8d0c481db0a844ea9e999a1337f1c4
Author: Beau <cbeauhilton@gmail.com>
Date:   Tue, 30 Apr 2024 13:41:50 -0500

update

Diffstat:
M.gitignore | 1-
Abuild/about/index.html | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/atom.xml | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/camplist/index.html | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/church/luke-15-11-32/index.html | 306+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/colophon/index.html | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/contact/index.html | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/feed.xml | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/gifs/index.html | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/images/cashapp.png | 0
Abuild/images/gifs/bueller-ferrari-crash.gif | 0
Abuild/images/gifs/jimi.gif | 0
Abuild/images/gifs/mr-bean-cupcake-double-take.gif | 0
Abuild/images/gifs/mr-bean-cupcake.gif | 0
Abuild/images/gifs/soul-train.gif | 0
Abuild/images/hatchimals-glow-in-the-dark.jpg | 0
Abuild/images/ncmpcpp-mopidy-full.png | 0
Abuild/images/ncmpcpp-mopidy-selector.png | 0
Abuild/images/ncmpcpp-mopidy-tracks.png | 0
Abuild/images/s1-cape-hfs.jpg | 0
Abuild/images/s1-is.png | 0
Abuild/images/stuffy_pterodactyl.jpg | 0
Abuild/images/venmo.jpg | 0
Abuild/images/yt-dlp-downloading-example.png | 0
Abuild/images/yt-dlp-filename-example.jpg | 0
Abuild/index.html | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/liesel/index.html | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/now/index.html | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/pay/index.html | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/add-zfs-mirror/index.html | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/cad-fish/index.html | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/choaked/index.html | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/claude-notes/index.html | 448+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/employee-wifi/index.html | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/geocheatcode/index.html | 244+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/history-egc/index.html | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/index.html | 340+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/intake-2022-03-25/index.html | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/medical-humanities-org/index.html | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/mime/index.html | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/mr-2021/index.html | 420+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/oo-et-al/index.html | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/pagecrypt/index.html | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/pixel6screen/index.html | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/pp-tech-infra/index.html | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/rmd-py/index.html | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/s1/index.html | 316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/subsonic-cli/index.html | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/thanks/index.html | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/ugbsd/index.html | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/posts/yt-dlp/index.html | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/style.css | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/template/index.html | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/thanks/index.html | 209+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/twix/index.html | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/uses/index.html | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/wants/index.html | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/wip/abstracts/index.html | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/wip/template/index.html | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
59 files changed, 8299 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,4 +1,3 @@ -build/ .devenv/* .soupault-cache nohup.out diff --git a/build/about/index.html b/build/about/index.html @@ -0,0 +1,317 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a class="nav-active" href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h2> + husband and father + </h2> + <p> + Talented, beautiful people surround me. The <a href="/now">now +page</a> usually has the most current updates in this arena. + </p> + <h2> + physician + </h2> + <p> + Oncology fellow, Vanderbilt 2022-2025.<br> +Internal medicine resident, Vanderbilt 2020-2022.<br> +Medical school, Cleveland Clinic Lerner College of Medicine of Case +Western Reserve University 2015-2020. + </p> + <p> + I enjoy treating people with any cancer, but have a particular +affinity for head-and-neck and upper GI cancers (together, 2/3 of the +“aerodigestive” cancers, the other 1/3 being lung). There are many right +ways to be a doctor, but the way I understand my role is this: to be +with people in their suffering and their joy (suffering is everywhere, +but there is a special joy known only in the oncology clinic), to see +and know the soul within the body (whatever the tumor or the scalpel or +the radiation beam or the drug has done to that body), to cure when I +can (and deal with the fallout from that cure), and help always (to the +end and beyond). + </p> + <p> + There are glimmers of hope and serious advances in recent years, but +these remain horrible diseases, many of which have few treatment options +once they’ve reached an advanced stage, and the treatments we do have +tend to be quite difficult to tolerate. Most cancers can be disfiguring, +but these especially so, whether from the tumors themselves or from the +therapies. Aerodigestive cancers also disproportionately affect folks +who live out in the country, or in the cities but with few resources, +and these folks are my folks. + </p> + <p> + We need to help each other, and there is much to do. + </p> + <h2> + educator + </h2> + <p> + Harvard Macy Institute faculty, 2018-2020. Health Care Education +2.0. + </p> + <p> + <a href="https://vimbook.org">https://vimbook.org</a>, +2020-present.<br> +The Vanderbilt Internal Medicine Handbook was started by Mike Neuss, +MD/PhD in the late 2010s when he was a resident. It’s an incredible +resource, primarily envisioned as a physical book to keep in your white +coat pocket for quick, authoritative reference. It had a website when I +came to Vandy, but the UX… left something to be desired. I rebuilt it +into its current state (website and infrastructure only - each section +has its own author(s)), and help maintain the back end. + </p> + <p> + Chase Webber is the faculty support, and has been amazing. + </p> + <p> + It’s used globally, and one of my goals is to make it easier for +smaller, particularly international programs to have their own versions. +It uses only free and open-source software, and fits comfortably into +pretty much any free server despite being a fairly large book with +multimedia. + </p> + <p> + The main problem is that updating the content, while it is just in +Markdown (a very simple text format you can learn in ~7 minutes), feels +a little too tech-y to be comfortable for people who haven’t spent time +in a code text editor. What it really needs is funding, and a part-time +developer with protected time. + </p> + <h2> + data scientist + </h2> + <p> + <a href="https://scholar.google.com/citations?user=Ng5AgXAAAAAJ">Google +Scholar profile</a> + </p> + <p> + <em>If you are interested data science consulting, <a href="/contact">contact me</a>. Current rate is listed at that +link.</em> + </p> + <p> + <em>Major projects are listed below in reverse chronological order +(roughly), newest projects at the top.</em> + </p> + <h3> + overview + </h3> + <p> + My work has morphed over the years, as everyone’s does, but the +consistent thread and drive throughout has been on coaxing large, messy, +complex data to tell us a story about ourselves, about all of us as +societies and neighborhoods as well as each one of us individually, to +empower us to speak our own sequels. + </p> + <p> + To translate that into buzzwords, for your bingo game: I’m an +oncologist who uses explainable artificial intelligence among other +techniques to diagnose and address healthcare disparities, including +democratizing personalized medicine and pursuing synergies in the global +academic-industrial complex. + </p> + <p> + I was trained as an anthropologist, where reductionism is an insult, +at the same time that I was trained as a scientist, where reductionism +is the central conceit. Despite the way I set up that last sentence, +there is no true conflict, as the goal for most scientists and +anthropologists is the same: to make things at least a little better for +someone, but hopefully a lot better for everyone. Modern anthropology is +inherently activist, far from the crusty sepia-toned image of a staid +researcher sitting just outside the village campfire furiously +scribbling in a notebook, and so is modern medical research (we all read +Tuskegee and are appalled and want to do better, though precious few +become <a href="https://en.wikipedia.org/wiki/Paul_Farmer">Paul +Farmer</a>). + </p> + <p> + Data science was an unexpected boon, a set of tools that lets me deal +with staggering complexity in a disciplined way, to a degree unifying +the anthropologist’s drive to let the data be itself (messy, human) with +the scientist’s drive to simplify. + </p> + <p> + I became acquainted with using code to model the world when I was +doing physics research (equivalent circuit modeling and scanning laser +doppler vibrometry on a Nigerian-style clay pot drum, total hoot, I <a href="https://doi.org/10.1121/1.3654998">presented</a> it at the +Acoustical Society of America Annual Meeting and we published it in <a href="https://doi.org/10.1121/1.4789892">JASA</a>), and the +research-centric medical school at Cleveland Clinic gave me the better +part of five years and a supportive environment to dive in deeper to +computer science, machine learning, etc. + </p> + <p> + Now that have the freedom to choose my own direction, data science +projects that were informed by anthropology but had centroids in other +disciplines have become squarely within the overlap of my personal Venn +diagram. + </p> + <p> + Additionally, as I have moved from academia to the worlds of private +practice and industry, I am increasingly inspired toward using these +interests to hit cancer where it needs it the most: in the clinic of the +community oncologist, where the vast majority of cancer patients receive +care, by bringing timely insights from every relevant axis to bear on +every visit. + </p> + <p> + <a href="https://en.wikipedia.org/wiki/Information_wants_to_be_free">Information +almost wants to be free</a>, and there is now so much of it, that a lot +can be done for free or at a low cost. (I’m take special glee in +byproducts, “digital waste,” some say, but there is gold in them there +hills - <a href="https://en.wikipedia.org/wiki/Shigeru_Ban">Shigeru +Ban</a> is my hero). There are abstracts from conferences aplenty +describing the cutting edge of everything, usually seen as jots and +tiddles on the march of science forward but forgotten when the journal +article gets published, and lab values and imaging results and clinic +notes generated in the usual course of patient care, used once or a few +times and then forgotten and discarded in the wake of what comes next - +in all of this digital refuse I believe there are insights to be gained, +efficiencies to be achieved, lives to be saved. + </p> + <hr> + <h3> + disparities in cancer research across space and time + </h3> + <p> + This ongoing project starts with a custom metadata archive of all the +abstracts from the two big annual cancer meetings (ASH and ASCO - as a +starting point), made machine-readable and hence more easily accessible +en masse. Here’s a <a href="https://ash-abstracts.vercel.app/abstracts_small/abstracts">rough +prelim</a> of what that looks like, with an interactive map and +sorting/search/export (you can hit JSON or CSV endpoints trivially to +get nicely formatted data, as opposed to the hulking web scrapers and +HTML wranglers I wrote to get the data the first time). Analyses are +planned on the authors and affiliations (global mapping, with a time +component), and how those overlap with disease states (e.g. how much +sickle cell research comes out of Sub-Saharan Africa? We know it’s bad, +but nobody has quantified how bad - the idea is to have a platform for +answering these questions easily), before branching out into things like +conflicts of interest and various analyses using NLP, etc. + </p> + <hr> + <h3> + Cleveland Clinic Center for Clinical Artificial Intelligence + </h3> + <h3> + explainable machine learning for readmissions, with a focus on +sociodemographics + </h3> + <p> + While at Cleveland Clinic, I was one of the founding members of the +Center for Clinical Artificial Intelligence, and its first dedicated +analyst. We had the delightful opportunity to work with a rich dataset +from one of the world’s largest hospitals, focused on predicting the +risk of readmission (discharging from the hospital and “bouncing back” +too soon) and extended length of stay. We had access to not only health +data, but socioeconomic data, for millions of patients, and I further +enriched this with census data. + </p> + <p> + With only an address and a date, one can learn about a person’s +neighborhood in incredible detail (though not the person themselves - +the US Census is wise about privacy in the data they publish). It turns +out that a person’s neighborhood is a major predictor in their health +outcomes, as is their insurance provider, in addition to a host of +health parameters and hospital process clues. + </p> + <p> + I used interpretable machine learning techniques, with a focus on +revealing actionable items that the patients and medical teams could +hope to influence, as well as to call out structural issues that +organizations and governments need to know. One of the problems with +machine learning is that it can only ever restate (and in some cases, as +it feeds back on itself, more firmly entrench) the biases that led to +the historical data you fed to it. If you design it to show you these +biases, show you <em>all</em> of its biases, explicitly, to tell you +exactly how much a person’s race, ethnicity, gender, and neighborhood +played a role in its predictions (alongside medical diagnoses and lab +values), you have transformed an algorithm from a potentially +destructive tool, a heinous thing that pushes hurting people farther +down, into a tool for positive change. If these biases are shown in an +easy-to-read visual, that patients, clinicians, and administrators can +all understand, all the better. See what it looks like <a href="https://doi.org/10.1038/s41746-020-0249-z">here</a>. + </p> + <hr> + <h3> + Cleveland Clinic Taussig Cancer Institute + </h3> + <h3> + explainable machine learning for blood cancer diagnostics + </h3> + <p> + Initially, when I was going to be a malignant hematologist (I still +think it is a beautiful field, but was drawn away to other pastures), I +wanted to level the playing field for advanced diagnostics. + </p> + <p> + A world-class hematopathologist together with a world-class +clinician, preferably a whole group of these together, are required to +make certain diagnoses, and these only after at least one invasive +biopsy. What if we could mobilize the rich genetic and phenotypic data +available in simple blood samples and from the electronic medical record +to support diagnostics, and, eventually, democratize them? Further, what +if the answer the machine gives could be not only accurate, but +interpretable? + </p> + <p> + What if we could get the machine to explain itself and its reasoning, +both as a check against biological implausibility (and more insidious +problems such as systemic racism), and to reveal more areas for +research? What if a high resolution bone marrow biopsy image could be +read in moments by a smart phone in rural +Arkansas/Kandahar/Mogadishu/Kushalnagar/etc., instead of having to be +shipped to one of a handful of academic centers while the patient waits, +still sick, for an answer? + </p> + <p> + We made <a href="https://doi.org/10.1182/blood-2019-126967">some</a> +<a href="https://doi.org/10.1182/bloodadvances.2021004755">progress</a>, +but these problems remain largely unsolved. + </p> + <hr> + <h2> + internal links + </h2> + <p> + If you want to know which tools I use, visit <a href="/uses">/uses</a>. + </p> + <p> + If you are interested in the tech stack for this website, visit <a href="/colophon">/colophon</a>. + </p> + <p> + If you would like to throw money at me, for whatever reason, visit <a href="/pay">/pay</a>. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/atom.xml b/build/atom.xml @@ -0,0 +1,263 @@ +<?xml version='1.0' encoding='UTF-8'?> +<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> + <id>https://beauhilton.com/atom.xml</id> + <title>beauhilton</title> + <updated>2024-04-12T00:00:00+00:00</updated> + <author> + <name>beau hilton</name> + <email>beau@beauhilton.com</email> + </author> + <generator uri="https://soupault.app" version="4.8.0">soupault</generator> + <subtitle>beau's website</subtitle> + <entry> + <id>https://beauhilton.com/posts/choaked</id> + <title>The first detailed description of living with esophageal cancer - +John Casaubon’s 1690 diary</title> + <updated>2024-04-12T00:00:00+00:00</updated> + <content type="html"> + John Casaubon was an English surgeon in the late 1600s +who developed an esophageal tumor in late 1690 +and wrote about it in his diary +before dying in January of 1691. +It's harrowing, enlightening, and strangely beautiful. +This blog post is the only place in the world you can read the full transcription of the diary entry. + </content> + <link href="https://beauhilton.com/posts/choaked" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/claude-notes</id> + <title>Writing clinical notes using AI - a practical experience</title> + <updated>2024-04-09T00:00:00+00:00</updated> + <content type="html"> + With Claude 3 Opus (a newish ChatGPT4 competitor) as my copilot, I wrote a pretty darn good SOAP note + for an (invented yet realistic) new consult visit. It took a little massaging to get it right, + but boy howdy, it did a great job. Here are the prompts and outputs. + This stuff has serious potential for streamlining the boring and tedious parts of the job. + </content> + <link href="https://beauhilton.com/posts/claude-notes" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/s1</id> + <title>Drugs we can’t get: S1</title> + <updated>2024-03-29T00:00:00+00:00</updated> + <content type="html"> + There are a number of interesting drugs used in the global market that, + for one reason or another, do not have FDA approval and are therefore inaccessible + in the US, at least outside of clinical trials. S1 is one of them: a better capecitabine. + </content> + <link href="https://beauhilton.com/posts/s1" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pp-tech-infra</id> + <title>Patient-facing slide decks</title> + <updated>2024-03-23T00:00:00+00:00</updated> + <content type="html"> + While I plan on being a physician-scientist forever, I'm not going to work in academia. +Over the past few years I've put together very cool infrastructure for giving academic talks (click "talks" above), +and it was making me sad that it might not get much use after I leave the university. +But then, a ray of sunshine: Why not use my slide deck infrastructure to help in patient conversations? + </content> + <link href="https://beauhilton.com/posts/pp-tech-infra" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/cad-fish</id> + <title>Cold agglutinin disease: fish out of water?</title> + <updated>2024-03-22T00:00:00+00:00</updated> + <content type="html"> + Cold agglutinin disease is a fascinating and strange phenomenon, and might happen because we're fish. + </content> + <link href="https://beauhilton.com/posts/cad-fish" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/history-egc</id> + <title>A timeline of esophageal cancer</title> + <updated>2023-10-20T00:00:00+00:00</updated> + <content type="html"> + A couple of friends and I wrote a review article on the history of esophageal cancer. +The timeline was so interesting I thought I'd share it here, in a place where it can be easily found and updated. + </content> + <link href="https://beauhilton.com/posts/history-egc" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/add-zfs-mirror</id> + <title>How to add a mirror to a single ZFS disk</title> + <updated>2023-10-19T00:00:00+00:00</updated> + <content type="html"> + tl;dr: <code>zpool attach data /dev/disk/by-partlabel/zfs-3a1xx /dev/sdx0</code>. Adjust for your own pool and disks. + </content> + <link href="https://beauhilton.com/posts/add-zfs-mirror" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/yt-dlp</id> + <title>yt-dlp Nix config</title> + <updated>2023-10-18T00:00:00+00:00</updated> + <content type="html"> + yt-dlp is an incredibly useful and customizable tool +for downloading online videos +from YouTube and elsewhere. +Here's my setup +(declared in Nix, but easily generalizable). + </content> + <link href="https://beauhilton.com/posts/yt-dlp" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/subsonic-cli</id> + <title>Command-line interfaces for self-hosted music</title> + <updated>2023-09-28T00:00:00+00:00</updated> + <content type="html"> + Self-hosting a music server is great. +Listening to the tunes via the command line is the way. + </content> + <link href="https://beauhilton.com/posts/subsonic-cli" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pixel6screen</id> + <title>Pixel 6 DIY screen replacement, with fingerprint reader calibration +using Linux</title> + <updated>2023-09-19T00:00:00+00:00</updated> + <content type="html"> + The internet, up to now, says you need Windows or MacOS to calibrate the Pixel's fingerprint reader after installing a new screen and digitizer. +The internet, up to now, was wrong. + </content> + <link href="https://beauhilton.com/posts/pixel6screen" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pagecrypt</id> + <title>password protecting static web pages</title> + <updated>2023-01-12T00:00:00+00:00</updated> + <content type="html"> + Static site generators, by and large, do not have support for password protecting individual pages. +This post shows a strategy that works for any SSG and does not require server access controls. + </content> + <link href="https://beauhilton.com/posts/pagecrypt" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/oo-et-al</id> + <title>good machine learning in medicine</title> + <updated>2022-12-29T00:00:00+00:00</updated> + <content type="html"> + Because most machine learning in medicine sucks, I thought you might like to see an example of it done well. + </content> + <link href="https://beauhilton.com/posts/oo-et-al" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/medical-humanities-org</id> + <title>medical-humanities.org</title> + <updated>2022-12-26T00:00:00+00:00</updated> + <content type="html"> + I made a static website as an electronic learning system and forum, +with the option for password protected posts and a controlled editing workflow, +for free and without a dedicated server. This post has the highlights. + </content> + <link href="https://beauhilton.com/posts/medical-humanities-org" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/thanks</id> + <title>I made a thanks page</title> + <updated>2022-12-19T00:00:00+00:00</updated> + <content type="html"> + A public, running journal of "hey, thanks" +to the folks who make my life better, in big and small ways. +Check it out . + </content> + <link href="https://beauhilton.com/posts/thanks" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/mime</id> + <title>fix MIME Types to unbreak RSS feeds served by OpenBSD’s +httpd(8)</title> + <updated>2022-11-13T00:00:00+00:00</updated> + <content type="html"> + I've been getting back into RSS lately. +Turns out, my own RSS feed was broken. + </content> + <link href="https://beauhilton.com/posts/mime" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/ugbsd</id> + <title>Upgrading out-of-date OpenBSD installs</title> + <updated>2022-11-11T00:00:00+00:00</updated> + <content type="html"> + First of all, don't do how I do. +Upgrade your installs regularly. +OpenBSD makes it very easy. + </content> + <link href="https://beauhilton.com/posts/ugbsd" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/geocheatcode</id> + <title>geocheatcode</title> + <updated>2022-04-22T00:00:00+00:00</updated> + <content type="html"> + Here is background and code +for a trick I use to get +Google to give me best-in-class guesses +for latitude and longitude, +despite goofy and/or downright bad location searches. + </content> + <link href="https://beauhilton.com/posts/geocheatcode" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/intake-2022-03-25</id> + <title>Intake presentation on candidal esophagitis</title> + <updated>2022-03-25T00:00:00+00:00</updated> + <content type="html"> + candidal esophagitis, achalasia, H Pylori PUD + </content> + <link href="https://beauhilton.com/posts/intake-2022-03-25" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/employee-wifi</id> + <title>Set Up Enterprise Wifi on Arch Linux</title> + <updated>2021-09-17T00:00:00+00:00</updated> + <content type="html"> + Most big institutions have guest and employee wifi networks. +Guest wifi is usually fine, fast enough for the basics, +but far inferior to employee wifi. +On a custom-built OS, such as a fairly minimalist Linux distribution, +getting the employee wifi to work +can be a beast. + </content> + <link href="https://beauhilton.com/posts/employee-wifi" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/mr-2021</id> + <title>Morning Report 08/23/2021</title> + <updated>2021-08-23T00:00:00+00:00</updated> + <content type="html"> + Diagnosis is... MDS/MPN/MF NOS. +i.e., who knows. + </content> + <link href="https://beauhilton.com/posts/mr-2021" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/rmd-py</id> + <title>R Markdown is my spirit animal</title> + <updated>2019-10-20T00:00:00+00:00</updated> + <content type="html"> + Turns out that a better way does exist, and it is R Markdown. + </content> + <link href="https://beauhilton.com/posts/rmd-py" rel="alternate"/> + </entry> + +</feed> +\ No newline at end of file diff --git a/build/camplist/index.html b/build/camplist/index.html @@ -0,0 +1,201 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Camping Checklist + </h1> + <p> + Adapted from REI’s. + </p> + <h2> + Campsite + </h2> + <ul> + <li> + [ ] Tent (and footprint, stakes) + </li> + <li> + [ ] Tarp + </li> + <li> + [ ] Stakes + </li> + <li> + [ ] Sleeping bags + </li> + <li> + [ ] Sleeping pads + </li> + <li> + [ ] Camping pillow + </li> + <li> + [ ] Headlamps or flashlights (and extra batteries) + </li> + <li> + [ ] Camp chairs + </li> + <li> + [ ] Camp table (if no picnic table) + </li> + <li> + [ ] Lantern (and mantles and fuel/batteries if needed) + </li> + </ul> + <p> + Optional: + </p> + <ul> + <li> + [ ] Sunshade, tarp or screen house + </li> + <li> + [ ] Hammock + </li> + <li> + [ ] Cots + </li> + <li> + [ ] Sleeping bag liners + </li> + <li> + [ ] Firewood sourced near campsite + </li> + <li> + [ ] Camp rug + </li> + <li> + [ ] Tablecloth and clips (or tape) + </li> + <li> + [ ] Clothesline with clips + </li> + </ul> + <h2> + Tools &amp; Repair Items + </h2> + <ul> + <li> + [ ] Multi-tool + </li> + <li> + [ ] Duct tape + </li> + <li> + [ ] Extra cord + </li> + <li> + [ ] Tent-pole repair sleeve + </li> + <li> + [ ] Pad/Mattress repair kit + </li> + <li> + [ ] Mallet or hammer (for hammering tent stakes) + </li> + <li> + [ ] Saw or axe (for cutting firewood) + </li> + <li> + [ ] Small broom and dustpan + </li> + </ul> + <p> + camp mug icon Kitchen Many campgrounds have drinkable water. If not, +bring your own, or be prepared to treat water if there’s a water source. +Also, for even more ideas and food suggestions, see our separate Camp +Kitchen Checklist. + </p> + <p> + Stove and fuel Matches/light/firestarter Cook pots (and pot holder) +Frying pan Eating utensils Cooking utensils Bottle opener, can opener, +corkscrew Sharp knife Plates/bowls Mugs/cups Cutting board Cooler Ice or +ice substitutes Water bottles Camp sink or wash bins Biodegradable soap +Pot scrubber/sponge(s) Trash/recycling bags Dish towel Optional: + </p> + <p> + Camp grill and fuel Grill rack Griddle Dutch oven Charcoal Portable +coffee/tea maker Rolling ice cream maker Marshmallow/hot dog roasting +forks Small food-storage containers/bags/foil Large water jugs Large, +clear plastic bins to store kitchen gear + </p> + <p> + pen and pencil icon Campsite Extras Most of the following items are +optional, though depending on how remote your campsite is, navigation +tools such as a map, compass and/or GPS may be required (for more info, +read about the Ten Essentials). + </p> + <p> + Solar and portable power Binoculars Navigation tools Field guides +(flowers, insects) Star chart/night-sky identifier Book/reading material +Notebook and pen/pencil Music player with headphones Games and toys Dog +gear Dry bags, stuff sacks or clear plastic bins to store items + </p> + <p> + puffy vest icon Clothing &amp; Footwear Moisture-wicking underwear +Moisture-wicking T-shirts Quick-drying pants/shorts Long-sleeve shirts +(for sun, bugs) Lightweight fleece or jacket Boots or shoes suited to +terrain Socks (synthetic or wool) Sleepwear Additional items for rainy +and/or cold weather: + </p> + <p> + Rainwear (jacket and pants) Long underwear Warm insulated jacket or +vest Fleece pants Gloves or mittens Warm hat Optional: + </p> + <p> + Swimsuits Water sandals In-camp sandals or booties Bandanas + </p> + <p> + soap icon Health &amp; Hygiene Toilet paper Hand sanitizer Toothbrush +and toothpaste Toiletry kit Quick-dry towel Menstrual products +Prescription medications First-aid kit or first-aid supplies (see +First-Aid Checklist) Sun and bug protection: + </p> + <p> + Sunscreen Sunglasses (and sunglasses straps) Sun hat Lip balm Insect +repellent Insect repellent device Optional: + </p> + <p> + Urinary products Sanitation trowel (if no toilets) Baby wipes Alcohol +or antiseptic wipes Mirror Brush/comb Cosmetics Spare eyeglasses/contact +lens supplies Eyeshades Earplugs Portable camp shower + </p> + <p> + personal ID and credit card icon Personal Items Credit card and/or +cash ID Cellphone Campsite reservation confirmation (if required)* + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/church/luke-15-11-32/index.html b/build/church/luke-15-11-32/index.html @@ -0,0 +1,306 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Luke 15:11-32 + </h1> + <h2> + Introduction + </h2> + <p> + One of the nice things about being asked to give a ten minute talk on +one of Jesus’ parables, in addition to the inherent beauty and depth of +the things, is that the parables are short. + </p> + <p> + This allows a luxurious classical exegesis, meaning we can give some +context, read the whole text, then circle back and examine details. + </p> + <p> + (this written version is much more than 10 minutes, btw - the actual +talk was just the highlights, as the Spirit grabbed me) + </p> + <h2> + Context + </h2> + <p> + Luke 15 opens with Jesus hanging out with some reprobates, called the +“publicans and sinners” in the KJV. + </p> + <p> + Luke 15:2 And both the Pharisees and the scribes murmured a great +deal, saying: “This man welcomes sinners and eats with them.” + </p> + <p> + To put it simply, the faithful members of the God’s church were +disturbed at this upstart rabbi’s lunch crew. + </p> + <p> + Publicans are tax-collectors. In the New Testament, this refers +specifically to Jewish people who had taken jobs with the Roman +government to collect taxes, mostly from their fellow Jews. + </p> + <p> + Everyone hates taxes. The situation around the year 0 was especially +rough, not far off from what we see in the classic Robin Hood movies, +with the Sheriff of Nottingham tapping the last few pennies out of the +old beggar’s boot. + </p> + <p> + Publicans were hated even when they were just doing their job as +instructed, and had the additional reputation of lining their own +pockets. There was no good way to find out what the actual decreed tax +law should be, so people had to pay whatever the publican demanded, and +folks often guessed (sometimes rightly) that the publican was on a +little “Cost Plus” action. The publicans were therefore seen as +traitors, worldly and godless people who had sold out to The Man and +were getting rich off the suffering of God’s people. + </p> + <p> + To bring us up to date and make this story real, we can use our +heated political climate to approximate how the scribes and Pharisees +felt - imagine the publicans are your most hated political rivals, the +folks about which you find yourself saying, “Gee Marge, I don’t know how +so-and-so can be a member of political party X, or hold a job doing Y, +and still consider herself a Christian.” + </p> + <p> + It was at least that bad, if not worse. + </p> + <h2> + David Bentley Hart translation, Luke 15:11-32 + </h2> + <p> + Now I’m going to read the whole parable, using a wonderful +translation from David Bentley Hart, both because his translation is +faithful and honest, and also because I think it’s valuable to hear the +words anew by making them just alien enough to wake up old ears that +have heard the KJV version a thousand times. + </p> + <p> + 11 And he said, “A certain man had two sons. + </p> + <p> + 12 And the younger of them said to the father, ‘Father, give me the +share of the property falling to me.’ And he divided his living between +them. + </p> + <p> + 13 And not many days later, the younger son, having collected +everything, departed for a far country, and dissipated his property by +living prodigally. + </p> + <p> + 14 When he had spent everything a severe famine spread throughout +that country, and he began to be in need. + </p> + <p> + 15 And he went and attached himself to one of that country’s +citizens, and he sent him into his fields to feed the pigs; + </p> + <p> + 16 And he longed to fill his stomach with the carob pods that the +pigs ate, and no one gave him anything. + </p> + <p> + 17 And coming to himself he said, ‘How many of my father’s hired men +are overflowing with bread, but I am here perishing from famine. + </p> + <p> + 18 I will get up and go to my father, and I will say to him, “I have +sinned against heaven and before you, + </p> + <p> + 19 I am no longer worthy to be called your son.”’ + </p> + <p> + 20 And he rose and went to his own father. And while he was yet far +away his father saw him and was inwardly moved with pity, and ran and +fell upon his neck and kissed him fervently. + </p> + <p> + 21 And his son said to him, ‘Father, I have sinned against heaven and +before you, I am no longer worthy to be called your son.’ + </p> + <p> + 22 But the father said to his slaves, ‘Quickly bring out the best +robe and put it on him, and place a ring on his finger and sandals on +his feet, + </p> + <p> + 23 And bring the fattened calf and kill it, and let us sit and have +good cheer, + </p> + <p> + 24 Because this son of mine was dead and has come to life again, was +lost and has been found.’ And they began to celebrate. + </p> + <p> + 25 But his older son was in a field; and as he came and drew near the +house he heard music and dancing, + </p> + <p> + 26 And calling one of the servants over he asked what all this might +be. + </p> + <p> + 27 And he told him that ‘Your brother has come, and your father has +killed the fattened calf, because he has got him back in good +health.’ + </p> + <p> + 28 But in his response he was indignant and did not wish to go in; +and his father came out and pleaded with him. + </p> + <p> + 29 But in reply he said to the father, ‘Look, for so many years I am +slaving for you, and I have never disobeyed a command of yours, and you +never gave me a goat so that I could make merry with my friends, + </p> + <p> + 30 But when this son of yours came, he who has devoured your +livelihood with whores, you killed the fattened calf for him.’ + </p> + <p> + 31 And he said to him, ‘Child, you are always with me, and all my +things are yours. + </p> + <p> + 32 But we had to celebrate and rejoice, because this brother of yours +was dead and came to life, and was lost, and has been found.’” + </p> + <h2> + Some notes on the text + </h2> + <p> + If we go back to the beginning of the parable, we see a son who is +impatient and bored living at home, who wants to see the world and +party. He talks Dad into giving him his inheritance early so he can do +just that. + </p> + <p> + This translation uses the word “prodigally,” which doesn’t show up in +the KJV but does show up repeatedly in classical Christian writings on +this parable. The KJV uses the phrase “riotous living,” others use the +word “wild” or “reckless,” but “prodigal” probably is the best word we +have for what he was up to - the Greek ἀσώτως (asótós) means, literally, +“not saved,” which is exactly what the son did with his inheritance +before landing the job as a pig farmer. + </p> + <p> + Prodigality, in itself, is not necessarily a bad thing. Great +generosity can also be called “prodigal.” But we found out what the son +was spending his money on - prostitutes (the Greek is πορνῶν - pornōn) +and parties. + </p> + <p> + When the son returns to repent, it is as a man down on his luck, +looking to take a humble yet stable (ha) job with benefits, not as a +prince trying to reclaim his throne. He states he is “no longer worthy +to be called” a son of his father. Before he can even try to talk pops +into giving him a job mucking stables for a bed and three square a day, +before he can say a word, Dad <em>runs</em> to him and brings him in +close. He crashes through forgiving, straight to celebrating, and gets a +prodigal party of his own started. He dresses the kid in their best +clothes and new shoes and kicks off a barbecue, complete with a band and +dance-off. + </p> + <p> + The older kid is in the field working, hears what’s happening, and is +not having it. He’s been doing all the things for all the years, +including right now, and he never got a party. + </p> + <p> + Dad is generous and patient, and doesn’t scold the understandably +self-righteous and hurt older son, but gently affirms that he is still +his son, has lost nothing, and tries to help him see the cause for +celebration. + </p> + <p> + At the end, we never find out the older son’s response. + </p> + <p> + The older son is the primary target of the tale, the same kind of guy +as the Pharisees and scribes, who kept all the rules and couldn’t help +getting miffed when the bad kids seemingly get rewarded for being +bad. + </p> + <h2> + Conclusion + </h2> + <p> + When I read the scriptures, I find it much more useful to see myself +as the butt of the joke, particularly when someone is getting reamed. Of +course it feels nice to think of myself as the Nephi and not the Laman +or Lemuel, but what good does that do me? Jesus’ parables, especially +those in Luke, are harshest on those who cannot see the way they are +painting the outside of their sepulchre with such care, fancy-ass paint, +while the inside is rotting flesh and moldering bones. + </p> + <p> + Jesus’ parables are rich and faceted, endless - there’s something +here for the prodigal, the one who has wasted all and is scared to hell +of coming back to ask for forgiveness: see how forgiveness is the thing +the Father does most easily, and what He really wants is not just to +forgive, but to celebrate, with his own positive prodigality. Also note +the types of sin he was explicitly forgiving in this parable and its +context - the prodigal wasting money and morality with prostitutes, the +publicans cheating honest people - Jesus’ Atonement doesn’t just forgive +nabbing a candy bar from the gas station and glancing at your +classmate’s exam sheet, he gets right in there with the intense +stuff. + </p> + <p> + There’s something here for the good kids, the ones who have been +keeping the letter of the law, and probably doing an ok job with the +spirit of it too, but, <em>because</em> of how good they have been, can +be quick to judge, and even cross over into hate, when they meet someone +from the other side of the tracks. Learn to see that foul-mouthed +so-and-so as God does, as one of His own, and join the party: celebrate +every win, whether or not it looks like your own, and be gentle to every +defeat (whether or not it looks like your own). + </p> + <p> + There’s something here for the parent, who has been hurt by the poor +choices of a child and isn’t sure how to deal with their plea for +forgiveness. Treat the kid like the queen she is, fire up the grill, +call the neighbors, and get her gussied up for the party. (and if a +certain someone is pissed that the black sheep is now wearing the new +Nikes and dancing all night, try to help them see that they are still +every bit as valuable, and feel what a joy it is that she’s back). + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/colophon/index.html b/build/colophon/index.html @@ -0,0 +1,129 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Colophon + </h1> + <p> + This site is hosted on an <a href="https://www.openbsd.org/">OpenBSD</a> server on <a href="https://vultr.com">vultr</a>, built using plain text files +processed by <a href="https://soupault.app">soupault</a> and auto-<a href="https://en.wikipedia.org/wiki/Rsync">rsync’d</a> to the server as +part of a pre-commit hook. + </p> + <p> + The source files are available on <a href="https://git.beauhilton.com/site/">my git server</a> and <a href="https://github.com/cbeauhilton/beauhilton.com">GitHub</a>. + </p> + <p> + I also use <a href="https://eradman.com/entrproject/">entr</a> (on +Nix) or <a href="https://github.com/grego/caretaker">caretaker</a> (on +Arch) during development to auto-rebuild as I edit the source files. + </p> + <p> + Regarding the design, the focus is on simplicity and a small +footprint. It’s the kind thing to do, for the user and the planet. No +Javascript, just static HTML. I used to specify fonts, e.g. one of my +favorites, <a href="https://www.ibm.com/plex/">IBM Plex</a>, but in an +effort to keep things light and tidy, I now just use system fonts. + </p> + <p> + <a href="https://talks.beauhilton.com">https://talks.beauhilton.com</a> and +<a href="https://notes.beauhilton.com">https://notes.beauhilton.com</a> +are not part of the website proper, but are rather generated using +GitHub Pages. The talks are built using <a href="https://sli.dev/">slidev</a>, which translates markdown files into +beautiful web-first slide decks (I now only use PowerPoint under great +duress), and the notes use <a href="https://quartz.jzhao.xyz/">quartz</a>, which translates <a href="https://obsidian.md/">Obsidian</a>-style markdown files (see a +theme here?) into a website of interconnected notes a la <a href="https://en.wikipedia.org/wiki/Zettelkasten">Zettelkasten</a>. + </p> + <h2> + Nix Workflow + </h2> + <p> + As of 2023-10-10 or so, I use a Nix-based workflow with flakes and <a href="https://devenv.sh/">devenv.sh</a>. The basic steps are similar to +what is included below in the Non-Nix section, though more conveniently +packaged and portable. + </p> + <p> + It’s delightful. + </p> + <p> + I may write it up at some point, but for now, look at <a href="https://git.beauhilton.com/site/file/flake.nix.html">flake.nix</a> +in the source code. One of the great things about Nix is that it’s +self-documenting and self-contained. + </p> + <p> + On my non-Nix laptop running Arch, I still use the workflow below, +though at some point I’ll probably install Nix on Arch and unify my +approach. + </p> + <h2> + Non-Nix Workflow + </h2> + <p> + The workflow is terminal-based and pretty basic. + </p> + <p> + It amounts to: + </p> + <pre tabindex="0"><code class="language-shell">cd src/site +./sh.sh +$EDITOR site/gulag_archipelago.md +</code></pre> + <p> + <code>sh.sh</code> contains the following: + </p> + <pre tabindex="0"><code class="language-shell">$TERMINAL -e caretaker &amp;&gt;/dev/null &amp; disown +$TERMINAL -e python3 -m http.server --directory build &amp;&gt;/dev/null &amp; disown +$TERMINAL -e $BROWSER http://localhost:8000 &amp;&gt;/dev/null &amp; disown +</code></pre> + <p> + This will open three new terminals running: a caretaker instance for +auto-rebuild (I recently activated caching in soupault, rebuilds are +lightning quick), a web server for preview, and a browser pointing to +the server. + </p> + <p> + At that point I will usually throw the terminals running the server +and <code>caretaker</code> to another desktop to achieve a clean editing +environment. + </p> + <p> + When it’s ready to go live, I use an alias called <code>glazy</code>: +<code>git add . &amp;&amp; git commit -m "update" &amp;&amp; git push</code>. +This will trigger the pre-commit hook, which rebuilds the site again and +activates rsync to send the built site to the web server, before pushing +the source files to GitHub and my git server. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/contact/index.html b/build/contact/index.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a class="nav-active" href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <p> + This website is my social media account. + </p> + <p> + If you want to get in touch, email: <a href="mailto:beau@beauhilton.com">beau@beauhilton.com</a>. + </p> + <p> + I’ll respond within the week. + </p> + <h2> + Consulting + </h2> + <p> + If you are contacting me to request data science consulting, write to +the email above with “consulting” somewhere in the subject line. + </p> + <p> + I am currently willing to discuss engagements, pending specifics. +Minimum $350/h for consulting, unless you’re a student, in which case, +if the project is interesting and I can truly be of assistance, it’s +free. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/feed.xml b/build/feed.xml @@ -0,0 +1,263 @@ +<?xml version='1.0' encoding='UTF-8'?> +<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> + <id>https://beauhilton.com/atom.xml</id> + <title>beauhilton</title> + <updated>2024-04-12T00:00:00+00:00</updated> + <author> + <name>beau hilton</name> + <email>beau@beauhilton.com</email> + </author> + <generator uri="https://soupault.app" version="4.8.0">soupault</generator> + <subtitle>beau's website</subtitle> + <entry> + <id>https://beauhilton.com/posts/choaked</id> + <title>The first detailed description of living with esophageal cancer - +John Casaubon’s 1690 diary</title> + <updated>2024-04-12T00:00:00+00:00</updated> + <content type="html"> + John Casaubon was an English surgeon in the late 1600s +who developed an esophageal tumor in late 1690 +and wrote about it in his diary +before dying in January of 1691. +It's harrowing, enlightening, and strangely beautiful. +This blog post is the only place in the world you can read the full transcription of the diary entry. + </content> + <link href="https://beauhilton.com/posts/choaked" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/claude-notes</id> + <title>Writing clinical notes using AI - a practical experience</title> + <updated>2024-04-09T00:00:00+00:00</updated> + <content type="html"> + With Claude 3 Opus (a newish ChatGPT4 competitor) as my copilot, I wrote a pretty darn good SOAP note + for an (invented yet realistic) new consult visit. It took a little massaging to get it right, + but boy howdy, it did a great job. Here are the prompts and outputs. + This stuff has serious potential for streamlining the boring and tedious parts of the job. + </content> + <link href="https://beauhilton.com/posts/claude-notes" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/s1</id> + <title>Drugs we can’t get: S1</title> + <updated>2024-03-29T00:00:00+00:00</updated> + <content type="html"> + There are a number of interesting drugs used in the global market that, + for one reason or another, do not have FDA approval and are therefore inaccessible + in the US, at least outside of clinical trials. S1 is one of them: a better capecitabine. + </content> + <link href="https://beauhilton.com/posts/s1" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pp-tech-infra</id> + <title>Patient-facing slide decks</title> + <updated>2024-03-23T00:00:00+00:00</updated> + <content type="html"> + While I plan on being a physician-scientist forever, I'm not going to work in academia. +Over the past few years I've put together very cool infrastructure for giving academic talks (click "talks" above), +and it was making me sad that it might not get much use after I leave the university. +But then, a ray of sunshine: Why not use my slide deck infrastructure to help in patient conversations? + </content> + <link href="https://beauhilton.com/posts/pp-tech-infra" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/cad-fish</id> + <title>Cold agglutinin disease: fish out of water?</title> + <updated>2024-03-22T00:00:00+00:00</updated> + <content type="html"> + Cold agglutinin disease is a fascinating and strange phenomenon, and might happen because we're fish. + </content> + <link href="https://beauhilton.com/posts/cad-fish" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/history-egc</id> + <title>A timeline of esophageal cancer</title> + <updated>2023-10-20T00:00:00+00:00</updated> + <content type="html"> + A couple of friends and I wrote a review article on the history of esophageal cancer. +The timeline was so interesting I thought I'd share it here, in a place where it can be easily found and updated. + </content> + <link href="https://beauhilton.com/posts/history-egc" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/add-zfs-mirror</id> + <title>How to add a mirror to a single ZFS disk</title> + <updated>2023-10-19T00:00:00+00:00</updated> + <content type="html"> + tl;dr: <code>zpool attach data /dev/disk/by-partlabel/zfs-3a1xx /dev/sdx0</code>. Adjust for your own pool and disks. + </content> + <link href="https://beauhilton.com/posts/add-zfs-mirror" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/yt-dlp</id> + <title>yt-dlp Nix config</title> + <updated>2023-10-18T00:00:00+00:00</updated> + <content type="html"> + yt-dlp is an incredibly useful and customizable tool +for downloading online videos +from YouTube and elsewhere. +Here's my setup +(declared in Nix, but easily generalizable). + </content> + <link href="https://beauhilton.com/posts/yt-dlp" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/subsonic-cli</id> + <title>Command-line interfaces for self-hosted music</title> + <updated>2023-09-28T00:00:00+00:00</updated> + <content type="html"> + Self-hosting a music server is great. +Listening to the tunes via the command line is the way. + </content> + <link href="https://beauhilton.com/posts/subsonic-cli" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pixel6screen</id> + <title>Pixel 6 DIY screen replacement, with fingerprint reader calibration +using Linux</title> + <updated>2023-09-19T00:00:00+00:00</updated> + <content type="html"> + The internet, up to now, says you need Windows or MacOS to calibrate the Pixel's fingerprint reader after installing a new screen and digitizer. +The internet, up to now, was wrong. + </content> + <link href="https://beauhilton.com/posts/pixel6screen" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/pagecrypt</id> + <title>password protecting static web pages</title> + <updated>2023-01-12T00:00:00+00:00</updated> + <content type="html"> + Static site generators, by and large, do not have support for password protecting individual pages. +This post shows a strategy that works for any SSG and does not require server access controls. + </content> + <link href="https://beauhilton.com/posts/pagecrypt" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/oo-et-al</id> + <title>good machine learning in medicine</title> + <updated>2022-12-29T00:00:00+00:00</updated> + <content type="html"> + Because most machine learning in medicine sucks, I thought you might like to see an example of it done well. + </content> + <link href="https://beauhilton.com/posts/oo-et-al" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/medical-humanities-org</id> + <title>medical-humanities.org</title> + <updated>2022-12-26T00:00:00+00:00</updated> + <content type="html"> + I made a static website as an electronic learning system and forum, +with the option for password protected posts and a controlled editing workflow, +for free and without a dedicated server. This post has the highlights. + </content> + <link href="https://beauhilton.com/posts/medical-humanities-org" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/thanks</id> + <title>I made a thanks page</title> + <updated>2022-12-19T00:00:00+00:00</updated> + <content type="html"> + A public, running journal of "hey, thanks" +to the folks who make my life better, in big and small ways. +Check it out . + </content> + <link href="https://beauhilton.com/posts/thanks" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/mime</id> + <title>fix MIME Types to unbreak RSS feeds served by OpenBSD’s +httpd(8)</title> + <updated>2022-11-13T00:00:00+00:00</updated> + <content type="html"> + I've been getting back into RSS lately. +Turns out, my own RSS feed was broken. + </content> + <link href="https://beauhilton.com/posts/mime" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/ugbsd</id> + <title>Upgrading out-of-date OpenBSD installs</title> + <updated>2022-11-11T00:00:00+00:00</updated> + <content type="html"> + First of all, don't do how I do. +Upgrade your installs regularly. +OpenBSD makes it very easy. + </content> + <link href="https://beauhilton.com/posts/ugbsd" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/geocheatcode</id> + <title>geocheatcode</title> + <updated>2022-04-22T00:00:00+00:00</updated> + <content type="html"> + Here is background and code +for a trick I use to get +Google to give me best-in-class guesses +for latitude and longitude, +despite goofy and/or downright bad location searches. + </content> + <link href="https://beauhilton.com/posts/geocheatcode" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/intake-2022-03-25</id> + <title>Intake presentation on candidal esophagitis</title> + <updated>2022-03-25T00:00:00+00:00</updated> + <content type="html"> + candidal esophagitis, achalasia, H Pylori PUD + </content> + <link href="https://beauhilton.com/posts/intake-2022-03-25" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/employee-wifi</id> + <title>Set Up Enterprise Wifi on Arch Linux</title> + <updated>2021-09-17T00:00:00+00:00</updated> + <content type="html"> + Most big institutions have guest and employee wifi networks. +Guest wifi is usually fine, fast enough for the basics, +but far inferior to employee wifi. +On a custom-built OS, such as a fairly minimalist Linux distribution, +getting the employee wifi to work +can be a beast. + </content> + <link href="https://beauhilton.com/posts/employee-wifi" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/mr-2021</id> + <title>Morning Report 08/23/2021</title> + <updated>2021-08-23T00:00:00+00:00</updated> + <content type="html"> + Diagnosis is... MDS/MPN/MF NOS. +i.e., who knows. + </content> + <link href="https://beauhilton.com/posts/mr-2021" rel="alternate"/> + </entry> + + <entry> + <id>https://beauhilton.com/posts/rmd-py</id> + <title>R Markdown is my spirit animal</title> + <updated>2019-10-20T00:00:00+00:00</updated> + <content type="html"> + Turns out that a better way does exist, and it is R Markdown. + </content> + <link href="https://beauhilton.com/posts/rmd-py" rel="alternate"/> + </entry> + +</feed> +\ No newline at end of file diff --git a/build/gifs/index.html b/build/gifs/index.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + GIFs + </h1> + <p> + Ladies and gentleman of great culture and impeccable taste also call +them DAVEs. + </p> + <p> + <a href=""><img src="/images/gifs/mr-bean-cupcake.gif#center" alt="mr-bean-cupcake"></a> + </p> + <p> + <a href=""><img src="/images/gifs/mr-bean-cupcake-double-take.gif#center" alt="mr-bean-cupcake-double-take"></a> + </p> + <p> + <a href=""><img src="/images/gifs/jimi.gif#center" alt="jimi"></a> + </p> + <p> + <a href=""><img src="/images/gifs/soul-train.gif#center" alt="soul-train"></a> + </p> + <p> + <a href=""><img src="/images/gifs/bueller-ferrari-crash.gif#center" alt="bueller-ferrari-crash"></a> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/images/cashapp.png b/build/images/cashapp.png Binary files differ. diff --git a/build/images/gifs/bueller-ferrari-crash.gif b/build/images/gifs/bueller-ferrari-crash.gif Binary files differ. diff --git a/build/images/gifs/jimi.gif b/build/images/gifs/jimi.gif Binary files differ. diff --git a/build/images/gifs/mr-bean-cupcake-double-take.gif b/build/images/gifs/mr-bean-cupcake-double-take.gif Binary files differ. diff --git a/build/images/gifs/mr-bean-cupcake.gif b/build/images/gifs/mr-bean-cupcake.gif Binary files differ. diff --git a/build/images/gifs/soul-train.gif b/build/images/gifs/soul-train.gif Binary files differ. diff --git a/build/images/hatchimals-glow-in-the-dark.jpg b/build/images/hatchimals-glow-in-the-dark.jpg Binary files differ. diff --git a/build/images/ncmpcpp-mopidy-full.png b/build/images/ncmpcpp-mopidy-full.png Binary files differ. diff --git a/build/images/ncmpcpp-mopidy-selector.png b/build/images/ncmpcpp-mopidy-selector.png Binary files differ. diff --git a/build/images/ncmpcpp-mopidy-tracks.png b/build/images/ncmpcpp-mopidy-tracks.png Binary files differ. diff --git a/build/images/s1-cape-hfs.jpg b/build/images/s1-cape-hfs.jpg Binary files differ. diff --git a/build/images/s1-is.png b/build/images/s1-is.png Binary files differ. diff --git a/build/images/stuffy_pterodactyl.jpg b/build/images/stuffy_pterodactyl.jpg Binary files differ. diff --git a/build/images/venmo.jpg b/build/images/venmo.jpg Binary files differ. diff --git a/build/images/yt-dlp-downloading-example.png b/build/images/yt-dlp-downloading-example.png Binary files differ. diff --git a/build/images/yt-dlp-filename-example.jpg b/build/images/yt-dlp-filename-example.jpg Binary files differ. diff --git a/build/index.html b/build/index.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <br> + Hi there. My name is Beau Hilton. +<br> +<br> + I'm a cancer doctor and data scientist. +<br> +<br> + The <a href="/thanks">thanks page</a> is the most interesting thing on this website. +<br> +<br> + For a quick personal update, see the + <a href="/now">now</a> page. +<br> +<br> + For a bit more depth, see the + <a href="/about">about</a> page. + It has extended summaries of major projects, + and a few links at the bottom to things folks on the internet often like to know about. +<br> +<br> + You can also see + <a href="/posts">blog posts</a>, + <a href="https://notes.beauhilton.com">notes</a>, + slides from public <a href="https://talks.beauhilton.com">talks</a>, + and <a href="https://git.beauhilton.com">code</a> for personal projects and configuration + (<a href="https://github.com/cbeauhilton">GitHub</a> has more of my public projects). +<br> +<br> + I'd love to chat. + Don't hesitate to <a href="/contact">reach out</a>. + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/liesel/index.html b/build/liesel/index.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Liesel’s wishlist + </h1> + <hr> + <p> + <a href="https://www.walmart.com/ip/NECA-GREMLINS-Movie-Gizmo-Mogwai-Dancing-Musical-8-Plush-Toy-Doll-Figure-NEW/791742706">Dancing +Gizmo plush doll</a> + </p> + <p> + <a href="https://www.walmart.com/ip/NECA-GREMLINS-Movie-Gizmo-Mogwai-Dancing-Musical-8-Plush-Toy-Doll-Figure-NEW/791742706"><img src="https://i5.walmartimages.com/asr/73fa2830-15f3-4443-a2c1-2af0fdcf5e7c_1.d15d42112b8a2771d5f3d63788249fa2.jpeg#center" alt="Dancing Gizmo plush doll"></a> + </p> + <hr> + <p> + <a href="https://www.walmart.com/ip/Small-Brown-Bunny-Miyoni-Plush-by-Aurora-10911/38676885">Brown +bunny stuffy</a> + </p> + <p> + <a href="https://www.walmart.com/ip/Small-Brown-Bunny-Miyoni-Plush-by-Aurora-10911/38676885"><img src="https://i5.walmartimages.com/asr/1357a985-b74d-4d1c-a4c6-7526373baaf2.f3cc5037c611b9c1eef846676ff1028f.jpeg?odnHeight=612&amp;odnWidth=612&amp;odnBg=FFFFFF" alt="brown bunny"></a> + </p> + <hr> + <p> + <a href="https://www.amazon.com/Tribello-Pterodactyl-Stuffed-Animal-Dinosaur/dp/B096D4GHD5">Pterodactyl +stuffy</a> + </p> + <p> + <a href="https://www.amazon.com/Tribello-Pterodactyl-Stuffed-Animal-Dinosaur/dp/B096D4GHD5"><img src="/images/stuffy_pterodactyl.jpg#center" alt="stuffy"></a> + </p> + <hr> + <p> + <a href="https://www.amazon.com/Hatchimals-CollEGGtibles-Nightglow-12-Pack-Exclusive/dp/B07B83HP9K">Glow-in-the-dark +Hatchimals</a> + </p> + <p> + <a href="https://www.amazon.com/Hatchimals-CollEGGtibles-Nightglow-12-Pack-Exclusive/dp/B07B83HP9K"><img src="/images/hatchimals-glow-in-the-dark.jpg#center" alt="hatchimals"></a> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/now/index.html b/build/now/index.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a class="nav-active" href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h2> + home + </h2> + <p> + 6 humans, 1 dog, an ever-changing number of chickens. + </p> + <p> + Everyone is healthy and happy. + </p> + <p> + Summer garden is going in. + </p> + <p> + Hendersonville, TN. + </p> + <h2> + work + </h2> + <p> + Nearing the end of the second out of three years of oncology +fellowship. I’m going into private practice, and super psyched about it. +We’re working with some incredible groups across the South and Southeast +to find the right fit. It’s going to be tough to decide - the modern +oncology private practice has the potential to be a magical place, and +so many groups are Doing Things Right. + </p> + <hr> + <p> + This <a href="https://nownownow.com/about">now page</a> was last +updated 2024-04-12. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/pay/index.html b/build/pay/index.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Pay me! + </h1> + <hr> + <h2> + Cash App (preferred) + </h2> + <p> + <a href="https://cash.app/$cbeauhilton"><img src="/images/cashapp.png#center" alt="cashappQR"></a> + </p> + <hr> + <h2> + Venmo + </h2> + <p> + <a href="https://venmo.com/u/Beau-Hilton-1"><img src="/images/venmo.jpg#center" alt="venmoQR"></a> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/add-zfs-mirror/index.html b/build/posts/add-zfs-mirror/index.html @@ -0,0 +1,195 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + How to add a mirror to a single ZFS disk + </h1> + <p> + <time id="post-date">2023-10-19</time> + </p> + <p id="post-excerpt"> + tl;dr: <code>zpool attach data /dev/disk/by-partlabel/zfs-3a1xx /dev/sdx0</code>. Adjust for your own pool and disks. + </p> + <h2> + A mirror is a Very Good Thing + </h2> + <p> + I got a second identical disk to add as a ZFS mirror to my existing +setup. + </p> + <p> + Redundancy FTW. ZFS is king and queen. Needs at least two disks to +reap the full benefit (though a single-disk setup is still rad - CoW +with snapshots and send/receive are worth it, and NixOS makes it easy to +set up). + </p> + <h2> + It’s all about the disk path + </h2> + <p> + The basic command is (as a super user, or using sudo): + </p> + <pre tabindex="0"><code class="language-sh">zpool attach name<span class="hl kwb">-of-the-pool</span> disk<span class="hl kwb">-you-already-had</span> disk<span class="hl kwb">-you-want-to-add</span> +</code></pre> + <p> + On Linux, with a new drive, no need for formatting or any other disk +preparation. Just plug it in. + </p> + <p> + But how to specify which disks to use in the command? I saw several +guides that just used <code>/dev/sdx</code>, but it didn’t work. + </p> + <p> + I don’t know what it is about my setup that differs from the guides I +found online (if you have a hint, <a href="beauhilton.com/contact">lmk</a>), so YMMV, but below is some of +what I tried and what eventually worked, mostly for my own +reference. + </p> + <p> + In my setup, <code>/dev/sdb</code> was my existing drive and +<code>/dev/sda</code> is the one I was trying to add (these names are +determined at boot time and can vary from boot to boot - ZFS takes care +of finding things again on the back end after you’ve added a drive, +regardless of the label you used to add it, so using the +<code>/dev/sdx</code> name is just fine in many situations). + </p> + <p> + However, using + </p> + <pre tabindex="0"><code class="language-sh">zpool attach data <span class="hl opt">/</span>dev<span class="hl opt">/</span>sdb dev<span class="hl opt">/</span>sda +</code></pre> + <p> + gave me: + </p> + <pre tabindex="0"><code class="language-sh">cannot attach <span class="hl opt">/</span>dev<span class="hl opt">/</span>sda to <span class="hl opt">/</span>dev<span class="hl opt">/</span>sdb<span class="hl opt">:</span> no such device <span class="hl kwa">in</span> pool +</code></pre> + <p> + I tried a bunch of different things, from just the lsblk name with +the partition (“sdb1”), to by-id (“ata-ST1400…”), to full path +combinations, etc. + </p> + <p> + What finally worked was the by-partlabel identifier for the existing +disk, combined with the /dev/sdx0 name of the new one. + </p> + <p> + A little <code>zdb -l</code> on the existing drive gave me the path I +wanted: + </p> + <pre tabindex="0"><code class="language-sh">zdb <span class="hl kwb">-l</span> <span class="hl opt">/</span>dev<span class="hl opt">/</span>sdb1 +<span class="hl kwb">------------------------------------</span> +LABEL <span class="hl num">0</span> +<span class="hl kwb">------------------------------------</span> + version<span class="hl opt">:</span> <span class="hl num">5000</span> + name<span class="hl opt">:</span> <span class="hl sng">'data'</span> + state<span class="hl opt">:</span> <span class="hl num">0</span> + txg<span class="hl opt">:</span> <span class="hl num">170113</span> + pool_guid<span class="hl opt">:</span> <span class="hl num">8237228336559358688</span> + errata<span class="hl opt">:</span> <span class="hl num">0</span> + hostid<span class="hl opt">:</span> <span class="hl num">3236406100</span> + hostname<span class="hl opt">:</span> <span class="hl sng">'dell7050'</span> + top_guid<span class="hl opt">:</span> <span class="hl num">11182661003591634341</span> + guid<span class="hl opt">:</span> <span class="hl num">11182661003591634341</span> + vdev_children<span class="hl opt">:</span> <span class="hl num">1</span> + vdev_tree<span class="hl opt">:</span> + <span class="hl kwb">type</span><span class="hl opt">:</span> <span class="hl sng">'disk'</span> + id<span class="hl opt">:</span> <span class="hl num">0</span> + guid<span class="hl opt">:</span> <span class="hl num">11182661003591634341</span> + path<span class="hl opt">:</span> <span class="hl sng">'/dev/disk/by-partlabel/zfs-3a1e459c75dc9b74'</span> + whole_disk<span class="hl opt">:</span> <span class="hl num">1</span> + metaslab_array<span class="hl opt">:</span> <span class="hl num">128</span> + metaslab_shift<span class="hl opt">:</span> <span class="hl num">34</span> + ashift<span class="hl opt">:</span> <span class="hl num">12</span> + asize<span class="hl opt">:</span> <span class="hl num">14000504438784</span> + is_log<span class="hl opt">:</span> <span class="hl num">0</span> + DTL<span class="hl opt">:</span> <span class="hl num">3865</span> + create_txg<span class="hl opt">:</span> <span class="hl num">4</span> + features_for_read<span class="hl opt">:</span> + com.delphix<span class="hl opt">:</span>hole_birth + com.delphix<span class="hl opt">:</span>embedded_data + labels <span class="hl opt">=</span> <span class="hl num">0 1 2 3</span> +</code></pre> + <p> + So I tried: + </p> + <pre tabindex="0"><code class="language-sh">zpool attach data <span class="hl opt">/</span>dev<span class="hl opt">/</span>disk<span class="hl opt">/</span>by<span class="hl kwb">-partlabel</span><span class="hl opt">/</span>zfs<span class="hl kwb">-3a1e459c75dc9b74</span> <span class="hl opt">/</span>dev<span class="hl opt">/</span>sda1 +</code></pre> + <h2> + Great success + </h2> + <pre tabindex="0"><code class="language-conf">-&gt;&gt; zpool status + pool<span class="hl opt">:</span> data + state<span class="hl opt">:</span> ONLINE +<span class="hl kwa">status</span><span class="hl opt">:</span> One or more devices is currently being resilvered<span class="hl opt">.</span> The pool will + continue to function<span class="hl opt">,</span> possibly in a degraded state<span class="hl opt">.</span> +<span class="hl kwa">action</span><span class="hl opt">:</span> Wait for the resilver to complete<span class="hl opt">.</span> + scan<span class="hl opt">:</span> resilver in progress since Thu Oct <span class="hl kwb">19 17</span><span class="hl opt">:</span><span class="hl kwb">05</span><span class="hl opt">:</span><span class="hl kwb">26 2023</span> + <span class="hl kwb">2.33</span>T scanned at <span class="hl kwb">1.90</span>G/s<span class="hl opt">,</span> <span class="hl kwb">252</span>G issued at <span class="hl kwb">205</span>M/s<span class="hl opt">,</span> <span class="hl kwb">3.77</span>T total + <span class="hl kwb">252</span>G resilvered<span class="hl opt">,</span> <span class="hl kwb">6.53</span>% done<span class="hl opt">,</span> <span class="hl kwb">04</span><span class="hl opt">:</span><span class="hl kwb">59</span><span class="hl opt">:</span><span class="hl kwb">42</span> to go +<span class="hl kwa">config</span><span class="hl opt">:</span> + + NAME STATE READ WRITE CKSUM + data ONLINE <span class="hl kwb">0 0 0</span> + mirror-<span class="hl kwb">0</span> ONLINE <span class="hl kwb">0 0 0</span> + zfs-<span class="hl kwb">3</span>a1e459c75dc9b74 ONLINE <span class="hl kwb">0 0 0</span> + sda1 ONLINE <span class="hl kwb">0 0 0</span> (resilvering) + +<span class="hl kwa">errors</span><span class="hl opt">:</span> No known data errors +</code></pre> + <p> + …and the next day, after resilvering completed (and a reboot to make +sure the disk came online): + </p> + <pre tabindex="0"><code class="language-conf">-&gt;&gt; zpool status + pool<span class="hl opt">:</span> data + state<span class="hl opt">:</span> ONLINE + scan<span class="hl opt">:</span> resilvered <span class="hl kwb">3.77</span>T in <span class="hl kwb">05</span><span class="hl opt">:</span><span class="hl kwb">13</span><span class="hl opt">:</span><span class="hl kwb">53</span> with <span class="hl kwb">0</span> errors on Thu Oct <span class="hl kwb">19 22</span><span class="hl opt">:</span><span class="hl kwb">19</span><span class="hl opt">:</span><span class="hl kwb">19 2023</span> +<span class="hl kwa">config</span><span class="hl opt">:</span> + + NAME STATE READ WRITE CKSUM + data ONLINE <span class="hl kwb">0 0 0</span> + mirror-<span class="hl kwb">0</span> ONLINE <span class="hl kwb">0 0 0</span> + zfs-<span class="hl kwb">3</span>a1e459c75dc9b74 ONLINE <span class="hl kwb">0 0 0</span> + zfs-e2937e0fc8ebe95a ONLINE <span class="hl kwb">0 0 0</span> + +<span class="hl kwa">errors</span><span class="hl opt">:</span> No known data errors +</code></pre> + <p> + (notice that what was <code>sda1</code> is now referred to by +partlabel) + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/cad-fish/index.html b/build/posts/cad-fish/index.html @@ -0,0 +1,203 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Cold agglutinin disease: fish out of water? + </h1> + <p> + <time id="post-date">2024-03-22</time> + </p> + <p id="post-excerpt"> + Cold agglutinin disease is a fascinating and strange phenomenon, and might happen because we're fish. + </p> + <h2> + CAD: a matter of degree + </h2> + <p> + CAD is a disease of the cells that make the immune system, in which +they overproduce a protein called cold agglutinin, resulting in a +cascade of unfortunate events that are typically triggered by the blood +getting slightly too cold (going outside in the winter, getting ice +cream out of the freezer, drinking a Slurpie, etc.). Red blood cells +clump together and cause painful, blue fingers/toes/etc., sometimes so +severe the affected bits die and fall off, and an autoimmune attack on +the red blood cells begins, resulting in some of them being eaten alive +by the liver and spleen and others being (literally) exploded while +still in the blood vessels. + </p> + <p> + Everybody has cold agglutinins, these proteins that cause the +clumping (“agglutination”), at some low level. They’re a type of IgM, a +class of large proteins that are a key part of the immune system. IgM is +really good at sticking things together, which is exactly what you want +to happen in certain infections, etc., but which happens aberrantly, and +sometimes dramatically, with red blood cells in CAD. + </p> + <p> + All red blood will agglutinate at 0-5C. This has been known since, at +the latest, 1903. Karl Landsteiner figured it out. He’s the guy who won +the Nobel Prize for discovering blood types, which was based on +experiments with “iso-agglutination.” With blood typing came the ability +to cross-match blood for safe transfusion, which resulted in a huge leap +forward in our ability to help people who lose a lot of it, as in +surgery and trauma. We think of Landsteiner as the blood typing dude, +but it’s probably more accurate and expansive to think of him as the +dude who first exhaustively characterized the different situations in +which blood agglutinates. + </p> + <p> + Landsteiner’s discoveries came just in time for the World Wars, and +folks got to collecting blood in earnest, on a massive scale. We went +from a few laboratory fridges with dozens or hundreds of blood samples +for experiments, to blood banks worldwide, collectively full of hundreds +of thousands of units of blood for use in the operating room and +battlefield. Some oddities about human existence are only found when the +numbers grow to this size: blood bank technicians found that some blood +agglutinates all the way up to 25C (~77F, “room temperature”). This +resulted in difficulty with accurately typing blood, which led to a +number of deaths. + </p> + <p> + In 1946 Lubinski and Goldbloom at Johns Hopkins published a paper +describing seven patients with blood that would agglutinate all the way +up to 37C (98.6F). All of these patients had brisk hemolysis (red blood +cell explosion). + </p> + <p> + Putting it together, we have three categories of blood agglutination +in response to temperature: everyone’s blood will agglutinate in a +freezer, a small but significant portion of people have blood that +agglutinates at room temperature, and there are an unfortunate few who +have blood that agglutinates while still (relatively) warm in their +bodies. In all of these cases, it’s a cold agglutinin, a certain IgM +protein, that coordinates the clumping. + </p> + <p> + As a doctor I can accept that sometimes the body does horrible +things, about which the most that can be fairly said, despite all that +science can provide, is that they are random. A person’s blood deciding +to turn on them at the slightest cold provocation is well within the +realm of crazy things we deal with on a daily basis. I would love to +understand why everything horrible happens, but often have to move +forward only knowing that it does happen, and hope that there might be a +thing or two I can do to offset the horribleness. + </p> + <p> + I can also accept that unnatural environments lead to unnatural +phenomena, such as blood clumping in a freezer. That’s a +physical/chemical situation that never happens in a living animal (at +least, in vertebrates. Don’t get me started on the Antarctic midge). +There doesn’t need to be an evolutionary justification for the clumping +in this case, just a biochemical one. + </p> + <p> + It’s the room temperature thing that bothers me. In physiologic +findings that are so clearly a matter of degree, with an obvious sliding +scale, I wonder: what in our deep past created the affordance for this +thing in the first place? Why do we have cold agglutinins at all? + </p> + <h2> + Whence cold agglutinins? Probably fish. And fish are us. + </h2> + <p> + Sigbjorn Berentsen is a Norwegian physician and researcher (CAD is, +as you might expect, much more common in colder climates), and is The +Man when it comes to understanding and treating CAD in the modern +era. + </p> + <p> + A recent paper from him had this to say about the most likely +possibility of the origin of cold agglutinins: + </p> + <blockquote> + <p> + …the physiological function of CAs has not been clarified. It is +difficult to envision a functional role of antibodies with a temperature +optimum way below body temperature. Comparative studies, however, have +strongly indicated that the evolution of the adaptive immune system +began with the jawed vertebrates. Cartilaginous fish, which are +phylogenetically ancient and considered closely related to the first +jawed vertebrates, have only one immunoglobulin class in common with +humans: IgM… [T]he temperature optimum of CAs is much closer to the +environmental and body temperature of non-mammal sea vertebrates. +Furthermore, CAs can react with antigens other than RBC surface +macromolecules, and structures closely related to the I antigen are +present on some microorganisms such as Streptococcus and Listeria +species. Thus, one might explain human CAs as remnants of a primitive +vertebrate immune system. + </p> + </blockquote> + <p> + <a href="https://doi.org/10.3389/fimmu.2020.00590">https://doi.org/10.3389/fimmu.2020.00590</a> + </p> + <p> + So, ancient fish, swimming in room temperature or colder water, had +to fight certain bacteria. The fish are us, if you go back far enough. +We happened to have held on to this ability, these proteins, an +immunologic vestigial tail. Certain proteins on our red blood cells look +an awful lot like the proteins on those bacteria, and, if you are +unlucky enough that your vestigial tail grows out more than the average +bear, friendly fire ensues. (That last sentence has a staggering number +of mixed metaphors. Smiling, tongue firmly in cheek, he turned to you +and said, “Humans <em>are</em> mixed metaphors.”) + </p> + <h2> + Conclusion, prefaced by an aside on Jaron Lanier + </h2> + <p> + Jaron Lanier is a computer scientist, ethnomusicologist, and +all-around wonderful weirdo who was behind a lot of the early virtual +reality experiments in the 70s-80s (and now works on VR with Microsoft +when he’s not putting on concerts showcasing Chinese mouth-organs). He +would do this thing where he would create VR avatars with many more +limbs than humans (lobster is a classic one) and attach sensors to the +participants to allow them to control all the limbs with various subtle +movements (hips, elbows, knees, etc.). They found that it didn’t take +long for the humans to achieve surprising proficiency acting as a +&gt;4-limbed creature, and he would wax poetic about the ancient +phylogenetic compatibility still hidden in the motor centers of the +brain, and other related, delicious ideas (maybe it’s not four limbs and +20 digits that are mapped discretely and <em>a priori</em> into the +human brain, maybe it’s the capacity to map any number of prehensile +bits that is inherent, etc. The therapeutic and geeky possibilities +leading from this are way too much fun to contain in an aside). + </p> + <p> + Anyway, the point it this: I love it when the answer is, “idk, maybe +we’re fish. What’s a fish, anyway?” + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/choaked/index.html b/build/posts/choaked/index.html @@ -0,0 +1,162 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + The first detailed description of living with esophageal cancer - +John Casaubon’s 1690 diary + </h1> + <p> + <time id="post-date">2024-04-12</time> + </p> + <p id="post-excerpt"> + John Casaubon was an English surgeon in the late 1600s +who developed an esophageal tumor in late 1690 +and wrote about it in his diary +before dying in January of 1691. +It's harrowing, enlightening, and strangely beautiful. +This blog post is the only place in the world you can read the full transcription of the diary entry. + </p> + <h2> + John Casaubon’s diary + </h2> + <blockquote> + <p> + Monday Dec 29. 90. + </p> + </blockquote> + <blockquote> + <p> + At dinner I was almost choaked by swallowing a bit of a roasted Sd of +mutton which as I thought stuck in the passage about the mouth of the +stomach. But it suffered noething to goe downe and the stomach threw all +up, though never soe small in quantitie, to all our amazements the +sckilfull not knowing what 2 make of my condition. It being an unusuall +afflixion wch. my melancholi suggested it an extraordinarie judgment. I +could swallow about 2 spoonfulls about half way (as I thought) and then +it would flush up in spite of my hart. Some small humiditie or dropps of +what I dranck, rather distilld, or dropt into the stomach which afforded +a bare living nourishment and on a sudden I grew lean as a skeleton and +at some tymes very faint and feeble, although I recouerd in some measure +and had stomach 2 eate, my meate doeth noe gt. good and I am in a kind +of atrophie. What warme weather may do I cant’ tell, but hope well. +Alwayes after I have bine at Stoole I am for a whyle very faint or weake +which I much wonder at. It is a sine of gt weakenes certainly and of +insoaed decay. + </p> + </blockquote> + <h2> + Context + </h2> + <p> + A couple of friends and I wrote a <a href="https://doi.org/10.3390/cancers16030618">paper</a> on the history +of esophageal cancer, mentioned elsewhere on this blog. + </p> + <p> + One of the neat things in the paper is the first full transcription +of a diary entry from John Casaubon, which is the first first-person +detailing of esophageal cancer I can find. It’s the last entry in the +diary, and from what I could gather he died within the next week or two. +It has been transcribed in partial form in <a href="https://doi.org/10.1016/j.gtc.2009.01.003">other</a> <a href="https://pubmed.ncbi.nlm.nih.gov/28952239/">papers</a>, but I had +to know what I was missing in the ellipses, so wrote to the archivist at +the Southampton City Archives in the United Kingdom, who was great and +sent me a scan of the relevant page. The copyright for the microfilm +scan of the diary is owned by the British Library (oh, the complexities +of copyright), but the text itself is ancient and therefore public +domain, so I finished the transcription and included it in the paper. My +transcription also does not attempt to modernize or “correct” any of the +spelling or punctuation: this is exactly what he wrote (including using +“2” instead of “to,” and the absolutely delightful 1600s British +phonetic spelling of the word “inside” as “insoaed”). + </p> + <p> + However! I should say, “One of the neat things in the paper was +<em>supposed</em> to be…” + </p> + <p> + Somehow, at some point in the revision process, a line in the +transcription disappeared. None of us noticed the omission, focused as +we were on other things the reviewers wanted tuned up. The transcription +is also present in full in my author’s working copy, so I have no idea +how a small chunk was omitted. There was no copy-pasta, I sent the +working copy to the journal in full. In any case, I wrote to the journal +to ask that the missing line be added, and, after a review process, was +refused. It doesn’t change the scientific conclusions of the paper, and +would require publishing a correction, so they said no. I pushed back, +as it is the only truly unique discrete data in the whole paper +(everything else is contextualization, arrangement, and interpretation +of prior publications). Alas, I suppose my humanist’s heart has +different priorities than the scientific journal’s editors. + </p> + <p> + So, now, this blog post is the only public place you can find the +whole transcription. That’s a bummer, I wish it was immortalized in a +PubMed-indexed journal article, but this is the next best thing. + </p> + <p> + If you are interested in what was omitted in the journal article’s +version, I split out the missing section below. + </p> + <blockquote> + <p> + At dinner I was almost choaked by swallowing a bit of a roasted Sd of +mutton which as I thought stuck in the passage about the mouth of the +stomach. But it suffered noething to goe downe and the stomach threw all +up, though never soe small in quantitie, to all our amazements the +sckilfull not knowing what 2 make of my condition. It being an unusuall +afflixion wch. my melancholi suggested it an extraordinarie judgment. I +could swallow about 2 spoonfulls about half way (as I thought) and then +it would flush up in spite of my hart. Some small humiditie or dropps of +what I dranck, rather distilld, or dropt into the stomach which +afforded + </p> + </blockquote> + <blockquote> + <p> + <em>a bare living nourishment and on a sudden I grew lean as a +skeleton and at some tymes very faint and feeble, although I recouerd in +some measure and had stomach 2 eate, my</em> + </p> + </blockquote> + <blockquote> + <p> + meate doeth noe gt. good and I am in a kind of atrophie. What warme +weather may do I cant’ tell, but hope well. Alwayes after I have bine at +Stoole I am for a whyle very faint or weake which I much wonder at. It +is a sine of gt weakenes certainly and of insoaed decay. + </p> + </blockquote> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/claude-notes/index.html b/build/posts/claude-notes/index.html @@ -0,0 +1,448 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Writing clinical notes using AI - a practical experience + </h1> + <p> + <time id="post-date">2024-04-09</time> + </p> + <p id="post-excerpt"> + With Claude 3 Opus (a newish ChatGPT4 competitor) as my copilot, I wrote a pretty darn good SOAP note + for an (invented yet realistic) new consult visit. It took a little massaging to get it right, + but boy howdy, it did a great job. Here are the prompts and outputs. + This stuff has serious potential for streamlining the boring and tedious parts of the job. + </p> + <h2> + LLM, the Great and Terrible + </h2> + <p> + <a href="https://www.anthropic.com/claude">Claude</a> is one of +several new kids on the block in the land of highly capable Large +Language Models (LLMs), and is comparable to (but exceeding in certain +aspects) the incumbent ChatGPT4. + </p> + <p> + I decided to see how it would do writing a SOAP note for an imaginary +(but common and realistic) new patient consult in an oncology +clinic. + </p> + <p> + Why “the Great and Terrible?” Everybody knows by now that LLMs are +great at a lot of things, including writing coherent and fluent English +and conforming to pretty much any common text format you can find online +(from legal documents to Python or JavaScript code). Most folks also +know that LLMs aim to please, and will make up the details they lack in +order to satisfy your request, so their output cannot be trusted too +far, particularly in technical areas. My goal in this was to see how +close I could get to a usable clinic note, with full awareness that it +was going to hallucinate and require a tune-up on the back end. In other +words, I am confident LLMs are “terrible” in certain ways, but needed +convincing that they are “great” in this particular arena. + </p> + <h2> + Round 1: The Initial Prompt + </h2> + <p> + I asked Claude for the following: + </p> + <blockquote> + <p> + please write a maximally billable SOAP-style medical note for an +office visit with a new patient with likely stage III esophageal +squamous cell carcinoma. Note that we discussed the need for full +staging with FDG-PET CT to determine the final course of action, and the +risks and benefits of a CROSS-style chemoradiotherapy regimen if stage +III disease is confirmed vs systemic therapy if stage IV disease is +confirmed. The patient describes mild dysphagia to solid foods but +minimal weight loss, has no notable physical exam findings, and labs are +unremarkable other than mild anemia. I reviewed the available +cross-sectional imaging and concur with the radiologist’s report. + </p> + </blockquote> + <p> + And here’s the output: + </p> + <hr> + <p> + Here is a maximally billable SOAP-style medical note for the patient +encounter you described: + </p> + <p> + S (Subjective): 62 yo M with newly diagnosed esophageal cancer +presents to oncology clinic to establish care and discuss treatment +options. Reports mild dysphagia to solid foods x 3 weeks but denies +significant weight loss, odynophagia, chest pain, nausea/vomiting, +hematemesis, melena, hematochezia, or other GI symptoms. ROS negative +except as above. PMH notable for HTN, HLD, and GERD. FH neg for GI +malignancies. SH former smoker, quit 10 years ago, 30 pack-year history. +Married, retired accountant, lives at home with wife. Medications +include lisinopril, atorvastatin, omeprazole. No known allergies. + </p> + <p> + O (Objective):<br> +Vitals: Temp 98.6 F, BP 128/78, HR 72, RR 14, 98% RA, Wt 180 lb, Ht 70 +in<br> +General: NAD, well-appearing. HEENT: PERRL, EOMI, oral mucosa moist. +Neck: no LAD. CV: RRR, no m/r/g. Pulm: CTAB. Abd: soft, NT/ND, no +masses. Ext: no c/c/e, 2+ pulses.<br> +Recent EGD: Esophageal mass 30 cm from incisors, partially obstructing +lumen, biopsies c/w squamous cell carcinoma. CT chest/abd/pelvis: 5 cm +distal esophageal mass, obliterating 75% of lumen. 2 cm regional lymph +node. No distant metastases identified. Radiologist assessment: T3N1M0, +clinical stage III. Labs: CBC: WBC 6.8, Hgb 11.5, Plt 225. CMP nl except +Alb 3.2. CEA 5.2. + </p> + <p> + A (Assessment): + </p> + <ul> + <li> + Esophageal squamous cell carcinoma, clinical stage III (T3N1M0). +Awaiting PET/CT for full staging and treatment planning. + </li> + <li> + Dysphagia secondary to above. Tolerating po currently without +significant loss. Monitor symptoms, intake closely. + </li> + <li> + H/o GERD on omeprazole. Continue current therapy. + </li> + <li> + Anemia, likely anemia of chronic disease but will evaluate as +outpatient. + </li> + </ul> + <p> + P (Plan): + </p> + <ol type="1"> + <li> + Will obtain FDG-PET/CT scan to complete staging. + </li> + <li> + If no distant metastatic disease, recommend neoadjuvant +chemoradiotherapy per CROSS regimen (carboplatin/paclitaxel q week x 5 + +41.4 Gy in 23 fractions). Discussed expected toxicities including +fatigue, esophagitis, nausea, neutropenia and importance of close +monitoring. + </li> + <li> + If metastatic disease identified, will pursue systemic chemotherapy, +likely FOLFOX or EOX regimen, rather than local therapy. May require +palliative measures for dysphagia (stent, dilation prn). + </li> + <li> + Check iron studies, B12, folate. Replace as indicated. + </li> + <li> + Nutrition consult. Encourage high calorie/protein foods. + </li> + <li> + RTC in 1 week to review PET/CT results and finalize treatment plan. +Sooner prn for worsening dysphagia, intolerance of po. + </li> + </ol> + <hr> + <p> + The LLM has added in a host of things I didn’t ask it for +specifically but do appreciate it including, which is what I hoped for +when I asked for a “maximally billable note” - e.g. the review of +systems, PMH, FH, SH, a reasonable assessment and plan for the anemia, +RTC, etc. Certain aspects are completely fabricated (age, vital signs, +the specifics of the radiology report, labs). Some things are +technically correct but not what I would do (e.g. very few people in the +US use the EOX regimen), so would need adjusting. I was a bit surprised +that it went ahead and put in the general plan for CROSS too - those +details are correct. + </p> + <h2> + Round 2: The Placeholder Marks + </h2> + <p> + I asked Claude to replace the invented values with placeholder marks +so I could fill them in later: + </p> + <blockquote> + <p> + That’s pretty good. Instead of inventing vital signs, imaging +reports, and lab values, please write it again to instead put in *** +placeholder marks in these areas so I can fill them in later. + </p> + </blockquote> + <p> + Claude obliged, creating a SOAP note template with *** all over the +place. It was a bit too much, as you can see: + </p> + <hr> + <p> + Sure, here’s the revised SOAP note with placeholder marks: + </p> + <p> + S (Subjective): *** yo M with newly diagnosed esophageal cancer +presents to oncology clinic to establish care and discuss treatment +options. Reports mild dysphagia to solid foods x *** weeks but denies +significant weight loss, odynophagia, chest pain, nausea/vomiting, +hematemesis, melena, hematochezia, or other GI symptoms. ROS negative +except as above. PMH notable for ***. FH *** for GI malignancies. SH *** +smoker, quit *** years ago, *** pack-year history. ***, ***, lives ***. +Medications include ***. *** allergies. + </p> + <p> + O (Objective): Vitals: Temp *** F, BP *<strong>/</strong>, HR ***, RR +***, ***% RA, Wt *** lb, Ht *** in General: ***. HEENT: ***. Neck: ***. +CV: ***. Pulm: ***. Abd: <em><strong>. Ext: <em><strong>. Recent EGD: +Esophageal mass *** cm from incisors, partially obstructing lumen, +biopsies c/w squamous cell carcinoma. CT chest/abd/pelvis: *** cm distal +esophageal mass, obliterating <em><strong>% of lumen. *** cm regional +lymph node. No distant metastases identified. Radiologist assessment: +T</strong></em>N</strong></em>M</strong></em>, clinical stage ***. Labs: +CBC: WBC ***, Hgb ***, Plt ***. CMP *** except ***. CEA ***. + </p> + <p> + A (Assessment): + </p> + <ul> + <li> + Esophageal squamous cell carcinoma, clinical stage *** +(T<em><strong>N</strong></em>M***). Awaiting PET/CT for full staging and +treatment planning. + </li> + <li> + Dysphagia secondary to above. *** tolerating po currently without +significant *** loss. Monitor symptoms, intake closely. + </li> + <li> + *** on ***. Continue current therapy. + </li> + <li> + Anemia, likely anemia of chronic disease but will evaluate as +outpatient. + </li> + </ul> + <p> + P (Plan): + </p> + <ol type="1"> + <li> + Will obtain FDG-PET/CT scan to complete staging. + </li> + <li> + If no distant metastatic disease, recommend neoadjuvant +chemoradiotherapy per CROSS regimen (carboplatin/paclitaxel q week x 5 + +41.4 Gy in 23 fractions). Discussed expected toxicities including +fatigue, esophagitis, nausea, neutropenia and importance of close +monitoring. + </li> + <li> + If metastatic disease identified, will pursue systemic chemotherapy, +likely FOLFOX or EOX regimen, rather than local therapy. May require +palliative measures for dysphagia (stent, dilation prn). + </li> + <li> + Check iron studies, B12, folate. Replace as indicated. + </li> + <li> + Nutrition consult. Encourage high calorie/protein foods. + </li> + <li> + RTC in *** week(s) to review PET/CT results and finalize treatment +plan. Sooner prn for worsening dysphagia, intolerance of po. + </li> + </ol> + <hr> + <h2> + Round 3: The Goldilocks Zone + </h2> + <p> + Finally, I hit what seems to be a sweet spot: + </p> + <blockquote> + <p> + Forget what I said, please only put in *** placeholders for vital +signs and imaging. It’s ok to make up values for everything else. + </p> + </blockquote> + <p> + It still needs fixing, but isn’t so full of *** that it’s jarring (or +impossible to parse - what does “*** on ***” mean? Anything, and +nothing, that’s what.) + </p> + <hr> + <p> + Understood. Here’s the updated SOAP note with *** placeholders for +vital signs and imaging only: + </p> + <p> + S (Subjective): 62 yo M with newly diagnosed esophageal cancer +presents to oncology clinic to establish care and discuss treatment +options. Reports mild dysphagia to solid foods x 3 weeks but denies +significant weight loss, odynophagia, chest pain, nausea/vomiting, +hematemesis, melena, hematochezia, or other GI symptoms. ROS negative +except as above. PMH notable for HTN, HLD, and GERD. FH neg for GI +malignancies. SH former smoker, quit 10 years ago, 30 pack-year history. +Married, retired accountant, lives at home with wife. Medications +include lisinopril, atorvastatin, omeprazole. No known allergies. + </p> + <p> + O (Objective): Vitals: Temp *** F, BP *<strong>/</strong>, HR ***, RR +<em><strong>, <em><strong>% RA, Wt 180 lb, Ht 70 in General: NAD, +well-appearing. HEENT: PERRL, EOMI, oral mucosa moist. Neck: no LAD. CV: +RRR, no m/r/g. Pulm: CTAB. Abd: soft, NT/ND, no masses. Ext: no c/c/e, +2+ pulses. Recent EGD: Esophageal mass *** cm from incisors, partially +obstructing lumen, biopsies c/w squamous cell carcinoma. CT +chest/abd/pelvis: *** cm distal esophageal mass, obliterating +<em><strong>% of lumen. *** cm regional lymph node. No distant +metastases identified. Radiologist assessment: +T</strong></em>N</strong></em>M</strong></em>, clinical stage ***. Labs: +CBC: WBC 6.8, Hgb 11.5, Plt 225. CMP nl except Alb 3.2. CEA 5.2. + </p> + <p> + A (Assessment): + </p> + <ul> + <li> + Esophageal squamous cell carcinoma, clinical stage III (T3N1M0). +Awaiting PET/CT for full staging and treatment planning. + </li> + <li> + Dysphagia secondary to above. Tolerating po currently without +significant weight loss. Monitor symptoms, intake closely. + </li> + <li> + H/o GERD on omeprazole. Continue current therapy. + </li> + <li> + Anemia, likely anemia of chronic disease but will evaluate as +outpatient. + </li> + </ul> + <p> + P (Plan): + </p> + <ol type="1"> + <li> + Will obtain FDG-PET/CT scan to complete staging. + </li> + <li> + If no distant metastatic disease, recommend neoadjuvant +chemoradiotherapy per CROSS regimen (carboplatin/paclitaxel q week x 5 + +41.4 Gy in 23 fractions). Discussed expected toxicities including +fatigue, esophagitis, nausea, neutropenia and importance of close +monitoring. + </li> + <li> + If metastatic disease identified, will pursue systemic chemotherapy, +likely FOLFOX or EOX regimen, rather than local therapy. May require +palliative measures for dysphagia (stent, dilation prn). + </li> + <li> + Check iron studies, B12, folate. Replace as indicated. + </li> + <li> + Nutrition consult. Encourage high calorie/protein foods. + </li> + <li> + RTC in 1 week to review PET/CT results and finalize treatment plan. +Sooner prn for worsening dysphagia, intolerance of po. + </li> + </ol> + <hr> + <h2> + The Verdict + </h2> + <p> + Overall, writing the first LLM prompt, copying the result into the +chart, and adjusting it for correctness would take about 5 minutes. +Improving the prompt as I did adds some time, but you can keep whatever +prompt engineering bits you figure out for future use. You could also +build yourself a custom template and ask it to fill it out, which would +likely prevent many of the hallucinations (e.g. prepopulate placeholders +for the vitals, labs, imaging, and tell the LLM to leave those +alone). + </p> + <p> + Really, not bad for concise yet comprehensive documentation of a new +consult. For subsequent visits, copying the note forward and adjusting +for new details would be more efficient than going back to the LLM. + </p> + <p> + Here’s the crazy thing about all of the above: the LLM did not ingest +any PHI whatsoever - I gave it a general description of the case only. +No HIPAA is violated. No EMR integration is necessary - this would work +as well in CPRS as it would in Epic. Together, these two features are +powerful, and means you can use this starting today. + </p> + <p> + I know a lot of organizations are nervous about LLMs and AI in +medicine in general, but I’m not certain I understand the hesitation in +this particular arena. The responsibility is still yours for accurate +documentation. The plan is also still yours, developed together with the +patient. Many efficiencies can be gained without needing HIPAA-violating +specifics, and without somehow asking the AI to become the doctor. + </p> + <p> + Also, as a friend pointed out the other day, many, many clinical +notes are chock full of mistakes, whether typos or things copied forward +and not corrected, or more egregious things like true mistakes in +clinical reasoning. It seems to me, based on my brief experience, that +using a smarter Clippy would serve more to cut down these kinds of +errors, rather than propagating sins worse than those we already commit. +No electronic tool, whether a copy button in Epic or a powerful LLM, is +any kind of replacement for being a good clinician or an excuse for +shoddy work. But, on the same token*, I also don’t insist on counting +RBCs myself for every CBC I order - this is a good technological +cognate, since I need to be able to recognize the situations in which +the automated counter doesn’t tell the whole truth, know when the +results in the computer are fishy, and be able to do the visual +inspection myself if necessary, but most of the time I can just order +the CBC and go on my merry way. + </p> + <p> + * ha, “token.” There’s an LLM dad joke for ya. + </p> + <p> + P.S. I asked Claude to write a blog post summarizing my experience +and including the prompts and outputs. It mostly sucked and needed a +complete rewrite. But then again, I didn’t try very hard on the prompt. +I’ve tried asking it to write insurance request letters (e.g. for the +FDG-PET CT, which sometimes gets rejected out of hand even though it’s +2024), consult request letters, consult response letters, and patient +summary letters. Those were all pretty good, minimal tweaking +needed. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/employee-wifi/index.html b/build/posts/employee-wifi/index.html @@ -0,0 +1,241 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Set Up Enterprise Wifi on Arch Linux + </h1> + <p> + <time id="post-date">2021-09-17</time> + </p> + <p id="post-excerpt"> + Most big institutions have guest and employee wifi networks. +Guest wifi is usually fine, fast enough for the basics, +but far inferior to employee wifi. +On a custom-built OS, such as a fairly minimalist Linux distribution, +getting the employee wifi to work +can be a beast. + </p> + <p> + This was a little tricky to get working but very worth it, so here’s +an outline, mostly for my own later benefit. + </p> + <p></p> + <p> + This post is specific to <a href="https://www.vumc.org">VUMC</a>, +with the VUMCEmployee network. + </p> + <p> + Similar steps should be applicable for other enterprise wifi users, +though this post will unquestionably be out of date before long, and the +intricacies of enterprise wifi are infinite. + </p> + <h2> + VUMCGuest is fine + </h2> + <p> + As with other public networks at large institutions, VUMCGuest is +just a little slow and finicky, and it’s annoying to have to +re-authenticate repeatedly to use all the HIPAA-compliant things. + </p> + <h2> + VUMCEmployee is better + </h2> + <p> + I’ll probably put a screenshot here at some point comparing speedtest +scores. VUMCEmployee gives over 100 Mbps down, and around 100 up. + </p> + <p> + It’s also more stable, and latency is around 10ms. + </p> + <p> + Most practical gain, other than faster everything: When I use +VUMCGuest, the keyboard shortcut I use to launch and automatically login +to Epic only works intermittently. On VUMCEmployee, it works reliably. +No more typing! It’s faster and, again, more reliable than tapping the +badge-readers at the VUMC workstations. + </p> + <h2> + Backend + </h2> + <p> + The personal networking stack of greatest beauty on Linux at this +point is: + </p> + <p> + <code>systemd-networkd</code> +<code>systemd-resolved</code> + +<code>iwd</code> + </p> + <p> + Disable and delete <code>NetworkManager</code> and other such +nonsense, if you are unwise like me and installed conflicting and +useless things. + </p> + <p> + If you’d like a GUI, <a href="https://github.com/J-Lentz/iwgtk">iwgtk</a> is nice, but the CLI +shipped with <code>iwd</code> (<code>iwctl</code>) is intuitive, +friendly, and well-documented. I keep the GUI version around for quickly +checking on things via a keyboard shortcut, but use the CLI for any +heavy lifting, which has thankfully become rare since landing on this +setup. + </p> + <h2> + Start with VUMCEmployeeSetup + </h2> + <p> + First, log on to the VUMCEmployeeSetup wifi. Then navigate to one of +my favorite websites, <a href="http://neverssl.com/">http://neverssl.com/</a>. This will force +the redirect to the VUMCEmployee enrollment page (I also use this site +for connecting to public wifi at airports, libraries, coffee shops, +etc.). Agree to the terms and conditions. Then click the “Show all +operating systems” link at the bottom, followed by the “Other Operating +Systems” tab that pops up at the bottom of the list. + </p> + <p> + The “Other Operating Systems” tab has three steps listed, which are +simply the pieces that the various installers put together for you. The +first two are downloads for certificates, and the third is a +template. + </p> + <p> + Finding this tab was the gold mine - initially I repackaged one of +the other Linux installers for Arch, because I thought that (since there +was an installer) the process must be complicated, and repackaging +things from Debian-based systems for Arch-based systems is easy enough. +The repackaged version of the installer was decent at first, but it +turns out that the manual process is easier and more reliable. I also +learned more about enterprise networks in the process, which was an +added bonus (I’m honestly not sure about the sarcasm:sincerity ratio in +the previous sentence). + </p> + <p> + Download the <code>PEM</code> files listed under Steps 1 (root +certificate) and 2 (client certificate). + </p> + <h2> + Make your own <code>iwd</code> profile + </h2> + <p> + Here’s where it goes: +<code>/var/lib/iwd/VUMCEmployee.8021x</code> + </p> + <p> + Below are the contents, sensitive info redacted, then we’ll go +through some of the key parts and one nicety. + </p> + <pre tabindex="0"><code class="language-toml"><span class="hl kwa">[IPv6]</span> +<span class="hl kwb">Enabled</span><span class="hl opt">=</span><span class="hl kwd">true</span> + +<span class="hl kwa">[Security]</span> +<span class="hl kwb">EAP-Method</span><span class="hl opt">=</span>PEAP +<span class="hl kwb">EAP-Identity</span><span class="hl opt">=</span>username +<span class="hl kwb">EAP-PEAP-CACert</span><span class="hl opt">=</span>embed<span class="hl opt">:</span>root_cert +<span class="hl kwb">EAP-PEAP-ServerDomainMask</span><span class="hl opt">=*</span>.radius.service.vumc.org +<span class="hl kwb">EAP-PEAP-Phase2-Method</span><span class="hl opt">=</span>MSCHAPV2 +<span class="hl kwb">EAP-PEAP-Phase2-Identity</span><span class="hl opt">=</span>username +<span class="hl kwb">EAP-PEAP-Phase2-Password</span><span class="hl opt">=</span>password + +<span class="hl kwa">[Settings]</span> +<span class="hl kwb">AutoConnect</span><span class="hl opt">=</span><span class="hl kwd">true</span> + +<span class="hl kwa">[@pem@root_cert]</span> +<span class="hl opt">-----</span>BEGIN CERTIFICATE<span class="hl opt">-----</span> +<span class="hl opt">*</span>lots of gobbledigook goes here<span class="hl opt">*</span> +<span class="hl opt">-----</span>END CERTIFICATE<span class="hl opt">-----</span> +</code></pre> + <p> + Most of these options are outlined in Step 3 from the +VUMCEmployeeSetup, cross-referenced against the Arch Wiki page on +<code>iwd</code>, subsection <a href="https://wiki.archlinux.org/title/Iwd#EAP-PEAP">Network +configuration</a>, and the <a href="https://iwd.wiki.kernel.org/networkconfigurationsettings"><code>iwd</code> +wiki proper</a>. + </p> + <p> + An easy-to-miss step: The <code>EAP-PEAP-Phase2-Method</code> +requirement for <code>MSCHAPV2</code> leads to another required install, +check the wiki for current instructions. + </p> + <p> + Put in your own username and password. + </p> + <p> + My favorite trick in this file is directly embedding the root +certificate in the line <code>EAP-PEAP-CACert=</code> with the syntax +<code>embed:root_cert</code> (any name is fine, doesn’t have to be +<code>root_cert</code>, it’s just a pointer). Then you add a definition +of <code>root_cert</code> in a <code>[@pem@root_cert]</code> section. +Insert the contents of the root certificate directly via copy-paste or +<code>cat</code>, etc. + </p> + <p> + Easiest method, as root: + </p> + <pre tabindex="0"><code class="language-shell">cat /home/beau/dl/root_cert.PEM &gt;&gt; /var/lib/iwd/VUMCEmployee.8021x +</code></pre> + <p> + With the direct embed method, you don’t need to point to the root +certificate file or keep it around at all. + </p> + <p> + Needless to say, <code>VUMCEmployee.8021x</code> is a sensitive file +and should be protected appropriately. However, this file or a version +of it is what the automated tools would have made anyway, so there’s no +special risk here - AND since you did it all yourself you know there was +no funny business coming from a black-box installer. + </p> + <h2> + The other certificate (Client) + </h2> + <p> + I can’t remember what I had to do with the client cert, probably +added using the Chrome/Firefox certificate managers. + </p> + <p> + I had to do this before when getting set up for VA remote access, the +Arch Wiki comes through again with an article on <a href="https://wiki.archlinux.org/title/Common_Access_Card">Common Access +Cards</a> that includes instructions on adding certs to browsers. + </p> + <p> + There’s a chance it’s not even needed? The <a href="https://iwd.wiki.kernel.org/networkconfigurationsettings">specification</a> +no longer supports adding a client cert field without a key, which I +don’t have, and do not, apparently, need (see the section “EAP-PEAP with +tunneled EAP-MSCHAPV2”). At any rate, this setup is working now and I +won’t futz with it further until something breaks. + </p> + <h2> + -&gt; ~~Profit~~ Prosper + </h2> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/geocheatcode/index.html b/build/posts/geocheatcode/index.html @@ -0,0 +1,244 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + geocheatcode + </h1> + <p> + <time id="post-date">2022-04-22</time> + </p> + <p id="post-excerpt"> + Here is background and code +for a trick I use to get +Google to give me best-in-class guesses +for latitude and longitude, +despite goofy and/or downright bad location searches. + </p> + <h2> + Map all the things + </h2> + <p> + I love maps. + </p> + <p> + Several of my projects involve mapping things at scale. + </p> + <p> + When you want to map a few things, you type searches into Google Maps +and get addresses and/or latitudes and longitudes quickly and +reliably. + </p> + <p> + But what if you’d like to map 90,000 things whose locations you don’t +yet know? + </p> + <p> + <a href="https://developers.google.com/maps">Google</a> and <a href="https://www.openstreetmap.org/">OpenStreetMap</a>, as well as +others, provide mapping services you can call programmatically from your +software. You send in some query, such as “VUMC Internal Medicine,” and +they return information relevant to that query, such as street address +and latitude and longitude. Up to a certain number of queries per day or +hour, the services are free, and since my work is academic, rather than +real-time mapping for some for-profit app, I am happy to send in small +batches to stay under the limits in the free tier. + </p> + <p> + I’ve used these services to make large maps, and they work pretty +well. + </p> + <p> + <em>Pretty</em> well. + </p> + <h2> + But mapping is hard + </h2> + <p> + Problems with these services: + </p> + <ol type="1"> + <li> + they expected well-formed and reasonable queries + </li> + <li> + if they didn’t know the answer, the guesses were often wildly off, +or they would refuse to guess at all + </li> + </ol> + <p> + If I’m mapping 90,000 things, I’m going to write some code to go +through each of those 90,000 things and ask the mapping services to +kindly tell me what I want to know. Though I write sanitation code to +clean up the 90,000 things, I’m not going to quality check each of those +90,000 things. Sometimes things among the 90,000 things are kinda nuts +(misspelled, inclusive of extraneous data, oddly formatted), in +idiosyncratic ways that are impossible to completely cover, no matter +how much code I write to catch the weird cases. + </p> + <p> + I would like a solution that is fairly tolerant of weirdnesses, and +makes good guesses. + </p> + <h2> + Google is really good at search + </h2> + <p> + I noticed that when I manually typed things into the Google Maps +search bar, it forgave a myriad of sins and did a great job centering +the map on its best guess. When I copied and pasted some of the weird +things among the 90,000 into the Google Maps search bar (the same things +that made the official mapping services - including Google’s - go all +Poltergeist), <em>voila!</em>, the right answer appeared, success rates +nearing 100%. + </p> + <p> + I thought there must be a way to repeat this process with code, in a +scalable way. + </p> + <p> + Turns out there is, and it’s easy. + </p> + <h2> + <code>geocheatcode.py</code> + </h2> + <pre tabindex="0"><code class="language-python"> +<span class="hl kwa">from</span> requests_html <span class="hl kwa">import</span> HTMLSession + +session <span class="hl opt">=</span> <span class="hl kwd">HTMLSession</span><span class="hl opt">()</span> + + +<span class="hl kwa">def</span> <span class="hl kwd">google_lat_lon</span><span class="hl opt">(</span>query<span class="hl opt">:</span> <span class="hl kwb">str</span><span class="hl opt">):</span> + + url <span class="hl opt">=</span> <span class="hl sng">"https://www.google.com/maps/search/?api=1"</span> + params <span class="hl opt">= {}</span> + params<span class="hl opt">[</span><span class="hl sng">"query"</span><span class="hl opt">] =</span> query + + r <span class="hl opt">=</span> session<span class="hl opt">.</span><span class="hl kwd">get</span><span class="hl opt">(</span>url<span class="hl opt">,</span> params<span class="hl opt">=</span>params<span class="hl opt">)</span> + + reg <span class="hl opt">=</span> <span class="hl sng">"APP_INITIALIZATION_STATE=[[[{}]"</span> + res <span class="hl opt">=</span> r<span class="hl opt">.</span>html<span class="hl opt">.</span><span class="hl kwd">search</span><span class="hl opt">(</span>reg<span class="hl opt">)[</span><span class="hl num">0</span><span class="hl opt">]</span> + lat <span class="hl opt">=</span> res<span class="hl opt">.</span><span class="hl kwd">split</span><span class="hl opt">(</span><span class="hl sng">","</span><span class="hl opt">)[</span><span class="hl num">2</span><span class="hl opt">]</span> + lon <span class="hl opt">=</span> res<span class="hl opt">.</span><span class="hl kwd">split</span><span class="hl opt">(</span><span class="hl sng">","</span><span class="hl opt">)[</span><span class="hl num">1</span><span class="hl opt">]</span> + + <span class="hl kwa">return</span> lat<span class="hl opt">,</span> lon + + +extraneous <span class="hl opt">=</span> <span class="hl sng">""" something something</span> +<span class="hl sng"> the earth is banana shaped</span> +<span class="hl sng"> latitude and longitude </span> +<span class="hl sng"> wouldn't you like to know, maybe """</span> + +relevant <span class="hl opt">=</span> <span class="hl sng">""" Vanderbilt University Medical Center </span> +<span class="hl sng"> Internal Medicine """</span> + +query <span class="hl opt">=</span> extraneous <span class="hl opt">+</span> relevant + +lat<span class="hl opt">,</span> lon <span class="hl opt">=</span> <span class="hl kwd">google_lat_lon</span><span class="hl opt">(</span>query<span class="hl opt">)</span> + +<span class="hl kwa">print</span><span class="hl opt">(</span> + <span class="hl sng">"Hello. "</span> + <span class="hl sng">"My name is Google. "</span> + <span class="hl sng">"I am really good at guessing what you meant. "</span> + f<span class="hl sng">"Your query was '</span><span class="hl ipl">{query}</span><span class="hl sng">'. "</span> + <span class="hl sng">"Here are the coordinates you probably wanted. "</span> + f<span class="hl sng">"The latitude is</span> <span class="hl ipl">{lat}</span><span class="hl sng">, and the longitude is</span> <span class="hl ipl">{lon}</span><span class="hl sng">. "</span> + <span class="hl sng">"Don't believe me? "</span> + <span class="hl sng">"Here it is again, "</span> + <span class="hl sng">"in a format you can paste into the search bar:</span> <span class="hl esc">\n</span><span class="hl sng">"</span> + f<span class="hl sng">"</span><span class="hl ipl">{lat}</span><span class="hl sng">,</span> <span class="hl ipl">{lon}</span> <span class="hl sng"></span><span class="hl esc">\n</span><span class="hl sng">"</span> + <span class="hl sng">"Told ya. "</span> +<span class="hl opt">)</span> +</code></pre> + <p> + Despite having all that extra junk in the query, this returns the +right answer. Because Google is many things good and evil, but of these +one is certain: Google is <em>really</em> good at search. + </p> + <h2> + How does the code work? + </h2> + <p> + If you inspect the source HTML on the Google Maps website after you +search for something and it centers the map on its best guess, and you +scroll way on down (or Ctrl-F search for it) you’ll find +<code>APP_INITIALIZATION_STATE</code>, which contains latitude and +longitude for the place the map centered on. + </p> + <ul> + <li> + <a href="https://www.google.com/maps?q=something+whose+latitude+and+longitude+you+would+like+to+know,+maybe+VUMC+Internal+Medicine">example +search</a> + </li> + <li> + <a href="view-source:https://www.google.com/maps/search/something+whose+latitude+and+longitude+you+would+like+to+know,+maybe+VUMC+Internal+Medicine/">example +source</a> (you have to copy and paste this link into a new tab +manually, clicking won’t work) + </li> + </ul> + <p> + I use the lovely <a href="https://docs.python-requests.org/projects/requests-html/en/latest/"><code>requests-html</code></a> +Python library to send the query to Google, receive the response, and +search through the response for the part I want to extract. Then I use a +little standard Python to parse the extracted part and save the +important bits. + </p> + <h2> + With great power… + </h2> + <p> + Don’t go crazy with this. + </p> + <p> + The trick is good for leisurely automation of location retrieval when +you have squirrelly queries. + </p> + <p> + If you need real-time mapping of many things, you don’t want this +solution. Use the actual APIs, and work instead on formatting the +queries properly before sending them to Google/OSM. + </p> + <p> + Also, if you try to query too much/too quickly, Google will shut you +out after a little while. Put a few seconds of delay between each +request and run it overnight and/or in automated batches. + </p> + <h2> + Know a better way? + </h2> + <p> + I’d love to know. Drop me a line. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/history-egc/index.html b/build/posts/history-egc/index.html @@ -0,0 +1,563 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + A timeline of esophageal cancer + </h1> + <p> + <time id="post-date">2023-10-20</time> + </p> + <p id="post-excerpt"> + A couple of friends and I wrote a review article on the history of esophageal cancer. +The timeline was so interesting I thought I'd share it here, in a place where it can be easily found and updated. + </p> + <p> + I’ll put a link to the article when it’s published. + </p> + <p> + For now, I’m not including any references, and this is an abbreviated +version. I hope to fix both of these things in the future, with the goal +of a definitive, comprehensive list with a clear paper trail (though a +list such as this does require some curation - I’m not interested in +every small technical advance, only major firsts and practice-changing +updates). + </p> + <p> + As a side note, it would be cool if <a href="hemonc.org">HemOnc.org</a> had tables (<em>a</em> table? for +comparative work?) of all oncologic drug approvals, with dates and +indications, for every global approval agency. Maybe with a link to the +trial that led to each approval? (It’s not always 1:1 between +trial:approval, but would be nice to know for the majority of cases +where that pattern holds). It’s a huge task, but would be so useful for +clinicians, researchers, and investors. I’m amazed nobody has done this +yet, though there are some partial lists that were helpful. HemOnc does +have a few wiki entries on dates of drug approvals, but they’re sparse. +(It’s not an easy task, particularly for the Chinese approvals - the +only definitive source for the Chinese NMPA appears to be a pdf that is +in Chinese only. If you read Chinese and would like to help, please +shoot me an email - see the contact link above) + </p> + <p> + If you are several steps ahead and beat me to building the drug +approval tables: brava/bravo/brave/bravi, please lmk and I’ll send you a +string of happy, grateful emojis, and we can talk about +collaboration. + </p> + <p> + Likewise, if you know of an important event in esophageal cancer +history, have a reference, and think I should add it here, please +contact me. + </p> + <h2> + Early History + </h2> + <table> + <thead> + <tr> + <th colspan="3"> + Key events in the early history of esophageal cancer + </th> + </tr> + </thead> + <tbody> + <tr> + <td> + Date + </td> + <td> + Event + </td> + <td> + Notes + </td> + </tr> + <tr> + <td> + 3000 BCE + </td> + <td> + First description of esophageal surgery, written in Egypt. + </td> + <td> + Smith Surgical Papyrus. + </td> + </tr> + <tr> + <td> + 0 BCE + </td> + <td> + First description of EC, written in China. + </td> + <td> + Epidemiologic links to EC described between alcohol, hot drinks, and advanced age. + </td> + </tr> + <tr> + <td> + 131-200 + </td> + <td> + First descriptions of EC written in the West. + </td> + <td> + Dates are the life of Galen, Roman Greek physician who wrote extensively. Poor prognosis described. + </td> + </tr> + <tr> + <td> + 1090 - 1162 + </td> + <td> + First palliative methods for EC described, including esophagogastric feeding tubes. + </td> + <td> + Dates are the life of Ibn Zuhr, Arabian physician who described these methods. + </td> + </tr> + <tr> + <td> + 1543 + </td> + <td> + First detailed illustrations and descriptions of the upper gastrointestinal tract. + </td> + <td> + Vesalius, <i>De Humanis Corporis Fabrica</i> + </td> + </tr> + <tr> + <td> + 1690 + </td> + <td> + First personal description of living with EC. + </td> + <td> + Diary of John Casaubon, English surgeon. + </td> + </tr> + <tr> + <td> + 1770 + </td> + <td> + First written Western hypothesis of the epidemiologic link between alcohol and EC. + </td> + <td> + Ernst Gottfried Gyser, <i>Medical inaugural dissertation on the fatal hunger, caused by callous narrowing of the esophagus, with phenomena worthy of attention which are detected in certain abdominal viscera.</i> + </td> + </tr> + <tr> + <td> + 1857 + </td> + <td> + First described EC operation. + </td> + <td> + Albrecht Theodor von Middeldorph, Breslau surgeon. + </td> + </tr> + <tr> + <td> + 1868 + </td> + <td> + Esophagoscope invented. + </td> + <td> + Adolf Kussmaul, German surgeon. + </td> + </tr> + <tr> + <td> + 1872 + </td> + <td> + First known esophagectomy. + </td> + <td> + Christian Billroth, Austrian surgeon, with Vincenz Czerny assisting. + </td> + </tr> + <tr> + <td> + 1877 + </td> + <td> + First known cervical esophagectomy. + </td> + <td> + Vincenz Czerny. Post-operative survival of 15 months. + </td> + </tr> + <tr> + <td> + 1913 + </td> + <td> + First known curative EC resection. + </td> + <td> + Franz Torek, United States surgeon. Post-operative survival of 12 years. + </td> + </tr> + <tr> + <td> + 1933 + </td> + <td> + First report on a series of EC resections. + </td> + <td> + Tohru Oshawa, Japanese surgeon. 18 resections, 56% mortality. + </td> + </tr> + <tr> + <td> + 1947 + </td> + <td> + First large report on a series of EC resections in the West. + </td> + <td> + Richard Sweet, United States surgeon. 213 resections, 17% mortality, 8% 5-year survival. + </td> + </tr> + <tr> + <td> + 1959 + </td> + <td> + First report with &lt;10% operative mortality + </td> + <td> + Komei Nakayama, Japanese surgeon. 953 resections, 5.8% mortality. + </td> + </tr> + <tr> + <td> + 1981 + </td> + <td> + First report with &lt;5% operative mortality + </td> + <td> + Hiroshi Akiyama, Japanese surgeon. 210 resections, 1.4% mortality, 34.6% 5-year survival. + </td> + </tr> + <tr> + <td colspan="3"> + Acronyms: BCE - Before Common Era. EC - Esophageal Cancer. + </td> + </tr> + </tbody> + </table> + <h2> + Key clinical trials and approvals + </h2> + <table> + <thead> + <tr> + <th colspan="3"> + Key clinical trials and approvals + </th> + </tr> + </thead> + <tbody> + <tr> + <td> + 1981 + </td> + <td> + First neoadjuvant RT trial for EC + </td> + <td> + Launois et al. 40 Gy. Results were negative. + </td> + </tr> + <tr> + <td> + 1984 + </td> + <td> + First neoadjuvant CRT trial for EC + </td> + <td> + Leichman et al. 30 Gy, cisplatin. pCR 37%, operative mortality 27%, no survival benefit. + </td> + </tr> + <tr> + <td> + 1988 + </td> + <td> + First perioperative chemotherapy trial for EC + </td> + <td> + Roth et al. No benefit for cohort overall. mOS of responders 20mo, non-responders 6.2mo, surgery alone 8mo. + </td> + </tr> + <tr> + <td> + 2002 + </td> + <td> + First whole-cohort positive perioperative chemotherapy trial + </td> + <td> + Lancet, United Kingdom. Cisplatin+fluorouracil. mOS 16.8mo vs 13.3mo for surgery alone. + </td> + </tr> + <tr> + <td> + 2010 + </td> + <td> + Trastuzumab shown to have benefit for HER2+ GC and GEJC + </td> + <td> + ToGA trial. Trastuzumab+chemotherapy. mOS 13.8mo vs 11.1mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2012 + </td> + <td> + CROSS trial first report + </td> + <td> + Van Hagen et al. 40 Gy, carboplatin+paclitaxel. mOS 49.4mo vs 24.0mo for surgery alone. + </td> + </tr> + <tr> + <td> + 2017-09-22 + </td> + <td> + First FDA approval for IO for EGC + </td> + <td> + KEYNOTE-059, pembrolizumab monotherapy, approved for 3rd line. Approval was later withdrawn as pembrolizumab moved to earlier lines. + </td> + </tr> + <tr> + <td> + 2019-07-30 + </td> + <td> + First FDA approval for 2nd line IO for EGC + </td> + <td> + KEYNOTE-181, pembrolizumab monotherapy. ESCC with CPS &gt;=10. mOS 8.2mo vs 7.1mo for chemotherapy. + </td> + </tr> + <tr> + <td> + 2020-06-10 + </td> + <td> + First FDA approval for 2nd line IO for EGC, agnostic of CPS + </td> + <td> + ATTRACTION-3, nivolumab monotherapy. ESCC. mOS 10.9mo vs 8.4mo for chemotherapy. + </td> + </tr> + <tr> + <td> + 2020-06-19 + </td> + <td> + First NMPA approval for locally-produced IO, 2nd line camrelizumab for ESCC + </td> + <td> + ESCORT, camrelizumab monotherapy. ESCC. mOS 8.3mo vs 6.2mo for chemotherapy. + </td> + </tr> + <tr> + <td> + 2021-01-15 + </td> + <td> + First FDA approval for antibody drug conjugate in EGC + </td> + <td> + DESTINY-Gastric01, fam-trastuzumab deruxtecan-nxki. EGC, AC, HER2+, 2nd line. mOS 12.5mo vs 8.4mo for chemotherapy. + </td> + </tr> + <tr> + <td> + 2021-03-22 + </td> + <td> + First FDA approval for 1st line IO for EGC + </td> + <td> + KEYNOTE-590, pembrolizumab with chemotherapy, EGC, AC and SCC, CPS agnostic. mOS 13.9mo (ESCC w CPS &gt;=10) vs 8.8mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2021-04-16 + </td> + <td> + Second FDA approval for 1st line IO for EGC + </td> + <td> + CheckMate 649, nivolumab with chemotherapy, similar setting to KEYNOTE-590. mOS 13.8 vs 11.1mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2021-05-05 + </td> + <td> + First FDA approval for 1st line IO + chemotherapy + HER2-targeted therapy + </td> + <td> + KEYNOTE-811, pembrolizumab + trastuzumab + chemotherapy. ORR 74.4% vs 51.9% for trastuzumab + chemotherapy alone. CR 11.3% vs 3.1%, respectively. + </td> + </tr> + <tr> + <td> + 2021-05-20 + </td> + <td> + First FDA approval for adjuvant IO monotherapy + </td> + <td> + CheckMate 577, nivolumab after CROSS, EGC, AC and SCC, CPS agnostic. ESCC mDFS 29.7mo vs 11mo for placebo, EAC 19.4mo vs 11mo. + </td> + </tr> + <tr> + <td> + 2021-12-10 + </td> + <td> + NMPA approval for 1st line camrelizumab + chemotherapy for ESCC + </td> + <td> + ESCORT-1st, camrelizumab with chemotherapy. mOS 15.3mo vs 12.0mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2022-02-21 + </td> + <td> + NMPA approval for 1st line tislelizumab monotherapy for GC and GEJC + </td> + <td> + Based on phase I/II studies. + </td> + </tr> + <tr> + <td> + 2022-04-13 + </td> + <td> + NMPA approval for 2nd line tislelizumab monotherapy for ESCC + </td> + <td> + RATIONALE-302, tislelizumab monotherapy vs chemotherapy, ESCC, PD-L1 agnostic. mOS 8.6mo vs 6.3mo for chemotherapy. + </td> + </tr> + <tr> + <td> + 2022-05-19 + </td> + <td> + NMPA approval for 1st line tislelizumab + chemotherapy for ESCC + </td> + <td> + RATIONALE-306, tislelizumab with chemotherapy, ESCC, PD-L1 agnostic. mOS 17.2mo vs 10.6mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2022-05-27 + </td> + <td> + First FDA approval for 1st line dual IO + </td> + <td> + CheckMate 648, nivolumab with ipilimumab, ESCC, PD-L1 &gt;=1%. mOS 13.2mo for IO + chemotherapy vs 12.8mo for IO + IO vs 10.7mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2022-06-20 + </td> + <td> + NMPA approval for 1st line sintilimab + chemotherapy for GC and GEJC, agnostic of CPS. + </td> + <td> + ORIENT-16, sintilimab + chemotherapy vs chemotherapy, AC. For CPS &gt;= 5, mOS 19.2mo vs 12.9mo for chemotherapy alone. For unselected CPS, mOS 15.2mo vs 12.3mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2023-01-24 + </td> + <td> + First OS data available for HER2 vaccine therapy + </td> + <td> + HERIZON study, HER-Vaxx (IMU-131)+chemotherapy, metastatic or advanced HER2+ GC and GEJC. mOS 13.9mo for vaccine+chemotherapy vs 8.3mo for chemotherapy alone. + </td> + </tr> + <tr> + <td> + 2023-02-24 + </td> + <td> + NMPA approval for 1st line tislelizumab + chemotherapy for GC and GEJC. + </td> + <td> + RATIONALE-305, tislelizumab + chemotherapy vs chemotherapy, AC. For PD-L1 &gt;=5%, mOS 17.2mo for IO + chemotherapy vs 12.6mo for chemotherapy alone. + </td> + </tr> + <tr> + <td colspan="3"> + Acronyms and abbreviations: CPS - combined positive score. (C)RT - (chemo)radiotherapy. (E)AC - (esophageal) adenocarcinoma. EC - Esophageal Cancer. EGC - esophagogastric cancers. (E)SCC - (esophageal) squamous cell carcinoma. FDA - United States Food and Drug Administration.IO - immuno-oncologic therapy. pCR - pathologic complete response. PD-L1 - programmed death-ligand 1.mDFS - median disease-free survival. mo - month(s). mOS - median overall survival. NMPA - China’s National Medical Products Administration. ORR - overall response rate. + </td> + </tr> + </tbody> + </table> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/index.html b/build/posts/index.html @@ -0,0 +1,340 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1 id="title"> + Posts + </h1> + <p> + You can subscribe to the <a href="/atom.xml">Atom feed</a> to receive updates. + </p> + <hr style="opacity:0.2; margin-top:2em"> + <div id="posts-index"> + <h2> + <a href="/posts/choaked">The first detailed description of living with esophageal cancer - +John Casaubon’s 1690 diary</a> + </h2> + <p> + <strong>Last update:</strong> 2024-04-12. + </p> + <p> + John Casaubon was an English surgeon in the late 1600s +who developed an esophageal tumor in late 1690 +and wrote about it in his diary +before dying in January of 1691. +It's harrowing, enlightening, and strangely beautiful. +This blog post is the only place in the world you can read the full transcription of the diary entry. + </p> + <a href="/posts/choaked">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/claude-notes">Writing clinical notes using AI - a practical experience</a> + </h2> + <p> + <strong>Last update:</strong> 2024-04-09. + </p> + <p> + With Claude 3 Opus (a newish ChatGPT4 competitor) as my copilot, I wrote a pretty darn good SOAP note + for an (invented yet realistic) new consult visit. It took a little massaging to get it right, + but boy howdy, it did a great job. Here are the prompts and outputs. + This stuff has serious potential for streamlining the boring and tedious parts of the job. + </p> + <a href="/posts/claude-notes">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/s1">Drugs we can’t get: S1</a> + </h2> + <p> + <strong>Last update:</strong> 2024-03-29. + </p> + <p> + There are a number of interesting drugs used in the global market that, + for one reason or another, do not have FDA approval and are therefore inaccessible + in the US, at least outside of clinical trials. S1 is one of them: a better capecitabine. + </p> + <a href="/posts/s1">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/pp-tech-infra">Patient-facing slide decks</a> + </h2> + <p> + <strong>Last update:</strong> 2024-03-23. + </p> + <p> + While I plan on being a physician-scientist forever, I'm not going to work in academia. +Over the past few years I've put together very cool infrastructure for giving academic talks (click "talks" above), +and it was making me sad that it might not get much use after I leave the university. +But then, a ray of sunshine: Why not use my slide deck infrastructure to help in patient conversations? + </p> + <a href="/posts/pp-tech-infra">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/cad-fish">Cold agglutinin disease: fish out of water?</a> + </h2> + <p> + <strong>Last update:</strong> 2024-03-22. + </p> + <p> + Cold agglutinin disease is a fascinating and strange phenomenon, and might happen because we're fish. + </p> + <a href="/posts/cad-fish">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/history-egc">A timeline of esophageal cancer</a> + </h2> + <p> + <strong>Last update:</strong> 2023-10-20. + </p> + <p> + A couple of friends and I wrote a review article on the history of esophageal cancer. +The timeline was so interesting I thought I'd share it here, in a place where it can be easily found and updated. + </p> + <a href="/posts/history-egc">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/add-zfs-mirror">How to add a mirror to a single ZFS disk</a> + </h2> + <p> + <strong>Last update:</strong> 2023-10-19. + </p> + <p> + tl;dr: <code>zpool attach data /dev/disk/by-partlabel/zfs-3a1xx /dev/sdx0</code>. Adjust for your own pool and disks. + </p> + <a href="/posts/add-zfs-mirror">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/yt-dlp">yt-dlp Nix config</a> + </h2> + <p> + <strong>Last update:</strong> 2023-10-18. + </p> + <p> + yt-dlp is an incredibly useful and customizable tool +for downloading online videos +from YouTube and elsewhere. +Here's my setup +(declared in Nix, but easily generalizable). + </p> + <a href="/posts/yt-dlp">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/subsonic-cli">Command-line interfaces for self-hosted music</a> + </h2> + <p> + <strong>Last update:</strong> 2023-09-28. + </p> + <p> + Self-hosting a music server is great. +Listening to the tunes via the command line is the way. + </p> + <a href="/posts/subsonic-cli">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/pixel6screen">Pixel 6 DIY screen replacement, with fingerprint reader calibration +using Linux</a> + </h2> + <p> + <strong>Last update:</strong> 2023-09-19. + </p> + <p> + The internet, up to now, says you need Windows or MacOS to calibrate the Pixel's fingerprint reader after installing a new screen and digitizer. +The internet, up to now, was wrong. + </p> + <a href="/posts/pixel6screen">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/pagecrypt">password protecting static web pages</a> + </h2> + <p> + <strong>Last update:</strong> 2023-01-12. + </p> + <p> + Static site generators, by and large, do not have support for password protecting individual pages. +This post shows a strategy that works for any SSG and does not require server access controls. + </p> + <a href="/posts/pagecrypt">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/oo-et-al">good machine learning in medicine</a> + </h2> + <p> + <strong>Last update:</strong> 2022-12-29. + </p> + <p> + Because most machine learning in medicine sucks, I thought you might like to see an example of it done well. + </p> + <a href="/posts/oo-et-al">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/medical-humanities-org">medical-humanities.org</a> + </h2> + <p> + <strong>Last update:</strong> 2022-12-26. + </p> + <p> + I made a static website as an electronic learning system and forum, +with the option for password protected posts and a controlled editing workflow, +for free and without a dedicated server. This post has the highlights. + </p> + <a href="/posts/medical-humanities-org">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/thanks">I made a thanks page</a> + </h2> + <p> + <strong>Last update:</strong> 2022-12-19. + </p> + <p> + A public, running journal of "hey, thanks" +to the folks who make my life better, in big and small ways. +Check it out <a href="/thanks">here</a>. + </p> + <a href="/posts/thanks">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/mime">fix MIME Types to unbreak RSS feeds served by OpenBSD’s +httpd(8)</a> + </h2> + <p> + <strong>Last update:</strong> 2022-11-13. + </p> + <p> + I've been getting back into RSS lately. +Turns out, my own RSS feed was broken. + </p> + <a href="/posts/mime">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/ugbsd">Upgrading out-of-date OpenBSD installs</a> + </h2> + <p> + <strong>Last update:</strong> 2022-11-11. + </p> + <p> + First of all, don't do how I do. +Upgrade your installs regularly. +OpenBSD makes it very easy. + </p> + <a href="/posts/ugbsd">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/geocheatcode">geocheatcode</a> + </h2> + <p> + <strong>Last update:</strong> 2022-04-22. + </p> + <p> + Here is background and code +for a trick I use to get +Google to give me best-in-class guesses +for latitude and longitude, +despite goofy and/or downright bad location searches. + </p> + <a href="/posts/geocheatcode">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/intake-2022-03-25">Intake presentation on candidal esophagitis</a> + </h2> + <p> + <strong>Last update:</strong> 2022-03-25. + </p> + <p> + candidal esophagitis, achalasia, H Pylori PUD + </p> + <a href="/posts/intake-2022-03-25">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/employee-wifi">Set Up Enterprise Wifi on Arch Linux</a> + </h2> + <p> + <strong>Last update:</strong> 2021-09-17. + </p> + <p> + Most big institutions have guest and employee wifi networks. +Guest wifi is usually fine, fast enough for the basics, +but far inferior to employee wifi. +On a custom-built OS, such as a fairly minimalist Linux distribution, +getting the employee wifi to work +can be a beast. + </p> + <a href="/posts/employee-wifi">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/mr-2021">Morning Report 08/23/2021</a> + </h2> + <p> + <strong>Last update:</strong> 2021-08-23. + </p> + <p> + Diagnosis is... MDS/MPN/MF NOS. +i.e., who knows. + </p> + <a href="/posts/mr-2021">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + <h2> + <a href="/posts/rmd-py">R Markdown is my spirit animal</a> + </h2> + <p> + <strong>Last update:</strong> 2019-10-20. + </p> + <p> + Turns out that a better way does exist, and it is R Markdown. + </p> + <a href="/posts/rmd-py">Read more</a> + <hr style="opacity:0.2; margin-top: 3em"> + <br> + </div> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/intake-2022-03-25/index.html b/build/posts/intake-2022-03-25/index.html @@ -0,0 +1,99 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Intake presentation on candidal esophagitis + </h1> + <p> + <time id="post-date">2022-03-25</time> + </p> + <h2> + cc: trouble swallowing and weight loss + </h2> + <p> + 28M w few weeks of trouble swallowing (gets stuck “right here,” +points to mid-sternum), solid/liquids same, gradual over months-weeks, +some vomiting w/o specific timing. Sometimes has pain when not eating. +20lb weight loss over months. No skin lesions. ?thrush. + </p> + <h2> + PMHx/PSHx + </h2> + <p> + dx BPD, no other dx or procedures + </p> + <h2> + SHx + </h2> + <ul> + <li> + MSM w occasional use of protection, no PrEP + </li> + <li> + occ MJ use, no other substances + </li> + <li> + unemployed, lives w mom + </li> + <li> + no unusual hobbies or travel + </li> + </ul> + <h2> + PE + </h2> + <p> + HR 100, SBP 80 -&gt; 100 w 500mL LR, AF cachectic (temporal, +hypothenar wasting) +skin tenting diffuse abd tenderness + </p> + <h2> + w/u + </h2> + <p> + Hgb 10, MCV 88, WBC ~4, ANC 1500 BMP wnl Alb 3.4 HIV+, VL 15k, rest +of STI -ve + </p> + <p> + CXR wnl (AP and lateral) + </p> + <h2> + dx + </h2> + <p id="post-excerpt"> + candidal esophagitis, achalasia, H Pylori PUD + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/medical-humanities-org/index.html b/build/posts/medical-humanities-org/index.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + medical-humanities.org + </h1> + <p> + This post is a work in progress. + </p> + <p> + <time id="post-date">2022-12-26</time> + </p> + <p id="post-excerpt"> + I made a static website as an electronic learning system and forum, +with the option for password protected posts and a controlled editing workflow, +for free and without a dedicated server. This post has the highlights. + </p> + <p> + It’s here: <a href="https://medical-humanities.org">medical-humanities.org</a> + </p> + <h2> + First, free as in beer + </h2> + <p> + New educational endeavors are, in my experience anyway, almost always +bootstrapped. They start with an idea, passion, even erudition, but +rarely with money. + </p> + <p> + This was no different. + </p> + <p> + There’s some funding coming in, including some I’m grateful for as it +will recompense the time I spent building the website, but overall this +thing needs to run for free. + </p> + <p> + Because of that, I used the best suite of free tools I know of: +GitHub, GitHub Actions, Netlify’s free tier, NetlifyCMS, Hugo, and +digital elbow grease. + </p> + <h2> + Second, free as in freedom (of speech, and the ability to choose +what to share on the open web) + </h2> + <p> + While we have a strict policy against violating HIPAA, we also want +an open forum that can be honest, vulnerable, critical if need be. + </p> + <p> + Though the students are encouraged to make their writing available +for all to read, forming a kind of living magazine from the assignments, +we also want to make it very easy to keep the assignments just within +the group if desired. + </p> + <p> + This combination of desired features led to a need for selective +password protection of certain pages, opted into or out of by each +student writer. + </p> + <p> + Usually, password protection on a website is akin to a lock on a +door, beyond which is a table that has the stuff you want to read. The +routes to sensitive data are locked by the server, you need the key to +get into the room, but once you get in the room you are free to wander +over to the table and leaf through the dusty stack of papers. Since I’m +not paying for a server I fully control, this approach is not going to +work. Every route is accessible by the whole internet, every door is +open. So, instead of worrying about a door and a lock, we trade the +dusty stack of papers for a Rubix cube with a million facets, containing +a message that only comes to light when you match up all the pieces. +Anybody can come and check out the toy, but unless you know the secret +to solving it, it’s just a jumble. + </p> + <p> + To build the Rubix cube I used <a href="https://github.com/Greenheart/pagecrypt">Pagecrypt</a>, which +encrypts individual HTML pages and provides a dialogue to enter a +password to decrypt it. To mark which pages should be encrypted, I used +a simple front-matter key, which a <code>grep</code> command picks out +on every site rebuild. + </p> + <p> + Another neat aspect of this is that the <em>entire</em> page is +encrypted, even the comments section, so if a student wants to make a +post somewhat private and have a personal conversation with the other +members of the class, it’s comfortably hidden from the view of the +public internet. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/mime/index.html b/build/posts/mime/index.html @@ -0,0 +1,145 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + fix MIME Types to unbreak RSS feeds served by OpenBSD’s +httpd(8) + </h1> + <p> + <time id="post-date">2022-11-13</time> + </p> + <h2> + RSS is life - but mine was broken + </h2> + <p> + As of today (2022-11-13) my website lives on an OpenBSD server hosted +at <a href="https://vultr.com">vultr</a>. + </p> + <p> + It’s great, delightfully simple and low-resource, robust, extendable, +low-maintenance. + </p> + <p id="post-excerpt"> + I've been getting back into RSS lately. +Turns out, my own RSS feed was broken. + </p> + <p> + I knew it was janky, but would have had no idea how broken it was if +not for the great folks on the <a href="https://datasette.io">datasette</a> Discord, one of whom reached +out to let me know my RSS link wasn’t working. + </p> + <p> + This could not stand! + </p> + <p> + I’ve been meaning to fix my RSS feed anyway, and now I had a good +reason. + </p> + <h2> + fixing the file itself + </h2> + <p> + I ended up tearing out my previous RSS solution, <a href="https://romanzolotarev.com/rssg.html"><code>rssg</code></a>, which +is great but made some assumptions about my site’s layout that aren’t +true. I could have rewritten the script, but I’m lazy and a little +strapped for time, so I ended up replacing it with a hand-written RSS +file. + </p> + <p> + (The RSS spec is easy enough to write by hand, a little copy-paste +and replace to add a new article - at some point I’ll probably migrate +to <code>hugo</code> or similar and hand off the feed creation to a more +flexible script, but for now this works). + </p> + <p> + After I was certain the file format was fine and had the info I +wanted, I thought I was good. + </p> + <h2> + fixing the MIME Type + </h2> + <p> + The kind soul who reached out to let me know the RSS feed was +malformed reached out again to let me know he was now getting a MIME +Type error. + </p> + <p> + My feedreader of choice, <code>newsboat</code>, is very forgiving of +what it accepts, and didn’t throw any errors when I tested it. +<code>FreshRSS</code>, on the other hand, is more strict, and the feed +would fail even though the file itself was fine. + </p> + <p> + I looked into it, and found out that <code>httpd(8)</code> only +supports a handful of MIME Types by default, so my server was sending +out <code>application/octet-stream</code> (a generic type) instead of +the <code>rss+xml</code> type, and it was confusing the feedreader. + </p> + <h2> + add all the types + </h2> + <p> + Thank goodness, and as usual in OpenBSD, there’s a very easy way to +add all the relevant types one might need. + </p> + <p> + OpenBSD has an internal MIME declaration file you can link to from +within <code>httpd.conf(5)</code>. + </p> + <p> + Here’s the relevant bit, just chuck this on the end of the conf +file: + </p> + <pre tabindex="0"><code class="language-shell"> +types { + include "/usr/share/misc/mime.types" +} +</code></pre> + <p> + And reload <code>httpd(8)</code>. + </p> + <h2> + great success + </h2> + <p> + Much thanks to my new friend on the Datasette Discord, the fantastic +OpenBSD documentation, as always, and <a href="https://blog.lambda.cx/posts/openbsd-httpd-mime-types/">lambda.cx</a> +for writing a post almost identical to mine (except that his had nothing +to do with RSS - he was fixing PDF serving, which should now be fixed on +my site as well). + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/mr-2021/index.html b/build/posts/mr-2021/index.html @@ -0,0 +1,420 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Morning Report 08/23/2021 + </h1> + <p> + <time id="post-date">2021-08-23</time> + </p> + <p> + Details modified, generalized, and otherwise fudged to be +HIPAA-compliant. + </p> + <h2> + HPI + </h2> + <p> + 72F with chest pain, abdominal pain, and constipation. + </p> + <p> + 2-3mo weight loss, night sweats. + </p> + <p> + 2-3wk +perineal ?cyst, initially ttp and hurt to walk, but now +nontender. + </p> + <p> + ~1wk constipation, BRB on TP. + </p> + <p> + +crampy LLQ pain 8/10, x3-4 days, improves with positioning (supine +with head raised somewhat, 3-4 pillows). + </p> + <p> + +LUQ and left-sided chest pain x1-2 days, radiates to L arm, not +related to exertion, lasts a few minutes. + </p> + <h2> + OP Meds + </h2> + <ul> + <li> + duloxetine 60mg + </li> + <li> + ASA 81mg + </li> + <li> + melatonin 6mg + </li> + <li> + no notable allergies + </li> + </ul> + <h2> + PMSHx + </h2> + <ul> + <li> + TVH-BSO for fibroids and endometriosis (~20y ago) + </li> + <li> + hemorrhoids (no surgeries) + </li> + <li> + s/p Moderna COVID vaccine (~4wk ago) + </li> + <li> + UTD on mammograms, colonoscopies, no deviations from regular +schedule + </li> + </ul> + <h2> + SHx + </h2> + <ul> + <li> + monogamous x45y, G2P2 sons, 6yo grandson, all healthy + </li> + <li> + never smoker + </li> + <li> + social EtOH, none this year + </li> + <li> + no non-Rx medicines + </li> + <li> + previously secretary + </li> + <li> + likes to DIY: painting, home crafts, gardening + </li> + </ul> + <h2> + FHx + </h2> + <ul> + <li> + M GM: uterine cancer (~40yo) + </li> + <li> + P GF: lung ca, unknown type (~70yo) + </li> + </ul> + <h2> + PE + </h2> + <ul> + <li> + VS: wnl + </li> + <li> + GEN: NAD + </li> + <li> + HEENT: no LAD + </li> + <li> + PULM: fine + </li> + <li> + CV: fine + </li> + <li> + ABD: NTND, +splenomegaly + </li> + <li> + GYN: 0.5cm lesion R side of anterior perineum, NT, freely +mobile + </li> + <li> + NEURO: fine + </li> + </ul> + <h2> + Labs + </h2> + <ul> + <li> + Hgb 12.7 + </li> + <li> + WBC 58.3 + <ul> + <li> + 0 blasts + </li> + <li> + 0 atypical lymphs + </li> + <li> + <ul> + <li> + slight L shift + </li> + </ul> + </li> + </ul> + </li> + <li> + Plt 490 + </li> + <li> + BMP grossly wnl (gluc 202, <a href="https://www.ashclinicalnews.org/viewpoints/editors-corner/illegitimi-epic-non-carborundum-dont-let-epic-bastards-grind/">Cr +fine</a>) + </li> + <li> + LFTs fine + </li> + <li> + Trop &lt;0.01 + </li> + <li> + urate 10.4 + </li> + <li> + phos 5.0 + </li> + <li> + LDH 330 + </li> + <li> + fibrinogen 355 + </li> + </ul> + <h2> + Other studies + </h2> + <ul> + <li> + EKG wnl + </li> + <li> + CT-PE -ve + </li> + <li> + CT a/p wwo + <ul> + <li> + +10x7cm pelvic mass (central/R adnexum, exerting mass effect on +sigmoid colon) + </li> + <li> + spleen ~20cm largest dimension w ?infarcts x2, + </li> + <li> + L internal iliac vein filling defects c/w nonocclusive DVT + </li> + </ul> + </li> + <li> + PET/CT + <ul> + <li> + splenomegaly with diffusely increased uptake, diffuse FDG uptake of +axial and appendicular skeleton, mild uptake of abdominal pelvic lymph +nodes, and minimal to mild uptake in the pelvic mass. + </li> + </ul> + </li> + </ul> + <h2> + Further notes on hospital course + </h2> + <ul> + <li> + CEA 1.7 (wnl), CA-125 52 (-) + </li> + <li> + urate 9.5 5d later w IVF, given rasburicase 3mg x1 -&gt; urate +3.8 + </li> + <li> + phos similarly without movement, sevelamer eventually helpful + </li> + <li> + pelvic mass bx: smooth muscle + </li> + <li> + BMBx: hypercellular &gt;90%, no blasts, +trilineage atypica &gt; +myeloid, MF-1 fibrosis. + </li> + <li> + JAK2 -ve, BCR/ABL -ve + </li> + <li> + NGS + <ul> + <li> + BRAF 5% (MGUS, MM, hairy cell, hystiocytic/dendritic cell, solid +tumors, therapy-related myeloid neoplasms) + </li> + <li> + KRAS 39% (MDS, AML, MDS/MPN inc CMML and JMML) + </li> + <li> + BCOR 49% (?, possibly germline since allele fraction ~50%) + </li> + <li> + BCORL1 48% (ditto) + </li> + <li> + EZH2 93% (?, likely germline w loss of heterozygosity) + </li> + </ul> + </li> + </ul> + <h2> + And then… + </h2> + <p id="post-excerpt"> + Diagnosis is... MDS/MPN/MF NOS. +i.e., who knows. + </p> + <p> + Started on hydroxyurea and decitabine, c/b recurrent bacteremia, so +currently tx on hold. + </p> + <hr> + <h2> + TLS + </h2> + <p> + The big idea, and a few finer points. + </p> + <p> + <a href="https://jamanetwork.com/journals/jamaoncology/fullarticle/2680750">![TLS](https://cdn.jamanetwork.com/ama/content_public/journal/oncology/937239/cpg180002fa.png?Expires=1632594426&amp;Signature=y4M-w5gXSYJCAVMqGVEyfaPaqZocE9nGaWFnmr7GY7vuiD35l7dL-yJLWn4l3huTo4yBhri1nM0KjQ4dZBBjEYH5tPmKExEJ0D6V~WNou9Av-OEwhyQh79y9feHp790YWY6hTKRJJge958meDu~OmNl8Sl0Wn1N4buZZgVNMRdRds9fKbaDr4DhEdCbMgFbbLSeW9h8KIOm49Gog8FREQNntRaN1jILZgKPBTr9sUNv2BUiapZaLPO4teIf33LkJXcStx6o1VVsZJoP-G-sfMKG3ql1O~23E6LFJeirnMt5MYQdfk-LZlieuSw16HzqTXr-jBtOicDtyFzDJ9VcQ~g__&amp;Key-Pair-Id=APKAIE5G5CRDK6RD3PGA +=500x500 ‘JAMA Oncology 2018, TLS Review’)</a> + </p> + <h3> + Cairo-Bishop classification system + </h3> + <p> + (Most of the following derived from <a href="https://www.asn-online.org/education/distancelearning/curricula/onco/Chapter4.pdf">Chapter +4</a> of the American Society of Nephrology online <a href="https://www.asn-online.org/education/distancelearning/curricula/onco/">Onco-Nephrology +curriculum</a>, which is good and great.) + </p> + <h3> + Laboratory TLS + </h3> + <p> + Definition: Chemotherapy plus the two or more of the following within +3d before or 7d after initiation (so doesn’t account for the spontaneous +TLS seen in our patient). + </p> + <p> + | Metabolite/Electrolyte | Criterion | | :———————– | +:––––––––––––––––––––: | | Uric Acid | &gt;=8 mg/dL or 25% increase from +baseline | | Potassium | &gt;=6mEq/L or 25% increase from baseline | | +Phosphorus | &gt;=4.5mg/dL or 25% increase from baseline | | Calcium | +25% <em>decrease</em> from baseline | + </p> + <p> + The “25% increase/decrease” part is contested, as it may not be +clinically meaningful if the value stays within the normal range. + </p> + <h3> + Clinical TLS + </h3> + <p> + | Laboratory TLS and one or more of | | :–––––––––––––––– | | +creatinine &gt;= 1.5 ULN (Note: just use AKI criteria) | | cardiac +arrhythmia or sudden death | | seizure | + </p> + <ul> + <li> + risk assessment + </li> + </ul> + <h3> + Treating TLS + </h3> + <p> + IVF, electrolytes, rasburicase. + </p> + <p> + Rasburicase is the subject of a recent “Things We Do for No +Reason.” + </p> + <p> + <a href="https://www.journalofhospitalmedicine.com/jhospmed/article/241443/hospital-medicine/things-we-do-no-reasontm-rasburicase-adult-patients-tumor">Pay-walled +article</a>, <a href="https://cdn.mdedge.com/files/s3fs-public/JHM01607424.PDF">PDF made +available by the authors</a> + </p> + <p> + TL;DR: the evidence is thin, but could be reasonable to + </p> + <ul> + <li> + ppx w IVF and allopurinol for low-med risk, + </li> + <li> + use single 3mg dose rasburicase as ppx in high-risk disease (don’t +use weight-based dosing), + </li> + <li> + tx active TLS (laboratory or clinical) with aggressive fluid +resuscitation and electrolyte mgmt, possibly single 3mg dose. + </li> + </ul> + <p> + Hard outcomes in support of rasburicase are generally lacking, e.g. +consistently reducing renal injury, renal failure, length of stay. + </p> + <p> + It also seems like the classification criteria need revamping, with a +larger N. It’s been a while. However, like redefining fever, it’s +difficult to get a clean slate, because we act on the established +criteria so aggressively. + </p> + <hr> + <h2> + MDS/MPN overlap syndromes + </h2> + <p> + Not much to say here, except that the dx is not always clear-cut, +even with BMBx and NGS data, so the clinical picture matters, and +sometimes we have to shoot in the dark. + </p> + <hr> + <p> + Last updated: 2021-08-22 + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/oo-et-al/index.html b/build/posts/oo-et-al/index.html @@ -0,0 +1,168 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + good machine learning in medicine + </h1> + <p> + <time id="post-date">2022-12-29</time> + </p> + <p id="post-excerpt"> + Because most machine learning in medicine sucks, I thought you might like to see an example of it done well. + </p> + <p> + <a href="https://doi.org/10.1056/CAT.22.0214">https://doi.org/10.1056/CAT.22.0214</a> + </p> + <p> + At least on the surface, this looks good. The article is paywalled so +I haven’t gotten to dig into their methods yet, but will update when I +am able to read the whole thing. The approach is the thing I’m keyed in +on - implementation details of course matter, but the biggest problem +with machine learning in medicine is not technique, but angle. Too +often, ML is a new shiny, no meat on its bones (I’m not discounting some +of the delightful advances in e.g. automatic read of ophthalmologic +images, that’s kickass tech and truly practice-changing, but it does +amount to image processing. The stuff I’m talking about here is not a +smarter camera, but automated gestalt handed to you by a mechanical +Turk). + </p> + <h2> + ML is mostly for automation, but automating medicine is scary + </h2> + <p> + The big idea is that while machine learning is great for many things, +the most important thing in industrial machine learning is teaching a +machine to make independent decisions to make things easier for humans +who already have too much cognitive load, or not enough hands, and a +pesky attachment to oxygen, food, and sleep. E.g. if there’s a knob +someone needs to turn when a certain complex set of things happens, and +sometimes the human forgets because they were occupied with all the +switches and buttons instead, or they were on lunch, or sleeping off the +Superbowl party, it sure would be nice to make an algorithm that can +independently assess whether the complex condition has been sufficiently +met, and go ahead and turn the knob for you (and maybe, while it’s at +it, get you a few ibuprofen for that hangover headache). + </p> + <p> + In medicine we usually don’t want a bot making independent decisions, +but this paper from UPMC is a great example of the kind of independent +decision we could stomach, or even welcome. + </p> + <h2> + build a model that is high-yield and low-risk + </h2> + <p> + This system builds a mortality model, which is fun in itself, but +then goes to the next level to automate an e-consult to the palliative +care team for patients at highest risk of mortality after discharge. + </p> + <p> + (Avati et al did the same basic thing at Stanford using a neural +network, which is a fine technology, but their explanatory models were +these shitty, ugly text-based tables that make you want to stab yourself +in the eyes - <a href="https://doi.org/10.1186%2Fs12911-018-0677-8">https://doi.org/10.1186%2Fs12911-018-0677-8</a>). + </p> + <p> + It’s beautiful. Nothing bad bubbles up if the algorithm falls down +altogether (we’re just back where we were before the model went live). +Nothing horrible happens if the algorithm makes a weird claim (every +consult will still be triaged through a human). Possible positives are +numerous. The conversation itself may be one of the most pivotal in the +patient’s end-of-life journey, the hospital system will likely have +reduced readmissions for cases that should be managed at home with +hospice, and we will have more data to put towards figuring out how to +identify the modifiable risk factors for early post-discharge death. + </p> + <p> + This team used the same tech I did when I built a mortality model for +CCF, my favorite kind of algorithm, tree-based models called +gradient-boosting machines (GBMs). + </p> + <h2> + interpretability - gotta do it, maybe they did + </h2> + <p> + What I can’t see yet is if they took the next obvious step, which is +to apply interpretability models on top. The main reason to use a GBM, +in my mind, other than they’re fast to train compared to neural networks +and perform the same if there’s enough data and you tune them properly, +is that they’re inherently compatible with the best meta-models that +allow you to interrogate, both on a per-prediction and cohort level, why +the model is saying whatever it’s saying - they’re actually less of a +black box than many standard statistical models, believe it or not. + </p> + <p> + The best tool for doing this is called SHAP, and the output is +gorgeous - <a href="https://shap.readthedocs.io/en/latest/example_notebooks/overviews/An%20introduction%20to%20explainable%20AI%20with%20Shapley%20values.html">check +it out</a>. We used it here, I think to lovely effect: <a href="https://www.nature.com/articles/s41746-020-0249-z">https://www.nature.com/articles/s41746-020-0249-z</a>, +and it’s only gotten better since then) + </p> + <p> + The other thing I love about pairing the interpretability models with +the predictive models is now you have something you can really learn +from, and, hence, teach from. + </p> + <h2> + but, will this worsen burnout? + </h2> + <p> + The main issue, (given that the model works and has been proven +trustworthy) and which I don’t think I’ve heard anyone talk about in +great depth, is the new alert fatigue this kind of system would make, +for already overworked palliative care teams, and what mitigations they +are taking to keep the firehose of new possible consults manageable. One +thing we could do, and I have faith our house staff could do it well, +would be to implement the same system and have it first trigger an alert +to the primary team, with a recommendation to have the convo and reach +out to pall care if there is any hint of a loose end, or an automated +pivot to pall care if the notes don’t document GOC within a certain +number of days of the alert (or could pop up one of those boxes we love +so… much with a radio button asking you if you’ve had “the talk” +yet). + </p> + <p> + Anywho, I’m not saying I want to actually do this project, I’ve got +other stuff going on, but if you’re reading this you’re the kind of +person who is interested in what tech can do for a hospital system, and +this is a model (ha) combination of the very cutting edge of tech and +the oldest technique we have, which is to offer a hand to the dying and +with them face the abyss. My vision of the future is less Skynet, cold +and isolated, but rather humans forefront, with machines that run in the +background to nudge us into and help make room for more (non-digital, +non-Apple mediated) facetime. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/pagecrypt/index.html b/build/posts/pagecrypt/index.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + password protecting static web pages + </h1> + <p> + <time id="post-date">2023-01-12</time> + </p> + <p id="post-excerpt"> + Static site generators, by and large, do not have support for password protecting individual pages. +This post shows a strategy that works for any SSG and does not require server access controls. + </p> + <p> + <a href="https://github.com/Greenheart/pagecrypt">PageCrypt</a> is +the tool I went with. It’s a TypeScript library that uses the native +<code>Web Crypto API</code> to encrypt html pages, stuff the encrypted +gobbledigook behind a simple password form, and decrypt the page when +the correct key is given. + </p> + <p> + I’m using the CLI version, but there are also native TypeScript and +Node.js versions. + </p> + <p> + The basic idea is this, taken from their docs: + </p> + <pre tabindex="0"><code class="language-sh">npx pagecrypt <span class="hl opt">&lt;</span>src<span class="hl opt">&gt; &lt;</span>dest<span class="hl opt">&gt; [</span>password<span class="hl opt">] [</span>options<span class="hl opt">]</span> +</code></pre> + <p> + Below is an excerpt from a <code>package.json</code> for a Hugo site +I maintain. First I build the site, then run the <code>postbuild</code> +command, which stitches together a piece of code that creates a list of +all the pages we’d like to encrypt and another bit that does the +encryption proper. + </p> + <pre tabindex="0"><code class="language-json"><span class="hl kwa">{</span> + <span class="hl kwc">"make-pw-files-file"</span><span class="hl opt">:</span> <span class="hl sng">"grep -rlF 'password_required: true' content | sed s+</span><span class="hl esc">\\</span><span class="hl sng">.md+</span><span class="hl esc">\\</span><span class="hl sng">/index.html+g | sed s+content/+public/+g &gt; pw_file"</span><span class="hl opt">,</span> + <span class="hl kwc">"protect-files"</span><span class="hl opt">:</span> <span class="hl sng">"cat pw_file | while read f || [[ -n $f ]]; do npx pagecrypt $f $f $PAGECRYPT; done"</span><span class="hl opt">,</span> + <span class="hl kwc">"postbuild"</span><span class="hl opt">:</span> <span class="hl sng">"npm run -s make-pw-files-file &amp;&amp; npm run -s protect-files "</span><span class="hl opt">,</span> +<span class="hl kwa">}</span> +</code></pre> +<br> + <h2> + <code>make-pw-files-file</code> + </h2> + <pre tabindex="0"><code class="language-sh"><span class="hl kwc">grep</span> <span class="hl kwb">-rlF</span> <span class="hl sng">'password_required: true'</span> content <span class="hl opt">|</span> <span class="hl kwc">sed</span> s<span class="hl opt">+</span><span class="hl esc">\\</span>.md<span class="hl opt">+</span><span class="hl esc">\\</span><span class="hl opt">/</span>index.html<span class="hl opt">+</span>g <span class="hl opt">|</span> <span class="hl kwc">sed</span> s<span class="hl opt">+</span>content<span class="hl opt">/+</span>public<span class="hl opt">/+</span>g <span class="hl opt">&gt;</span> pw_file +</code></pre> + <p> + This part uses a few standard Unix commands, the ubiquitous +<code>grep</code> and <code>sed</code>. + </p> + <p> + First it creates a list of markdown source files that have the header +<code>password_required: true</code>. + </p> + <p> + Here’s how that part works: + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl kwc">grep</span> <span class="hl kwb">-rlF</span> <span class="hl sng">"text you're looking for"</span> path<span class="hl opt">/</span>to<span class="hl opt">/</span>files<span class="hl opt">/</span>of<span class="hl opt">/</span>interest +</code></pre> + <ul> + <li> + <code>-r</code> or <code>--recursive</code> searches though the +sub-directories of whichever path you gave it + </li> + <li> + <code>l</code> or <code>--files-with-matches</code> prints the +filenames of any files that match the search + </li> + <li> + <code>F</code> or <code>--fixed-strings</code> searches for the +exact string you ask for, not using regular expressions + </li> + </ul> + <p> + This will output something like: + </p> + <pre tabindex="0"><code class="language-sh">content<span class="hl opt">/</span>file0.md +content<span class="hl opt">/</span>file7.md +content<span class="hl opt">/</span>yet_another_file.md +</code></pre> + <p> + Next it passes that to <code>sed</code>, which replaces +<code>.md</code> with <code>/index.html</code>* resulting in: + </p> + <pre tabindex="0"><code class="language-sh">content<span class="hl opt">/</span>file<span class="hl opt">/</span>index.html +content<span class="hl opt">/</span>file<span class="hl num">7</span><span class="hl opt">/</span>index.html +content<span class="hl opt">/</span>yet_another_file<span class="hl opt">/</span>index.html +</code></pre> + <p> + * you’d have to adjust this command if you aren’t using a +page-per-folder style + </p> + <p> + Then it switches out <code>content/</code> with <code>public/</code>, +leading to the final list: + </p> + <pre tabindex="0"><code class="language-sh">public<span class="hl opt">/</span>file<span class="hl opt">/</span>index.html +public<span class="hl opt">/</span>file<span class="hl num">7</span><span class="hl opt">/</span>index.html +public<span class="hl opt">/</span>yet_another_file<span class="hl opt">/</span>index.html +</code></pre> + <p> + and sends those to a file. + </p> + <p> + Sending the list to a file is not necessary, could just pipe it again +to the stuff in <code>protect-files</code>, but I was getting itchy at +how long the command was getting. + </p> + <br> + <h2> + <code>protect-files</code> + </h2> + <pre tabindex="0"><code class="language-sh"><span class="hl kwc">cat</span> pw_file <span class="hl opt">|</span> <span class="hl kwa">while</span> <span class="hl kwb">read</span> f <span class="hl opt">|| [[</span> <span class="hl kwb">-n</span> <span class="hl kwd">$f</span> <span class="hl opt">]];</span> <span class="hl kwa">do</span> npx pagecrypt <span class="hl kwd">$f $f $PAGECRYPT</span><span class="hl opt">;</span> <span class="hl kwa">done</span> +</code></pre> + <p> + This part emits the contents of <code>pw_file</code>, then loops +through each line (<code>while read f || [[ -n $f ]]</code>) and +encrypts the corresponding file (<code>do npx pagecrypt</code>), finally +saving it back to itself (<code>$f $f</code>). + </p> + <p> + <code>$PAGECRYPT</code> is an environment variable that specifies the +password. + </p> + <p> + You could also set a password-per-page, either auto-generated (but +you’d have to figure out how to get that password to your users), or +using something like another header value in the <code>.md</code> files +that you grep for and save somewhere. For my use case, this is simpler +and scales well. + </p> + <br> + <h2> + and that’s it + </h2> + <p> + As always, <a href="../../contact">let me know</a> if you have any +questions or know of a better way. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/pixel6screen/index.html b/build/posts/pixel6screen/index.html @@ -0,0 +1,210 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Pixel 6 DIY screen replacement, with fingerprint reader calibration +using Linux + </h1> + <p> + <time id="post-date">2023-09-19</time> + </p> + <p id="post-excerpt"> + The internet, up to now, says you need Windows or MacOS to calibrate the Pixel's fingerprint reader after installing a new screen and digitizer. +The internet, up to now, was wrong. + </p> + <h2> + Physical install + </h2> + <p> + My wife’s Pixel 6’s screen stopped working. Phone seemed to be ok +otherwise. + </p> + <p> + We looked at the cost of replacing the phone vs repairing the +screen. + </p> + <p> + A similarly capable phone would cost quite a bit more than the +replacement screen kit, which was ~$130 from <a href="https://www.ifixit.com/products/google-pixel-6-screen-genuine">iFixit</a>. + </p> + <p> + So we bought the replacement screen, watched a few videos on YouTube, +and were off to the races. + </p> + <p> + The tear-down and physical installation were easy. Kudos to Google +for making the Pixels easy to work on. I won’t give much detail here: +just use the videos, whichever ones have a bunch of views. + </p> + <p> + I did waste the included screen adhesive on the first go-around, +because I didn’t realize that the broken screen I removed had been +separated from its frame (so the old frame was still installed and I +installed the adhesive to the its top, rather than in the phone casing +where it belongs, and found out when the phone wouldn’t click back +together with the new screen). It was about $10, including shipping, for +a second adhesive (also iFixit). Fit like a glove. + </p> + <p> + Total $140, and Verizon sent us a free new Pixel 7 anyway (long +story), so now my wife has the 7 and I upgraded from my old Pixel 2XL to +this refurb’d 6. Dang, what an upgrade. Even though the Pixel 6 is +widely considered the dud of the group, I’m loving it. + </p> + <h2> + Fingerprint reader calibration is needed + </h2> + <p> + After it was all installed and working well, the next hurdle was +recalibrating the fingerprint reader. The fingerprint reader is part of +the new screen, and needs calibrated, or it will not even attempt to +work (seems more an “activation” than a “calibration,” no?). + </p> + <p> + The website Google provides for calibration is <a href="https://pixelrepair.withgoogle.com/udfps">https://pixelrepair.withgoogle.com/udfps</a>. +If you look around the internet for troubleshooting related to this +tool, you’ll see a number of old posts recounting various problems, most +of which seem to have been ironed out by this writing. + </p> + <p> + However, the one problem I couldn’t find a fix or happy update for +was how to use that website if you’re not running Windows or MacOS. + </p> + <p> + <a href="https://www.reddit.com/r/GooglePixel/comments/xq82ri/pixel_6_fingerprint_calibration/">This +Redditor couldn’t get it working on Linux or Windows, bad luck?</a>. + </p> + <p> + <a href="https://issuetracker.google.com/issues/217589152?pli=1">Anon +is very angry at Google for not supporting Linux for the calibration +(ctrl-F “linux” to find)</a>. + </p> + <p> + We no longer have anything but Linux/OpenBSD systems in the house +(while I love FOSS and feel glee in this, it is not entirely on purpose, +and I don’t hate Windows or MacOS - my wife’s MBP met an early demise at +the thrown milk cup of a boisterous toddler, or I would have tried that +machine first to avoid the possible headache of ironing out a solution +for Linux for a [hopefully] one-time computing event.). + </p> + <p> + The udfps website was finding my phone, but refusing to go further. I +was in fastboot. Browser didn’t matter (tried OG google-chrome-stable, +vivaldi-stable, firefox). USB-A vs USB-C computer-side connection didn’t +matter (some folks mentioned needing USB-A, so I tried). Activating +Android developer mode didn’t help, and activating USB debugging within +the developer options didn’t either. + </p> + <p> + I saw some posts talking about installing USB drivers to get udfps to +work for Windows machines, so decided to poke around and see if maybe it +was a driver issue on Linux as well. + </p> + <p> + It (probably) was. + </p> + <h2> + Android build tools to the rescue + </h2> + <p> + On Arch Linux (these tools are widely available, distro doesn’t +matter, this is just what I used): + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl slc"># enable multilib - see link below</span> +paru <span class="hl slc"># make sure things are up to date generally</span> +paru <span class="hl kwb">-S</span> android<span class="hl kwb">-tools</span> android<span class="hl kwb">-sdk-build-tools</span> <span class="hl slc"># includes adb and other goodies</span> +reboot +</code></pre> + <p> + Re multilib - not sure if this is strictly needed - see <a href="https://wiki.archlinux.org/title/android#Android_Emulator">https://wiki.archlinux.org/title/android#Android_Emulator</a>. + </p> + <p> + After grabbing the Android build tools listed above and rebooting, +the website found my phone and ran the calibration software without a +hitch. The website didn’t seem to work prior to rebooting, and I’m a +lazy cretin/wizened ol’ wannabe sysadmin, so fancy a reboot to fix all +of life’s woes. + </p> + <p> + The phone does need at least one reboot to activate the calibration +and enable the fingerprint reader, but the calibration software tells +you that, no secret magic here. + </p> + <p> + I don’t recall if I used vivaldi-stable or google-chrome-stable to +run udfps, but I think it was the prior (I bet any Chromium-based +browser would work, provided the right system tools are in place). + </p> + <p> + I also can’t remember if I used USB-A to USB-C or dual-sided USB-C, +but I think it was the dual USB-C. + </p> + <p> + I do think developer mode and USB debugging active on the phone are +required, but I’m not completely certain. + </p> + <p> + I did this all on a Thinkpad T14s. + </p> + <p> + In any case, fingerprint unlock is a go! + </p> + <p> + Almost too easy. + </p> + <h2> + Manual clean up - what, you think this is NixOS? + </h2> + <p> + You probably won’t need these tools again, at least not for a long +while, so: + </p> + <pre tabindex="0"><code class="language-sh">paru <span class="hl kwb">-R</span> android<span class="hl kwb">-tools</span> android<span class="hl kwb">-sdk-build-tools</span> <span class="hl slc"># about 156MiB, not much, but it's the principle of the thing</span> +sudo pacman <span class="hl kwb">-R</span> <span class="hl kwd">$(comm -12 &lt;(pacman -Qq | sort)</span> <span class="hl opt">&lt;(</span>pacman <span class="hl kwb">-Slq</span> multilib <span class="hl opt">|</span> <span class="hl kwc">sort</span><span class="hl opt">))</span> <span class="hl slc"># undo the multilib stuff</span> +sudo <span class="hl kwc">sed</span> <span class="hl kwb">-i</span> <span class="hl sng">'s/\[multilib\]/\#\[multilib\]/'</span> <span class="hl opt">/</span>etc<span class="hl opt">/</span>pacman.conf <span class="hl slc"># undo more of the multilib stuff</span> +paru <span class="hl slc"># finish undoing the multilib stuff</span> +</code></pre> + <h2> + Next steps + </h2> + <h3> + ? 🦒 ? + </h3> + <p> + idk, maybe. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/pp-tech-infra/index.html b/build/posts/pp-tech-infra/index.html @@ -0,0 +1,212 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Patient-facing slide decks + </h1> + <p> + <time id="post-date">2024-03-23</time> + </p> + <p id="post-excerpt"> + While I plan on being a physician-scientist forever, I'm not going to work in academia. +Over the past few years I've put together very cool infrastructure for giving academic talks (click "talks" above), +and it was making me sad that it might not get much use after I leave the university. +But then, a ray of sunshine: Why not use my slide deck infrastructure to help in patient conversations? + </p> + <h2> + talks.beauhilton.com + </h2> + <p> + Academics give lots of presentations. I gave at least one 15min +presentation per week in medical school, and still expect a few 15-45min +presentations per half-year in fellowship. + </p> + <p> + PowerPoint was long ago eschewed in favor of online-first +presentation platforms, typically Google Slides. (Eventually Office365 +came out and PowerPoint came on par with Google Slides, but I had +already moved away.) No emailing around files and accidentally sending +the old version, or running into an incompatible version of the +software, and the presentation could be modified all the way up to (and, +occasionally, during) the event itself. All you need is an internet +connection. + </p> + <p> + Eventually I wanted to move away from proprietary infrastructure +altogether, so started using <a href="https://sli.dev">Slidev</a>. +Slidev is geared toward developers, and as such uses all +industry-standard web technologies, nicely packaged up to make it easy +to go from a text file to a nice-looking presentation. + </p> + <p> + The defaults are great, and, since it’s all web standards, the sky is +the limit as far as customization. + </p> + <p> + The presentation lives in a single text file (markdown). This makes +it easily versionable, tracked by git and backed up to [GitHub, GitLab, +self-hosted git solutions, etc.]. Since I keep a copy on GitHub, the +ease of editing while on-the-go approaches the ease of editing a Google +Slide (all you need is an internet connection and to be logged in). + </p> + <p> + Once the presentation is online, I’m only ever a click or two away +from accessing it. I make sure everything is HIPAA-compliant, and to the +public internet it goes. + </p> + <p> + It’s been great for making talks in my academic program, and, when I +thought I would stay in academia forever, it made sense to me to spend +the time to build out my own infrastructure and subdomain for talks. + </p> + <h2> + emphasizing the “physician” in “physician-scientist” + </h2> + <p> + Recently, I realized that I’d be happier shifting the +physician-scientist balance more toward physician and less toward +scientist, at least as measured by days per week dedicated to each. +While I think I’ll always see myself as as physician-scientist, my +future oncology job (hopefully not “jobs,” but who knows) will be in +private practice, where I’ll see patients 3 or 4 days per week and do +research with the other 0.5-2 days that remain. + </p> + <p> + (The following three paragraphs are an aside on how much time is +spent on what in academia, and touches on why I decided to leave. I +should probably move this out and expand it into its own post. It +doesn’t have much to do with the core of this one.) + </p> + <p> + Classic academia is usually patient care 0.5-1 day per week, research +the remainder - but that’s somewhat misleading, since academics +typically have a number of dedicated inpatient weeks, which may or may +not put a damper on the ability to do research during that time, +depending on how busy they get and whether it’s July (with brand new +trainees) or June (with seasoned trainees). Even accounting for this, it +doesn’t even out to the number of patient-care days per year in private +practice, not by a long shot, but for most folks it isn’t so freed from +day-to-day patient care as it is advertised on the tin. There are a some +academics who do a few weeks of inpatient care per year and that’s it, +no clinic, but that’s the exception. + </p> + <p> + You also pay your own salary out of your research funding, so there’s +a large time burden of not doing research, but writing grants to +convince funders that your research is cool and worth funding. With the +research I do and am interested in continuing, a university +infrastructure adds little, where it isn’t actively working against me, +and I’d rather pay my salary, which will be much bigger, from taking +care of people in clinic than working through the weekend to meet grant +deadlines (while I may also still be on call for the hospital). + </p> + <p> + The university infrastructure is great for basic and clinical +science, and some flavors of data science, but my scientometric stuff is +truly better if done vigilante-style, not attached to academia’s +politics, and predictive modeling/etc. is available and important to +private practice collectives (AON, USON, OneOnc), some of whom have more +robust data infrastructure than the universities do. My most successful +clinical data science project thus far was actually done under the +purview of Business Intelligence for Cleveland Clinic, working with the +Center for Clinical Artificial Intelligence, and the publication was the +side project - this is much more in line with what I may find myself +doing with clinical data science with one of the big three onc groups: +do the thing, do it well, and if you feel like publishing it, gravy. The +scientometric stuff is more classic research, where publication itself +is the deliverable, but even here I’m much more interested in publishing +a living website and tool than a paper in a journal. + </p> + <p> + (And now, back to our regularly scheduled program.) + </p> + <p> + Outside of academia, there’s a high chance I won’t give presentations +nearly as often as I am accustomed to. At first, this made me +simultaneously happy (presentations are so. much. work.) and sad (aww, +my cute little talks website will just gather dust. Poor buddy). Then! I +went to a dinner meeting to learn about renal cancer and get paid to +hang out with friends and eat, and most of the physicians talked about +bringing up primary data to help in discussions with patients. Most +physicians do this when they think it will help, and it certainly wasn’t +the first time I’d heard people talk about it, but the timing was right. +I realized that I have a great use for my talks website, and that I’ve +already been using it this way for some time. + </p> + <h2> + talks in clinic - data for shared decision-making + </h2> + <p> + At least 3 or 4 times in the past few months, I’ve been having +discussions with patients about their prognosis and various options, and +wished I had the graphs to show them without having to poke around +Google and possibly fight with a paywall, then realized I just gave a +talk on the same thing, the talk is on my website, and it has those +graphs. + </p> + <p> + It was very useful to go over the primary data with the patient (not +everybody wants to see this stuff, but a significant number do), and +having a talk I gave to reference immediately lent an additional modicum +of trust to the conversation (most trust is built from showing you care, +but another portion is built from showing you know what you’re +doing). + </p> + <p> + Hearing the physicians at that dinner meeting talk about how they’re +using primary data in their shared decision-making, combined with my +recent decision to go into private practice, and thoughts about what to +do with my website, led me to the following idea: for diseases I’m most +interested in, and for diseases I treat the most, it will be very useful +to have a talk I made and maintain, geared toward patients, to +immediately pull up and have available in clinic, and have the link to +give the patient for review, particularly in those conversations with +their loved ones where they’re trying to remember all the stuff you said +to make a group decision. It would also be easy and useful to have a +slide describing the regimen and its schedule, especially if the way +we’re giving it doesn’t quite match up with the published regimen (e.g. +one of the many regimens that is written as “2 on, 1 off” but we’re +giving it every other week instead). + </p> + <p> + I’m definitely not going to make a talk for every disease or use one +in every conversation, that would be insane and impossible to maintain, +but if I pay attention to the data I use repeatedly, a 30-60min session +adding some of these to a slide deck with a little explanation would +more than carry its weight in future conversations. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/rmd-py/index.html b/build/posts/rmd-py/index.html @@ -0,0 +1,225 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + R Markdown is my spirit animal + </h1> + <p> + <time id="post-date">2019-10-20</time> + </p> + <h2> + update 2022-12-02 + </h2> + <p> + The R Markdown folks have a new project called <a href="https://quarto.org">Quarto</a>, looks like it does all the things +RMD does plus more. + </p> + <h2> + original post + </h2> + <p> + In a [previous post]({% post_url 2019-06-10-python-write-my-paper %}) +I talked about how easy it is, if you’re already doing your own stats +anyway in some research project, to have a Python script output +paragraphs with all the stats written out and updated for you to add +into your paper. + </p> + <p> + The main problem with the approach I outlined was how to get those +nicely updated paragraphs into the document you are sharing with +colleagues. + </p> + <p> + Medicine, in particular, seems wed to Microsoft Word documents for +manuscripts. Word does not have a great way to include text from +arbitrary files, forcing the physician-scientist to manually copy and +paste those beautifully automated paragraphs. As I struggled with this, +I thought (here cue Raymond Hettinger), “There must be a better +way.” + </p> + <p id="post-excerpt"> + Turns out that a better way does exist, and it is R Markdown. + </p> + <p> + Though I was at first resistant to learning about R Markdown, mostly +because I am proficient in Python and thought the opportunity cost for +learning R at this point would be too high, as soon as I saw it demoed I +changed my tune. Here’s why. + </p> + <h2> + Writing text + </h2> + <ul> + <li> + R Markdown is mostly markdown. + <ul> + <li> + Markdown is by far the easiest way to write plaintext documents, +especially if you want to apply formatting later on without worrying +about the specifics while you’re writing (e.g. <code>#</code> just +specifies a header - you can decide how you want the headers to look +later, and that styling will automatically be applied). + </li> + <li> + Plaintext is beautiful. It costs nearly nothing in terms of raw +storage, and is easy to keep within a version control system. Markdown +plaintext is human-readable whether or not the styling has been applied. +Your ideas will never be hidden in a proprietary format that requires +special software to read. + </li> + <li> + I had been transitioning to writing in Markdown anyway, so +1 for R +Markdown. + </li> + </ul> + </li> + <li> + R Markdown is also a little LaTeX. + <ul> + <li> + LaTeX is <a href="https://tex.stackexchange.com/questions/1319/showcase-of-beautiful-typography-done-in-tex-friends">gorgeous</a> +and wonderful, the most flexible and expressive of all the typesetting +tools (though not as fast as our old friend Groff…). It also has a +steeper learning curve than Markdown, and is not so pretty on the screen +in its raw form. R Markdown lets you do the bulk of your work in simple +Markdown, then seamlessly invoke LaTeX when you need something a little +fancier. + </li> + </ul> + </li> + <li> + R Markdown is also a little HTML. + <ul> + <li> + HTML is also expressive, and can be gorgeous and wonderful. It is a +pain to write. As with LaTeX, you can simply drop in some HTML where you +need it, and R Markdown will deal with it as necessary. + </li> + </ul> + </li> + <li> + R Markdown is academic-friendly. + <ul> + <li> + Citations and formatting guidelines for different journals are the +tedious banes of any academic’s existence. R Markdown has robust support +for adding in citations that will be properly formatted in any desired +style, just by changing a tag at the top of the document. Got a +rejection from Journal 1 and want to submit to Journal 2, which has a +completely different set of citation styles and manuscript formatting? +NBD. + </li> + </ul> + </li> + </ul> + <h2> + Writing code + </h2> + <p> + R Markdown, as the name implies, can also run R code. Any analysis +you can dream of in R can be included in your document, and you can +choose whether you want to show the code and its output, the output +alone, or the code alone. People will think you went through all the +work of making that figure, editing it in PowerPoint, screenshotting it +to a .png, then dropping that .png file into your manuscript, but the +truth is… you scripted all of that, so the manuscript itself made the +.png and included it where it needed to go. + </p> + <p> + R Markdown is by no means restricted to R code. This is the killer +app that won me over. Simply by specifying that a given code block is +Python, and installing a little tool (<code>reticulate</code>) that +allows R to interface with Python, I can run arbitrary Python code +within the document and capture the output however I want. That results +paragraph? Sure. Fancy images of predictions from my machine learning +model? But of course. + </p> + <p> + If you don’t want to use any R code ever, that’s fine. R Markdown +doesn’t mind. Use SAS, MATLAB (via Octave), heck, even bash scripts - +the range of language support is fantastic. + </p> + <h2> + Working with friends + </h2> + <p> + R Markdown can be compiled to pretty much any format you can dream +of. My current setup simultaneously puts out an HTML document (that can +be opened in any web browser), a PDF (because I love PDFs), and (AND!) a +.docx Word file, all beautifully formatted, on demand, whenever I hit my +keyboard shortcut. I can preview the PDF or HTML as I write, have a +.docx to send to my PI, and life is good. + </p> + <p> + Also, because you can write in any programming language, you can +easily collaborate between researchers that are comfortable in different +paradigms. You can pass data back and forth between your chosen +languages (for me, R and Python), either directly or by saving +intermediate data to a format that both languages can read. + </p> + <h2> + Automating tasks + </h2> + <p> + Many analyses and their manuscripts, especially if they use similar +techniques (e.g. survival modeling), are rather formulaic. Many +researchers have scripts they keep around and tweak for new analyses +revolving around the same basic subject matter or approach. With R +Markdown, your entire manuscript becomes a runnable program, further +automating the boring parts of getting research out into the open. + </p> + <p> + One of the <a href="https://www.youtube.com/watch?v=MIlzQpXlJNk">first +introductions</a> I had to R Markdown shared the remarkable idea of +setting the file to run on a regular basis, generating a report based on +any updated data, and then sending this report to all the interested +parties automatically. While much academic work could not be so fully +automated, parts of it certainly can be. + </p> + <p> + Perhaps your team is building a database for outcomes in a given +disease, and has specified the analysis in great detail beforehand. One +of my mentors gives the advice that in any project proposal you should +go as far as to mock up the results section, including all figures, so +you make sure you are collecting the right data. If this was done in an +R Markdown document rather than a simple Word document, you could have +large parts of the template manuscript become the real manuscript as the +database fleshes out over time. Then when it’s done, look over the data, +make additions and subtractions as needed, write the discussion +sections, and send it in. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/s1/index.html b/build/posts/s1/index.html @@ -0,0 +1,316 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Drugs we can’t get: S1 + </h1> + <p> + <time id="post-date">2024-03-29</time> + </p> + <p id="post-excerpt"> + There are a number of interesting drugs used in the global market that, + for one reason or another, do not have FDA approval and are therefore inaccessible + in the US, at least outside of clinical trials. S1 is one of them: a better capecitabine. + </p> + <h2> + What is S1? + </h2> + <p> + S1 is the muy sexy common name of a drug manufactured by Taiho +Pharmaceutical in Japan. (It did get a brand name a few years after it +went to market: “Teysuno”). + </p> + <p> + It is a combination of three drugs, all in a pill. + </p> + <p> + The first is a prodrug, called tegafur or ftorafur (“FT” in many +papers), that converts to 5-fluorouracil (5-FU) in the body. +Capecitabine, the only oral 5-FU agent we use in the US, is also a 5-FU +prodrug. + </p> + <p> + The second is gimeracil, a drug that inhibits the enzyme +dyhydropyrimidine dehydrogenase (DPD). This reduces tegafur breakdown in +the GI tract, which allows it to make its way into the bloodstream. +(Patients with inherent DPD deficiency cannot break down drugs in this +family once they make it into the bloodstream, leading to potentially +lethal side effects from 5-FU and it’s cousins - gimeracil is only +creating a local DPD deficiency in the gut. Brilliant.). + </p> + <p> + The third is oteracil, which prevents 5-FU activation in the GI +tract, reducing off-target local adverse effects (capecitabine has +horrible GI side effects in many patients). Also brilliant. + </p> + <p> + <img src="/images/s1-is.png" alt="The FU drugs, including S1"> + </p> + <p> + This is a very rationally conceived drug. Using a prodrug with a +companion that lets it survive long enough to be absorbed lets us use an +oral formulation. Oral is so much more convenient than a pump the +patient has to wear for a couple of days (and which sometimes +malfunctions in strange ways). In capecitabine we already have an oral +5-FU agent that works. However, many of the adverse effects of +capecitabine are local to the GI tract, leading to dose reductions or +drug switch in many cases, so combining something like capecitabine with +something that reduces badness in this location also makes a lot of +sense. + </p> + <p> + This rationality bears out in clinical practice as well (this is not +always the case - a popular saying amongst clinical trialists is “the +road to hell is paved with biological plausibility.” The majority of +ideas that work out well in a petri dish or animal model do not work out +at all when we try them in humans. Hence clinical trials.). Trial after +trial have established S1 as the standard of care in many relevant +regimens in Asia, pretty much any situation where we would use +infusional 5-FU or capecitabine in the US. (I’m sure there’s nuance +here, but it appears generally true.) S1 works well, is easier to give, +and is better tolerated. + </p> + <h2> + So why don’t we have it in the US? + </h2> + <p> + Good. Question. + </p> + <p> + It’s not that it has been completely ignored by researchers in the +West, as you’ll see. The Europeans can get it. And I’m sure Taiho would +love to expand their market to the US. + </p> + <p> + Truthfully, I can’t say I know all the reasons. These things are +complex and the FDA’s reasons are not always readily apparent or written +clearly (though they often are - I have equally strong respect and +disdain for that particular agency, but the trend in my feeling is +toward respect. I used to feel only disdain. The more I learn what and +how they do All The Things, the more I see a bunch of humans really +trying to do their best, rationally to the extent possible, in difficult +situations, with many conflicting interested parties). + </p> + <p> + The clearest reason that S1 is a Big Deal in Asia but unknown here is +a difference in the prevalence of certain versions of enzymes that +convert the tegafur to 5-FU. + </p> + <p> + <em>Aside: I’m going to use the terribly imprecise terms “Asian” and +“Westerner.” The studies in this area use the terms “Asian” and +“Caucasian,” which is worse, as in, “even more wrong than the +alternative I chose.” There is huge genetic and biologic variability +within and across the places we call “Asia” and “The West,” and, if +humans do anything, humans migrate. This biped was made for walkin’, and +that’s just what it do. Don’t take these terms too seriously.</em> + </p> + <p> + Folks from Asian countries tend to have a set of CYP2A6 polymorphisms +that lead to much slower conversion of this particular drug, or, more +appropriately said (Taiho is a Japanese company, after all), Westerners +tend to have a CYP2A6 reality that makes them convert tegafur too damn +fast. Dose-finding studies correspond well with the known differences in +enzymes: the recommended daily dose in Asia is 40mg/m2 twice a day, +whereas the Western dose is 30mg/m2 twice a day. + </p> + <p> + There are other findings from the dosing studies that don’t precisely +line up with differences in processing after absorption. The most severe +toxicity in Asian populations is bone marrow suppression, whereas it is +GI toxicity in Western populations. I don’t know why the oteracil +doesn’t pull its weight in the guts of Westerners. Then again, it might +be entirely unrelated to oteracil, I have no idea. + </p> + <h2> + The Dutch, as usual, are leading the way + </h2> + <p> + The most interesting study to-date using S1 in Westerners was done in +the Netherlands and published as the “<a href="https://doi.org/10.1093/annonc/mdx122">SALTO Study</a>.” + </p> + <p> + (S1 has approvals in Europe, though for a much shorter list of +indications compared with Japan and China, so folks governed by the EMA +can get it and play around, whereas there is no provision at all for +getting it in the US outside of clinical trial - it has orphan +designation but is not approved for anything) + </p> + <p> + They looked at 161 patients who qualified for 5-FU-based monotherapy +for metastatic colorectal cancer. Combination drug therapy is the +standard of care frontline therapy in the metastatic setting, but +monotherapy is a reasonable option for older and more frail patients, +which is who this trial enrolled. They were randomized to S1 vs +capecitabine, and compared efficacy as well as rates of adverse effects. +Efficacy was comparable, and most adverse effects were also comparable, +with the notable exception of hand-foot syndrome. The rates of this were +45% in the S1 group, vs 73% in the capecitabine group. They were also +better able to maintain dose intensity in the S1 group, which is a good +surrogate for the <em>je ne sais quoi</em> of all the little things that +being on therapy does to a person but aren’t fully captured in the other +metrics. Though hand-foot syndrome is not a lethal problem, it can be a +huge quality-of-life problem, particularly when the point of therapy is +palliative in the first place. + </p> + <p> + The same group also published a <a href="https://doi.org/10.1080/0284186X.2016.1278459">retrospective</a> +on 52 patients who had hand-foot syndrome on capecitabine and were +switched to S1, which they then tolerated beautifully. The graph below +is from this paper. “Before” is on the left, and “after” is on the +right. The difference is stark. + </p> + <p> + <img src="/images/s1-cape-hfs.jpg" alt="HFS improves significantly after switching from capecitabine to S1"> + </p> + <h2> + Why I’d love to have S1 in the US + </h2> + <p> + One tough part of my job is telling somebody who wants to continue +therapy but isn’t tolerating the “easiest” form of therapy, even after +dose reduction and maximizing supportive care, that their only options +are to continue to push forward with the poorly tolerated therapy (to a +degree - I’m not afraid to say no and refuse to prescribe if I feel like +I’m hurting someone), or stop cancer-directed therapy altogether. I love +hospice and the services it provides, and many patients are relieved to +make this move, but a significant portion are not. Having another option +in the armamentarium, something else to try for the patient who wants to +try something, especially in such a commonly used class of drugs, would +be great. S1 has clear benefit for patients who have an indication for +5-FU-based therapy but have developed significant hand-foot syndrome, +and I would use it in this situation if I had it on formulary. + </p> + <p> + Also, though I practice in “the West,” not everyone here hails from +the Caucasus + </p> + <p> + <em>“Harumph,” he roared, suddenly on his feet and staring down at +me, his tweed’s elbow patches straining as he assumed the pose of a +portly academic Superman, “most Caucasians do not, in fact, hail from +the Caucasus. Very few do. That was proto-eugenic Neo-Platonic foolery. +If you use the term Caucasian, you have to accept the fallacious +philosophy upon which it was built, and you are equally obligated to +accept the terms from which it is inextricable, namely ‘Caucasoid,’ +‘Mongoloid,’ ‘Negroid.’ Good sir, I do not believe this was your purpose +nor desire. If you must use an imprecise term, at least let it be one of +the cardinal directions, which are not unladen but are not actively +destructive of scientific and societal progress, good sense, morality, +and decency.” The final word was given in a whisper.</em> + </p> + <p> + so having S1 as an up-front option for folks of Asian ancestry would +be nice - it’s a clearly better drug in Asian countries, and I doubt it +was the ground underfoot that made the difference. + </p> + <p> + An idea related to this, with perhaps more biological justification +than a nebulous definition of ancestry, would be to deploy CYP2A6 +screening of some sort to select folks who may most benefit from S1 +rather than capecitabine. + </p> + <p> + This could be done in several ways, all of which have precedence in +other types of screening and at some centers. Ideally you’d do trials to +determine if any of these actually pan out (see above, on the path to +hell). They’re all extrapolations. + </p> + <p> + One option would be to screen all patients with known Asian ancestry, +as is done in some centers for various indications (e.g. GPD deficiency +screening for patients of African descent prior to starting potentially +problematic drugs). + </p> + <p> + Another would be to screen only those who have had dose-limiting GI +intolerance to capecitabine, to make an argument that perhaps they would +tolerate S1 better. (Though, in reality, if S1 was suddenly available +and someone’s GI adverse effects were particularly horrendous on +capecitabine, I’d probably talk with the patient about it and try it if +they want, rather than what I might normally do, which would be to try +infusional 5-FU or a drug from a different class, depending on the +specifics of the situation. I think an empiric approach would be +appropriate, as it wouldn’t require fancy testing which may or may not +actually be predictive, and is what we do most of the time with other +cognate drugs, even if they have class-effect toxicities - some folks +just tolerate Drug A better than Drug B). + </p> + <p> + A third option would be to screen everyone to try and find folks with +compatible CYP2A6 to select for up-front S1. This is expensive. Only +fancy places do population-wide pharmacogenomics (etc.) in practice, and +there are deep debates about how much good this actually does. But hey, +cool if you can get it, especially if you have data to back it up, but +even then make you’d have to make sure you don’t take it without a grain +or six of salt. + </p> + <p> + As it is, even if I wanted to test out some of these ideas, or see if +the Dutch prospective study replicates, I’d have to go through an insane +approval process, and it would be expensive and time consuming. If the +drug was approved and available, studies like the Dutch retrospective +become almost trivially easy. + </p> + <p> + One day. Maybe when the Big Boss of the FDA starts reading my blog +and sends me a golden goose for my genius, along with a Christmas basket +full of S1 and Cadbury. (That’s how it works, right?) + </p> + <h2> + Until next time + </h2> + <p> + This kind of thing is one of my favorites, a thoroughly enjoyable +line of inquiry - what drugs are out there that I can’t get? What +inspiration is there to be had from the practice patterns of other +countries? Would those drugs and patterns work here - why or why +not? + </p> + <p> + It pairs nicely with my obsession with the histories of therapies for +cancers. Love me a critical genealogy,* love me some heteroglossia and +unfinalizability. Butler and Bakhtin ftw. + </p> + <hr> + <p> + * I idly wondered if there had been much movement on that term, which +I got at least thirdhand from Judith Butler, and it looks like there’s +going to be a cool book coming out in the next year or two: <a href="https://absolute-disruption.com/a-genealogy-of-genealogy/">A +Genealogy of Genealogy</a> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/subsonic-cli/index.html b/build/posts/subsonic-cli/index.html @@ -0,0 +1,290 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Command-line interfaces for self-hosted music + </h1> + <p> + <time id="post-date">2023-09-28</time> + </p> + <p id="post-excerpt"> + Self-hosting a music server is great. +Listening to the tunes via the command line is the way. + </p> + <h2> + Subsonic-compatible server backbone + </h2> + <p> + I have <a href="https://www.navidrome.org/">Navidrome</a> installed +(via Docker on NixOS). It’s very nice. + </p> + <p> + With a reverse proxy, <a href="https://tailscale.com/">tailscale</a>, +and LetsEncrypt set up, I can access it via any Subsonic-compatible +music player at <a href="https://music.beauslab.casa">https://music.beauslab.casa</a> (this +URL is available only on my tailnet, so it will 404 for everyone +else). + </p> + <h2> + Desktop GUI interfaces + </h2> + <p> + <a href="https://sublimemusic.app/">Sublime-music</a> is pretty good. +I also often find myself using the Navidrome web UI. + </p> + <p> + (On mobile, <a href="https://symfonium.app/">Symfonium</a> (paid) or +<a href="https://substreamerapp.com/">SubStreamer</a> on Android and <a href="http://michaelsapps.dk/playsubapp/">play:Sub</a> (paid) or <a href="https://substreamerapp.com/">SubStreamer</a> on iOS are my go-tos, +though there are many <a href="http://www.subsonic.org/pages/apps.jsp">others</a>) + </p> + <h2> + CLI interfaces: contenders (STMP, jellycli, sksonic) + </h2> + <p> + If I’m in programming mode, I prefer command-line interfaces, +particularly if they let me use keyboard muscle-memory (i.e. vi +bindings). + </p> + <p> + As such, I tried a few CLI front-ends to access and play my +Navidrome-served tunes. + </p> + <p> + I’m sure there are others. + </p> + <p> + <a href="https://github.com/wildeyedskies/stmp/tree/main">STMP</a> is +clean and works well, but doesn’t have vi bindings yet. + </p> + <p> + <a href="https://github.com/tryffel/jellycli/tree/master">jellycli</a> is +the most polished, and uses vi bindings, but even so the in-app nav is +finicky and doesn’t quite fit my brain (though that might be mostly due +to conflicts with other terminal keybindings I have set up). + </p> + <p> + <a href="https://gitlab.com/yvelon/sksonic">sksonic</a> is a +suckless-style implementation in C, e.g. edit config.h and recompile. It +works, but isn’t polished enough for daily usage (though I don’t expect +it to be - the author states it’s a personal project, and I think +they’re doing a great job, so will keep an eye on it). Partial vi-key +support, could easily be added given the suckless style. + </p> + <h2> + CLI interfaces: the one I picked (ncmpcpp with mopidy backend) + </h2> + <p> + After these, I found myself wishing that I could use <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> and hook it up to +my Subsonic back end. + </p> + <p> + And then I realized: hey, this is a Linux TUI, and ncmpcpp is just a +front-end for <a href="https://www.musicpd.org/">mpd</a>, of course you +can switch out mpd for something that’s Subsonic-aware. + </p> + <p> + ncmpcpp is beautiful, polished, fast, with great vi-key support, and +I’ve been using it for years for local music playback. + </p> + <p> + <a href="https://mopidy.com/">mopidy</a> is a fairly drop-in mpd +replacement that is pluggable, with a number of awesome <a href="https://mopidy.com/ext/">extensions</a>. + </p> + <p> + I should have looked here first. C’est la vie. + </p> + <p> + I perused a few blog posts to get a sense of what to do: + </p> + <ul> + <li> + <a href="https://fsylum.net/blog/setting-up-ncmpcpp-mopidy-spotify-arch-linux/">fsylum’s +post</a> + </li> + <li> + <a href="https://blog.deepjyoti30.dev/using-spotify-with-ncmpcpp-mopidy-linux">Deepjyoti +Barman’s post</a> + </li> + <li> + <a href="https://www.digitalneanderthal.com/post/ncmpcpp/">Digital +Neanderthals’ post</a> (what a great online moniker, well done - his +physical setup is also a delight, sheer cyberdeck practicality) + </li> + </ul> + <p> + It’s pretty easy. + </p> + <p> + The rad thing is that you can get a unified frontend for all your +sources, e.g. Subsonic, Spotify, local files, YouTube, SoundCloud, etc., +just install a plugin and add a config section and you’re off to the +races, never having to leave the terminal. + </p> + <blockquote> + <p> + Source selection (could have many more items here). + </p> + </blockquote> + <p> + <img src="/images/ncmpcpp-mopidy-selector.png" alt="Source selection"> + </p> + <blockquote> + <p> + Artist selection. + </p> + </blockquote> + <p> + <img src="/images/ncmpcpp-mopidy-full.png" alt="Preview"> + </p> + <blockquote> + <p> + Track view. + </p> + </blockquote> + <p> + <img src="/images/ncmpcpp-mopidy-tracks.png" alt="Track view"> + </p> + <h2> + Set up + </h2> + <h3> + Install the things + </h3> + <p> + My main laptop still runs Arch (btw). If I ever switch to NixOS on +this machine, or add this setup to the NixOS server, I’ll probably make +a new post with the Nix way to do this. I bet it’s hardly different, +other than the <code>.nix</code> files. + </p> + <p> + e.g. <code>paru -S ncmpcpp mopidy mopidy-subidy mopidy-mpd</code> + </p> + <p> + Also uninstall and stop mpd, if you’re using it. + </p> + <h3> + Config files + </h3> + <p> + (most of the what’s in the files below is unnecessary for this post, +but I’ve never been mad that someone posted their whole config) + </p> + <p> + (also note that the mopidy config file doesn’t allow # comments, I +just used them for ease of reading with syntax highlighting, will have +to delete prior to actually using) + </p> + <p> + <code>~/.config/ncmpcpp/config</code> + </p> + <pre tabindex="0"><code class="language-sh">ncmpcpp_directory <span class="hl opt">=</span> ~<span class="hl opt">/</span>.config<span class="hl opt">/</span>ncmpcpp +lyrics_directory <span class="hl opt">=</span> ~<span class="hl opt">/</span>.config<span class="hl opt">/</span>lyrics + +progressbar_look <span class="hl opt">= -&gt;</span> +display_volume_level <span class="hl opt">=</span> no + +autocenter_mode <span class="hl opt">=</span> <span class="hl kwc">yes</span> +message_delay_time <span class="hl opt">=</span> <span class="hl num">1</span> + +playlist_display_mode <span class="hl opt">=</span> columns +playlist_editor_display_mode <span class="hl opt">=</span> columns +browser_display_mode <span class="hl opt">=</span> columns + +media_library_primary_tag <span class="hl opt">=</span> album_artist +media_library_albums_split_by_date <span class="hl opt">=</span> no + +ignore_leading_the <span class="hl opt">=</span> <span class="hl kwc">yes</span> +ignore_diacritics <span class="hl opt">=</span> <span class="hl kwc">yes</span> +external_editor <span class="hl opt">=</span> vim +use_console_editor <span class="hl opt">=</span> <span class="hl kwc">yes</span> +</code></pre> + <p> + <code>~/.config/mopidy/mopidy.conf</code> + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl opt">[</span>core<span class="hl opt">]</span> +cache_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CACHE_DIR</span><span class="hl opt">/</span>mopidy +config_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CONFIG_DIR</span><span class="hl opt">/</span>mopidy +data_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_DATA_DIR</span><span class="hl opt">/</span>mopidy +max_tracklist_length <span class="hl opt">=</span> <span class="hl num">10000</span> +restore_state <span class="hl opt">=</span> true + +<span class="hl opt">[</span><span class="hl kwc">file</span><span class="hl opt">]</span> <span class="hl slc"># might switch out for mopidy-local at some point, adds search support via sqlite metadata archive</span> +enabled <span class="hl opt">=</span> true +media_dirs <span class="hl opt">=</span> + ~<span class="hl opt">/</span>media<span class="hl opt">/</span>tunes +excluded_file_extensions <span class="hl opt">=</span> + .directory + .html + .jpeg + .jpg + .log + .nfo + .pdf + .png + .txt + .<span class="hl kwc">zip</span> +show_dotfiles <span class="hl opt">=</span> false +follow_symlinks <span class="hl opt">=</span> false +metadata_timeout <span class="hl opt">=</span> <span class="hl num">1000</span> + +<span class="hl opt">[</span>m3u<span class="hl opt">]</span> +playlists_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CONFIG_DIR</span><span class="hl opt">/</span>mopidy<span class="hl opt">/</span>playlists + +<span class="hl opt">[</span>mpd<span class="hl opt">]</span> +enabled <span class="hl opt">=</span> true +hostname <span class="hl opt">=</span> <span class="hl num">127.0.0.1</span> +port <span class="hl opt">=</span> <span class="hl num">6600</span> <span class="hl slc"># defaults ftw - no change to ncmpcpp config needed if defaults are kept</span> +max_connections <span class="hl opt">=</span> <span class="hl num">20</span> +connection_timeout <span class="hl opt">=</span> <span class="hl num">60</span> + +<span class="hl opt">[</span>subidy<span class="hl opt">]</span> +enabled <span class="hl opt">=</span> true +url <span class="hl opt">=</span> https<span class="hl opt">://</span>music.beauslab.casa +username <span class="hl opt">=</span> admin +password <span class="hl opt">=</span> admin <span class="hl slc"># behind a tailnet anyway, come at me bro</span> +api_version <span class="hl opt">=</span> <span class="hl num">1.16</span> +</code></pre> + <h2> + Future goals + </h2> + <ul> + <li> + snapcast for whole-house audio (<a href="https://www.reddit.com/r/selfhosted/comments/icjmiq/a_music_server_with_a_tli_client/">Reddit +post</a> with some good tips) + </li> + </ul> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/thanks/index.html b/build/posts/thanks/index.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + I made a thanks page + </h1> + <p> + <time id="post-date">2022-12-19</time> + </p> + <p id="post-excerpt"> + A public, running journal of "hey, thanks" +to the folks who make my life better, in big and small ways. +Check it out <a href="/thanks">here</a>. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/ugbsd/index.html b/build/posts/ugbsd/index.html @@ -0,0 +1,101 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Upgrading out-of-date OpenBSD installs + </h1> + <p> + <time id="post-date">2022-11-11</time> + </p> + <p id="post-excerpt"> + First of all, don't do how I do. +Upgrade your installs regularly. +OpenBSD makes it very easy. + </p> + <p> + But, if you do happen to get behind… + </p> + <p> + <code>sysupgrade</code> is very likely to fail. + </p> + <h2> + What happens when you try to upgrade a very old install? + </h2> + <p> + Lots of 404 errors. + </p> + <p> + The <code>sysupgrade</code> utility tries to grab the next version of +the OS from one of the many mirrors (the specific one your system will +use is in <code>/etc/installurl</code>.) + </p> + <p> + The default mirrors only keep the last 2 or 3 versions around, so +when <code>sysupgrade</code> constructs the url and tries to hit it for +downloads, it will fail. + </p> + <h2> + Where to get old versions? + </h2> + <p> + There are a couple of mirrors that keep almost all the old versions +around. + </p> + <p> + <a href="https://mirror.yandex.ru/pub/OpenBSD/">https://mirror.yandex.ru/pub/OpenBSD/</a> +has files going back to OpenBSD 2.x - they seem like the most serious +archivists, at least of the mirrors I looked at. + </p> + <p> + <a href="https://mirror.sjtu.edu.cn/OpenBSD/">https://mirror.sjtu.edu.cn/OpenBSD/</a> +has files going back to 6.5 as of this writing (2022-11-11), also not +too shabby. + </p> + <p> + Do a little <code>vi /etc/installurl</code> and change the link to +one of the above, depending on how delinquent you’ve been. + </p> + <p> + That should allow you to do serial <code>sysupgrade</code> commands +until you catch up. + </p> + <p> + When you get close to the current version, consider switching back to +a closer mirror, both for faster installs and to be kind to the folks +who just saved your bacon. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/posts/yt-dlp/index.html b/build/posts/yt-dlp/index.html @@ -0,0 +1,216 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a class="nav-active" href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + yt-dlp Nix config + </h1> + <p> + <time id="post-date">2023-10-18</time> + </p> + <p id="post-excerpt"> + yt-dlp is an incredibly useful and customizable tool +for downloading online videos +from YouTube and elsewhere. +Here's my setup +(declared in Nix, but easily generalizable). + </p> + <p> + If you just want the config, scroll to the bottom (ignore the +ramblings under the asterisk). + </p> + <h2> + yt-dlp + </h2> + <p> + youtube-dl was, for years, the de facto standard for retrieving +videos from YouTube (and other websites - e.g. Vimeo) for local use, but +eventually it got old and crufty. + </p> + <p> + <a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a> is a fork of +youtube-dl that is more actively maintained, with many upgrades. + </p> + <p> + It has sane defaults, but I have a few things I change to make it +suit my uses. + </p> + <p> + I mostly use it to download instructional videos so they’re easier to +use: no getting interrupted by ads whenever I scrub back and forth to +find or rewatch a particular section, and I can proceed without an +internet connection. + </p> + <p> + It’s also a boon for archival of any video you use frequently for any +reason, e.g. in an educational setting - if you have a lesson plan that +depends on a clip from an online video, it is wise to have your own copy +of the video, both to reduce dependence on finicky wifi and to make it +more likely you’ll have the vid for every time you repeat this lesson in +the future. Videos go offline for strange, sundry, and unpredictable +reasons. + </p> + <p> + (I maintain that YouTube and related video sites, taken as a whole, +are the single greatest source of procedural knowledge ever created by +humankind* - the problems that threaten their utility are, first, +curation, and second, durability) + </p> + <h2> + configuring + </h2> + <p> + yt-dlp accepts a config file, usually placed at +<code>~/.config/yt-dlp/config</code>, so you don’t have to have a long +string of flags and options in your shell command to yt-dlp (you can +override your config file with shell options, so it’s reasonable to set +your defaults to your most common use and not worry about messing up +some divergent situation that may come up). + </p> + <p> + For example, to download the whole <a href="https://www.youtube.com/c/JohnWatsonRooney">JohnWatsonRooney +YouTube channel</a>, all I had do was: + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl kwb">cd</span> youtube<span class="hl kwb">-downloads</span><span class="hl opt">/</span>JohnWatsonRooney +yt<span class="hl kwb">-dlp</span> <span class="hl sng">"https://www.youtube.com/c/JohnWatsonRooney"</span> +</code></pre> + <p> + And it did something like this: + </p> + <p> + <img src="/images/yt-dlp-downloading-example.png" alt="yt-dlp downloading example"> + </p> + <p> + Resulting in: + </p> + <p> + <img src="/images/yt-dlp-filename-example.jpg" alt="yt-dlp filename example"> + </p> + <p> + In the second screenshot you can see that some files are still in +process - when all the parts are downloaded, yt-dlp smushes them into an +mkv container, so the videos/thumbnails/subtitle files are clean and +accessible to most video players. + </p> + <h2> + config + </h2> + <p> + Here’s my config file, with some annotation. + </p> + <p> + I’m using Nix with Home Manager, but you can translate this into the +usual yt-dlp config file syntax with ease. + </p> + <p> + One of the great things about Nix is that it lets me group +installation and configuration for programs that make sense together - +here, I want to use aria2 as the downloader, so I declare the aria2 +options to pass to yt-dlp, and also make sure aria2 is installed (it’s +ok if you installed aria2 in another part of your setup - if a program +is declared for installation in multiple places, Nix is smart enough to +install it only once, so it’s often wise to err on the side of +bundling). + </p> + <p> + If I take this config to any other machine with Nix installed, I’ll +get the whole setup including dependencies. This example is very simple, +just adding another program, but the principle scales to arbitrarily +complex setups. + </p> + <pre tabindex="0"><code class="language-nix"><span class="hl opt">{</span> + programs<span class="hl opt">.</span>yt<span class="hl opt">-</span>dlp <span class="hl opt">= {</span> + enable <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> + settings <span class="hl opt">= {</span> + embed<span class="hl opt">-</span>chapters <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> <span class="hl slc"># embed all the things</span> + embed<span class="hl opt">-</span>metadata <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> + embed<span class="hl opt">-</span>thumbnail <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> + convert<span class="hl opt">-</span>thumbnail <span class="hl opt">=</span> <span class="hl sng">"jpg"</span><span class="hl opt">;</span> + <span class="hl slc"># so every file manager can show the thumbnail - webp support is not quite universal</span> + embed<span class="hl opt">-</span>subs <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> + sub<span class="hl opt">-</span>langs <span class="hl opt">=</span> <span class="hl sng">"all"</span><span class="hl opt">;</span> + <span class="hl slc"># subtitle files are very small, </span> + <span class="hl slc"># and sometimes language names are declared badly, </span> + <span class="hl slc"># so worth it to grab them all</span> + downloader <span class="hl opt">=</span> <span class="hl sng">"aria2c"</span><span class="hl opt">;</span> + downloader<span class="hl opt">-</span>args <span class="hl opt">=</span> <span class="hl sng">"aria2c:'-c -x16 -s16 -k2M'"</span><span class="hl opt">;</span> + <span class="hl slc"># -c is resume if interrupted ("continue"), </span> + <span class="hl slc"># -x is max connections to a server, </span> + <span class="hl slc"># -s is number of connections used for download of a specific file, </span> + <span class="hl slc"># -k is size of chunks</span> + download<span class="hl opt">-</span>archive <span class="hl opt">=</span> <span class="hl sng">"yt-dlp-archive.txt"</span><span class="hl opt">;</span> + <span class="hl slc"># writes a file to the current directory specifying which files have already been downloaded - </span> + <span class="hl slc"># nice for updating your collection of a channel's videos </span> + <span class="hl slc"># (just run the download command again and it will grab only what you're missing)</span> + restrict<span class="hl opt">-</span>filenames <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> <span class="hl slc"># disallow spaces, weird characters, etc.</span> + output <span class="hl opt">=</span> <span class="hl sng">"%(upload_date&gt;%Y-%m-%d)s--%(uploader)s--%(title)s--%(id)s.%(ext)s"</span><span class="hl opt">;</span> + <span class="hl slc"># I like to be able to sort by date </span> + <span class="hl slc"># and have enough info in the filename </span> + <span class="hl slc"># so I don't need to open it to find out what it is, </span> + <span class="hl slc"># so I include the:</span> + <span class="hl slc"># - ISO 8601-style date</span> + <span class="hl slc"># - uploader's name</span> + <span class="hl slc"># - title of the video</span> + <span class="hl slc"># - video ID (for easy copy pasta if I ever want to find it online, </span> + <span class="hl slc"># e.g. to see the comment section or show notes.)</span> + <span class="hl opt">};</span> + <span class="hl opt">};</span> + programs<span class="hl opt">.</span>aria2 <span class="hl opt">= {</span> + enable <span class="hl opt">=</span> <span class="hl kwb">true</span><span class="hl opt">;</span> + <span class="hl opt">};</span> +<span class="hl opt">}</span> +</code></pre> + <h2> + side note + </h2> + <p> + * Contrary to popular belief, things that go online do <em>not</em> +stay online forever: <a href="https://en.wikipedia.org/wiki/Digital_obsolescence">digital +obsolescence</a> is real, and is <a href="https://blog.archive.org/2023/03/25/the-fight-continues/">probably +going to get worse</a> before it gets better (“?better”). This section +is under an asterisk and at the end because it is a side thought, just +an idea that tools like yt-dlp may have import that goes beyond helping +me write web scrapers, build saunas, etc. - maybe they have the +primitives to help build a videographic Whole Earth Catalog for the +ages. I don’t think everything is going to explode any time soon, but +wouldn’t it be interesting to have a digital archive with videos, rather +than just text, of how to do the basic things (and some not-so-basic +things) that make life possible and enjoyable? Some kind of all-in-one +system with redundant storage and a power-supply (hand crank? solar?), +durable screen and speakers, to help you bootstrap the physical needs of +a society? I’m sure the raw content is out there. + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/style.css b/build/style.css @@ -0,0 +1,317 @@ +:root +{ + --Canvas-bg: #201b1b; + --Canvas-color: #fff; + --Pre-bg: #151515; + --Pre-color: #fff; + --Pre-border: #222; + --Main-color: #f2f2f2; + --Code-color: #2adba4; + --Accent1-color: #2adba4; /* green */ + --Accent2-color: #368aeb; /* blue */ + --Highlight-num: #43a60d; + --Highlight-esc: #dfad06; + --Highlight-str: #f77f1d; + --Highlight-pps: #458759; + --Highlight-slc: #a0a0a0; + --Highlight-com: #a0a0a0; + --Highlight-ppc: #94e39; + --Highlight-opt: #ffffff; + --Highlight-ipl: #4dc987; + --Highlight-lin: #555555; + --Highlight-kwa: #d9396a; + --Highlight-kwb: #8655e7; + --Highlight-kwc: #ffffff; + --Highlight-kwd: #00a48f; +} + +img { + display: inline-block; + max-width: 100%; +} + +img[src*='#center'] { + display: block; + margin: auto; +} + +pre, code, sample { + hyphens: none; + color: inherit; +} + +pre +{ + overflow-x: scroll; + scrollbar-width: thin; + scrollbar-color: inherit; + padding: 2rem; + margin-left: -2rem; + margin-right: -2rem; + border: 1px solid var(--Pre-border); + background: var(--Pre-bg); + color: var(--Pre-color); +} + +table { + max-width: 100%; +} + +html { + font-size: 70.5%; +} + +h2 { + font-weight: 200; +} + +h3 { + font-weight: 200; +} + +body { + line-height: 1.5; + font-size: 1.6rem; + max-width: 38em; + margin: auto; + padding: 13px; +} + +.thanks-date { + font-weight:bold; +} + +.thanks-to { + font-style: italic; + font-weight: 200; +} + +.thanks { + padding-top:1em; + padding-bottom:1em; +} + +/* Structural blocks */ + +#page-wrapper +{ + max-width: 88rem; + + padding: 1rem 2rem 2rem; + + margin-left: auto; + margin-right: auto; +} + + +/* Visual styles */ + +html +{ + background: var(--Canvas-bg); + color: var(--Canvas-color); +} + +header +{ + text-align: center; +} + +::selection +{ + background: var(--Selection-bg); + color: var(--Selection-color); +} + +/* shared gradient border */ +nav, footer +{ + border-width: 0; + border-style: solid; + border-color: var(--Accent1-color); + border-image: linear-gradient(to right, var(--Accent1-color), var(--Accent2-color)) 2; +} + +nav +{ + font-size: 1.8rem; + border-bottom-width: 2px; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + word-spacing: 5px; + text-align: center; +} + +main +{ + color: var(--Main-color); + text-rendering: optimizeLegibility; +} + +footer +{ + text-align: center; + padding-top: 1rem; + margin-top: 1rem; + border-top-width: 2px; +} + +div#banner-text +{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.banner +{ + display: flex; + flex-direction: row; + gap: 1rem; + justify-content: center; + align-items: center; + line-height: 1; +} + +.banner-title +{ + margin: 0; + font-size: 3.6rem; + font-weight: 200; + letter-spacing: 0.425em; + /* letter-spacing is applied even to the last letter, + so for proper centering, we have to remove it ourselves, sadly */ + margin-right: -0.425em; +} + +.banner-title a +{ + text-decoration:none; + color: var(--Main-color); +} + +.banner-title a:hover +{ + text-decoration:none; + color: var(--Accent1-color); +} + +a { + color: var(--Accent2-color); +} + +a:hover, a:focus +{ + text-decoration: underline; + color: var(--Accent1-color); +} + +a.nav-active { + color: var(--Accent1-color); + font-weight: 200; +} + +nav a { text-decoration: none; } + +a.here { text-decoration: none; } + +hr +{ + border: 0 none; + color: var(--Accent2-color); + background-color: currentColor; + height: 2px; +} + +hr.footnotes { width: 40%; } + +a.footnote +{ + text-decoration: none; + margin-right: 0.4rem; +} + +ul.toc { list-style: none; } + +h5 { font-size: 1.6rem; } +h6 { font-size: 1.4rem; } + +code, kbd, samp +{ + color: var(--Code-color); +} + + +/** Typography */ + +@supports (hyphens: auto) +{ + main + { + text-align: justify; + hyphens: auto; + } +} + +body +{ + font-family: system-ui, sans-serif; + font-weight: 200; +} + +table, th, td +{ + border: 1px solid var(--Accent1-color); + border-collapse: collapse; +} + +th, td +{ + padding: 0.5em; + hyphens: none; + text-align: left; +} + +.centered { text-align: center; } + +/* Style definition file generated by highlight 3.52, http://www.andre-simon.de/ */ +/* highlight theme: Kwrite Editor */ +body.hl { background-color: #e0eaee; } +pre.hl { color: #000000; background-color:#e0eaee; font-size: 10pt; font-family: monospace; } +.hl.num { color: var(--Highlight-num); } +.hl.esc { color: var(--Highlight-esc); } +.hl.str { color: var(--Highlight-str); } +.hl.pps { color: var(--Highlight-pps); } +.hl.slc { color: var(--Highlight-slc); font-style: italic; } +.hl.com { color: var(--Highlight-com); font-style: italic; } +.hl.ppc { color: var(--Highlight-ppc); } +.hl.opt { color: var(--Highlight-opt); } +.hl.ipl { color: var(--Highlight-ipl); } +.hl.lin { color: var(--Highlight-lin); } +.hl.kwa { color: var(--Highlight-kwa); font-weight: bold; } +.hl.kwb { color: var(--Highlight-kwb); } +.hl.kwc { color: var(--Highlight-kwc); font-weight: bold; } +.hl.kwd { color: var(--Highlight-kwd); } + +@media screen and (max-width: 34em) +{ + .banner, .banner-title + { + display: block; + text-align: center; + margin: auto; + } + .banner + { + margin-bottom: 2rem; + } +} + +@media screen and (max-width: 28em) +{ + .banner-title + { + font-size: 3.2rem; + } +} diff --git a/build/template/index.html b/build/template/index.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Post Template + </h1> + <p> + <time id="post-date">1978-01-01</time> + </p> + <p id="post-excerpt"> + Text of the post-excerpt goes here. + </p> + <h2> + Heading + </h2> + <p> + Link example: <a href="https://www.ifixit.com/products/google-pixel-6-screen-genuine">iFixit</a>. + </p> + <p> + Multiline script example: + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl slc"># enable multilib - see link below</span> +paru <span class="hl slc"># make sure things are up to date generally</span> +paru <span class="hl kwb">-S</span> android<span class="hl kwb">-tools</span> android<span class="hl kwb">-sdk-build-tools</span> <span class="hl slc"># includes adb and other goodies</span> +reboot +</code></pre> + <p> + Image example: <img src="/images/ncmpcpp-mopidy-selector.png" alt="Source selection"> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/thanks/index.html b/build/thanks/index.html @@ -0,0 +1,209 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a class="nav-active" href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <p> + This is a “thanks page.” + </p> + <p> + <a href="/about">About</a>, <a href="https://nownownow.com/about">now</a>, and <a href="https://uses.tech">uses</a> pages are nice formulas, standardized +yet flexible ways for people visiting your site to get to know you +better, each from a slightly different angle. + </p> + <p> + The thanks page is also meant to bring the reader and author closer +together. By saying “hey, thanks” to folks who made a difference that +day, it gets back to that old idea that we create each other in our +relationships. The author gets to reflect on and state the positive +thing, and the reader, whether or not he or she is the one being +thanked, can get a kick out of watching joy and kindness flourish in the +world. + </p> + <p> + It’s a little more personal and permanent than a thumbs up on a post +on whichever social media platform dominates at the moment, and fits +well with a <a href="https://www.jackcheng.com/the-slow-web/">Slow +Web</a> aesthetic. + </p> + <p> + If you like this idea and decide to make your own thanks page, please +do, and <a href="/contact">let me know</a>. I’ll link to your page +here. + </p> + <br> + <hr> + <div class="thanks"> + <time datetime="2023-11-26" class="thanks-date"> + 2023-11-26 + </time> + <p class="thanks-to"> + Jen, Cody, et al. + </p> + <p class="thanks-for"> + Thanks for hanging out and helping out! It was a blast. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2023-11-09" class="thanks-date"> + 2023-11-09 + </time> + <p class="thanks-to"> + Jeremy and Travis + </p> + <p class="thanks-for"> + Thanks for helping with the LRP. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2023-11-08" class="thanks-date"> + 2023-11-08 + </time> + <p class="thanks-to"> + the internet + </p> + <p class="thanks-for"> + Thanks for absorbing an infinite number of starts and stops. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-24" class="thanks-date"> + 2022-12-24 + </time> + <p class="thanks-to"> + Benjamin + </p> + <p class="thanks-for"> + Thanks for holding down the fort. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-23" class="thanks-date"> + 2022-12-23 + </time> + <p class="thanks-to"> + Forrest, Moriah, Cat + </p> + <p class="thanks-for"> + Thanks to Forrest, for being a furry alien. + The time was too short buddy. + Also, thanks to Moriah and Cat, for holding things down for me until I could talk again. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-22" class="thanks-date"> + 2022-12-22 + </time> + <p class="thanks-to"> + Lori + </p> + <p class="thanks-for"> + Thanks for making a magic early Christmas. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-21" class="thanks-date"> + 2022-12-21 + </time> + <p class="thanks-to"> + Chase + </p> + <p class="thanks-for"> + Thanks for reminding me how cool it is, all of it. + Especially med ed, and how it interfaces with day-to-day practice. + (We should totally do the sick-not-sick button thing.) + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-19" class="thanks-date"> + 2022-12-19 + </time> + <p class="thanks-to"> + Mark + </p> + <p class="thanks-for"> + Thanks for the masterclass on secondary erythrocytosis and it’s management, + and candor about how this oncology thing never really gets easier + (and may even get harder, as the patients get closer to your own age). + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-18" class="thanks-date"> + 2022-12-18 + </time> + <p class="thanks-to"> + Moriah + </p> + <p class="thanks-for"> + Thanks for being willing to trade a shift later this week + so we can do a date-offset Christmas with the family. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-16" class="thanks-date"> + 2022-12-16 + </time> + <p class="thanks-to"> + Ronak and Eric + </p> + <p class="thanks-for"> + Thanks for jumping in to discuss your + experiences with inpatient induction chemo + for head and neck cancers - valuable insights, humane, lively. + </p> + </div> + <hr> + <div class="thanks"> + <time datetime="2022-12-15" class="thanks-date"> + 2022-12-15 + </time> + <p class="thanks-to"> + The NAVA BMT nurses + </p> + <p class="thanks-for"> + Thanks for sticking with me and a veteran + who needed to sleep off the extra milligram of sedation. + </p> + </div> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/twix/index.html b/build/twix/index.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Twix-like cookie recipe + </h1> + <hr> + <p> + Lightly modified from this <a href="https://www.dinneratthezoo.com/wprm_print/14720">original +recipe</a>. + </p> + <p> + <a href="https://www.dinneratthezoo.com/wprm_print/14720"><img src="https://www.dinneratthezoo.com/wp-content/uploads/2018/06/twix-cookies-1.jpg#center" alt="picture from original recipe"></a> + </p> + <h2> + Ingredients + </h2> + <ul> + <li> + 1 1/2 cups butter softened + </li> + <li> + 1 cup powdered sugar + </li> + <li> + 1 1/2 teaspoons vanilla extract + </li> + <li> + 3 cups all purpose flour + </li> + <li> + 1/4 teaspoon salt + </li> + <li> + 11 ounces caramels (<em>we made our own, but only because the store +didn’t have any caramels that weren’t individually wrapped</em>) + </li> + <li> + 1 tablespoon evaporated milk or cream + </li> + <li> + 2 cups milk chocolate chips + </li> + <li> + 2 teaspoons shortening + </li> + </ul> + <h2> + Instructions + </h2> + <ul> + <li> + Preheat oven to 350 degrees F. Line a sheet pan with parchment paper +or a nonstick baking mat. + </li> + <li> + Place the butter in the bowl of a mixer and beat until light and +fluffy. Add the powdered sugar and beat until combined. + </li> + <li> + Add the vanilla extract, flour and salt to the bowl. Mix until +combined. + </li> + <li> + Place the dough on a sheet of plastic wrap. Fold the plastic wrap +around the dough and chill in the freezer for 20 minutes. + </li> + <li> + Flour your work surface and roll out the dough into a 1/2 inch +sheet. + </li> + <li> + Use a 2 or 3 inch round cookie cutter to cut out cookies (<em>we +used 8 oz Mason jars</em>). + </li> + <li> + Place the cookies 1 inch apart on the prepared baking sheet. + </li> + <li> + Bake the cookies for 12-13 minutes or until edges are light brown. +Repeat the process with the remaining dough. + </li> + <li> + Cool the cookies on a rack. + </li> + <li> + Place the caramels and evaporated milk in a bowl. Microwave at 45 +second increments until caramel is melted. Stir until smooth. + </li> + <li> + Place a spoonful of caramel onto each cookie, using the back of the +spoon to spread it to the edges of the cookie. + </li> + <li> + Let the cookies sit until caramel has firmed up, about 20 +minutes. + </li> + <li> + Place the milk chocolate chips and shortening into a bowl. Microwave +in 30 second increments until chocolate is melted. Stir until +smooth. + </li> + <li> + Place a spoonful of melted chocolate onto each cookie and spread it +over the caramel layer. + </li> + <li> + Let the cookies sit until the chocolate has hardened, then serve or +store in an airtight container for up to 5 days. + </li> + </ul> + <h2> + Notes + </h2> + <ul> + <li> + These are super sticky. Wrap in wax paper. + </li> + <li> + Taste better, with better mouthfeel, if moderately chilled. + </li> + </ul> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/uses/index.html b/build/uses/index.html @@ -0,0 +1,280 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + uses + </h1> + <h2> + operating systems + </h2> + <ul> + <li> + <a href="https://wiki.archlinux.org/title/Arch_Linux">Arch Linux</a> +(daily driver) + </li> + <li> + <a href="https://www.openbsd.org/">OpenBSD</a> (website server) + </li> + <li> + <a href="https://www.nixos.org/">NixOS</a> (personal server + most +research) + </li> + <li> + <a href="https://www.apple.com/macos/">macOS</a> (most of the +hospital stuff works better on macOS) + </li> + </ul> + <h2> + software + </h2> + <ul> + <li> + window managers: <a href="https://dwm.suckless.org/">dwm</a> (on +Arch), <a href="https://hyprland.org/">Hyprland</a> (on NixOS) + </li> + <li> + $TERMINAL: <a href="https://sw.kovidgoyal.net/kitty/">kitty</a> + </li> + <li> + $EDITOR: <a href="https://www.lunarvim.org/">Lunarvim</a> + </li> + <li> + shell history: <a href="https://github.com/ellie/atuin">Atuin</a> + </li> + <li> + notes: <a href="https://obsidian.md/">Obsidian</a> + </li> + <li> + references: <a href="https://www.zotero.org/">Zotero</a> + </li> + <li> + standalone PDF reader: <a href="https://pwmt.org/projects/zathura/">Zathura</a> + </li> + <li> + terminal-based data file viewer (e.g. CSV): <a href="https://github.com/saulpw/visidata">VisiData</a> + </li> + <li> + wrangling JSON: <a href="https://github.com/stedolan/jq">jq</a> + </li> + <li> + remembery: <a href="https://apps.ankiweb.net/">Anki</a> + </li> + <li> + terminal music player: <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> + </li> + <li> + web music player: <a href="https://navidrome.org/">Navidrome</a>, +sometimes <a href="https://open.spotify.com/">Spotify</a> + </li> + <li> + bookmarking service: <a href="https://raindrop.io/">Raindrop.io</a> + </li> + <li> + networking: <a href="https://tailscale.com/">Tailscale</a> + </li> + <li> + passwords: <a href="https://bitwarden.com/">Bitwarden</a> + </li> + </ul> + <h2> + site-building software + </h2> + <ul> + <li> + <a href="https://github.com/Greenheart/pagecrypt">Pagecrypt</a> + </li> + <li> + <a href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a> + </li> + <li> + <a href="https://gohugo.io/">Hugo</a> + </li> + <li> + <a href="https://github.com/jackyzha0/quartz">Quartz</a> + </li> + <li> + <a href="https://github.com/giscus/giscus">Giscus</a> + </li> + <li> + <a href="https://datasette.io/">Datasette</a> + </li> + <li> + <a href="https://github.com/slidevjs/slidev">Slidev</a> + </li> + <li> + <a href="https://github.com/tiangolo/sqlmodel">SQLModel</a> + </li> + </ul> + <h2> + Mac-specific software + </h2> + <ul> + <li> + <a href="https://www.raycast.com/">Raycast</a> + </li> + <li> + <a href="https://iina.io/">IINA</a> + </li> + </ul> + <h2> + aesthetics (computer) + </h2> + <ul> + <li> + font: <a href="https://www.ibm.com/plex/">IBM Plex</a> + </li> + <li> + colors: Selenized/<a href="https://github.com/wuelnerdotexe/vim-enfocado">Enfocado</a> + </li> + <li> + prompt: <a href="https://starship.rs/">Starship</a> + </li> + </ul> + <h2> + SaaS + </h2> + <ul> + <li> + <a href="https://vercel.com/">Vercel</a> + </li> + <li> + <a href="https://github.com/features/actions">GitHub +Actions</a> + </li> + </ul> + <h2> + reference + </h2> + <ul> + <li> + <a href="https://hemonc.org/wiki/Main_Page">HemOnc.org</a> + </li> + <li> + <a href="https://www.vimbook.org/">vimbook.org</a> + </li> + <li> + <a href="https://chemocare.com/">Chemocare</a> + </li> + </ul> + <h2> + phone (multiplatform) + </h2> + <ul> + <li> + <a href="https://www.snipd.com/">Snipd</a> + </li> + </ul> + <h2> + phone (Android) + </h2> + <ul> + <li> + <a href="https://kisslauncher.com/">KISS Launcher</a> + </li> + <li> + <a href="https://github.com/Donnnno/Arcticons">Arcticons</a> + </li> + <li> + <a href="https://newpipe.net/">NewPipe</a> + </li> + </ul> + <h2> + phone (iOS) + </h2> + <ul> + <li> + <a href="">Working Copy</a> + </li> + </ul> + <h2> + computers + </h2> + <ul> + <li> + Lenovo Thinkpad T14s + </li> + <li> + Macbook Pro M1 + </li> + <li> + Lenovo Thinkpad X220 + </li> + </ul> + <h2> + phones + </h2> + <ul> + <li> + Google Pixel 2 XL (personal) + </li> + <li> + iPhone (whichever one work provides) + </li> + </ul> + <h2> + cars + </h2> + <ul> + <li> + Toyota Prius Three 2013 + </li> + <li> + Honda Pilot 2009 + </li> + </ul> + <h2> + wearables + </h2> + <ul> + <li> + watch: <a href="https://www.casio.com/us/watches/casio/product.F-91W-1/">Casio +F-91W</a> + </li> + <li> + backpack: <a href="https://www.peakdesign.com/collections/all-bags/products/everyday-backpack">Peak +Design Everyday Backpack (30L, black)</a> + </li> + </ul> + <h2> + software projects I’m watching + </h2> + <ul> + <li> + <a href="https://podverse.fm/">Podverse</a> + </li> + </ul> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/wants/index.html b/build/wants/index.html @@ -0,0 +1,90 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Wishlist + </h1> + <p> + While there are always <a href="https://rosewhitemusic.com/piano/writings/ten-thousand-things/#:~:text=%E2%80%9CThe%20Ten%20Thousand%20Things%E2%80%9D%20is,The%20One%20produced%20the%20two.">ten +thousand material things</a> I want, some of which are in the Amazon +Wishlist below, I’m more into digital capability these days. + </p> + <p> + Digital, use-anywhere gift cards are the way to go. + </p> + <p> + E.g. Visa or MasterCard. + </p> + <h2> + beauhilton.com + </h2> + <p> + I use <a href="https://www.vultr.com/">Vultr</a> to host my server, +which in turn hosts this website. It’s also $5 a month, which is a great +deal for a server that I fully manage and is plenty powerful for a +simple website. + </p> + <p> + Happy to receive any funds to support this going forward. + </p> + <h2> + *.beauhilton.com + </h2> + <p> + There are a bunch of services I would love to add to my website. + </p> + <p> + E.g. <a href="https://github.com/advplyr/audiobookshelf">AudioBookShelf</a> +could be audiobooks.beauhilton.com, <a href="https://wiki.kavitareader.com/en">Kavita</a> could be +books.beauhilton.com, <a href="https://github.com/nextcloud/all-in-one#nextcloud-all-in-one">Nextcloud</a> +could be cloud.beauhilton.com, etc. + </p> + <p> + Would ideally use a little independent server space for each of +these, e.g. a Linode. + </p> + <h2> + Amazon + </h2> + <p> + And finally: + </p> + <p> + <a href="https://www.amazon.com/hz/wishlist/ls/3AKNW7PDL7STX?ref_=wl_share">Amazon +Wishlist</a> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/wip/abstracts/index.html b/build/wip/abstracts/index.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Abstracts + </h1> + <p> + <time id="post-date">1978-01-01</time> + </p> + <p id="post-excerpt"> + Text of the post-excerpt goes here. + </p> + <h2> + Heading + </h2> + <blockquote> + <p> + The assurance of a complete and irrevocable break with everything +which beclouds the past lies in a true and courageous comprehension of +its full consequences. + </p> + <p> + — Alexander Tvardovsky, editor of <em>Novy Mir</em>. Foreward to +<em>One Day in the Life of Ivan Denisovich</em> by Alexander +Solzhenitsyn. 1963. + </p> + </blockquote> + <p> + On the night of December 2nd, 2018, I was too angry to sleep. I’m not +easy to ruffle (one of my cofellows dubbed me “Beau ‘Cool-as-a-Cucumber’ +Hilton” - I have many faults, but easy ruffleability is not among them), +and I have narcolepsy, so I can count the number of nights I’ve spent +both angry and sleepless on a single finger. + </p> + <p> + That afternoon I was reflecting on the plenary session given by Dr +Leon Tshilolo at the American Society of Hematology 60th Annual Meeting, +where he presented data on the use of hydroxyurea in sickle cell disease +in Africa. It was a beautiful talk, a major advance in the field of +hematology, and a wakeup call. + </p> + <p> + Hydroxyurea is an inexpensive drug that makes a huge difference for +many folks with sickle cell disease, and has been used for decades. The +majority of people with sickle cell disease live in Sub-Saharan Africa. +(The paper that accompanied Dr Tshilolo’s talk, which was published in +The New England Journal of Medicine roughly one month later, began with +the characteristically understated: “Hydroxyurea is an effective +treatment for sickle cell anemia, but few studies have been conducted in +sub-Saharan Africa, where the burden is greatest.”) This study deserved +to be the plenary session. Unlike ever-more-expensive targeted therapies +that benefit a few with rare diseases (I do not disparage these drugs, +far from it, but the contrast is poignant), this is a cheap therapy that +can benefit millions. Recognizing the incredible scientific, political, +and financial maneuvering that led to this study and its positive +outcomes, as the day went on my initial elation turned to depression, +then to anger. That this study happened at all is a triumph, that it +took this long to happen is a tragedy. + </p> + <p> + So I sat in my hotel room, furious, imagining, lost. + </p> + <p> + I was trained as an anthropologist and activist at the same time I +was trained as a scientist, and here was a disturbing revelation that +seemed to fit squarely in my Venn Diagram, but what I could do about it, +how I could make a difference, how I could even know where to start, +escaped me. Eventually the sun surprised me, and the next day took me +(thankfully, there were some less-electrifying talks to sleep through +later that day). + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html> diff --git a/build/wip/template/index.html b/build/wip/template/index.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <link rel="stylesheet" href="/style.css" type="text/css"> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="/style.css"> + <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> + <title></title> + </head> + <body> + <div id="page-wrapper"> + <div id="header" role="banner"> + <header class="banner"> + <div id="banner-text"> + <span class="banner-title"><a href="/">beauhilton</a></span> + </div> + </header> + <nav> + <a href="/about">about</a> +<a href="/now">now</a> +<a href="/thanks">thanks</a> +<a href="/posts">posts</a> +<a href="https://notes.beauhilton.com">notes</a> +<a href="https://talks.beauhilton.com">talks</a> +<a href="https://git.beauhilton.com">git</a> +<a href="/contact">contact</a> +<a href="/atom.xml">rss</a> + </nav> + </div> + <main> + <h1> + Post Template + </h1> + <p> + <time id="post-date">1978-01-01</time> + </p> + <p id="post-excerpt"> + Text of the post-excerpt goes here. + </p> + <h2> + Heading + </h2> + <p> + Link example: <a href="https://www.ifixit.com/products/google-pixel-6-screen-genuine">iFixit</a>. + </p> + <p> + Multiline script example: + </p> + <pre tabindex="0"><code class="language-sh"><span class="hl slc"># enable multilib - see link below</span> +paru <span class="hl slc"># make sure things are up to date generally</span> +paru <span class="hl kwb">-S</span> android<span class="hl kwb">-tools</span> android<span class="hl kwb">-sdk-build-tools</span> <span class="hl slc"># includes adb and other goodies</span> +reboot +</code></pre> + <p> + Image example: <img src="/images/ncmpcpp-mopidy-selector.png" alt="Source selection"> + </p> + </main> + <div id="footnotes"></div> + <footer></footer> + </div> + </body> +</html>