tag:blogger.com,1999:blog-53044092024-03-17T16:17:21.485-07:00Amit's ThoughtsAmit has <em>crazy thoughts</em>.Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.comBlogger271125tag:blogger.com,1999:blog-5304409.post-63960244649930400862023-12-19T08:35:00.000-08:002023-12-19T13:18:38.910-08:00Status codes like TODO<p>
I often put <kbd>TODO</kbd> comments into my projects, including in source code. And I'll change it to <kbd>DONE</kbd> afterwards. I ended up keeping a list of four-letter codes:
</p>
<figure id="org9db3b12">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4fdTsvZDcBoAtMzmqkiH9FSqyqt6-7bVGZV8eP_zCZoDFa5DcYdrzMjGaSEL1bQS5DPgrdDfQpsE3PPr9nYO-iwP_f4nxOtZ5yBmwUSLrI_fNM6eXJ0NSGJ_i7Lp1Jbs-edI2Wz6D7MVRkzb0Nkh3rm-9htzmNp53vNVu24c3rH-hffm_RuWh/s1600/2023-12-18-status-codes.png"><img alt="Diagram showing how my status codes are related to each other, e.g. TODO happens before DONE" border="0" data-original-height="275" data-original-width="584" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4fdTsvZDcBoAtMzmqkiH9FSqyqt6-7bVGZV8eP_zCZoDFa5DcYdrzMjGaSEL1bQS5DPgrdDfQpsE3PPr9nYO-iwP_f4nxOtZ5yBmwUSLrI_fNM6eXJ0NSGJ_i7Lp1Jbs-edI2Wz6D7MVRkzb0Nkh3rm-9htzmNp53vNVu24c3rH-hffm_RuWh/s1600/2023-12-18-status-codes.png"/></a>
</figure>
<a name='more'></a>
<p>
This is my collection so far:
</p>
<ul class="org-ul">
<li><kbd>IDEA</kbd>: maybe someday</li>
<li><kbd>TODO</kbd>: doing later</li>
<li><kbd>SOON</kbd>: doing soon</li>
<li><kbd>NEXT</kbd>: doing now</li>
<li><kbd>DONE</kbd>: done</li>
<li><kbd>HACK</kbd>: done in a cheesy way, blend of todo and done</li>
<li><kbd>WAIT</kbd>: waiting for some external change (event)</li>
<li><kbd>HOLD</kbd>: waiting for some internal change (of mind)</li>
<li><kbd>STOP</kbd>: stopped waiting, decided not to work on it</li>
<li><kbd>NOTE</kbd>: end state, just keep track of it</li>
</ul>
<p>
<strong>I don't actually use all of these</strong>! In practice I use:
</p>
<ul class="org-ul">
<li>source code: <kbd>TODO</kbd>, <kbd>NOTE</kbd>, <kbd>HACK</kbd></li>
<li>task list: <kbd>TODO</kbd>, <kbd>DONE</kbd>, sometimes <kbd>WAIT</kbd> (for a colleague) <kbd>HOLD</kbd> <kbd>STOP</kbd> <kbd>IDEA</kbd></li>
<li>game queue: <kbd>WAIT</kbd> (for a game to get out of early access), <kbd>TODO</kbd> (game is something I want to play, but don't have time), <kbd>NEXT</kbd> (playing) , <kbd>DONE</kbd> (finished the game, or at least the parts I want to play), <kbd>STOP</kbd> (decided not to get the game)</li>
</ul>
<p>
Is this overly complicated? <s>Maybe</s> Definitely!
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com3tag:blogger.com,1999:blog-5304409.post-44764316894342468032023-11-29T17:55:00.000-08:002023-11-29T18:03:56.388-08:00Using an LLM to query my notes<figure style="padding: 0 1em; clear: left; float: left; max-width: 30vw; height: auto">
<img alt="robot asks a question holding a book" data-original-height="512" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh2X78XIFWnmvwx-Y-9Zj4wn6K7tFbTdrcDkT5fp6hECaQp-T06s04hg-LfMC13V3FnlZ-30IZC0xXmIH0lKBM26AQeFeeLOI01O0iirCgQxPPKBkInV8Kfylxrl2h9_LvXb9FGW4GElHZZPoCsxmJ4fpXU38vzFolKm63XK6TSfM_wWeYPTgu/s1600/robot%20asks%20a%20question%20holding%20a%20book_631681.png"/>
<figcaption>"<code>robot asks a question holding a book</code>" image from stable diffusion</figcaption>
</figure>
<p>
I occasionally play with LLMs (large language models). Last time I had tried <a href="https://til.simonwillison.net/llms/embed-paragraphs">Simon Willison's llm software</a> to search over my notes. Today I tried <a href="https://github.com/amaiya/onprem#talk-to-your-documents">amaiya/onprem</a> to ask questions about my notes. The documentation is pretty good but I made a few changes for my configuration, so I decided to write them down here. <em>I'm running these on my Mac M1</em> and not on my Linux or Windows machines.
</p>
<p>
First step, get the thing installed:
</p>
<div class="org-src-container">
<pre class="src src-sh"><span class="builtin">cd</span> ~/Projects/machine-learning/
mkdir onprem
<span class="builtin">cd</span> onprem
<span class="comment-delimiter"># </span><span class="comment">need to use python 3.9 through 3.11 for torch support; 3.12 doesn't support it yet</span>
<span class="comment-delimiter"># </span><span class="comment">check the version I have installed</span>
python3 --version
<span class="comment-delimiter"># </span><span class="comment">if python3 isn't a reasonable version, then install or choose a different python</span>
<span class="comment-delimiter"># </span><span class="comment">before doing the next step</span>
python3.11 -m venv venv
<span class="builtin">source</span> venv/bin/activate
<span class="comment-delimiter"># </span><span class="comment">install onprem itself, which also installs torch</span>
pip install onprem
mkdir data
</pre>
</div>
<a name='more'></a>
<p>
The main change I'm making is that I want to store the data in <code>./data</code> not in <code>~/onprem_data</code>, so that's why I made a directory for it to store the data. I don't want to store a bunch of things in my home directory.
</p>
<p>
Second step, test it out using the code from their web site. Instead of the default <kbd>LLM()</kbd> I set several parameters:
</p>
<ol class="org-ol">
<li><kbd>use_larger</kbd> will download the 13B model instead of the 7B model; omit this if you have 8GB</li>
<li><kbd>n_gpu_layers</kbd> will tell it to use the gpu; but I can't tell if it's actually any faster</li>
<li>the <kbd>path</kbd> arguments I point at my local data directory</li>
</ol>
<pre class="example">
python
</pre>
<div class="org-src-container">
<pre class="src src-python"><span class="keyword">from</span> onprem <span class="keyword">import</span> LLM
<span class="variable-name">llm</span> <span class="operator">=</span> LLM(use_larger<span class="operator">=</span><span class="constant">True</span>, n_gpu_layers<span class="operator">=</span>64,
model_download_path<span class="operator">=</span><span class="string">"./data"</span>, vectordb_path<span class="operator">=</span><span class="string">"./data"</span>)
<span class="variable-name">prompt</span> <span class="operator">=</span> <span class="string">"""Extract the names of people in the supplied sentences. Here is an example:</span>
<span class="string">Sentence: James Gandolfini and Paul Newman were great actors.</span>
<span class="string">People:</span>
<span class="string">James Gandolfini, Paul Newman</span>
<span class="string">Sentence:</span>
<span class="string">I like Cillian Murphy's acting. Florence Pugh is great, too.</span>
<span class="string">People:"""</span>
<span class="variable-name">saved_output</span> <span class="operator">=</span> llm.prompt(prompt)
</pre>
</div>
<p>
This should print an answer <code>Cillian Murphy, Florence Pugh</code>. That tells me the software is successfully installed and the LLM data is also successfully installed.
</p>
<p>
Third step, I fed it my documents. I keep them in emacs org-mode format, but I converted them to text format:
</p>
<div class="org-src-container">
<pre class="src src-sh">mkdir input
<span class="builtin">cd</span> input
cp ~/Documents/notes/* .
<span class="keyword">for</span> f<span class="keyword"> in</span> *.org; <span class="keyword">do</span> pandoc $<span class="variable-name">f</span> -o ${<span class="variable-name">f</span>//.org/}.txt; <span class="keyword">done</span>
</pre>
</div>
<p>
Ok, now that there are files in <code>input/</code>, I ran the llm code again. Previously I used <kbd>llm.prompt()</kbd> to ask questions of the LLM directly. This time, following the docs, I used <kbd>llm.inject()</kbd> to load my input files and then <kbd>llm.ask()</kbd> to ask questions about the input files:
</p>
<div class="org-src-container">
<pre class="src src-sh">python
</pre>
</div>
<div class="org-src-container">
<pre class="src src-python"><span class="keyword">from</span> onprem <span class="keyword">import</span> LLM
<span class="variable-name">llm</span> <span class="operator">=</span> LLM(use_larger<span class="operator">=</span><span class="constant">True</span>, n_gpu_layers<span class="operator">=</span>64, model_download_path<span class="operator">=</span><span class="string">"./data"</span>, vectordb_path<span class="operator">=</span><span class="string">"./data"</span>)
llm.ingest(<span class="string">"./input/"</span>)
<span class="variable-name">result</span> <span class="operator">=</span> llm.ask(<span class="string">"What is carbon dioxide? Remember to only use the provided context."</span>)
</pre>
</div>
<p>
That's it! I tried asking a bunch of questions, had mixed results, and then ran out of ideas of what I should ask.
</p>
<p>
I like onprem's <a href="https://amaiya.github.io/onprem/examples.html">examples page</a> and want to try out more of them. I also want to try out <a href="https://simonwillison.net/2023/Nov/29/llamafile/">llamafile</a>.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-32808400348412684792023-10-06T15:34:00.002-07:002023-11-29T20:31:42.994-08:00Emacs and shellcheck<p>
Julia Evans had a great talk called <a href="https://jvns.ca/blog/2023/10/06/new-talk--making-hard-things-easy/">Making Hard Things Easy</a>. One of the takeaways for me was that I should be using tools for parts of a system I find hard to remember. In particular, when writing <code>bash</code> scripts I should be using <code>shellcheck</code>.
</p>
<p>
It turns out Emacs 29 has support for <code>shellcheck</code>, and older versions of Emacs can use <a href="https://github.com/federicotdn/flymake-shellcheck">the flymake-shellcheck page</a>.
</p>
<p>
To set it up in Emacs 29:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">use-package</span> <span class="constant">flymake</span>
<span class="builtin">:bind</span> ((<span class="string">"H-e"</span> . flymake-show-project-diagnostics)))
(<span class="keyword">use-package</span> <span class="constant">sh-script</span>
<span class="builtin">:hook</span> (sh-mode . flymake-mode))
</pre>
</div>
<p>
I use <a href="https://github.com/minad/consult">consult</a> for navigating my errors, and I want to make errors more noticable in the mode line, so my flymake configuration is:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">use-package</span> <span class="constant">flymake</span>
<span class="builtin">:bind</span> ((<span class="string">"H-e"</span> . my/consult-flymake-project))
<span class="builtin">:preface</span>
(<span class="keyword">defun</span> <span class="function-name">my/consult-flymake-project</span> ()
(<span class="keyword">interactive</span>)
(consult-flymake t))
<span class="builtin">:custom</span>
(flymake-suppress-zero-counters t)
<span class="builtin">:config</span>
(<span class="keyword">defface</span> <span class="variable-name">my/flymake-modeline-error-echo</span>
'((t <span class="builtin">:inherit</span> 'flymake-error-echo <span class="builtin">:background</span> <span class="string">"red"</span>))
<span class="doc">"Mode line flymake errors"</span>)
(put 'flymake-error 'mode-line-face 'my/flymake-modeline-error-echo)
(<span class="keyword">defface</span> <span class="variable-name">my/flymake-modeline-warning-echo</span>
'((t <span class="builtin">:inherit</span> 'flymake-warning-echo <span class="builtin">:background</span> <span class="string">"orange"</span>))
<span class="doc">"Mode line flymake warnings"</span>)
(put 'flymake-warning 'mode-line-face 'my/flymake-modeline-warning-echo))
</pre>
</div>
<p>
It's too early to know what other tweaks I might want, but so far it's alerted me to several errors in my shell scripts.
</p>
<p>
<strong>Update:</strong> [2023-10-07] <a href="https://news.ycombinator.com/item?id=37797764">Comments on HN</a> pointed to <a href="https://github.com/bash-lsp/bash-language-server/">bash-language-server</a> which works with emacs lsp or eglot.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com1tag:blogger.com,1999:blog-5304409.post-27765816165392872112023-06-20T15:13:00.006-07:002023-06-20T15:17:19.526-07:00Road Archaeology, part 2<p>
In a <a href="https://amitp.blogspot.com/2022/09/road-archaeology-part-1.html">previous post</a> I showed some examples of how railroads influenced the shape of Interstate 5 in California. In this post I have some more examples of what I call "road archaeology". Looking at the present roads, we can make guesses about the past.
</p>
<p>
In Las Vegas the major casinos are along "The Strip". Just to the west of this is the interstate highway, I-15. What is the history here? My <em>guess</em>, following the patterns from the previous blog post, would be that "The Strip" was the original highway, and I-15 was built parallel to it. If you look through <a href="https://historicaerials.com/viewer">Historial Aerials</a> you can see that this is indeed what happened. Here's the interactive map to browse:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=36.134733567703265~-115.1622804001189&lvl=13.31&typ=d&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>Las Vegas Strip vs I-15</figcaption>
</figure>
<a name='more'></a>
<p>
It's not obvious from that map though, because Las Vegas is much larger than the examples in the previous blog post. I made some drawings of what to look for:
</p>
<figure>
<svg viewBox="-291 400 754 750">
<g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="4">
<path stroke="#b5b3ad" d="
M-59.7 902.2c-30.8-17.4-67.7-.1-101.5-3.8-35.5 8.9-45.7-18.6-40.9-49.6-7.6-42.4-76.7-38.6-63.7-90.4 5-32.9-12.0-66.7-.6-98.7 29.3-31.7 18.5-75.7 20.0-111.5 29.2-16.6 65.2-1.1 97.0-1.1 40.2 15.9 77.4-1.0 107.5-26.0 39.0-3.4 78.2 11.7 117.5 4.5 18.2-2.9 26.6 16.7 35.1 28.8
M-281.3 408.6c43.2 34.4 65.6 87.1 103.6 126.4 19.4 24.8 42.7 51.6 36.7 85.8 2.7 31.5-8.7 73.0 11.2 97.8 35.1 9.7 69.7-7.8 105.8-.0
M-12.8 719.6c1.7.1 8.7.5 10.4.5
M5.3 721.8c30.0 6.1 68.6 7.9 60.7 49.7 8.1 36.8 4.7 87.2 49.6 100.1 27.9 20.5 38.3 56.3 54.9 86.0 16.6 33.2 54.0 60.4 92.6 53.0 48.4 6.9 32.3 76.4 74.6 92.0 30.2 13.3 68.0 23.3 99.3 9.0 8.9-6.9 14.2-18.0 15.3-29.2
M-52.8 902.0c44.6-8.6 59.5 31.0 73.1 63.1 43.6 12.9 90.1-4.4 134.2-9.4l4.5-.7 4.5-.7" />
<path stroke="#c5c3df" d="
M-135.9 595.4c30.5 36.9 58.9 76.1 86.0 115.7
M72.8 789.3c35.4 37.8 70.2 76.4 104.4 115.1 34.7 32.9 63.8 71.0 96.6 105.9"/>
<path stroke="#9378e3" d="
M-86.1 1145.3c17.9-22.8 36.4-52.4 30.8-83.2
M-54.4 1063.1c-5.8-66.1 1.7-132.6-.3-198.8 1.4-33.3-12.0-74.4 18.0-99.0 3.1-4.0 5.9-8.4 7.5-13.3
M-30.2 753.6c6.6-33.9 32.4-62.0 44.2-95.4 31.5-40.8 62.4-88.3 113.7-105.5 39.2-23.7 83.6-36.6 123.3-59.0
M248.4 495.7c37.9-18.7 58.8-57.3 72.6-95.4"/>
<path stroke="#6ac0c8" d="
M-79.8 1145.8c18.2-28.8 40.9-59.3 37.2-95.5
M-42.6 1052.5c-.0-64.3-3.0-128.7-.2-192.9-6.2-42.7 15.3-80.2 34.3-116.5C4.9 714.8 8.4 679.6 40.2 664.4c64.5-50.2 140.8-86.1 196.3-147.3 4.4-5.4 9.3-10.8 10.8-17.9
M249.6 490.7c11.5-28.7 47.0-36.4 59.9-64.2"/>
</g>
<g font-family="sans-serif" font-size="24" font-weight="bold">
<text fill="#9378e3" transform="rotate(-50 655 302)" dy="1em">I-15</text>
<text fill="#6ac0c8" transform="rotate(-34 1081 259)" dy="1em">original highway</text>
<text fill="#6ac0c8" transform="rotate(-84 484 459)">"the strip"</text>
</g>
</svg>
<figcaption>Las Vegas Blvd vs I-15, zoomed out</figcaption>
</figure>
<p>
Another useful tool to explore road history is Google Earth. The standalone app (but <em>not</em> the web app, or Google Maps) lets you see historical imagery. An example is Bend, Oregon, USA. They built a parkway to the west of the main street:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=44.045547950241826~-121.30827206955075&lvl=12.805326316112348&typ=d&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>Bend Oregon bypass parkway to the west of the main road</figcaption>
</figure>
<p>
Here's how it looked in 1994, 2000, and 2004 in Google Earth:
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/roads/bend-parkway-1994.jpg" alt="Bend Parkway in 1994" />
<img src="https://www.redblobgames.com/x/screenshots/roads/bend-parkway-2000.jpg" alt="Bend Parkway in 2000" />
<img src="https://www.redblobgames.com/x/screenshots/roads/bend-parkway-2004.jpg" alt="Bend Parkway in 2004" />
<figcaption>Bend Parkway in 1994, 2000, and 2004</figcaption>
</figure>
<p>
You can see how it was regular land, then cleared for the parkway, and then the parkway was constructed.
</p>
<p>
These changes leave behind clues to what was there before. Historical Aerials and Google Earth can sometimes tell us more.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com1tag:blogger.com,1999:blog-5304409.post-54717623438484430862023-04-12T16:54:00.010-07:002024-01-29T08:43:38.063-08:00Mac keyboard with hidutil<p>
[Update: 13-Apr-2023 with some of the background context and some things I learned from <a href="https://news.ycombinator.com/item?id=35555475">hackernews</a>]
</p>
<p>
[Update: 18-Dec-2023] This hidutil stopped working for me in MacOS 13.6 and 14.2. Also see <a href="https://discussions.apple.com/thread/255340598?sortBy=best">other people having problems too</a>.
</p>
<p>
[Update: 28-Jan-2024] Some people say hidutil works again in Mac OS 14.3.
</p>
<p>
On my Mac, I've used KeyRemap4Macbook, Karabiner, Karabiner Elements, and FunctionFlip for some of my key remapping needs. The main things I want:
</p>
<ol class="org-ol">
<li>On the laptop keyboard, <em>some</em> media keys should be function keys but other media keys should stay media keys. When using <kbd>fn</kbd> I want to get the other version of the key.</li>
<li>On external keyboards, make the function keys act like the laptop keyboard.</li>
<li>On external keyboards, the numpad should act like "numlock off". For example, <kbd>4</kbd> should be Left Arrow.</li>
<li>On external keyboards, the Windows key should act as Option, and the Alt key should act as Command. This can usually be set in the System Preferences. (Except it doesn't work on one of my keyboards)</li>
<li>I also use those same external keyboards with my Windows and Linux machines, so I prefer to make these changes through software rather than firmware.</li>
</ol>
<a name='more'></a>
<p>
I recently learned about <code>hidutil</code>. It's built-in but has no user-friendly UI. Someone has created <a href="https://hidutil-generator.netlify.app/">this config generator</a> for it; I learned about it from <a href="https://rakhesh.com/mac/using-hidutil-to-map-macos-keyboard-keys/">Rakhesh Sasidharan's blog post</a>. Using that generator, I can change a media/function key to do something else, but I can't seem to set <kbd>fn+key</kbd>. I instead learned how to do that from <a href="https://www.nanoant.com/mac/macos-function-key-remapping-with-hidutil">Adam Strzelecki's blog post</a>. Also from the <em>comments</em> in Adam's blog post, I learned that there's a way to have a different configuration for each type of keyboard using the <kbd>--matching</kbd> flag.
</p>
<p>
I have three keyboards but at first I'm going to try using a single <code>hidutil</code> configuration for all three, and then later I will refine it as needed. I ended up writing a Python program to run <code>hidutil</code> with my desired configuration, a combination of the keys I can set using the config generator website and the keys I can set using Adam's blog post:
</p>
<div class="org-src-container">
<pre class="src src-python"><span class="keyword">import</span> subprocess, json
<span class="variable-name">output</span> <span class="operator">=</span> <span class="string">'{"UserKeyMapping":[</span><span class="constant">\n</span><span class="string">'</span>
<span class="comment-delimiter"># </span><span class="comment">First put in the numpad keys, which I got from </span>
<span class="comment-delimiter"># </span><span class="comment">https://hidutil-generator.netlify.app/</span>
<span class="comment-delimiter"># </span><span class="comment">https://www.freebsddiary.org/APC/usb_hid_usages.php</span>
<span class="comment-delimiter"># </span><span class="comment">also see https://github.com/ivangreene/keymap</span>
<span class="variable-name">output</span> <span class="operator">+=</span> <span class="string">"""</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x700000059,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004D</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x70000005A,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x700000051</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x70000005B,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004E</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x70000005C,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x700000050</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x70000005E,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004F</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x70000005F,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004A</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x700000060,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x700000052</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x700000061,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004B</span>
<span class="string"> },</span>
<span class="string"> {"HIDKeyboardModifierMappingSrc": 0x700000063,</span>
<span class="string"> "HIDKeyboardModifierMappingDst": 0x70000004C</span>
<span class="string"> },</span>
<span class="string">"""</span>
<span class="comment-delimiter"># </span><span class="comment">Function keys:</span>
<span class="comment-delimiter"># </span><span class="comment">1. set "Use F1, F2, etc. keys as standard function keys"</span>
<span class="comment-delimiter"># </span><span class="comment">2. turn f1, f2, f3, and f10, f11, f12 into media keys</span>
<span class="comment-delimiter"># </span><span class="comment">3. fn should reverse the meaning so fn+f1 will be f1 not media</span>
<span class="variable-name">key_mappings</span> <span class="operator">=</span> [] <span class="comment-delimiter"># </span><span class="comment">[src, dst]</span>
<span class="variable-name">function_keys</span> <span class="operator">=</span> subprocess.check_output(
<span class="string">"""ioreg -l |</span>
<span class="string"> grep FnFunctionUsageMap |</span>
<span class="string"> grep -Eo '0x[0-9a-fA-F]+,0x[0-9a-fA-F]+'</span>
<span class="string"> """</span>, shell<span class="operator">=</span><span class="constant">True</span>).decode(<span class="string">'utf-8'</span>).split(<span class="string">'</span><span class="constant">\n</span><span class="string">'</span>)
<span class="keyword">for</span> fn_key <span class="keyword">in</span> [1, 2, 3, 10, 11, 12]:
<span class="variable-name">src_key</span>, <span class="variable-name">dst_key</span> <span class="operator">=</span> function_keys[fn_key<span class="operator">-</span>1].replace(<span class="string">"0x"</span>, <span class="string">""</span>).split(<span class="string">","</span>)
<span class="variable-name">src_key</span> <span class="operator">=</span> <span class="string">'0x'</span> <span class="operator">+</span> src_key[:4] <span class="operator">+</span> <span class="string">'0000'</span> <span class="operator">+</span> src_key[4:]
<span class="variable-name">dst_key</span> <span class="operator">=</span> <span class="string">'0x'</span> <span class="operator">+</span> dst_key[:4] <span class="operator">+</span> <span class="string">'0000'</span> <span class="operator">+</span> dst_key[4:]
key_mappings.append((src_key, dst_key))
key_mappings.append((dst_key, src_key))
<span class="variable-name">output</span> <span class="operator">+=</span> <span class="string">',</span><span class="constant">\n</span><span class="string">'</span>.join([
<span class="string">' {"HIDKeyboardModifierMappingSrc": '</span> <span class="operator">+</span> src <span class="operator">+</span>
<span class="string">', "HIDKeyboardModifierMappingDst": '</span> <span class="operator">+</span> dst <span class="operator">+</span> <span class="string">'}'</span>
<span class="keyword">for</span> (src, dst) <span class="keyword">in</span> key_mappings])
<span class="variable-name">output</span> <span class="operator">+=</span> <span class="string">']}'</span>
<span class="comment-delimiter"># </span><span class="comment">print(output)</span>
<span class="variable-name">process</span> <span class="operator">=</span> subprocess.run([<span class="string">"hidutil"</span>, <span class="string">"property"</span>, <span class="string">"--set"</span>, output],
capture_output<span class="operator">=</span><span class="constant">True</span>)
<span class="comment-delimiter"># </span><span class="comment">print(process.stdout)</span>
</pre>
</div>
<p>
The script handles most of what I want. One remaining mystery is that the <kbd>fn</kbd> versions are incomplete — <kbd>fn+F7</kbd>, <kbd>fn+F8</kbd>, <kbd>fn+F9</kbd> work for me as media keys, but <kbd>fn+F4</kbd>, <kbd>fn+F5</kbd>, <kbd>fn+F6</kbd> don't work for me as apple-specific media keys. One missing feature is that on one external keyboard, I want to map the Windows key to Option, and the Alt key to Cmd. System Preferences sets these to <em>right</em> Option/Cmd, and I want the left keys to map to left keys and right keys to map to right keys. My workaround is to to it with firmware, and toggle that on/off when switching operating systems, but I'd like to figure out how to use hidutil to handle this too.
</p>
<p>
Other useful commands:
</p>
<div class="org-src-container">
<pre class="src src-sh"><span class="comment-delimiter"># </span><span class="comment">see the current mapping; optionally use --matching</span>
<span class="comment-delimiter"># </span><span class="comment">but they will be decimal instead of hexadecimal</span>
hidutil property --get <span class="string">"UserKeyMapping"</span>
<span class="comment-delimiter"># </span><span class="comment">erase the current mapping; optionally use --matching</span>
<span class="comment-delimiter"># </span><span class="comment">hidutil property --set '{"UserKeyMapping":[]}'</span>
</pre>
</div>
<p>
I currently run this manually on boot, but a <code>launchctl</code> file can be used to make it run automatically on boot. If using per-device configurations, they don't apply unless you run this while the keyboard is plugged in. That's inconvenient. <a href="https://www.digihunch.com/2022/11/key-mapping-on-external-pc-keyboard-on-macbook/">Digi Hunch's blog post</a> covers how to automatically load that configuration when the keyboard is plugged in.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com3tag:blogger.com,1999:blog-5304409.post-3959200928705788822022-09-28T11:02:00.006-07:002023-06-20T15:14:04.321-07:00Road Archaeology, part 1<p>
While on road trips I notice sometimes there are places where a road will deviate from the path I expect it to take. I take a note of it and then investigate what happened there. Usually there's some geography or history involved. Take I-5 in Northern California for example. There's a straight segment from Dunnigan CA to Williams CA:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=39.01201157818082~-122.06248631879635&lvl=9.87959065577242&typ=s&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>Map of I-5 between Dunnigan CA and Williams CA</figcaption>
</figure>
<a name='more'></a>
<p>
But let's zoom in a bit, to Arbuckle CA:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=39.0165246231179~-122.05287793130657&lvl=12.58815540442344&typ=d&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>Map of I-5 near Arbuckle CA</figcaption>
</figure>
<p>
I-5 looks like it'd be a straight line, but it bends to the west of town and then goes back to its original line. What's going on?
</p>
<p>
Interstate freeway I-5 from the 1970s mostly follows <a href="https://www.aaroads.com/california/ca-099.html">California highway CA-99W</a>, which used to be <a href="https://en.wikipedia.org/wiki/U.S._Route_99_in_California#Sacramento_to_Oregon">US highway US-99</a> in the 1920s, which used to be <a href="https://en.wikipedia.org/wiki/Pacific_Highway_(United_States)#History">Pacific Highway</a> in the 1910s. That highway followed the <a href="https://en.wikipedia.org/wiki/Southern_Pacific_Transportation_Company">Southern Pacific</a> rail line, which used to be the <a href="https://en.wikipedia.org/wiki/Central_Pacific_Railroad">Central Pacific Railroad</a>'s line in the late 1800s. And before that, there was the <a href="https://en.wikipedia.org/wiki/Siskiyou_Trail">Siskiyou Trail</a> from the early 1800s.
</p>
<p>
Why "mostly follows"? It's because CA-99 is still there, as is the rail line. The downtown commercial area of Arbuckle is adjacent to the rail line. The town was created in 1875 and the train depot was built in 1876. The commercial buildings were built near the train depot. A century later, when I-5 was built, they moved it several blocks to the west.
</p>
<p>
Arbuckle isn't the only place like this. Take a look at Williams CA:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=39.160800768868086~-122.14481180229257&lvl=12.112809407102864&typ=d&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>I-5 in Williams CA</figcaption>
</figure>
<p>
Here, I-5 follows a straight line adjacent to CA-99W and the railroad, but then takes a detour to the east. The town of <a href="https://www.countyofcolusa.org/216/Williams">Williams also started because of the railroad</a>, back in the 1870s. The freeway goes around the commercial district that would've started adjacent to the railroad.
</p>
<p>
You can see something similar in other towns along I-5 but it's not as obvious for some of the towns. It's really fun to look at <a href="https://historicaerials.com/viewer">historical maps</a> to see how the towns have grown over time.
</p>
<p>
But it's not always a town that causes the deviation. Sometimes it's just an exit, as the overpass won't allow exiting onto the frontage road:
</p>
<figure>
<iframe width="660" height="330" frameborder="0" src="https://www.bing.com/maps/embed?h=330&w=660&cp=39.406416754373595~-122.19265852670554&lvl=13.371346700211182&typ=d&sty=r&src=SHELL&FORM=MBEDV8" scrolling="no">
</iframe>
<figcaption>I-5 deviation for an exit</figcaption>
</figure>
<p>
Why follow the railroad at all? My guess is that back when the US government was trying to encourage a <a href="https://en.wikipedia.org/wiki/First_transcontinental_railroad">transcontinental east-west railroad</a>, they gave the railroads 200ft land adjacent to the track. That space would've been something the government could later use to build the freeways.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-89082763234122825182022-08-25T08:48:00.002-07:002022-08-25T08:48:28.573-07:00Emacs: marking text<p>
Although I primarily use Emacs, I love the idea of vim text objects, and wanted to incorporate them into my editing. The <a href="https://kakoune.org/why-kakoune/why-kakoune.html">Kakoune</a> introduction explains that vim uses verb first, noun second for its commands, whereas Kakoune uses noun first, verb second. <a href="https://simblob.blogspot.com/2019/10/verb-noun-vs-noun-verb.html">I wrote a blog post about why I prefer noun-verb over verb-noun</a>, not only in text editors but also in games and other applications.
</p>
<a name='more'></a>
<p>
I started cobbling together some commands in a <a href="https://github.com/abo-abo/hydra#readme">hydra</a>, trying to match vim keys when I could:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">defhydra</span> hydra-mark (<span class="builtin">:body-pre</span> (set-mark-command nil) <span class="builtin">:color</span> red)
<span class="doc">"</span>
<span class="doc">_w_, _,w_: word, symbol _i'_, _a'_: string _i)_, _a)_: pair</span>
<span class="doc">_t_, _f_: to char (exclude/include) _0_, _$_: begin/end of line</span>
<span class="doc">_;_: comment _u_: url _e_: email _>_: web-mode block or tag</span>
<span class="doc">_S_: sexp _d_: defun _p_: paragraph _s_: sentence</span>
<span class="doc">_h_, _j_, _k_, _l_: move _H-._: off</span>
<span class="doc"> "</span>
(<span class="string">"t"</span> mark-to-char-exclusive)
(<span class="string">"f"</span> mark-to-char-inclusive)
(<span class="string">"0"</span> move-beginning-of-line)
(<span class="string">"$"</span> move-end-of-line)
(<span class="string">"w"</span> er/mark-word)
(<span class="string">",w"</span> er/mark-symbol)
(<span class="string">"i'"</span> er/mark-inside-quotes)
(<span class="string">"a'"</span> er/mark-outside-quotes)
(<span class="string">"i)"</span> er/mark-inside-pairs)
(<span class="string">"a)"</span> er/mark-outside-pairs)
(<span class="string">"i]"</span> er/mark-inside-pairs)
(<span class="string">"a]"</span> er/mark-outside-pairs)
(<span class="string">"j"</span> next-line)
(<span class="string">"k"</span> previous-line)
(<span class="string">"h"</span> left-char)
(<span class="string">"l"</span> right-char)
(<span class="string">";"</span> er/mark-comment)
(<span class="string">"u"</span> er/mark-url)
(<span class="string">"e"</span> er/mark-email)
(<span class="string">"d"</span> er/mark-defun)
(<span class="string">"S"</span> mark-sexp)
(<span class="string">"s"</span> mark-end-of-sentence)
(<span class="string">"p"</span> mark-paragraph)
(<span class="string">">"</span> web-mode-mark-and-expand)
(<span class="string">"H-."</span> deactivate-mark <span class="builtin">:exit</span> t)
)
(<span class="keyword">defun</span> <span class="function-name">my/hydra-mark</span> ()
(<span class="keyword">interactive</span>)
(set-mark-command nil)
(hydra-mark/body))
(<span class="keyword">bind-key</span> <span class="string">"H-."</span> #'my/hydra-mark)
</pre>
</div>
<div><details><summary>And some helper functions:</summary>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">defun</span> <span class="function-name">move-to-char</span> (arg char)
(<span class="keyword">interactive</span> (list (prefix-numeric-value current-prefix-arg)
(read-char <span class="string">"Move to char: "</span> t)))
(search-forward (char-to-string char) nil nil arg))
(<span class="keyword">defun</span> <span class="function-name">mark-to-char-exclusive</span> (arg char)
<span class="doc">"Mark up to but not including ARGth occurrence of CHAR."</span>
(<span class="keyword">interactive</span> (list (prefix-numeric-value current-prefix-arg)
(read-char <span class="string">"Mark to char: "</span> t)))
(set-mark
(<span class="keyword">save-excursion</span>
(move-to-char arg char)
(backward-char)
(point))))
(<span class="keyword">defun</span> <span class="function-name">mark-to-char-inclusive</span> (arg char)
<span class="doc">"Mark up to and including ARGth occurrence of CHAR."</span>
(<span class="keyword">interactive</span> (list (prefix-numeric-value current-prefix-arg)
(read-char <span class="string">"Mark to char: "</span> t)))
(set-mark
(<span class="keyword">save-excursion</span>
(move-to-char arg char)
(point))))
(<span class="keyword">use-package</span> <span class="constant">expand-region</span>) <span class="comment-delimiter">;; </span><span class="comment">for the er/* commands</span>
</pre>
</div>
</details></div>
<p>
I've been using this since 2017. It's now 2022. How did it go?
</p>
<p>
Old habits are hard to break. I used this for urls, words, strings, almost none of the others. It's easier for me to move the cursor manually than to learn the specific commands, unless the command is something I use often.
</p>
<p>
So I'm going to call this experiment complete. I learned that it it's not going to work for me. That's ok. I try lots of things and most don't work. Some do, which is why I keep trying.
</p>
<p>
<em>I still think the idea is good</em> but I have 30 years of emacs muscle memory to fight.
</p>
<p>
I considered switching to one of these:
</p>
<ul class="org-ul">
<li><a href="https://github.com/plandes/mark-thing-at">mark-thing-at</a> lets you define keys for marking each type of thin</li>
<li><a href="https://github.com/clemera/objed">objed</a> lets you work on text objects, inspired by vim and kakoune</li>
<li><a href="https://github.com/magnars/expand-region.el#readme">expand-region</a> will <em>guess</em> the object instead of making me choose</li>
</ul>
<p>
I decided I'll remove my experiment code and try <code>expand-region</code> next.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com2tag:blogger.com,1999:blog-5304409.post-46041330163361404872022-07-06T16:35:00.003-07:002022-07-06T16:38:38.208-07:00Axial name highlighting<p>
I like to try various things out in my editor to see if they're useful. Most are interesting but not useful. On my <a href="https://www.redblobgames.com/grids/hexagons/">guide to hexagons</a> I use colors for the three hexagon axes (q, r, s). I thought it might be cool to do something similar in the text editor, for x and y:
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/axis-coloring-1.png" />
<figcaption>Coloring variables by which axis they refer to</figcaption>
</figure>
<a name='more'></a>
<p>
Type systems already do so much for us. A type system catches operations that should not be allowed, like <kbd>sqrt("hello")</kbd>. But primitive types tend to be tied to hardware formats like <code>int32</code>, <code>double</code>, <code>char*</code>. Some type systems work with the types humans think about instead of what machines think about. For example, a type system could catch an invalid operation like <kbd>3_meters + 5_grams</kbd>. Or <kbd>sql`SELECT * FROM ` + html`<img>`</kbd>.
</p>
<p>
These kinds of systems are sometimes awkward to work with when you have to prove to the compiler that your code is correct. But what if they're just warnings in the editor and not compile errors? I implemented this using regular expressions and <a href="https://tree-sitter.github.io/tree-sitter/">tree-sitter</a>. I already was using tree-sitter to highlight specific keywords:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(tree-sitter-hl-add-patterns 'python
[
[<span class="string">"assert"</span> <span class="string">"return"</span> <span class="string">"raise"</span> <span class="string">"finally"</span> <span class="string">"continue"</span> <span class="string">"try"</span> <span class="string">"except"</span>]
@keyword.major
])
</pre>
</div>
<p>
I highlighted those keywords in <span style="color:red;font-weight:bold">bold red</span>, overriding the default coloring for keywords. I can extend the same idea to variable and field names:
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/axis-coloring-2.png" />
<figcaption>Horizontal and vertical variable names</figcaption>
</figure>
<p>
The implementation for emacs:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(tree-sitter-hl-add-patterns lang
[
([(identifier) (property_identifier)]
@variable.horizontal
(.match? @variable.horizontal
<span class="string">"(^q|^x\\d*|^x[A-Z]\\w*|^[cC]ols?|COLS|[wW]idth|WIDTH|[lL]eft|[rR]ight)$"</span>))
([(identifier) (property_identifier)]
@variable.vertical
(.match? @variable.vertical
<span class="string">"(^r|^y\\d*|^y[A-Z]\\w*|^[rR]ows?|ROWS|[hH]eight|HEIGHT|[tT]op|[bB]ottom)$"</span>))
]))
</pre>
</div>
<p>
and then you need to create faces <code>tree-sitter-hl-face:variable.horizontal</code> and <code>tree-sitter-hl-face:variable.vertical</code>.
</p>
<p>
Of course, these are just naming conventions, not encoded in the type system or checked in any formal way. But what if they were understood by the type system? Wouldn't it be handy to get a warning if you tried calling <code>atan2(x, y)</code> instead of <code>atan2(y, x)</code>? Or a warning for <code>rect(x, x, w, h)</code> instead of <code>rect(x, y, w, h)</code>? Maybe. I don't know!
</p>
<p>
I believe tree-sitter is able to flag something like <code>atan2(x, y)</code>, but I didn't try implementing that.
</p>
<p>
What about other editors? Tree-sitter is in <a href="https://github.blog/2018-10-31-atoms-new-parsing-system/">Atom</a>, <a href="https://github.com/nvim-treesitter/nvim-treesitter">neovim</a>, <a href="https://emacs-tree-sitter.github.io/getting-started/">emacs</a>, and <a href="https://marketplace.visualstudio.com/items?itemName=evgeniypeshkov.syntax-highlighter">vscode</a>. And even without tree sitter, that regexp might be useful for highlighting any string with a word boundary pattern <kbd>\b</kbd> instead of <kbd>^</kbd> or <kbd>$</kbd>.
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/axis-coloring-3.png" />
<figcaption>x and y variable names</figcaption>
</figure>
<p>
Highlighting catches nowhere near as much as a type system, but it's so much easier to implement than a type system. I'll try it for a while and then decide whether to keep it. I like experimenting.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com3tag:blogger.com,1999:blog-5304409.post-74119694116095434402022-05-14T09:09:00.000-07:002022-05-14T09:09:35.269-07:00Beer mode and coffee mode<p>
Over the years I've mentioned to people that I work in two modes:
</p>
<dl>
<dt>Beer Mode 🍺</dt><dd>I'm relaxed and make connections between many different ideas. I can come up with new <strong>creative</strong> ideas.</dd>
<dt>Coffee Mode ☕</dt><dd>I'm focused and make progress on my work. I am <strong>productive</strong> and can complete existing projects.</dd>
</dl>
<p>
I assumed that the names "Beer Mode" and "Coffee Mode" are something I saw somewhere. But then when I went looking for it, I couldn't find any source. It seems to be called "open mode" and "closed mode" by others. So it's possible that these terms are something I came up with! I mentioned it <a href="https://twitter.com/redblobgames/status/1345087024139669505?s=21">on Twitter</a> and <a href="https://perell.com/note/open-mode-and-closed-mode/">David Perell wrote a page about it</a>.
</p>
<p>
I had a similar experience when I said <a href="https://twitter.com/redblobgames/status/1515132841750802433">Dreams are malleable</a> — I assumed I had seen this somewhere but I couldn't find a good source, so it's possible my brain came up with that phrase too. And also possibly <a href="https://en.wikipedia.org/wiki/Don%27t_be_evil">this one</a>. I say lots of off-the-cuff things (in beer mode) and don't remember most of them.
</p>
<p>
<a href="https://amitp.blogspot.com/2022/02/non-consensual-personalization.html">Non-consensual personalization</a> on the other hand is a phrase I carefully thought about.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-998916528933276342022-02-25T11:00:00.001-08:002022-02-25T11:00:00.204-08:00Microtunnels<p>
I'm a big fan of tunnels. I've previously blogged about <a href="https://amitp.blogspot.com/2005/11/faster-delivery-service.html">tunnels for package delivery</a> and <a href="https://amitp.blogspot.com/2016/12/tunnels-everywhere.html">tunnels for infrastructure</a> like electricity, internet, water, etc. But I think tunnels might also be useful at a very small scale, within my yard. If we had flexible tunnel boring machines that could dig 4mm diameter tunnels:
</p>
<ul class="org-ul">
<li>For each plant with invasive root systems (bamboo, blackberry) I'd tell the machine to <em>follow the roots</em> and set fire to them 🔥</li>
<li>For each tree I'd tell the machine to <em>follow the roots</em> and deliver nutrients and dislodge pests 🐛</li>
<li>For drough prone areas I'd tell the machine to dig a network of tunnels that could absorb precious rainwater into the ground so that it doesn't run off 🏜</li>
</ul>
<p>
I expect the small diameter tunnels would be much easier to dig but at the same time the flexible paths would be harder to build robots for.
</p>
<p>
[Terminology note: <a href="https://en.wikipedia.org/wiki/Microtunneling">microtunneling</a> already refers to 40mm tunnels much larger than these, and nanotunneling already refers to 40nm tunnels much smaller than these, but micro seems like a closer match]
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-72164122813862218942022-02-01T13:04:00.013-08:002022-02-14T08:18:07.025-08:00Non-consensual personalization<figure style="width:20%;float:left;margin-right:1ch">
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 676.65833 580" xmlns:xlink="http://www.w3.org/1999/xlink"><path id="a24dc8e0-63f3-4c57-9da7-8d00cfa1aebe-1073" data-name="Path 438" d="M576.714,689.7237a24.21461,24.21461,0,0,0,23.38269-4.11876c8.18977-6.87442,10.758-18.196,12.8467-28.68192l6.17973-31.01657-12.9377,8.90837c-9.30465,6.40641-18.81826,13.01866-25.26011,22.29785s-9.25223,21.94708-4.07792,31.988" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path id="bc8b2ee0-9ec2-4139-a7e3-e0b1b1382397-1074" data-name="Path 439" d="M578.7117,729.43427c-1.62839-11.86369-3.30382-23.88079-2.15884-35.87168,1.01467-10.64932,4.26373-21.0488,10.87831-29.57938a49.20606,49.20606,0,0,1,12.62466-11.44038c1.26215-.79648,2.42409,1.20354,1.16733,1.997A46.77942,46.77942,0,0,0,582.7187,676.8654c-4.02857,10.24607-4.67545,21.41582-3.98154,32.3003.41944,6.58218,1.31074,13.12121,2.20588,19.65251a1.19817,1.19817,0,0,1-.808,1.42251,1.16348,1.16348,0,0,1-1.42253-.808Z" transform="translate(-261.67083 -161.32613)" fill="#f2f2f2"/><path id="a6bcb68f-fec1-4497-88cc-56de52c10faf-1075" data-name="Path 442" d="M590.43273,710.39781a17.82511,17.82511,0,0,0,15.53141,8.01862c7.8644-.37318,14.41806-5.85972,20.31713-11.07027l17.452-15.4088-11.54987-.5528c-8.30619-.39784-16.82672-.771-24.73813,1.79338s-15.20758,8.72638-16.654,16.9154" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path id="a1650e23-bf32-4c95-848c-aacb59e17a01-1076" data-name="Path 443" d="M574.10872,736.254c7.83972-13.87142,16.93234-29.28794,33.1808-34.21551a37.02589,37.02589,0,0,1,13.95545-1.44105c1.48189.128,1.11179,2.41174-.367,2.28454a34.39826,34.39826,0,0,0-22.27164,5.89214c-6.27994,4.27454-11.16975,10.21756-15.30781,16.51907-2.53511,3.86051-4.80576,7.88445-7.07642,11.903C575.49654,738.48066,573.37471,737.55312,574.10872,736.254Z" transform="translate(-261.67083 -161.32613)" fill="#f2f2f2"/><path d="M834.3331,568.1169H261.67083V161.32613H834.3331Z" transform="translate(-261.67083 -161.32613)" fill="#fff"/><path d="M308.319,328.40241a5.57978,5.57978,0,0,0,0,11.15956H501.70843a5.57979,5.57979,0,0,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="hsl(210,50%,70%)"/><path d="M308.319,361.88106a5.57979,5.57979,0,1,0-.02353,11.15956H501.85128a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="hsl(210,50%,70%)"/><path d="M308.319,394.88106a5.57979,5.57979,0,1,0-.02353,11.15956h43.55577a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="hsl(210,50%,70%)"/><path d="M834.3331,568.1169H261.67083V161.32613H834.3331Zm-563.24864-9.41363h553.835V170.73976h-553.835Z" transform="translate(-261.67083 -161.32613)" fill="#e5e5e5"/><path d="M654.14325,478.73228a10.03692,10.03692,0,0,0-.04234,20.07379h95.83757a10.0369,10.0369,0,1,0,0-20.07379Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M654.14325,357.18463a10.03692,10.03692,0,0,0-.04234,20.07379h95.83757a10.0369,10.0369,0,1,0,0-20.07379Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,483.38106a5.57979,5.57979,0,1,0-.02353,11.15956H501.85128a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,516.38106a5.57979,5.57979,0,1,0-.02353,11.15956h43.55577a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,449.90241a5.57978,5.57978,0,0,0,0,11.15956H501.70843a5.57979,5.57979,0,0,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,206.90241a5.57978,5.57978,0,0,0,0,11.15956H501.70843a5.57979,5.57979,0,0,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,240.38106a5.57979,5.57979,0,1,0-.02353,11.15956H501.85128a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M308.319,273.38106a5.57979,5.57979,0,1,0-.02353,11.15956h43.55577a5.57978,5.57978,0,1,0,0-11.15956Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><path d="M654.14325,235.73228a10.03692,10.03692,0,0,0-.04234,20.07379h95.83757a10.0369,10.0369,0,1,0,0-20.07379Z" transform="translate(-261.67083 -161.32613)" fill="#e4e4e4"/><circle cx="412.66227" cy="84.34774" r="18" fill="#cacaca"/><path d="M705.79333,371.574a9.97765,9.97765,0,0,0,10.27632,11.3346l9.55853,20.70035,13.99627-2.74057L725.71538,371.825a10.03173,10.03173,0,0,0-19.92205-.25107Z" transform="translate(-261.67083 -161.32613)" fill="#ffb6b6"/><polygon points="540.954 288.584 501.954 269.293 474.434 222.586 455.198 231.891 480.162 285.848 543.226 322.253 540.954 288.584" fill="#3f3d56"/><polygon points="452.907 564.696 440.647 564.695 434.814 529.347 452.909 529.348 452.907 564.696" fill="#ffb6b6"/><path d="M717.70442,737.9058l-39.53077-.00147v-.5a15.38731,15.38731,0,0,1,15.38648-15.38623h.001l24.144.001Z" transform="translate(-261.67083 -161.32613)" fill="#2f2e41"/><polygon points="575.282 542.21 566.728 550.992 537.336 530.508 549.961 517.546 575.282 542.21" fill="#ffb6b6"/><path d="M847.64779,709.58775l-27.582,28.318-.35819-.34886a15.38729,15.38729,0,0,1-.28711-21.75769l.00068-.0007,16.84623-17.29565Z" transform="translate(-261.67083 -161.32613)" fill="#2f2e41"/><path d="M729.73468,515.65207h-8.47936l0,0a236.91236,236.91236,0,0,0-49.42272,83.37115L661.70318,628.682l36.10213,75.59,22.52779.40187-25.748-80.25184,25.94027-34.4,1.30776,69.15187,83.49213,43.76321,16.71006-24.6851-67.94-37.15,11.57-58.81995s23.2789-19.41188,9.72338-49.76Z" transform="translate(-261.67083 -161.32613)" fill="#2f2e41"/><path d="M841.3331,438.67387,806.09749,423.2416,767.31532,440.427s-10.98222,6.2469-3.98222,22.2469l-42.07778,52.9782s.07778.0218,52.9599,16.86993l47.71093-42.01618a58.74345,58.74345,0,0,0,19.407-51.83192Z" transform="translate(-261.67083 -161.32613)" fill="#3f3d56"/><circle cx="573.74888" cy="236.89892" r="24.56103" fill="#ffb6b6"/><path d="M867.22776,365.63151c-5.63671-4.58572-14.37921-5.587-20.19831-1.23521-10.14917-5.3269-23.86487-2.54823-31.14037,6.30878-2.61816,3.18714-4.47305,7.49893-3.17756,11.41475,1.29549,3.91576,6.8819,6.21772,9.7939,3.29669l-.05192,1.20334a19.49485,19.49485,0,0,1-12.1204,33.19831q12.07284,4.877,24.14539,9.754c3.38659,1.36806,6.88109,2.7578,10.53325,2.73911s7.54514-1.79319,8.96241-5.15925q1.52858,4.6851,3.05687,9.37027a154.226,154.226,0,0,0,14.71518-30.33694c2.43658-6.84569,4.40646-14.00465,4.14333-21.26636C875.62641,377.65739,872.86446,370.21723,867.22776,365.63151Z" transform="translate(-261.67083 -161.32613)" fill="#2f2e41"/><circle cx="412.66227" cy="327.34774" r="18" fill="#cacaca"/><circle cx="468.66227" cy="205.89538" r="18" fill="#a44"/><path d="M730.79333,361.574a9.97765,9.97765,0,0,0,10.27632,11.3346l9.55853,20.70035,13.99627-2.74057L750.71538,361.825a10.03173,10.03173,0,0,0-19.92205-.25107Z" transform="translate(-261.67083 -161.32613)" fill="#ffb6b6"/><polygon points="565.954 278.584 526.954 259.293 499.434 212.586 480.198 221.891 505.162 275.848 568.226 312.253 565.954 278.584" fill="#3f3d56"/><path d="M937.32917,738.67387h-381a1,1,0,0,1,0-2h381a1,1,0,0,1,0,2Z" transform="translate(-261.67083 -161.32613)" fill="#cacaca"/></svg>
<figcaption>Illustration from <a href="https://undraw.co/illustrations">unDraw</a></figcaption>
</figure>
<p>
I <em>want</em> to personalize things I use. I want to change the settings. I want to change the colors, the design, the functionality. It used to be more common that I could do this type of thing. But these days, it seems like companies want to use "AI" to personalize things without my consent. Instead of <em>asking</em> me what I want, they <em>decide</em> what I want.
</p>
<p>
On Netflix, I'd love to change the order of the various categories. But I can't. Netflix <em>decides for me</em> what the order should be. I no longer have a choice. This kind of thing seems to be happening across products and services. It's not only commercial software, but also places like Linux (edit: I mean the ecosystem, not the kernel) and Firefox (edit: I was thinking of the extensions and ui). And it's not only personalization. It used to be when I misspelled something on Google, the page would <em>ask me</em> "did I mean:". But these days, Google <em>decides for me</em> what I meant. It just goes ahead and changes the search words without asking.
</p>
<p>
One very surprising exception is Mac OS, which after decades of only allowing blue controls added the choice of color. But in most ways MacOS doesn't allow me to personalize things.
</p>
<p>
These companies might argue that it's for my benefit or that it's been studied or whatever, but it doesn't matter. There's a big difference between me <em>choosing</em> to paint my room green and a corporation coming into my house in the middle of the night and painting my room green.</p>
<p>Update: [2022-02-04] This post unexpectedly got on hackernews; see <a href="https://news.ycombinator.com/item?id=30178781">the comments</a>.</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com3tag:blogger.com,1999:blog-5304409.post-63757256504633344462022-01-24T12:37:00.001-08:002022-01-24T12:42:45.126-08:00Roman numerals and currency<p>
I find that <a href="https://en.wikipedia.org/wiki/Roman_numerals">Roman Numerals</a> didn't "click" for me. At an intellectual level, I understand how they work. But they felt unintuitive. Until now!
</p>
<figure>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Eventail_de_dollars_americains.svg/531px-Eventail_de_dollars_americains.svg.png" alt="photo of dollar bills" />
<figcaption><a href="https://commons.wikimedia.org/wiki/File:Eventail_de_dollars_americains.svg">Image of US paper currency, from Wikipedia, public domain</a></figcaption>
</figure>
<a name='more'></a>
<p>
Let's start with the simplified version:
</p>
<p>
<code>I</code> is 1. If you want more than 1 you write more of them: <code>II</code> is 2, <code>III</code> is 3, etc. But it doesn't keep going like this. <code>IIII</code> is 4 (yes, it is! I'll cover <code>IV</code> later). But 5 is too many, so they write it as <code>V</code>. Then we're back to adding <code>I</code> to count by 1: <code>VI</code> is 6, <code>VII</code> is 7, <code>VIII</code> is 8, <code>VIIII</code> is 9. But then at 10, they write <code>X</code>.
</p>
<p>
So the rule is to keep adding <code>I</code> but when there are too many you switch to another letter. <code>XI</code> is 11, <code>XII</code> is 12, <code>XIII</code> is 13, <code>XIIII</code> is 14, then <code>XV</code> is 15, <code>XVI</code> is 16, <code>XVII</code> is 17, <code>XVIII</code> is 18, <code>XVIIII</code> is 19, then <code>XX</code> is 20.
</p>
<p>
At <code>XXXXX</code> they switch to <code>L</code>. At <code>LXXXXX</code> they switch to <code>C</code>.
</p>
<p>
At <code>CCCCC</code> they switch to <code>D</code>. At <code>DCCCCC</code> they switch to <code>M</code>.
</p>
<p>
I get it. I understand the rules.
</p>
<p>
But it didn't <em>click</em> until I related it to something I use all the time: cash money. (<em>note: at least I did, until the pandemic; I originally wrote this post in 2019 and just hadn't published until now</em>)
</p>
<p>
<code>I</code> is like a $1 bill. <code>II</code> is like 2 $1 bills. <code>III</code> is like 3 $1 bills.
</p>
<p>
<code>V</code> is like a $5 bill. <code>VII</code> would be 7, which is a $5 bill and 2 $1 bills.
</p>
<p>
<code>X</code> is a $10 bill. <code>L</code> is a $50. <code>C</code> is a $100.
</p>
<p>
To represent $168, I'd use a $100 + $50 + $10 + $5 + $1 + $1 + $1. That's <code>C</code> + <code>L</code> + <code>X</code> + <code>V</code> + <code>I</code> + <code>I</code> + <code>I</code>. So it's the Roman numeral <code>CLXVIII</code>.
</p>
<p>
Sure, there are a few places it doesn't quite match up. Roman numerals don't have a $20 bill. And they sometimes (not always) use "subtractive" variants 4 = <code>IV</code> instead of <code>IIII</code>, 9 = <code>IX</code> instead of <code>VIIII</code>, and others. Romans were inconsistent about this, and <a href="https://en.wikipedia.org/wiki/Roman_numerals#Variant_forms">Wikipedia has a list</a>. But the idea of using monetary bills helped me build some intuition, turning it from purely intellectual knowledge to something I can better relate to.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com1tag:blogger.com,1999:blog-5304409.post-44926219142499129752021-06-03T10:18:00.020-07:002021-06-29T11:31:11.824-07:00Firefox 89 tab appearance<p>
<a href="https://www.mozilla.org/en-US/firefox/89.0/releasenotes/">Firefox 89</a> has a new appearance, removing features (ugh) and annoying some people while delighting others. It can be disabled by setting <code>browser.proton.enabled</code> to false:
</p>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJmW2nbDJOMhPa3JlVbbVQdEHQHvDPFJmXeQjSydHqJuDuTQwcohlPKyqL4JrnzHAH0e228nktvytOzcDrOVG3E8JJCbK5JM14eQ7NJPTnY_Dk3JyrSstOTtby-EUKUhsHhfeg/s0/firefox-89-proton-disabled.png"><img alt="Firefox 89 with Proton disabled" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJmW2nbDJOMhPa3JlVbbVQdEHQHvDPFJmXeQjSydHqJuDuTQwcohlPKyqL4JrnzHAH0e228nktvytOzcDrOVG3E8JJCbK5JM14eQ7NJPTnY_Dk3JyrSstOTtby-EUKUhsHhfeg/s0/firefox-89-proton-disabled.png"/></a>
<figcaption>Firefox 89 with Proton disabled</figcaption>
</figure>
<p>
I mostly like the new design though, but I strongly dislike some elements, especially the tabs:
</p>
<a name='more'></a>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUX4UyIHsf6DkyUR9jry0wBeG-14_QzROE_d8HPY4MWj1FJv1MYqTlqqLYC2sVdrM562GFPxolvCES47CVWLJKfDLKM5y93_7Jms2_yNZNF-SdYp_MOlw13fzSu90mNdlOIsU3/s0/Screen+Shot+2021-06-03+at+10.01.18.png"><img alt="Firefox 89 tab appearance" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUX4UyIHsf6DkyUR9jry0wBeG-14_QzROE_d8HPY4MWj1FJv1MYqTlqqLYC2sVdrM562GFPxolvCES47CVWLJKfDLKM5y93_7Jms2_yNZNF-SdYp_MOlw13fzSu90mNdlOIsU3/s0/Screen+Shot+2021-06-03+at+10.01.18.png"/></a>
<figcaption>Firefox 89 tab appearance</figcaption>
</figure>
<ol>
<li>I want the active tab to be much brighter. <s>I couldn't see a way to set the color in <a href="https://color.firefox.com/?theme=XQAAAAIaAQAAAAAAAABBKYhm849SCia2CaaEGccwS-xMDPr9KfClsSTPZ6KR10egvAnvMJ8XO1z9fJ7dFCZ0g3XO4Y2xd-pWchUZjnhS7EY4GGZUn6vkTrAK5BHuikAvYffRTJxiezg8FCFlyR5oK4Lpmxevi6sCTAvDGmsGPN3RlDXhkUxJD2XrLFumvRPsPVUoD9yFWAen_UuK2mr2j46TIm5ypkm1Y9GifPPM2Sdoek5YBZgQ2BXCjB__lASdAA">Firefox Color</a></s>. In Firefox Color, use the Advanced Colors / Tab Selected setting. Thanks to an anonymous commenter for this tip.</li>
<li>The inactive tabs blend into the background. I want to see distinct tabs.</li>
<li>The tabs no longer look like tabs! They are just buttons and feel disconnected from the rest of the browser.</li>
</ol>
<p>
Fortunately there are some <code>userChrome.css</code> rules that can change some of this:
</p>
<pre>
tab {
font-size: 17px !important;
font-family: Maven Pro !important;
}
.tabbrowser-tab[selected] .tab-label {
color: black !important;
font-weight: bold !important;
}
.tabbrowser-tab[selected] .tab-content {
background: #fcb731 ! important;
}
.tabbrowser-tab:not([selected]) .tab-content {
background: #585060;
}
</pre>
<p>
I wish the Firefox settings page let you edit this file but you can still <a href="https://www.userchrome.org/">edit the file in your profiles folder</a>. Here's what it looks like with these CSS rules:
</p>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh94b7qzslXzQLHivoEgG3Jv0ZhnNSsHjFUv8iWIe6RiUCTwzk84yGQK3Pj0roKyIiRkhHtrdZX_QcxFmEsZKcNUsZyE4oHLBhaUKiKtkgqWsnQmiSnf7rS1buO9k4ECyAOpqD/s0/Screen+Shot+2021-06-03+at+10.03.58.png"><img alt="Firefox 89 modified" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh94b7qzslXzQLHivoEgG3Jv0ZhnNSsHjFUv8iWIe6RiUCTwzk84yGQK3Pj0roKyIiRkhHtrdZX_QcxFmEsZKcNUsZyE4oHLBhaUKiKtkgqWsnQmiSnf7rS1buO9k4ECyAOpqD/s0/Screen+Shot+2021-06-03+at+10.03.58.png"/></a>
<figcaption>Firefox 89 modified</figcaption>
</figure>
<p>
I was still looking for a way to make the tabs look more like tabs. <a href="https://www.userchrome.org/firefox-89-styling-proton-ui.html">This guide</a> looks useful, as does <a href="https://github.com/black7375/Firefox-UI-Fix">this one</a>. They give CSS rules for <code>.tab-background</code>. Looking through the <a href="https://searchfox.org/mozilla-central/source/browser/base/content/browser.xhtml#1702">Firefox source code for browser.xhtml</a> and also <a href="https://searchfox.org/mozilla-central/source/browser/base/content/tabbrowser-tab.js">for tabbrowser-tab.js</a> gives me <em>all</em> the xhtml elements I can attach styles to, so I experimented with that. <b>Update 2021-06-04</b>: Here's the CSS I ended up with:
</p>
<pre>
tab {
font-size: 17px !important;
font-family: Maven Pro !important;
}
/* Use color and shape to make the tabs look more like tabs */
.tab-background {
background: #585060;
border-radius: 9px 9px 0 0 !important;
margin-bottom: 0px !important;
box-shadow: 0 0 2px 2px rgba(0,0,0,0.1) !important;
border: 1px solid rgba(0,0,0,.5) !important;
border-bottom-width: 0px !important;
}
/* Selected tabs I want a bright background with a dark foreground */
.tabbrowser-tab[selected] .tab-background {
background: #fcb731 !important;
}
.tabbrowser-tab[selected] .tab-label {
color: black !important;
font-weight: bold !important;
}
/* Draw a solid line underneath to make the selected tab look *connected* to the rest of the browser */
#TabsToolbar {
border-bottom: 2px solid #fcb731 !important;
}
/* Hover over tabs */
.tabbrowser-tab:hover .tab-background:not([selected]) {
background: #686070 !important;
}
</pre>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi28_p3fKUmV5uqNYpmII4K1q5SLEgZW4LMvjbyQJPhfPufjSRdyW8GMaN7xayFbnXWpL-dcip1F4P5Lnx-sDDXXTWqkEMOlvKFLSxhScAdWlw0sbJ3t3ccotxgiNfdCyLCeHhD/s0/Screen+Shot+2021-06-03+at+10.45.33.png"><img alt="Firefox 89 modified even more" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi28_p3fKUmV5uqNYpmII4K1q5SLEgZW4LMvjbyQJPhfPufjSRdyW8GMaN7xayFbnXWpL-dcip1F4P5Lnx-sDDXXTWqkEMOlvKFLSxhScAdWlw0sbJ3t3ccotxgiNfdCyLCeHhD/s0/Screen+Shot+2021-06-03+at+10.45.33.png"/></a>
<figcaption>Firefox 89 modified even more</figcaption>
</figure>
<p>
<b>Update 2021-06-27</b>: I switched to more of <a href="https://color.firefox.com/?theme=XQAAAAK4AQAAAAAAAABBKYhm849SCia9U4KEGccwS-xMDPsqyghisHPW4rCtMFlEufiop23XrdEbhojE7omhmDzA7E51ytvifid-rIrIoOIzG1rV2KXP_NVJiWyhqRhWSteGFbv5bVOKMLLkzi-l041yC4YECLaJEkTJGJ0T1j0mkpPBtb0dtNRg_C-oWK9WxPB5vdZRO_aAqnUqFuB9u8Ihl0Ns8hkJbDICLIEj184OiGYFnT3UVPJDPmOmzWtBF0EufjuYdiJX9R8bDiDUEifJvANDUhRMnzAO89tlHG3fKRbdSbmzaWOzERtR8Du7PTNlElmYI1NFDklUQqqMRSCfOlwM1ELC7Mr67YkA">a "silver" theme</a>, making the tabs feel more connected to the toolbar, and using gradients on the tabs:
</p>
<pre>
tab {
font-size: 17px !important;
font-family: Maven Pro !important;
}
/* Use color and shape to make the tabs look more like tabs */
.tab-background {
background: linear-gradient(hsla(0, 0%, 100%, 0.25), hsla(0, 0%, 40%, 1.0));
border-radius: 6px 6px 0 0 !important;
margin-bottom: 0px !important;
box-shadow: 0 0 2px 2px rgba(0,0,0,0.1) !important;
border: 1px solid rgba(0,0,0,.5) !important;
border-bottom-width: 0px !important;
}
/* Selected tabs I want a bright background with a dark foreground -- set Firefox Color's "Toolbar Color" to #ccc */
.tabbrowser-tab[selected] .tab-background {
background: linear-gradient(#eee, #ccc) !important;
}
.tabbrowser-tab[selected] .tab-label {
color: black !important;
font-weight: bold !important;
}
/* Draw a solid line underneath to make the selected tab look *connected* to the rest of the browser */
#TabsToolbar {
border-bottom: 2px solid #ccc !important;
}
/* Hover over tabs */
.tabbrowser-tab:hover .tab-background:not([selected]) {
background: #999 !important;
}
</pre>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzIDGohucY5a8vf6Vmpj4695B7oT0YcLpPcn6zgnkzY92jBwahArKncI7RuyxbeSx_R0WMzfzkfaioyvhG0BFoapFk07lCPbQnP1Yq8gOv68IAYEE1GjqhwJtpMEi6lAhhUnuD/s0/Screen+Shot+2021-06-29+at+11.24.56.png"><img alt="Firefox 89 lighter theme" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzIDGohucY5a8vf6Vmpj4695B7oT0YcLpPcn6zgnkzY92jBwahArKncI7RuyxbeSx_R0WMzfzkfaioyvhG0BFoapFk07lCPbQnP1Yq8gOv68IAYEE1GjqhwJtpMEi6lAhhUnuD/s0/Screen+Shot+2021-06-29+at+11.24.56.png"/></a>
<figcaption>Firefox 89 lighter theme</figcaption>
</figure>
<p>
So far I like it! There are some issues I haven't worked out yet. I'll keep tweaking it as I learn more. <b>Update 2021-06-04</b>: <a href="https://news.ycombinator.com/item?id=27392685">HackerNews comments</a> point to "Browser chrome and add-on debugging toolboxes" and "Remote debugging" in dev tools. This lets you directly inspect the dom of the browser so that you can figure out what you want to style. Amazing! Love Firefox even more now.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com18tag:blogger.com,1999:blog-5304409.post-34407845281007509032021-04-13T10:17:00.003-07:002021-06-04T11:21:19.059-07:00Automatically generate IDs for emacs org-mode headings<p>
I write some of my web pages with emacs org-mode, and then export to html.
Like markdown, org-mode is a convenient format to write a simple subset of html.
</p>
<p>
Each heading in the document will get exported with an ID so that it can be linked to from the table of contents. The default IDs look like <kbd>#org3091de9</kbd>. I usually replace these with a custom id that matches the section heading, so a heading <code>Bounding box</code> will get an id <kbd>#bounding-box</kbd>.
</p>
<a name='more'></a>
<p>
I've been doing this manually but looked for ways to do it automatically. I found alphapapa's <a href="https://github.com/alphapapa/unpackaged.el#export-to-html-with-useful-anchors">export to html with useful anchors</a> and Lee Hinman's <a href="https://writequit.org/articles/emacs-org-mode-generate-ids.html">emacs org mode generate ids</a>. Both of these were very useful! I used them to write this code:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">defun</span> <span class="function-name">my/org-generate-custom-ids</span> ()
<span class="doc">"Generate CUSTOM_ID for any headings that are missing one"</span>
(<span class="keyword">let</span> ((existing-ids (org-map-entries
(<span class="keyword">lambda</span> () (org-entry-get nil <span class="string">"CUSTOM_ID"</span>)))))
(org-map-entries
(<span class="keyword">lambda</span> ()
(<span class="keyword">let*</span> ((custom-id (org-entry-get nil <span class="string">"CUSTOM_ID"</span>))
(heading (org-heading-components))
(level (nth 0 heading))
(todo (nth 2 heading))
(headline (nth 4 heading))
(slug (my/title-to-filename headline))
(duplicate-id (member slug existing-ids)))
(<span class="keyword">when</span> (<span class="keyword">and</span> (not custom-id)
(< level 4)
(not todo)
(not duplicate-id))
(message <span class="string">"Adding entry %s to %s"</span> slug headline)
(org-entry-put nil <span class="string">"CUSTOM_ID"</span> slug)))))))
</pre>
</div>
<p>
When I run this function, it goes through all the headings, checks if there's an existing <code>CUSTOM_ID</code>, it's a level ≤3 heading, it's not marked TODO, and it won't be the same an existing id, then inserts the new id constructed from the heading.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="keyword">defun</span> <span class="function-name">my/title-to-filename</span> (title)
<span class="doc">"Convert TITLE to a reasonable filename."</span>
<span class="comment-delimiter">;; </span><span class="comment">Based on the slug logic in org-roam, but org-roam also uses a</span>
<span class="comment-delimiter">;; </span><span class="comment">timestamp, and I use only the slug. BTW "slug" comes from</span>
<span class="comment-delimiter">;; </span><span class="comment"><a href="https://en.wikipedia.org/wiki/Clean_URL#Slug"><https://en.wikipedia.org/wiki/Clean_URL#Slug></a></span>
(<span class="keyword">setq</span> title (s-downcase title))
(<span class="keyword">setq</span> title (s-replace-regexp <span class="string">"[</span><span class="negation-char"><span class="string">^</span></span><span class="string">a-zA-Z0-9]+"</span> <span class="string">"-"</span> title))
(<span class="keyword">setq</span> title (s-replace-regexp <span class="string">"-+"</span> <span class="string">"-"</span> title))
(<span class="keyword">setq</span> title (s-replace-regexp <span class="string">"^-"</span> <span class="string">""</span> title))
(<span class="keyword">setq</span> title (s-replace-regexp <span class="string">"-$"</span> <span class="string">""</span> title))
title)
</pre>
</div>
<p>
I only set this up this morning so it's too early to tell whether it'll be helpful but I'm hoping it'll save me some time constructing clean anchor ids on my web pages. <b>Update</b> I used this for a month and it <em>is</em> quite helpful!
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-71810106902836140492021-04-09T18:26:00.006-07:002021-04-09T19:45:16.694-07:00OpenTTD on Windows 10 + Steam<p>
Transport Tycoon / OpenTTD is my favorite game of all time, and I wanted to play it on Steam. I kept getting "file not writable" error. I tracked it down to the Windows security system blocking it. To unblock:
</p>
<ol>
<li> Start → </li>
<li> Settings → </li>
<li> Update & Security → </li>
<li> Windows security → </li>
<li> Open Windows Security → </li>
<li> Virus & threat protection → </li>
<li> Manage settings → </li>
<li> Controlled folder access → </li>
<li> Manage Controlled folder access → </li>
<li> Allow an app through Controlled folder access → </li>
<li> Add an allowed app → </li>
<li> openttd.exe </li>
</ol>
<p>
I am not a fan of making exceptions like this but I didn't find anything else that worked. If you have an alternate method of solving the permissions error, please let me know.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com1tag:blogger.com,1999:blog-5304409.post-56936130766047023012021-01-14T14:41:00.011-08:002021-01-24T12:12:28.337-08:00Building Emscripten on Apple ARM M1<p>
<strong>Update:</strong> [2021-01-24] The workarounds in this blog post are now obsolete, as openjdk, yuicompressor, and emscripten are now available in ARM homebrew.
</p>
<p>
On Mac, Emscripten is available in the Intel version of Homebrew, but not the ARM version of Homebrew. I use Emscripten rarely enough that this doesn't bother me. However, I thought I'd try compiling it on the ARM version.
</p>
<p>
I couldn't get openjdk working in ARM homebrew, but I was able to get emscripten installed in ARM homebrew by using the Intel/Rosetta version of openjdk:
</p>
<a name='more'></a>
<pre>
# install intel version of these dependencies, under rosetta
/usr/local/bin/<b>brew install openjdk yuicompressor</b>
# install arm version of these dependencies
/opt/homebrew/bin/<b>brew install python@3.9 node cmake</b>
# <b>trickery</b>: point to the intel version of openjdk, yuicompressor
<b>ln</b> -snf /usr/local/opt/openjdk /opt/homebrew/opt/
<b>ln</b> -snf /usr/local/opt/yuicompressor /opt/homebrew/opt/
# install arm version of emscripten from source
/opt/homebrew/bin/<b>brew install -s emscripten --ignore-dependencies</b>
# <b>trickery</b>: point to the arm version of emscripten
<b>ln</b> -snf /opt/homebrew/opt/emscripten /usr/local/opt/
</pre>
<p>
I'm sure this is *not* recommended but … it seems to be working so far!
</p>Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-23038716172750880952020-12-07T12:43:00.001-08:002020-12-07T12:43:01.042-08:00Tags vs labels<p>
In online collections (photos, bookmarks, blog posts, emails, etc.), “labels” and “tags” are typically words attached to the content. For example I have a <a href="https://www.flickr.com/photos/amitp/28417326384/">photo of a hummingbird</a> on which I used the labels <code>hummingbird</code> (what it is) and <code>coyote hills</code> (where it was). These words are non-hierarchical, unlike “categories” or “folders”.
</p>
<p>
But are “labels” and “tags” the same thing?
</p>
<p>
A long time ago, I read that <strong>they're different</strong>. The distinction as described was:
</p>
<ul class="org-ul">
<li>“labels” are when you mark <em>your own content</em> (first party)</li>
<li>“tags” are when you mark <em>other people's content</em> (third party)</li>
</ul>
<p>
This matches the behavior I see in other contexts:
</p>
<ul class="org-ul">
<li>the “label” on a t-shirt is what the manufacturer (first party) put on, while the “price tag” is what the store (third party) put on</li>
<li>in emacs and vi, there's a "tags" program that creates a mapping of words to source code, but it's attached by a third party (the tags program), not by the author of the source code</li>
<li>a “car label” is put on by the manufacturer (first party), while a “car tag” in the U.S. is given out by the state vehicle registration agency (third party)</li>
<li>“tagging” is graffiti, most often put on someone else's building</li>
<li>web servers have an “<a href="https://en.wikipedia.org/wiki/HTTP_ETag">etag</a>” which is attached to content not created by the web server itself, so that makes it a third party addition</li>
</ul>
<p>
But I think the distinction isn't clear. For example, Flickr uses “tags” when you mark your own content, but also “tags” when you annotate other people's content and also “tags” when the algorithms mark content automatically. And Gmail uses “labels” for your own emails, but also for other people's emails. Maybe this distinction is not relevant anymore.
</p>
<p>
Separately, “<a href="https://en.wikipedia.org/wiki/Hashtag">hashtags</a>” are something that started on Twitter. They're tags, but using the <code>#</code> symbol. This is different from “channels” on IRC, where topics are named <code>#dogs</code>, <code>#cats</code>, etc. Slack and Discord get the <code>#</code> channel names from IRC. Twitter's use is different from channels. Instagram, YouTube, and other sites also have hashtags like Twitter.
</p>
<p>
(I wanted to write this down as a reference for myself, the next time I'm wondering about tags vs labels.)
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com4tag:blogger.com,1999:blog-5304409.post-88105630409430982092020-11-30T10:39:00.021-08:002021-02-16T08:40:49.118-08:00Building Emacs 27 on Apple ARM M1<p>
On Mac, I sometimes run a prebuilt binary and <a href="https://amitp.blogspot.com/2017/10/building-mac-os-x-emacs-26.html">sometimes compile my own</a>. For Apple M1 (ARM) I started by using the x86 binaries from emacsformacosx.com but I wanted to try compiling a native ARM version too. I saw that the <code>work</code> branch of <a href="https://bitbucket.org/mituharu/emacs-mac/overview">Mitsuharu Yamamoto's Mac port</a> has M1 patches applied, so I decided to try it.
</p>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQGVyQN9B8PL-JCYepiTQUvdABtvikBEKvfN3bUXnMFKWIOOVlLGMOMeeLtFfL4A81xx2uGvx0xryF1Cl8Jver7hTtdJzOS_bDag_aePrkf1u5oGXhz4Qpr_r0S-yYppOMl0TK/s0/Screen+Shot+2020-11-30+at+10.28.33.png"><img alt="Screenshot of Emacs 27 compiled on Apple ARM M1" style="box-shadow: 0 1px 2px 2px rgb(0,0,0,0.5)" border="0" data-original-height="628" data-original-width="591" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQGVyQN9B8PL-JCYepiTQUvdABtvikBEKvfN3bUXnMFKWIOOVlLGMOMeeLtFfL4A81xx2uGvx0xryF1Cl8Jver7hTtdJzOS_bDag_aePrkf1u5oGXhz4Qpr_r0S-yYppOMl0TK/s0/Screen+Shot+2020-11-30+at+10.28.33.png"/></a>
</figure>
<a name='more'></a>
<p>
Make sure <code>/opt/homebrew/bin</code> (ARM homebrew) is earlier in your path than <code>/usr/local/bin</code> (Intel homebrew).
</p>
<div class="org-src-container">
<pre class="src src-sh"><span class="variable-name">EMACSAPP</span>=$HOME/Applications
brew install coreutils pkg-config libxml2 jansson gnutls autoconf gnu-sed
git clone --depth 1 --single-branch --branch work <span class="sh-escaped-newline">\</span>
https://bitbucket.org/mituharu/emacs-mac.git
cd emacs-mac
./autogen.sh
</pre>
</div>
<p>
and then build:
</p>
<div class="org-src-container">
<pre class="src src-sh">
make clean
find . -name \*.elc -exec rm '{}' ';'
./configure <span class="sh-escaped-newline">\</span>
--with-mac-metal --with-xml2 --without-imagemagick --with-json <span class="sh-escaped-newline">\</span>
--with-modules --without-makeinfo <span class="sh-escaped-newline">\</span>
--prefix=$<span class="variable-name">EMACSAPP</span>/Emacs.app/Contents/MacOS <span class="sh-escaped-newline">\</span>
--enable-mac-app=$<span class="variable-name">EMACSAPP</span> --enable-mac-self-contained
make -j3
mac/Emacs.app/Contents/MacOS/Emacs -q <span class="comment-delimiter"># </span><span class="comment">test it</span>
make install
</pre>
</div>
<p>
You should see it bring up a window with:
</p>
<pre class="example" id="orgcf5f47a">
This is GNU Emacs 27.1 (build 1, aarch64-apple-darwin20.1.0, Carbon Version 164 AppKit 2022.1)
of 2020-11-30
Copyright (C) 2020 Free Software Foundation, Inc.
</pre>
<p><strong>Updates</strong></p>
<p>As various packages were made available in Homebrew, the situation improved.</p>
<ul>
<li>[2020-11-30] Other parts of homebrew weren't complete enough for me to compile modules like vterm, so I temporarily switched back to emacsformacosx.com emacs</li>
<li>[2020-12-01] The emacsformacosx.com version flickrs <em>a lot</em> when using Rust + LSP + posframe, due to <a href="https://github.com/tumashu/posframe/issues/30">this issue</a>, so I switched back to the Mac Port, but compiled for x86.</li>
<li>[2020-12-03] I had some issues with *.elc files from previous compiles not being recompiled so I ended up deleting all the *.elc files in the emacs build folder, and that resolved the problem.</li>
<li>[2020-12-05] I also had to recompile all the *.elc files in elpa modules, with <code>(byte-recompile-directory "~/.emacs.d/elpa" 0 t)</code>.</li>
<li>[2020-12-07] I switched back to the ARM version, which works now. It seems faster but I don't know a good way to measure.</li>
<li>[2020-12-13] Modules like vterm seem to work now.</li>
<li>[2021-01-07] I learned that Homebrew emacs, <a href="https://github.com/d12frosted/homebrew-emacs-plus/issues/282">emacs-plus</a>, and railwaycat emacs now work on arm. I'm happy with the version I compiled, but <b>these would be the first things to try</b> if you don't want to compile your own.</li>
</ul>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com8tag:blogger.com,1999:blog-5304409.post-89696130790875379792020-06-08T18:17:00.003-07:002020-12-17T21:23:29.095-08:00Emacs: prettier tab-line<p>
Back in 2018 I posted about <a href="https://amitp.blogspot.com/2018/10/emacs-prettier-tabbar.html">making tabbar.el look pretty</a>. Emacs 27 includes two built-in ways to display tabs:
</p>
<ol class="org-ol">
<li><code>tab-bar-mode</code> works <em>per frame</em> to show <em>window configurations</em></li>
<li><code>tab-line-mode</code> works <em>per window</em> to show <em>buffers</em></li>
</ol>
<p>
Tab-line mode seems similar to tabbar.el, so I decided to switch from tabbar.el to tab-line.
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/emacs-tab-line.png" alt="Screenshot of emacs 27 tab-line-mode"/>
<figcaption>Emacs 27 tab-line mode</figcaption>
</figure>
<a name='more'></a>
<p>
I had customized tabbar.el to show only the buffers from the current project, sorted alphabetically. It's even easier with tab-line: <code>tab-line-tabs-function</code> can be set to <em>group</em> mode, which uses <code>tab-line-tabs-buffer-group-function</code> to choose the group name and <code>tab-line-tabs-buffer-group-sort-function</code> to sort the buffers in the group.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="paren">(</span><span class="keyword">require</span> '<span class="constant">s</span><span class="paren">)</span>
<span class="paren">(</span><span class="keyword">defun</span> <span class="function-name">my/tab-line-buffer-group</span> <span class="paren">(</span>buffer<span class="paren">)</span>
<span class="doc">"Use the project.el name for the buffer group"</span>
<span class="paren">(</span><span class="keyword">with-current-buffer</span> buffer
<span class="paren">(</span>s-chop-suffix <span class="string">"/"</span> <span class="paren">(</span>car <span class="paren">(</span>project-roots <span class="paren">(</span>project-current<span class="paren">))))))</span>
<span class="paren">(</span><span class="keyword">defun</span> <span class="function-name">my/buffer-sort</span> <span class="paren">(</span>a b<span class="paren">)</span> <span class="paren">(</span>string< <span class="paren">(</span>buffer-name a<span class="paren">)</span> <span class="paren">(</span>buffer-name b<span class="paren">)))</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-tabs-buffer-group-sort-function #'my/buffer-sort<span class="paren">)</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-tabs-buffer-group-function #'my/tab-line-buffer-group<span class="paren">)</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-tabs-function #'tab-line-tabs-buffer-groups<span class="paren">)</span>
</pre>
</div>
<p>
Next, I wanted to make the tabs look nicer. As before, I used powerline for this. I disabled the extra buttons by setting <code>tab-line-new-button-show</code> and <code>tab-line-close-button-show</code> to nil, then set <code>tab-line-tab-name-function</code> to a function that adds powerline wave symbols to both sides of the tab name:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="paren">(</span><span class="keyword">require</span> '<span class="constant">powerline</span><span class="paren">)</span>
<span class="paren">(</span><span class="keyword">defvar</span> <span class="variable-name">my/tab-height</span> <span class="constant">22</span><span class="paren">)</span>
<span class="paren">(</span><span class="keyword">defvar</span> <span class="variable-name">my/tab-left</span> <span class="paren">(</span>powerline-wave-right 'tab-line nil my/tab-height<span class="paren">))</span>
<span class="paren">(</span><span class="keyword">defvar</span> <span class="variable-name">my/tab-right</span> <span class="paren">(</span>powerline-wave-left nil 'tab-line my/tab-height<span class="paren">))</span>
<span class="paren">(</span><span class="keyword">defun</span> <span class="function-name">my/tab-line-tab-name-buffer</span> <span class="paren">(</span>buffer <span class="type">&optional</span> _buffers<span class="paren">)</span>
<span class="paren">(</span>powerline-render <span class="paren">(</span>list my/tab-left
<span class="paren">(</span>format <span class="string">" %s "</span> <span class="paren">(</span>buffer-name buffer<span class="paren">))</span>
my/tab-right<span class="paren">)))</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-tab-name-function #'my/tab-line-tab-name-buffer<span class="paren">)</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-new-button-show nil<span class="paren">)</span>
<span class="paren">(</span><span class="keyword">setq</span> tab-line-close-button-show nil<span class="paren">)</span>
</pre>
</div>
<p>
I used a color scheme that's consistent with my modeline:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="paren">(</span>set-face-attribute 'tab-line nil <span class="comment-delimiter">;; </span><span class="comment">background behind tabs</span>
<span class="builtin">:background</span> <span class="string">"gray40"</span>
<span class="builtin">:foreground</span> <span class="string">"gray60"</span> <span class="builtin">:distant-foreground</span> <span class="string">"gray50"</span>
<span class="builtin">:family</span> <span class="string">"Fira Sans Condensed"</span> <span class="builtin">:height</span> <span class="constant">1.0</span> <span class="builtin">:box</span> nil<span class="paren">)</span>
<span class="paren">(</span>set-face-attribute 'tab-line-tab nil <span class="comment-delimiter">;; </span><span class="comment">active tab in another window</span>
<span class="builtin">:inherit</span> 'tab-line
<span class="builtin">:foreground</span> <span class="string">"gray70"</span> <span class="builtin">:background</span> <span class="string">"gray90"</span> <span class="builtin">:box</span> nil<span class="paren">)</span>
<span class="paren">(</span>set-face-attribute 'tab-line-tab-current nil <span class="comment-delimiter">;; </span><span class="comment">active tab in current window</span>
<span class="builtin">:background</span> <span class="string">"#b34cb3"</span> <span class="builtin">:foreground</span> <span class="string">"white"</span> <span class="builtin">:box</span> nil<span class="paren">)</span>
<span class="paren">(</span>set-face-attribute 'tab-line-tab-inactive nil <span class="comment-delimiter">;; </span><span class="comment">inactive tab</span>
<span class="builtin">:background</span> <span class="string">"gray80"</span> <span class="builtin">:foreground</span> <span class="string">"black"</span> <span class="builtin">:box</span> nil<span class="paren">)</span>
<span class="paren">(</span>set-face-attribute 'tab-line-highlight nil <span class="comment-delimiter">;; </span><span class="comment">mouseover</span>
<span class="builtin">:background</span> <span class="string">"white"</span> <span class="builtin">:foreground</span> 'unspecified<span class="paren">)</span>
</pre>
</div>
<p>
Finally, I want to use keys to navigate the tabs. I bound <kbd>H-j</kbd> to <code>tab-line-switch-to-prev-tab</code> and <kbd>H-k</kbd> to <code>tab-line-switch-to-next-tab</code>. I use these same keys for terminals and web browsers.
</p>
<p>
I'm pretty happy with tab-line mode so far.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com11tag:blogger.com,1999:blog-5304409.post-9111943252807970942019-08-01T11:34:00.002-07:002024-02-21T16:11:36.768-08:00Notes about eyeglasses<p>
These are my barely-organized notes about my need for eyeglasses to correct my nearsightedness. <strong>It is likely that I have some of this wrong</strong> because I don't fully understand it.
</p>
<h3>Correction</h3>
<p>
When an optometrist measures your "prescription" they're measuring the 0th and 1st order <a href="https://en.wikipedia.org/wiki/Zernike_polynomials">zernicke polynomials</a>. The 0th order is "sphere" and is a single number, rounded to the closest 0.25. The 1st order is "cylinder" (astigmatism) and has two numbers: a direction axis and an amount. There are higher order aberrations too but the optometrist doesn't measure these. These higher order aberrations can cause halos and other effects; see this <a href="https://www.reviewofoptometry.com/CMSImagesContent/2007/10/2_13575_1.gif">example image</a> that shows a "coma" (point smeared out like a comet), "spherical aberration" (starbursts and halos), and "quadrefoil" (point spreads out multiple directions). Laser surgery can often correct these but sometimes the healing process generates new ones.
</p>
<a name='more'></a>
<h3>Focal range</h3>
<p>
The eye can adjust the focus between far and near. Being "nearsighted" means your focus range is too near, which means you can't reach the far distances, and some of your near range is wasted. Being "farsighted" means your focus range is too far, which means you can't reach the near distances, and some of your far range is wasted. All the corrections (glasses, contacts, laser surgery) <strong>move the range</strong> but don't expand it. As you get older <strong>the range shrinks</strong>; this is called "presbyopia".
</p>
<figure>
<svg viewBox="-2 -2 1004 983">
<g fill="hsl(200, 50%, 70%)" stroke="hsl(200, 50%, 50%)" stroke-width="2">
<rect x="50" y="0" height="180" width="400"/>
<rect x="0" y="200" height="180" width="400"/>
<rect x="100" y="400" height="180" width="400"/>
<rect x="50" y="600" height="180" width="300"/>
<rect x="150" y="800" height="180" width="300"/>
</g>
<rect fill="none" stroke="black" stroke-width="5"
x="50" y="-5" width="400" height="1010"/>
<g font-size="40" font-family="sans-serif" transform="translate(550, 0)">
<text y="150">Regular</text>
<text y="350">Nearsighted</text>
<text y="550">Farsighted</text>
<text y="750">Presbyopia - near</text>
<text y="950">Presbyopia - far</text>
</g>
</svg>
<figcaption>My mental model of focal range</figcaption>
</figure>
<p>
If you are nearsighted and get laser surgery, you'll move into the Regular range, but as you get older, you'll move into Presbyopia-far. This will mean you will need reading glasses. If you are nearsighted and didn't get laser surgery, you'll move into Presbyopia-near. This will mean you won't need reading glasses, but you'll need to take your glasses off to read things. In my case, <strong>computer use</strong> is in-between. It's not great with my regular glasses, but it's also not great when I take glasses off. I ended up getting in-between prescription glasses that are sharp at medium distances.
</p>
<h3>Eyeglass materials</h3>
<p>
I chose to wear glasses instead of contacts or getting laser surgery. I collected some information about different lens materials.
</p>
<ul class="org-ul">
<li><a href="http://www.allaboutvision.com/lenses/how-to-choose.htm">http://www.allaboutvision.com/lenses/how-to-choose.htm</a> - table of properties</li>
<li><a href="https://web.archive.org/web/20090815102701/http://www.hbutz.com:80/wwwboard/messages/201.html">https://web.archive.org/web/20090815102701/http://www.hbutz.com:80/wwwboard/messages/201.html</a> - lots of ranting, but there's a data table near the end</li>
<li><a href="http://www.eyecarebusiness.com/articleviewer.aspx?articleID=107335">http://www.eyecarebusiness.com/articleviewer.aspx?articleID=107335</a> also has a table</li>
<li><a href="https://www.eyecarebusiness.com/issues/2012/august-2012/a-look-at-lens-materials">https://www.eyecarebusiness.com/issues/2012/august-2012/a-look-at-lens-materials</a></li>
<li><a href="https://en.wikipedia.org/wiki/Corrective_lens#Ophthalmic_material_property_tables">https://en.wikipedia.org/wiki/Corrective_lens#Ophthalmic_material_property_tables</a> has a table</li>
<li><a href="https://web.archive.org/web/20160322110111/http://www.opticampus.com/tools/materials.php">https://web.archive.org/web/20160322110111/http://www.opticampus.com/tools/materials.php</a> had a table</li>
<li><a href="http://64.50.176.246/tools/materials.php">http://64.50.176.246/tools/materials.php</a></li>
<li><a href="http://ophthalmiclenses.blogspot.com/2011/07/lens-material-reference-chart.html">http://ophthalmiclenses.blogspot.com/2011/07/lens-material-reference-chart.html</a></li>
</ul>
<p>
nd, ne = refractive index
cvf = curve factor, lower is thinner
density = heaviness, lower is lighter
uv = wavelength, higher cuts out more uv I think
abbe = chromatic abberation, higher is better
r% = reflection, lower is better, higher needs anti-reflective coating, factor of 2 depending on how reported
</p>
<p>
I merged the tables from the sources above into:
</p>
<table class="standard">
<colgroup>
<col class="text-left" />
<col class="text-right" />
<col class="text-right" />
<col class="text-right" />
<col class="text-right" />
<col class="text-right" />
<col class="text-right" />
<col class="text-right" />
</colgroup>
<thead>
<tr>
<th scope="col" class="text-left"> </th>
<th scope="col" class="text-right">nd</th>
<th scope="col" class="text-right">ne</th>
<th scope="col" class="text-right">CVF</th>
<th scope="col" class="text-right">DENSITY</th>
<th scope="col" class="text-right">UV</th>
<th scope="col" class="text-right">ABBE</th>
<th scope="col" class="text-right">R (%)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left">Glasses</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">White Crown</td>
<td class="text-right">1.523</td>
<td class="text-right">1.525</td>
<td class="text-right">1.0</td>
<td class="text-right">2.5</td>
<td class="text-right">320</td>
<td class="text-right">59</td>
<td class="text-right">4–8</td>
</tr>
<tr>
<td class="text-left">Light Flint</td>
<td class="text-right">1.600</td>
<td class="text-right">1.604</td>
<td class="text-right">0.87</td>
<td class="text-right">2.6</td>
<td class="text-right">334</td>
<td class="text-right">42</td>
<td class="text-right">5.3</td>
</tr>
<tr>
<td class="text-left">1.7</td>
<td class="text-right">1.700</td>
<td class="text-right">1.705</td>
<td class="text-right">0.75</td>
<td class="text-right">3.2</td>
<td class="text-right">340</td>
<td class="text-right">35</td>
<td class="text-right">6.7</td>
</tr>
<tr>
<td class="text-left"> </td>
<td class="text-right">1.701</td>
<td class="text-right">1.706</td>
<td class="text-right">0.75</td>
<td class="text-right">3.2</td>
<td class="text-right">320</td>
<td class="text-right">42</td>
<td class="text-right">6.7</td>
</tr>
<tr>
<td class="text-left">1.8</td>
<td class="text-right">1.802</td>
<td class="text-right">1.807</td>
<td class="text-right">0.65</td>
<td class="text-right">3.7</td>
<td class="text-right">332</td>
<td class="text-right">35</td>
<td class="text-right">8.2</td>
</tr>
<tr>
<td class="text-left"> </td>
<td class="text-right">1.830</td>
<td class="text-right">1.838</td>
<td class="text-right">0.63</td>
<td class="text-right">3.6</td>
<td class="text-right">340</td>
<td class="text-right">32</td>
<td class="text-right">8.6</td>
</tr>
<tr>
<td class="text-left">1.9</td>
<td class="text-right">1.885</td>
<td class="text-right">1.893</td>
<td class="text-right">0.59</td>
<td class="text-right">4.0</td>
<td class="text-right">340</td>
<td class="text-right">31</td>
<td class="text-right">9.4</td>
</tr>
</tbody>
<tbody>
<tr>
<td class="text-left">Plastics</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">CR-39</td>
<td class="text-right">1.498</td>
<td class="text-right">1.500</td>
<td class="text-right">1.0</td>
<td class="text-right">1.32</td>
<td class="text-right">355</td>
<td class="text-right">58</td>
<td class="text-right">4.0</td>
</tr>
<tr>
<td class="text-left">Transitions CR-607</td>
<td class="text-right">1.497</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.27</td>
<td class="text-right"> </td>
<td class="text-right">56</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">PPG Trivex®</td>
<td class="text-right">1.532</td>
<td class="text-right">1.535</td>
<td class="text-right">0.94</td>
<td class="text-right">1.11</td>
<td class="text-right">380</td>
<td class="text-right">44–46</td>
<td class="text-right">4.4</td>
</tr>
<tr>
<td class="text-left">Conant Hi-Vex</td>
<td class="text-right">1.53</td>
<td class="text-right">1.560</td>
<td class="text-right"> </td>
<td class="text-right">1.25</td>
<td class="text-right"> </td>
<td class="text-right">46</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Sola Spectralite</td>
<td class="text-right">1.537</td>
<td class="text-right">1.540</td>
<td class="text-right">0.89</td>
<td class="text-right">1.21</td>
<td class="text-right">370</td>
<td class="text-right">47</td>
<td class="text-right">4.8</td>
</tr>
<tr>
<td class="text-left">X-Cel High-X</td>
<td class="text-right">1.554</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.20</td>
<td class="text-right"> </td>
<td class="text-right">38</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Essilor Ormex</td>
<td class="text-right">1.558</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.23</td>
<td class="text-right"> </td>
<td class="text-right">37</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Nova-Quatrex</td>
<td class="text-right">1.58</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.22</td>
<td class="text-right"> </td>
<td class="text-right">48</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">AO Alphalite</td>
<td class="text-right">1.582</td>
<td class="text-right">1.585</td>
<td class="text-right">0.90</td>
<td class="text-right">1.3</td>
<td class="text-right">380</td>
<td class="text-right">34</td>
<td class="text-right">5.1</td>
</tr>
<tr>
<td class="text-left">Polycarbonate</td>
<td class="text-right">1.586</td>
<td class="text-right">1.589</td>
<td class="text-right">0.86</td>
<td class="text-right">1.21</td>
<td class="text-right">385</td>
<td class="text-right">30</td>
<td class="text-right">5.2</td>
</tr>
<tr>
<td class="text-left">Hoya Eyas</td>
<td class="text-right">1.600</td>
<td class="text-right">1.603</td>
<td class="text-right">0.83</td>
<td class="text-right">1.3</td>
<td class="text-right">380</td>
<td class="text-right">42</td>
<td class="text-right">5.3</td>
</tr>
<tr>
<td class="text-left">Tribrid</td>
<td class="text-right">1.60</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.21</td>
<td class="text-right"> </td>
<td class="text-right">41</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Sola Finalite</td>
<td class="text-right">1.60</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.22</td>
<td class="text-right"> </td>
<td class="text-right">42</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">MR-6</td>
<td class="text-right">1.595</td>
<td class="text-right">1.600</td>
<td class="text-right"> </td>
<td class="text-right">1.34</td>
<td class="text-right"> </td>
<td class="text-right">36</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">MR-8</td>
<td class="text-right">1.598</td>
<td class="text-right">1.600</td>
<td class="text-right"> </td>
<td class="text-right">1.3</td>
<td class="text-right">400</td>
<td class="text-right">41</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">MR-7</td>
<td class="text-right">1.658</td>
<td class="text-right">1.67</td>
<td class="text-right"> </td>
<td class="text-right">1.35</td>
<td class="text-right"> </td>
<td class="text-right">31</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">MR-10</td>
<td class="text-right">1.661</td>
<td class="text-right">1.67</td>
<td class="text-right"> </td>
<td class="text-right">1.37</td>
<td class="text-right"> </td>
<td class="text-right">31</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Polyurethanes</td>
<td class="text-right">1.600</td>
<td class="text-right">1.603</td>
<td class="text-right">0.83</td>
<td class="text-right">1.3</td>
<td class="text-right">380</td>
<td class="text-right">36</td>
<td class="text-right">5.3</td>
</tr>
<tr>
<td class="text-left"> </td>
<td class="text-right">1.609</td>
<td class="text-right">1.612</td>
<td class="text-right">0.82</td>
<td class="text-right">1.4</td>
<td class="text-right">380</td>
<td class="text-right">32</td>
<td class="text-right">5.4</td>
</tr>
<tr>
<td class="text-left"> </td>
<td class="text-right">1.660</td>
<td class="text-right">1.664</td>
<td class="text-right">0.75</td>
<td class="text-right">1.4</td>
<td class="text-right">375</td>
<td class="text-right">32</td>
<td class="text-right">6.2</td>
</tr>
<tr>
<td class="text-left">Stylis</td>
<td class="text-right">1.670</td>
<td class="text-right">1.674</td>
<td class="text-right">0.74</td>
<td class="text-right">1.4</td>
<td class="text-right">375</td>
<td class="text-right">32</td>
<td class="text-right">6.3</td>
</tr>
<tr>
<td class="text-left">Hoya EYRY</td>
<td class="text-right">1.700</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.41</td>
<td class="text-right"> </td>
<td class="text-right">36</td>
<td class="text-right"> </td>
</tr>
<tr>
<td class="text-left">Hoya Tesalid</td>
<td class="text-right">1.710</td>
<td class="text-right">1.715</td>
<td class="text-right">0.70</td>
<td class="text-right">1.4</td>
<td class="text-right">380</td>
<td class="text-right">32</td>
<td class="text-right">6.9</td>
</tr>
<tr>
<td class="text-left">Nikon</td>
<td class="text-right">1.740</td>
<td class="text-right">1.746</td>
<td class="text-right">0.67</td>
<td class="text-right">1.4</td>
<td class="text-right">380</td>
<td class="text-right">32</td>
<td class="text-right">7.3</td>
</tr>
<tr>
<td class="text-left">MR-174</td>
<td class="text-right">1.74</td>
<td class="text-right"> </td>
<td class="text-right"> </td>
<td class="text-right">1.47</td>
<td class="text-right"> </td>
<td class="text-right">32</td>
<td class="text-right"> </td>
</tr>
</tbody>
</table>
<p>
Other notes:
</p>
<ul class="org-ul">
<li>Trivex impact resistant, lighter but thicker so ends up being same weight as higher index, better abbe than most materials, very good uv blocking (don't need uv coating), <s>scratches easily</s></li>
<li>Seems to be some tradeoff between lightness and thinness</li>
<li><a href="https://www.reddit.com/r/AskReddit/comments/4v3ts4/what_was_your_why_didnt_i_start_doing_this_sooner/d5vncsk/?context=1">This thread</a> says polycarbonate is the standard but CR-39 (thicker and cheaper) and high index plastic (thinner but expensive) don't get scratches as much as the middle options</li>
<li>High density leads to more reflectance</li>
<li>Of these, <strong>Trivex</strong> and <strong>MR-8</strong> seem most interesting, best Abbe number</li>
<li><a href="http://scottlburson2.blogspot.com/2016/01/lcd-backlights-and-eyeglass-lenses.html">Blog post</a> explaining why LED backlit monitors have worse chromatic aberration</li>
<li><a href="http://www.2020mag.com/l-and-t/41604/">this page</a> claims Trivex has minimal "material stress" which affects overall clarity</li>
<li><a href="http://ophthalmiclenses.blogspot.com/2012/05/all-about-mr-seriesmr-8-mr-7-mr-10-mr.html">this page</a> claims MR-8 has minimal material stress</li>
<li>also "Trivex has high resistance to circumferential deformation."</li>
<li><a href="http://www.st-optics.com/product/high-index-1-60-mr-8-spheric-aspheric/">this page</a> says MR-8 easier to drill, for rimless</li>
<li>MR-8 has an abbe number of 41 compared to 32 for most high index</li>
<li>Trivex has abbe 45; glass has 59</li>
<li>Trivex has much lower density than other materials, and for -3 to +3 it'll be the lightest lens, and outside that range the thinness of high index wins over the lower density</li>
<li>Glass, cr-39, trivex are <em>ground</em> whereas polycarb and MR-8 are <em>molded</em>. Grounding produces sharper images. But MR-8 is glass-molded which is better than injection-molded.</li>
<li>Trivex is slightly yellowish</li>
<li>CR-39 can shrink over time, popping out of the frame</li>
</ul>
<p>
I tried to find MR-8 but couldn't, and chose Trivex instead. I have gotten some scratches on it, although I don't have a proper comparison with other lens materials. But otherwise it's been a good choice for me. [Update: 2024 - Zenni claims to have MR-8 as an option]
</p>
<p>
I am sensitive to chromatic abberation. I see the color fringes on my screen. Even if you don't see the fringes, it's making things blurrier. The <strong>Lateral Chromatic Abberation</strong> is the prescription value divided by Abbe number. For example, if your prescription was -5 and you were considering high index lenses with Abbe 30, the lateral chromatic abberation would be 0.16. <a href="http://www.2020mag.com/l-and-t/41604/">This page</a> has a table:
</p>
<table class="standard">
<colgroup>
<col class="text-left" />
<col class="text-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="text-left">Lateral CA</th>
<th scope="col" class="text-left">Visual Acuity</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left">0.05 ∆</td>
<td class="text-left">20/20</td>
</tr>
<tr>
<td class="text-left">0.10 ∆</td>
<td class="text-left">20/22</td>
</tr>
<tr>
<td class="text-left">0.15 ∆</td>
<td class="text-left">20/24</td>
</tr>
<tr>
<td class="text-left">0.20 ∆</td>
<td class="text-left">20/26</td>
</tr>
<tr>
<td class="text-left">0.25 ∆</td>
<td class="text-left">20/28</td>
</tr>
<tr>
<td class="text-left">0.30 ∆</td>
<td class="text-left">20/31</td>
</tr>
<tr>
<td class="text-left">0.35 ∆</td>
<td class="text-left">20/34</td>
</tr>
<tr>
<td class="text-left">0.40 ∆</td>
<td class="text-left">20/39</td>
</tr>
<tr>
<td class="text-left">0.45 ∆</td>
<td class="text-left">20/44</td>
</tr>
<tr>
<td class="text-left">0.50 ∆</td>
<td class="text-left">20/51</td>
</tr>
<tr>
<td class="text-left">0.55 ∆</td>
<td class="text-left">20/60</td>
</tr>
<tr>
<td class="text-left">0.60 ∆</td>
<td class="text-left">20/75</td>
</tr>
</tbody>
</table>
<p>
If you instead went with Trivex, -5 divided by 44 for trivex is 0.11. On the table, that's the difference between 20/24 vision and 20/22 vision. Not a big difference but it is a reminder that <strong>lens material affects how sharp you see</strong>. Thinner isn't necessarily better!
</p>
<h3>Other</h3>
<ul class="org-ul">
<li><a href="http://www.2020mag.com/story/12334/">This article</a> claims Abbe is overrated, and polycarbonate <strong>aspheric</strong> lenses are better than cr-39 spherical lenses.</li>
<li><a href="http://www.2020mag.com/l-and-t/64819/">This article</a> explains <strong>base curve</strong> but I haven't read it. At the end it suggests Sola Enimga lenses may be amazing (and I found a forum post from someone who had them, said they were amazing) but Sola's no longer making them</li>
<li><a href="http://64.50.176.246/tools/thickness.php">This page</a> gives the lens thickness for different types of materials.</li>
<li><a href="https://www.2020mag.com/ce/double-asphericity-a-free-form-D5313">Free form lenses</a> sound interesting.</li>
<li><a href="http://www.daniellivingston.com/2012/06/measuring-your-own-pupillary-distance.html">Blue blocking</a> spectrum diagrams show which frequencies are blocked.</li>
</ul>
<p>
That's what I've collected so far. Any other resources I should know about?
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com2tag:blogger.com,1999:blog-5304409.post-77445373149346386992019-07-24T17:23:00.000-07:002019-07-24T17:27:31.746-07:00Emacs mode line simplified<p>
Back in 2017 I posted that <a href="https://amitp.blogspot.com/2017/01/emacs-spaceline-mode-line.html">I switched from my own custom Emacs modeline to Spaceline</a>. I liked having a simpler configuration with more features. Unfortunately I eventually realized that those features were slowing down my system. In particular, column number, which-function, and selection-info, and my custom unicode display had to be updated on every keystroke. I went back to the default mode line and used this trick to see when it was recalculated:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(defvar-local mode-line-eval-count 0 "Counting :eval")
<span class="comment">;;; put this in mode-line-format</span>
(add-to-list
'mode-line-format
'(:eval (progn
(setq mode-line-eval-count (+ 1 mode-line-eval-count))
(format "%+4d " mode-line-eval-count))))
</pre>
</div>
<p>
Every recalculation, the counter increases. By experimenting with the default mode line, I found that having <kbd>%c</kbd> in the mode line (column number) causes it to redisplay (almost) every keystroke, and <kbd>%l</kbd> (line number) causes it to redisplay when changing lines. I also realized during this experimentation that Emacs <em>felt</em> faster with the default mode line than with Spaceline.
</p>
<p>
I decided to switch from Spaceline to the default mode line, much closer to <a href="http://amitp.blogspot.com/2011/08/emacs-custom-mode-line.html">my setup before 2017</a>, but simpler, more modular, and matching <a href="https://amitp.blogspot.com/2018/10/emacs-prettier-tabbar.html">my tabbar</a>. It feels nice and it looks good. I thought I would miss a few of the fancy features from Spaceline, but I didn't miss them as much as I thought I would. Features I use:
</p>
<ul class="org-ul">
<li>Read-only and modified status show a bright color on the left.</li>
<li>Project directory and filename are in separate colors.</li>
<li>The color theme depends on project (red for work, blue for personal, purple for configuration).</li>
<li>Week number ties into my task tracking system.</li>
<li>Line number uses Emacs 26's <code>line-numbers-mode</code> instead of the mode line.</li>
</ul>
<figure>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4BGSSlMyxVKledy1jwQbd5DrrsOpTWcr9-fSMbws5Y8OWegi_Gn6sis4Zqk2nkuFzy0nd0zOGrP8KQYdrPuQZZ0aENmajaQZwHwys3grweMXJ5x3ZqCR6f1nrLY6b-GveSQ4l/s1600/Screen+Shot+2019-07-20+at+11.59.44.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4BGSSlMyxVKledy1jwQbd5DrrsOpTWcr9-fSMbws5Y8OWegi_Gn6sis4Zqk2nkuFzy0nd0zOGrP8KQYdrPuQZZ0aENmajaQZwHwys3grweMXJ5x3ZqCR6f1nrLY6b-GveSQ4l/s1600/Screen+Shot+2019-07-20+at+11.59.44.png" data-original-width="1514" data-original-height="962" /></a>
<figcaption>Screenshot of Emacs tabbar, line-numbers-mode, and mode-line</figcaption>
</figure>
<p>
I've put a simplified version of the code <a href="https://gist.github.com/redblobgames/5d9cf891120028440a4bdb429f101de6">in a gist</a>.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com2tag:blogger.com,1999:blog-5304409.post-13180665453475977792019-04-16T10:01:00.000-07:002019-04-16T10:01:02.769-07:00Fractal islands in the Pacific<p>
I'm not a big fan of the Pacific Ocean. There. I said it. I like water/land interfaces. Coasts, rivers, lakeshores, beaches, coral reefs, tide pools. The Pacific Ocean has too few of these. So … let's fix it. Here's an idea I had from around 2003 but never blogged about:
</p>
<figure>
<img src="https://www.redblobgames.com/x/screenshots/sift-science-plan-cropped.jpg" alt="Drawing of earth with volcanic islands added"/>
<figcaption>I couldn't find a whiteboard drawing from 2003 but I have this newer one</figcaption>
</figure>
<a name='more'></a>
<p>
The Hawaiian islands are great. Why not make more of them? Let's drill into the mantle and bring up more magma. Use this magma to form fractally-shaped islands throughout the Pacific Ocean. Dubai has tried this with sand islands on a small scale but they're doing it by the coast; I think we should do it in open ocean.
</p>
<ul class="org-ul">
<li>This creates lots of <em>coastlines</em>. Coastlines are good for life: more tide pools, more coral reefs. Coastlines are enjoyable for people: more beaches.</li>
<li>Bringing up magma has potential for geothermal energy. We'll use this for desalination for drinking water and hydroponic gardens.</li>
</ul>
<p>
The Pacific is so vast that there's space for <em>everyone on earth</em> to live near the beach. We can then move most humans off of the other continents and reclaim them for nature, biodiversity, and sightseeing.
</p>
<p>
I don't think it's feasible any time soon, but maybe in a few centuries…
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0tag:blogger.com,1999:blog-5304409.post-4323769038335066722019-04-10T16:32:00.001-07:002019-04-10T16:32:24.130-07:00iTunes Sync Error -256<p>
This was a mystery.
</p>
<p>
I had been messing with my photo sync settings in iTunes, so that I could get more photos onto my iPhone. I started getting this iTunes sync error, -256. I googled for this but naturally Google ignored "256", as it seems to enjoy ignoring the most important words in my queries. I couldn't find an answer, and I had no luck deleting and resyncing photos. I decided I should wipe the phone and restore from backup at some point, but "not today".
</p>
<p>
A few weeks later (today) I discovered the real culprit. At some point in the past few months I had accidentally deleted podcast files in iTunes. I had restored the iTunes catalog file, and I had restored the files themselves from Trash. Or so I thought. I discovered today that I hadn't gotten them all. Once I fixed that (by deleting in iTunes and telling it to download them again), the photo sync worked again!
</p>
<p>
Grr1: iTunes does too many things, and it's hard to diagnose errors. Grr2: "error -256" is unhelpful. If it told me what it was doing at the time, it would've helped me realize it was podcasts and not photos that were the problem. Grr3: iTunes catalog and the files on disk can get out of sync; this is fragile.
</p>
<p>
I'm writing this blog post so that if anyone else has error -256, and convinces Google not to ignore that term, they might find a solution here.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com1tag:blogger.com,1999:blog-5304409.post-25965490900561037112019-04-10T11:45:00.004-07:002019-04-10T11:57:06.355-07:00Heat needed to melt ice<p>
I knew that melting ice takes heat, but didn't have a good sense for how much. I decided to calculate it.
</p>
<ol class="org-ol">
<li><em>Specific heat</em> tells you how much heat it takes to increase temperature. For water, it's around 4.2 joules per gram of water to raise the temperature by +1°C.</li>
<li><em>Latent heat</em> (of fusion) tells you how much heat it takes to turn solid into liquid, while <em>not</em> changing temperature. For ice→water, it's 334 joules per gram of water.</li>
</ol>
<p>
So we have two different processes: water to hotter water, and ice to water. How do they compare? Let's divide 334 J/g/°C ÷ 4.2 J/g = 79.5 °C.
</p>
<p>
That means the same amount of heat can do either:
</p>
<ol class="org-ol">
<li>Melt ice.</li>
<li>Raise water temperature by 79.5°C (143°F).</li>
</ol>
<p>
<strong>Yow!</strong>
</p>
<p>
That's much higher than I expected. Did I do the calculation wrong? I checked <a href="https://en.wikipedia.org/wiki/Heat_capacity#Table_of_specific_heat_capacities">specific heat</a> and <a href="https://en.wikipedia.org/wiki/Latent_heat#Table_of_specific_latent_heats">latent heat</a> again, but I can't see anything wrong with the calculation.
</p>
<p>
Now imagine what happens with climate change. If you add heat to a system, and there's ice around, it will melt the ice. But if there's no ice around, that <em>same amount of heat</em> will increase the temperature by 79.5°C (143°F). eeek!!
</p>
<p>
(please tell me I did the calculation wrong, because those numbers are scary)
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com3tag:blogger.com,1999:blog-5304409.post-69999715376130090342019-02-12T09:54:00.001-08:002019-03-01T09:48:41.017-08:00Emacs Org mode and KaTeX<p>
Emacs Org mode can handle LaTeX math, and exports it to HTML using MathJax. On my pages I have been using KaTeX instead of MathJax. It loads faster but doesn't support as many features. Org mode doesn't have direct support for KaTeX but for the simple things I do on my pages, I can redirect MathJax to KaTeX using <a href="https://katex.org/docs/autorender.html">KaTeX autorender</a>:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp" style="white-space: pre-wrap"><span class="paren">(</span><span class="keyword">setq</span> org-html-mathjax-template
<span class="string">"<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.css\" integrity=\"sha384-9eLZqc9ds8eNjO3TmqPeYcDj8n+Qfa4nuSiGYa6DjLNcv9BtN69ZIulL9+8CqC9Y\" crossorigin=\"anonymous\"/></span>
<span class="string"><script defer=\"defer\" src=\"https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.js\" integrity=\"sha384-K3vbOmF2BtaVai+Qk37uypf7VrgBubhQreNQe9aGsz9lB63dIFiQVlJbr92dw2Lx\" crossorigin=\"anonymous\"></script></span>
<span class="string"><script defer=\"defer\" src=\"https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/contrib/auto-render.min.js\" integrity=\"sha384-kmZOZB5ObwgQnS/DuDg6TScgOiWWBiVt0plIRkZCmE6rDZGrEOQeHM5PcHi+nyqe\" crossorigin=\"anonymous\" onload=\"renderMathInElement</span><span class="string"><span class="paren">(</span></span><span class="string">document.body</span><span class="string"><span class="paren">)</span></span><span class="string">;\"></script>"</span><span class="paren">)</span>
</pre>
</div>
<p>
(it looks ugly but it's straight from the KaTeX autorender page, but with quotes backslashed)
</p>
<p>
This seems to work on the small tests I've done so far.
</p>
Amithttp://www.blogger.com/profile/12159325271882018300noreply@blogger.com0