Merge branch 'main' of https://git.woozle.org/neale/homepage
This commit is contained in:
commit
475c4a90d3
|
@ -0,0 +1,76 @@
|
||||||
|
---
|
||||||
|
title: Trains
|
||||||
|
date: 2023-03-07
|
||||||
|
---
|
||||||
|
|
||||||
|
This year I am trying to spend less time on airplanes,
|
||||||
|
as part of a global movement motivated by carbon emissions concerns.
|
||||||
|
|
||||||
|
Amtrak, the US national passenger rail company
|
||||||
|
(the *only* national passenge rail company in the US),
|
||||||
|
is in a really sad state right now.
|
||||||
|
They keep getting their budget cut,
|
||||||
|
and freight companies have found several innovative ways
|
||||||
|
to save money at the expense of safety and passenger rail quality.
|
||||||
|
So rail exists in the US, technically,
|
||||||
|
but it is not generally considered a desirable way to go.
|
||||||
|
Maybe that will change as people seek non-airplane methods of travel.
|
||||||
|
|
||||||
|
The place where I work will let me take rail,
|
||||||
|
but they won't reimburse more than the equivalent flight.
|
||||||
|
This has never been a problem for me:
|
||||||
|
flying has always come in more expensive than train.
|
||||||
|
|
||||||
|
On this upcoming trip, I have to stay overnight in Chicago,
|
||||||
|
because there is only one train per day on each line.
|
||||||
|
Even though the train is $315 less than the cheapest flight,
|
||||||
|
I am not allowed to apply any of that toward lodging reimbursement.
|
||||||
|
|
||||||
|
If you assume people are going to take the option that
|
||||||
|
lines up closest to their personal economic interest,
|
||||||
|
that's 2 points against the train,
|
||||||
|
both of which carry an outsized societal burden.
|
||||||
|
|
||||||
|
Point 1: Time
|
||||||
|
-------------
|
||||||
|
|
||||||
|
My time is worth something to me,
|
||||||
|
and taking 4 additional days for a work trip kinda sucks.
|
||||||
|
A lot of people will stop considering rail travel based just on this point.
|
||||||
|
There's a way to fix this,
|
||||||
|
by upgrading tracks so that passenger trains can go much faster,
|
||||||
|
and by finally addressing how the mega-long freight trains can't yeild to the passenger trains,
|
||||||
|
because there aren't stretches of side track long enough for them to do so.
|
||||||
|
(People who would know assure me that the freight companies are well aware of what they're doing to passenger rail)
|
||||||
|
|
||||||
|
This fix requires two things: a country willing to spend lots of money on passenger rail,
|
||||||
|
and the political will to do something that will make freight companies really upset.
|
||||||
|
I'm not seeing that the country is excited about any kind of infrastructure spending,
|
||||||
|
much less passenger rail.
|
||||||
|
And I'm definitely not seeing a country that wants to hurt any kind of commerce.
|
||||||
|
But maybe if more scientists are inconvenienced by rail,
|
||||||
|
the winds can shift.
|
||||||
|
|
||||||
|
|
||||||
|
Point 2: Money
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Even though it costs fewer dollars for me to take the train,
|
||||||
|
my company is not set up to handle this.
|
||||||
|
The result is that I have to pay out of pocket for the hotel stays,
|
||||||
|
and I will not get reimbursed.
|
||||||
|
|
||||||
|
If taking over 3 times longer wasn't enough to dissuade people,
|
||||||
|
telling them it will also cost them $400 that won't be reimbursed
|
||||||
|
is going to make rail travel look like a bad decision.
|
||||||
|
|
||||||
|
The fix for this is easier:
|
||||||
|
my company needs to figure out a way to consider that the train is saving them money,
|
||||||
|
and allow me to spend some of that savings on the required hotel.
|
||||||
|
I've started trying to see what I can do to make that happen.
|
||||||
|
It may take a few years, and depends on senior management caring,
|
||||||
|
but I think it has a higher chance of happening.
|
||||||
|
|
||||||
|
If enough places figure out how to stope penalizing people for taking the cheaper option,
|
||||||
|
maybe there will be sufficient public interest in point 1 for something to happen there.
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: Universal Date Format
|
||||||
|
date: 2023-03-14
|
||||||
|
---
|
||||||
|
|
||||||
|
YYYY🌍MM🌙DD
|
||||||
|
|
||||||
|
If we use this, we won't have to re-do date formats again when we colonize another planet.
|
||||||
|
|
||||||
|
Posting here to bolster any future claim that I thought of this first.
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
date: 2023-04-14
|
||||||
|
title: Kaktovik numerals
|
||||||
|
scripts:
|
||||||
|
- kaktovik.mjs
|
||||||
|
draft: true
|
||||||
|
---
|
||||||
|
|
||||||
|
I just saw a Scientific American article about the recent inclusion in Unicode of the
|
||||||
|
[Kaktovik Numerals](https://en.wikipedia.org/wiki/Kaktovik_numerals),
|
||||||
|
a base-20 counting system invented in 1990 by schoolchildren in northern Alaska.
|
||||||
|
|
||||||
|
Let's do some counting!
|
||||||
|
|
||||||
|
<div class="flex wrap counter" data-min="0" data-max="19">
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apple-inator</h3>
|
||||||
|
<button class="add" data-amount="-1">- 🍏</button>
|
||||||
|
<button class="add" data-amount="+1">+ 🍏</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apples</h3>
|
||||||
|
<div class="apples"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Seems pretty easy, right?
|
||||||
|
I had it group apples in rows, so it's easier to visually see how many apples you have.
|
||||||
|
|
||||||
|
Let's use 🍊 instead of 🍏🍏🍏🍏🍏,
|
||||||
|
to make it even easier to see how many rows we have.
|
||||||
|
|
||||||
|
<div class="flex wrap counter" data-min="0" data-max="19">
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apple-inator</h3>
|
||||||
|
<button class="add" data-amount="-1">- 🍏</button>
|
||||||
|
<button class="add" data-amount="+1">+ 🍏</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Fruit</h3>
|
||||||
|
<div class="fruit"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apples</h3>
|
||||||
|
<div class="apples"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="flex wrap counter" data-min="0" data-max="19">
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apple-inator</h3>
|
||||||
|
<button class="add" data-amount="-1">- 🍏</button>
|
||||||
|
<button class="add" data-amount="+1">+ 🍏</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Kaktovik</h3>
|
||||||
|
<div class="kaktovik justify-left"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Fruit</h3>
|
||||||
|
<div class="fruit"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Apples</h3>
|
||||||
|
<div class="apples"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="justify-center">Arabic</h3>
|
||||||
|
<div class="arabic justify-right"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Can you see how
|
||||||
|
the number of left-and-right lines is the number of complete rows of apples,
|
||||||
|
and the number of up-and-down lines is the number of apples left?
|
|
@ -0,0 +1,113 @@
|
||||||
|
const FruitNumerals = [
|
||||||
|
"", "🍏", "🍏🍏", "🍏🍏🍏", "🍏🍏🍏🍏",
|
||||||
|
"🍊", "🍊🍏", "🍊🍏🍏", "🍊🍏🍏🍏", "🍊🍏🍏🍏🍏",
|
||||||
|
"🍊🍊", "🍊🍊🍏", "🍊🍊🍏🍏", "🍊🍊🍏🍏🍏", "🍊🍊🍏🍏🍏🍏",
|
||||||
|
"🍊🍊🍊", "🍊🍊🍊🍏", "🍊🍊🍊🍏🍏", "🍊🍊🍊🍏🍏🍏", "🍊🍊🍊🍏🍏🍏🍏",
|
||||||
|
]
|
||||||
|
|
||||||
|
const KaktovikNumerals = [
|
||||||
|
"𝋀", "𝋁", "𝋂", "𝋃", "𝋄",
|
||||||
|
"𝋅", "𝋆", "𝋇", "𝋈", "𝋉",
|
||||||
|
"𝋊", "𝋋", "𝋌", "𝋍", "𝋎",
|
||||||
|
"𝋏", "𝋐", "𝋑", "𝋒", "𝋓",
|
||||||
|
]
|
||||||
|
|
||||||
|
function ToNumerals(numerals, n) {
|
||||||
|
let base = numerals.length
|
||||||
|
let its = []
|
||||||
|
if (n < base) {
|
||||||
|
return [numerals[n]]
|
||||||
|
}
|
||||||
|
while (n > 0) {
|
||||||
|
its.unshift(numerals[n % base])
|
||||||
|
n = Math.floor(n / base)
|
||||||
|
}
|
||||||
|
return its
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToFruit(n) {
|
||||||
|
let its = ToNumerals(FruitNumerals, n)
|
||||||
|
let doc = new DocumentFragment()
|
||||||
|
for (let it of its) {
|
||||||
|
let row = doc.appendChild(document.createElement("div"))
|
||||||
|
row.classList.add("row")
|
||||||
|
row.textContent = it
|
||||||
|
}
|
||||||
|
return doc
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToKaktovik(n) {
|
||||||
|
let its = ToNumerals(KaktovikNumerals, n)
|
||||||
|
return its.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToApples(n) {
|
||||||
|
let doc = new DocumentFragment()
|
||||||
|
while (n > 0) {
|
||||||
|
let apples = Math.min(n, 5)
|
||||||
|
let row = doc.appendChild(document.createElement("div"))
|
||||||
|
row.classList.add("row")
|
||||||
|
row.textContent = "🍏".repeat(apples)
|
||||||
|
n -= apples
|
||||||
|
}
|
||||||
|
return doc
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Counter {
|
||||||
|
/**
|
||||||
|
* Initialize a counter element.
|
||||||
|
*
|
||||||
|
* This makes buttons active,
|
||||||
|
* and does an initial render.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
*/
|
||||||
|
constructor(element, n=1) {
|
||||||
|
this.element = element
|
||||||
|
this.n = n
|
||||||
|
this.min = Number(this.element.dataset.min) || 0
|
||||||
|
this.max = Number(this.element.dataset.max) || Infinity
|
||||||
|
|
||||||
|
for (let e of this.element.querySelectorAll("button.add")) {
|
||||||
|
let amount = Number(e.dataset.amount) || 1
|
||||||
|
e.addEventListener("click", e => this.add(e, amount))
|
||||||
|
}
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
add(event, amount) {
|
||||||
|
let n = this.n + amount
|
||||||
|
n = Math.min(n, this.max)
|
||||||
|
n = Math.max(n, this.min)
|
||||||
|
if (n != this.n) {
|
||||||
|
this.n = n
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
for (let e of this.element.querySelectorAll(".kaktovik")) {
|
||||||
|
e.textContent = ToKaktovik(this.n)
|
||||||
|
}
|
||||||
|
for (let e of this.element.querySelectorAll(".fruit")) {
|
||||||
|
while (e.firstChild) e.firstChild.remove()
|
||||||
|
e.appendChild(ToFruit(this.n))
|
||||||
|
}
|
||||||
|
for (let e of this.element.querySelectorAll(".apples")) {
|
||||||
|
while (e.firstChild) e.firstChild.remove()
|
||||||
|
e.appendChild(ToApples(this.n))
|
||||||
|
}
|
||||||
|
for (let e of this.element.querySelectorAll(".arabic")) {
|
||||||
|
e.textContent = this.n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
for (let e of document.querySelectorAll(".counter")) {
|
||||||
|
new Counter(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", init)
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset='utf-8'>
|
<meta charset='utf-8'>
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<link rel="me" href="https://teh.entar.net/@neale">
|
<link rel="me" href="https://teh.entar.net/@neale">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Roboto:ital,wght@0,400;0,700;1,400&display=swap">
|
||||||
<!-- My stuff -->
|
<!-- My stuff -->
|
||||||
<link rel="icon" type="image/png" href="{{"/assets/images/face.png" | relURL}}">
|
<link rel="icon" type="image/png" href="{{"/assets/images/face.png" | relURL}}">
|
||||||
<link rel="stylesheet" media="screen" href="{{"/assets/css/default.css" | relURL}}">
|
<link rel="stylesheet" media="screen" href="{{"/assets/css/default.css" | relURL}}">
|
||||||
|
|
|
@ -14,7 +14,7 @@ body {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
max-width: 35em;
|
max-width: 35em;
|
||||||
font-family: "Lato", "Roboto", sans-serif;
|
font-family: "Lato", "Noto Color Emoji", "Roboto", sans-serif;
|
||||||
font-size: 13pt;
|
font-size: 13pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +178,9 @@ caption {
|
||||||
caption-side: bottom;
|
caption-side: bottom;
|
||||||
font-size: small;
|
font-size: small;
|
||||||
}
|
}
|
||||||
|
.jistify-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
.justify-right, input[type="number"] {
|
.justify-right, input[type="number"] {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +206,16 @@ caption {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.wrap {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
html {
|
html {
|
||||||
background-image: url("../images/bg-dark.jpg");
|
background-image: url("../images/bg-dark.jpg");
|
||||||
|
|
Loading…
Reference in New Issue