<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Power Overwhelming - Hacking</title><link href="https://toa.evanchen.cc/" rel="alternate"/><link href="https://toa.evanchen.cc/feeds/hacking.atom.xml" rel="self"/><id>https://toa.evanchen.cc/</id><updated>2024-10-31T13:37:00-04:00</updated><subtitle>The blog of Evan Chen</subtitle><entry><title>Hangul spellcheck for Vim</title><link href="https://toa.evanchen.cc/hangul-spellcheck/" rel="alternate"/><published>2024-10-31T13:37:00-04:00</published><updated>2024-10-31T13:37:00-04:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2024-10-31:/hangul-spellcheck/</id><summary type="html">&lt;p&gt;&lt;em&gt;There&amp;rsquo;s got to be a better way to do this. Someone please enlighten me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Modern Korean is written in 한글 (Hangul), which uses a syllabic alphabet. It
includes spaces between words, unlike Chinese or Japanese, which means that it&amp;rsquo;s
possible to have meaningful spellchecking.&lt;/p&gt;
&lt;p&gt;So of course one day I decided I wanted to configure Vim to support
spellchecking Hangul. Unfortunately, there&amp;rsquo;s no file &lt;code&gt;ko.utf-8.spl&lt;/code&gt; at
&lt;a href="http://ftp.vim.org/vim/runtime/spell/"&gt;ftp.vim.org&lt;/a&gt;, and in a cursory search I
couldn&amp;rsquo;t find an.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code&gt;hunspell&lt;/code&gt; tool does
&lt;a href="https://github.com/spellcheck-ko/hunspell-dict-ko"&gt;have a Korean dictionary&lt;/a&gt;,
and there&amp;rsquo;s a
&lt;a href="https://aur.archlinux.org/packages/hunspell-ko"&gt;PKGFILE provided for ARCH&lt;/a&gt;,
so by running &lt;code&gt;pikaur -S hunspell-ko&lt;/code&gt; I was able to obtain the files&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/usr/share/hunspell/ko_KR.aff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/share/hunspell/ko_KR.dic&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In theory, if you then run the Vim command&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:mkspell /tmp/ko /usr/share/hunspell/ko_KR&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;then Vim would create the file …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;There&amp;rsquo;s got to be a better way to do this. Someone please enlighten me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Modern Korean is written in 한글 (Hangul), which uses a syllabic alphabet. It
includes spaces between words, unlike Chinese or Japanese, which means that it&amp;rsquo;s
possible to have meaningful spellchecking.&lt;/p&gt;
&lt;p&gt;So of course one day I decided I wanted to configure Vim to support
spellchecking Hangul. Unfortunately, there&amp;rsquo;s no file &lt;code&gt;ko.utf-8.spl&lt;/code&gt; at
&lt;a href="http://ftp.vim.org/vim/runtime/spell/"&gt;ftp.vim.org&lt;/a&gt;, and in a cursory search I
couldn&amp;rsquo;t find an.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code&gt;hunspell&lt;/code&gt; tool does
&lt;a href="https://github.com/spellcheck-ko/hunspell-dict-ko"&gt;have a Korean dictionary&lt;/a&gt;,
and there&amp;rsquo;s a
&lt;a href="https://aur.archlinux.org/packages/hunspell-ko"&gt;PKGFILE provided for ARCH&lt;/a&gt;,
so by running &lt;code&gt;pikaur -S hunspell-ko&lt;/code&gt; I was able to obtain the files&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/usr/share/hunspell/ko_KR.aff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/share/hunspell/ko_KR.dic&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In theory, if you then run the Vim command&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:mkspell /tmp/ko /usr/share/hunspell/ko_KR&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;then Vim would create the file &lt;code&gt;/tmp/ko.utf-8.spl&lt;/code&gt;, which you can then place
into &lt;code&gt;~/.vim/spell&lt;/code&gt; and get spellchecking.&lt;/p&gt;
&lt;p&gt;Unfortunately, theory is not the same as practice, by which I mean that
the process threw a bunch of warnings and the resulting file
it totally didn&amp;rsquo;t work &amp;mdash; every word was being marked as misspelled.&lt;/p&gt;
&lt;p&gt;So I spent a bit of time trying to debug it, and being like,
&amp;ldquo;how come these two words that look exactly the same are showing up as different?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;It turns out there&amp;rsquo;s actually (at least) two different ways to encode of Hangul
into Unicode, namely
&lt;a href="https://w.wiki/BCBd"&gt;&lt;em&gt;NFD&lt;/em&gt; (decomposed) and &lt;em&gt;NFC&lt;/em&gt; (composed)&lt;/a&gt;.
The input program I&amp;rsquo;m using produces NFC glyphs, where each Hangul syllable block is
a single code point; but the spellcheck file
&lt;code&gt;/usr/share/hunspell/ko_KR.dic&lt;/code&gt; instead has entries in NFD,
where each &lt;em&gt;atom&lt;/em&gt; within the syllable block is a character.&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://toa.evanchen.cc/hangul-spellcheck/images/ko-nfd-nfc-diff.png" rel="noopener" target="_blank"&gt;&lt;img alt="That diff is spooky." src="https://toa.evanchen.cc/hangul-spellcheck/images/ko-nfd-nfc-diff.png"&gt;&lt;/a&gt;&lt;figcaption&gt;That diff is spooky.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Actually, NFD makes sense for a spellchecker,
because you&amp;rsquo;d want something like 한 (Romanized &lt;code&gt;han&lt;/code&gt;) and 항 (Romanized &lt;code&gt;hang&lt;/code&gt;)
to have an edit distance of 1/3 rather than 1.
Then, in order to deal with NFC inputs, the &lt;code&gt;/usr/share/hunspell/ko_KR.aff&lt;/code&gt;
provides many
&lt;a href="https://manpages.ubuntu.com/manpages/trusty/en/man4/hunspell.4.html"&gt;&lt;code&gt;ICONV&lt;/code&gt; and &lt;code&gt;OCONV&lt;/code&gt; directives&lt;/a&gt; that tell
the
spellchecker how to convert from NFC input into NFD and then back.
So &lt;code&gt;hunspell&lt;/code&gt; works well.&lt;/p&gt;
&lt;p&gt;The problem is that Vim&amp;rsquo;s &lt;code&gt;:mkspell&lt;/code&gt; command apparently doesn&amp;rsquo;t actually support
&lt;code&gt;ICONV&lt;/code&gt; and &lt;code&gt;OCONV&lt;/code&gt;.
In order to force it to work, I ended up just writing a Python script
that stripped all the unsupported commands from &lt;code&gt;ko_KR.aff&lt;/code&gt;,
and converted &lt;code&gt;ko_KR.dic&lt;/code&gt; into NFC format.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;unicodedata&lt;/span&gt;

&lt;span class="n"&gt;UNSUPPORTED_WORDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;LANG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;WORDCHARS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;ICONV&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;OCONV&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;AF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;MAXCPDSUGS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;MAXNGRAMSUGS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;MAXDIFF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;COMPOUNDMORESUFFIXES&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Make the aff file but take out things unsupported by Vim&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/hunspell/ko_KR.aff&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;infile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;ko_KR.aff&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;infile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;UNSUPPORTED_WORDS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Make the dic file but re-normalize it to NFC&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/hunspell/ko_KR.dic&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;infile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;infile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unicodedata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;NFC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ko_KR.dic&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After storing these mutilated files into
&lt;code&gt;~/dotfiles/vim/spell/korean-setup/ko_KR&lt;/code&gt;
and running
&lt;code&gt;:mkspell /tmp/ko ~/dotfiles/vim/spell/korean-setup/ko_KR&lt;/code&gt;,
the outputted &lt;code&gt;/tmp/ko.utf-8.spl&lt;/code&gt; can now check for spelling errors
(at least if the words are in NFC format).&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://toa.evanchen.cc/hangul-spellcheck/images/ko-spellcheck-demo.png" rel="noopener" target="_blank"&gt;&lt;img alt="It's working. Sorta." src="https://toa.evanchen.cc/hangul-spellcheck/images/ko-spellcheck-demo.png"&gt;&lt;/a&gt;&lt;figcaption&gt;It&amp;rsquo;s working. Sorta.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A summary of this process is posted on my
&lt;a href="https://github.com/vEnhance/dotfiles/tree/main/vim/spell/korean-setup"&gt;dotfiles GitHub&lt;/a&gt;.
To actually use this, just
&lt;a href="https://github.com/vEnhance/dotfiles/tree/main/vim/spell"&gt;download the &lt;code&gt;ko.utf-8.spl&lt;/code&gt; file directly&lt;/a&gt;,
no need to re-follow the steps.&lt;/p&gt;
&lt;p&gt;The issue is that because the spellcheck dictionary is using NFC now,
while it can highlight the red words, the &amp;ldquo;suggestions&amp;rdquo; provided
aren&amp;rsquo;t particularly good.
If you look at the suggestions for the spellcheck for the
typo&amp;rsquo;d word 항글, the top 10 are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; 1 &amp;quot;한글&amp;quot;
 2 &amp;quot;고글&amp;quot;
 3 &amp;quot;궁글&amp;quot;
 4 &amp;quot;담글&amp;quot;
 5 &amp;quot;답글&amp;quot;
 6 &amp;quot;댓글&amp;quot;
 7 &amp;quot;덧글&amp;quot;
 8 &amp;quot;동글&amp;quot;
 9 &amp;quot;둥글&amp;quot;
10 &amp;quot;빙글&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The problem is that because NFD encodes the characters by block,
any change to the entire first syllable cause an equally bad edit distance.
So while I&amp;rsquo;ve managed to get quick highlighting of mistakes,
the autocorrection of those mistakes isn&amp;rsquo;t really there.&lt;/p&gt;
&lt;p&gt;I feel like this whole process was a convoluted hack.
Is there a better way to do this?&lt;/p&gt;</content><category term="Hacking"/><category term="korean"/><category term="linux"/></entry><entry><title>Why Evan does not like JavaScript as a first language</title><link href="https://toa.evanchen.cc/javascript/" rel="alternate"/><published>2022-11-18T13:37:00-05:00</published><updated>2022-11-18T13:37:00-05:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2022-11-18:/javascript/</id><summary type="html">&lt;p&gt;Some people have asked me why I anti-recommend JavaScript for beginners
on my website FAQ.
This post will try to give a few reasons why.&lt;/p&gt;
&lt;p&gt;Some notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m referring to base JS. I like TypeScript a lot for example (it&amp;rsquo;s high on
  my tier list of programming languages for beginners).
  And I know about &lt;code&gt;eslint&lt;/code&gt;, but you asked me about recommendations for
  beginners, and I think beginners shouldn&amp;rsquo;t have to worry about setting up an
  IDE with strict linting until &lt;em&gt;after&lt;/em&gt; they can write a &lt;code&gt;for&lt;/code&gt; loop by
  themselves without screwing up.&lt;/li&gt;
&lt;li&gt;I have multi-file projects in mind. I don&amp;rsquo;t have a problem with using inline
  JavaScript for tiny 20-line snippets of code embedded in a webpage.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m an amateur programmer. Professional programming is a different ball game.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Weak typing&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m clumsy. I make many more mistakes than the average programmer.
The other day …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Some people have asked me why I anti-recommend JavaScript for beginners
on my website FAQ.
This post will try to give a few reasons why.&lt;/p&gt;
&lt;p&gt;Some notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m referring to base JS. I like TypeScript a lot for example (it&amp;rsquo;s high on
  my tier list of programming languages for beginners).
  And I know about &lt;code&gt;eslint&lt;/code&gt;, but you asked me about recommendations for
  beginners, and I think beginners shouldn&amp;rsquo;t have to worry about setting up an
  IDE with strict linting until &lt;em&gt;after&lt;/em&gt; they can write a &lt;code&gt;for&lt;/code&gt; loop by
  themselves without screwing up.&lt;/li&gt;
&lt;li&gt;I have multi-file projects in mind. I don&amp;rsquo;t have a problem with using inline
  JavaScript for tiny 20-line snippets of code embedded in a webpage.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m an amateur programmer. Professional programming is a different ball game.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Weak typing&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m clumsy. I make many more mistakes than the average programmer.
The other day I finally installed a Django-HTML linter in
&lt;a href="https://github.com/vEnhance/otis-web"&gt;OTIS-WEB&lt;/a&gt; and found out that the
&lt;a href="https://github.com/vEnhance/otis-web/commit/a347f306f6d4f3cebdda812fc3cecd1e18aa9c9e"&gt;majority of my templates had mismatched HTML tags I never noticed for
years&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If I write some nonsense code like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I would like the program to, you know, crash. It doesn&amp;rsquo;t.
It sets &lt;code&gt;y = undefined&lt;/code&gt;.
And then 100 lines later I have to figure out why some other function
didn&amp;rsquo;t do what it was supposed to, and trace back through the entire source.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s at a point where you can generate memes by just taking two different types
of objects and adding or subtracting them and then laughing at the result.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Welcome to Node.js v19.1.0.
Type &amp;quot;.help&amp;quot; for more information.
&amp;gt; &amp;#39;7&amp;#39; + 3
&amp;#39;73&amp;#39;
&amp;gt; &amp;#39;7&amp;#39; - 3
4
&amp;gt; &amp;#39;hi&amp;#39; + [&amp;#39;i&amp;#39;, &amp;#39;am&amp;#39;, &amp;#39;a&amp;#39;, &amp;#39;potato&amp;#39;]
&amp;#39;hii,am,a,potato&amp;#39;
&amp;gt; const x = 42;
undefined
&amp;gt; &amp;#39;1337&amp;#39; + x - x
133700
&amp;gt; &amp;#39;1337&amp;#39; - x + x
1337
&amp;gt; &amp;#39;wtf&amp;#39; - 2022 + &amp;#39;i?&amp;#39;
&amp;#39;NaNi?&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Like, at least in Python, you&amp;rsquo;ll get a &lt;code&gt;TypeError&lt;/code&gt; or &lt;code&gt;AttributeError&lt;/code&gt;
or something when you run the code (but not at &amp;ldquo;compile time&amp;rdquo;,
because scripting languages don&amp;rsquo;t have a &amp;ldquo;compile time&amp;rdquo;).
Python&amp;rsquo;s my native language, and it still annoyed me so much that I use both
&lt;code&gt;mypy&lt;/code&gt; and &lt;code&gt;pyright&lt;/code&gt; on all my Python code now to enforce what essentially
became Python with static types, despite Python&amp;rsquo;s type system being janky af.
You better believe I&amp;rsquo;m doing this with JavaScript too.&lt;/p&gt;
&lt;h2&gt;null, undefined, NaN&lt;/h2&gt;
&lt;p&gt;These keywords strike dread into my heart because I lack the professional
training to keep the differences straight in my head.&lt;/p&gt;
&lt;p&gt;Last I checked though:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Welcome to Node.js v19.1.0.
Type &amp;quot;.help&amp;quot; for more information.
&amp;gt; null === null
true
&amp;gt; undefined === undefined
true
&amp;gt; NaN === NaN
false
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Oh yeah, for those of you that don&amp;rsquo;t know, you always use &lt;code&gt;===&lt;/code&gt; and not &lt;code&gt;==&lt;/code&gt;
these days because the latter operator is a
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality"&gt;total minefield&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt; 0 == false
true
&amp;gt; 0 == null
false
&amp;gt; 0 == undefined
false
&amp;gt; 0 == !!null
true
&amp;gt; 0 == !!undefined
true
&amp;gt; [] == 0
true
&amp;gt; const a = new Number(42);
undefined
&amp;gt; const b = new Number(42);
undefined
&amp;gt; a == b
false
&amp;gt; a == 42 &amp;amp;&amp;amp; b == 42
true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well, &lt;code&gt;==&lt;/code&gt; is supposed to be symmetric at least. Except apparently in Internet
Explorer, where &lt;code&gt;window == document&lt;/code&gt; is true but &lt;code&gt;document == window&lt;/code&gt; is false,
in &lt;a href="https://stackoverflow.com/a/5669517/4826845"&gt;some versions anyway&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Variable scope&lt;/h2&gt;
&lt;p&gt;It used to be that you could forget a &lt;code&gt;var&lt;/code&gt; keyword and then suddenly your
variable became a global variable. These days we have &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; and we
just tell the beginners to always use one of these two and never use &lt;code&gt;var&lt;/code&gt; (or
worse no keyword at all) so I guess it&amp;rsquo;s not as bad as it used to be.&lt;/p&gt;
&lt;p&gt;Though of course &lt;a href="https://wtfjs.com/wtfs/2010-02-15-accidental-global"&gt;you can still find some contrived
examples&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Welcome to Node.js v19.1.0.
Type &amp;quot;.help&amp;quot; for more information.
&amp;gt; (function() { const x = y = 1; })();
undefined
&amp;gt; x
Uncaught ReferenceError: x is not defined
&amp;gt; y
1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(For those of you that don&amp;rsquo;t know, the whole &lt;code&gt;(function() {})()&lt;/code&gt; construction is
an actual JavaScript idiom that&amp;rsquo;s used to prevent exactly this situation.)&lt;/p&gt;
&lt;p&gt;And the &lt;code&gt;this&lt;/code&gt; keyword still strikes fear into my heart. I can&amp;rsquo;t understand it
for the life of me.&lt;/p&gt;
&lt;h2&gt;Modules and classes&lt;/h2&gt;
&lt;p&gt;The JavaScript base language used to have no module system.
Now we have CommonJS and ES modules instead.
Which I guess is fine, but it would have been nice to have these in the base
language, you know?
(I&amp;rsquo;m definitely not saying this because I spent an entire night fighting some
node dependency chain where one component used CommonJS, and the other used ES,
and they wouldn&amp;rsquo;t play along.)&lt;/p&gt;
&lt;p&gt;These days I think people just use &lt;code&gt;npm&lt;/code&gt; or something and be glad that with
Python I have standard library that won&amp;rsquo;t collapse one day because
&lt;a href="https://www.theregister.com/2016/03/23/npm_left_pad_chaos/"&gt;left-pad disappeared suddenly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, JavaScript uses a prototype-based object system that I never really
understood either, because it looks like the classes I&amp;rsquo;m used to, but isn&amp;rsquo;t. If
I was a professional programmer I&amp;rsquo;d probably take a few hours or days out of my
life to figure out what the heck was going on. I&amp;rsquo;m not, and whatever beginner is
reading my FAQ is &lt;em&gt;definitely&lt;/em&gt; not.&lt;/p&gt;
&lt;h2&gt;Easter eggs&lt;/h2&gt;
&lt;p&gt;Actually these might not be a downside 🙂. I like Easter eggs. Maybe not in
day-to-day code. But examples like this make for a good laugh, and they&amp;rsquo;re
harmless because if you actually run into them in real life you&amp;rsquo;re doing
something wrong anyway.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Welcome to Node.js v19.1.0.
Type &amp;quot;.help&amp;quot; for more information.
&amp;gt; null &amp;gt; 0
false
&amp;gt; null == 0
false
&amp;gt; null &amp;gt;= 0
true
&amp;gt; 100 &amp;lt;= 200 &amp;lt;= 300
true
&amp;gt; 300 &amp;gt;= 200 &amp;gt;= 100
false
&amp;gt; regex = /nani/g;
/nani/g
&amp;gt; regex.test(&amp;#39;nani?&amp;#39;);
true
&amp;gt; regex.test(&amp;#39;nani?&amp;#39;);
false
&amp;gt; [7, 12, 13].sort()
[ 12, 13, 7 ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See &lt;a href="https://wtfjs.com"&gt;wtfjs.com&lt;/a&gt; for more.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;JavaScript is the language that runs the web, so it&amp;rsquo;s kinda mandatory.
If you want client-side code to run everywhere, it needs to be in a browser, so
it has to be JavaScript.&lt;/p&gt;
&lt;p&gt;But I still think people should learn how to program first, and then learn
JavaScript, rather than the other way around.
Or, at least start with &lt;a href="https://github.com/jashkenas/coffeescript/wiki/list-of-languages-that-compile-to-js"&gt;one of the gazillion languages that transpiles to
JavaScript&lt;/a&gt;
so that you don&amp;rsquo;t have to fight language quirks and linters until after your
feet are at least moderately wet.&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>SysRq on Arch Linux Mac Mini</title><link href="https://toa.evanchen.cc/sysrq/" rel="alternate"/><published>2016-12-14T13:37:00-05:00</published><updated>2016-12-14T13:37:00-05:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2016-12-14:/sysrq/</id><summary type="html">&lt;p&gt;This post documents my adventures of getting the SysRQ key working on my Mac
Mini and Macbook (both running Arch Linux).
The suggestions of &lt;code&gt;loadkeys&lt;/code&gt; and &lt;code&gt;keyfuzz&lt;/code&gt; that are the first search entries don&amp;rsquo;t work for me,
so some more sophisticated black magic was necessary.&lt;/p&gt;
&lt;h2&gt;Remapping the Fn keys&lt;/h2&gt;
&lt;p&gt;This step is technically optional, but I did it because the function keys are a pain anyways.
Normally on Apple keyboards one needs to use the &lt;code&gt;Fn&lt;/code&gt; key to get the normal Fn
keys to behave as a &lt;code&gt;F&amp;lt;n&amp;gt;&lt;/code&gt; keystroke.
I prefer to reverse this behavior, so that the SysRq combinations is &lt;code&gt;Alt+F13+F&lt;/code&gt; rather than &lt;code&gt;Fn+Alt+F13+F&lt;/code&gt;,
say.&lt;/p&gt;
&lt;p&gt;For this, the advice on the &lt;a href="https://wiki.archlinux.org/index.php/Apple_Keyboard#Function_keys_do_not_work"&gt;Arch Wiki&lt;/a&gt; worked,
although it is not thorough on some points that I think should&amp;rsquo;ve been said.
On newer kernels, one does this by creating the file &lt;code&gt;/etc/modprobe.d …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This post documents my adventures of getting the SysRQ key working on my Mac
Mini and Macbook (both running Arch Linux).
The suggestions of &lt;code&gt;loadkeys&lt;/code&gt; and &lt;code&gt;keyfuzz&lt;/code&gt; that are the first search entries don&amp;rsquo;t work for me,
so some more sophisticated black magic was necessary.&lt;/p&gt;
&lt;h2&gt;Remapping the Fn keys&lt;/h2&gt;
&lt;p&gt;This step is technically optional, but I did it because the function keys are a pain anyways.
Normally on Apple keyboards one needs to use the &lt;code&gt;Fn&lt;/code&gt; key to get the normal Fn
keys to behave as a &lt;code&gt;F&amp;lt;n&amp;gt;&lt;/code&gt; keystroke.
I prefer to reverse this behavior, so that the SysRq combinations is &lt;code&gt;Alt+F13+F&lt;/code&gt; rather than &lt;code&gt;Fn+Alt+F13+F&lt;/code&gt;,
say.&lt;/p&gt;
&lt;p&gt;For this, the advice on the &lt;a href="https://wiki.archlinux.org/index.php/Apple_Keyboard#Function_keys_do_not_work"&gt;Arch Wiki&lt;/a&gt; worked,
although it is not thorough on some points that I think should&amp;rsquo;ve been said.
On newer kernels, one does this by creating the file &lt;code&gt;/etc/modprobe.d/hid_apple.conf&lt;/code&gt; and writing&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;options hid_apple fnmode=2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then I edited the file &lt;code&gt;/etc/mkinitcpio.conf&lt;/code&gt; to include the new file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;...
BINARIES=&amp;quot;&amp;quot;

&lt;span class="gh"&gt;#&lt;/span&gt; FILES
&lt;span class="gh"&gt;#&lt;/span&gt; This setting is similar to BINARIES above, however, files are added
&lt;span class="gh"&gt;#&lt;/span&gt; as-is and are not parsed in any way.  This is useful for config files.
FILES=&amp;quot;/etc/modprobe.d/hid_apple.conf&amp;quot;

&lt;span class="gh"&gt;#&lt;/span&gt; HOOKS
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, recompile the kernel for this change to take effect.
On Arch Linux one can just do this by issuing the command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will reinstall the entire kernel.&lt;/p&gt;
&lt;h2&gt;Obtaining the keystroke&lt;/h2&gt;
&lt;p&gt;Next, I needed to get the scancode of the key I wanted to turn into the SysRQ key.
For me attempting &lt;code&gt;showkey -s&lt;/code&gt; did not work so I instead had to use evtest,
as described in &lt;a href="https://wiki.archlinux.org/index.php/Map_scancodes_to_keycodes"&gt;this Arch Wiki&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;evtest
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;evtest
No&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;specified,&lt;span class="w"&gt; &lt;/span&gt;trying&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;/dev/input/event*
Available&lt;span class="w"&gt; &lt;/span&gt;devices:
/dev/input/event0:&lt;span class="w"&gt;  &lt;/span&gt;Logitech&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;Receiver
/dev/input/event1:&lt;span class="w"&gt;  &lt;/span&gt;Logitech&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;Receiver
/dev/input/event2:&lt;span class="w"&gt;  &lt;/span&gt;Apple,&lt;span class="w"&gt; &lt;/span&gt;Inc&lt;span class="w"&gt; &lt;/span&gt;Apple&lt;span class="w"&gt; &lt;/span&gt;Keyboard
/dev/input/event3:&lt;span class="w"&gt;  &lt;/span&gt;Apple,&lt;span class="w"&gt; &lt;/span&gt;Inc&lt;span class="w"&gt; &lt;/span&gt;Apple&lt;span class="w"&gt; &lt;/span&gt;Keyboard
/dev/input/event4:&lt;span class="w"&gt;  &lt;/span&gt;Apple&lt;span class="w"&gt; &lt;/span&gt;Computer,&lt;span class="w"&gt; &lt;/span&gt;Inc.&lt;span class="w"&gt; &lt;/span&gt;IR&lt;span class="w"&gt; &lt;/span&gt;Receiver
/dev/input/event5:&lt;span class="w"&gt;  &lt;/span&gt;HDA&lt;span class="w"&gt; &lt;/span&gt;NVidia&lt;span class="w"&gt; &lt;/span&gt;Headphone
/dev/input/event6:&lt;span class="w"&gt;  &lt;/span&gt;HDA&lt;span class="w"&gt; &lt;/span&gt;NVidia&lt;span class="w"&gt; &lt;/span&gt;HDMI/DP,pcm&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
/dev/input/event7:&lt;span class="w"&gt;  &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Button
/dev/input/event8:&lt;span class="w"&gt;  &lt;/span&gt;Sleep&lt;span class="w"&gt; &lt;/span&gt;Button
/dev/input/event9:&lt;span class="w"&gt;  &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Button
/dev/input/event10:&lt;span class="w"&gt; &lt;/span&gt;Video&lt;span class="w"&gt; &lt;/span&gt;Bus
/dev/input/event11:&lt;span class="w"&gt; &lt;/span&gt;PC&lt;span class="w"&gt; &lt;/span&gt;Speaker
/dev/input/event12:&lt;span class="w"&gt; &lt;/span&gt;HDA&lt;span class="w"&gt; &lt;/span&gt;NVidia&lt;span class="w"&gt; &lt;/span&gt;HDMI/DP,pcm&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;
/dev/input/event13:&lt;span class="w"&gt; &lt;/span&gt;HDA&lt;span class="w"&gt; &lt;/span&gt;NVidia&lt;span class="w"&gt; &lt;/span&gt;HDMI/DP,pcm&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;
Select&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;event&lt;span class="w"&gt; &lt;/span&gt;number&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;-13&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
Input&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.0.1
Input&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;ID:&lt;span class="w"&gt; &lt;/span&gt;bus&lt;span class="w"&gt; &lt;/span&gt;0x3&lt;span class="w"&gt; &lt;/span&gt;vendor&lt;span class="w"&gt; &lt;/span&gt;0x5ac&lt;span class="w"&gt; &lt;/span&gt;product&lt;span class="w"&gt; &lt;/span&gt;0x220&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;0x111
Input&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;name:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Apple, Inc Apple Keyboard&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is on my Mac Mini; the list of devices looks different on my laptop.
After this pressing the desired key yields something which looked like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1456870457.844237&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--------------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYN_REPORT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;------------&lt;/span&gt;
&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1456870457.924097&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EV_MSC&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MSC_SCAN&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;70068&lt;/span&gt;
&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1456870457.924097&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EV_KEY&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;183&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KEY_F13&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the F13 key which I want to map into a SysRq &amp;mdash; the keycode 70068 above
(which is in fact a hex code) is the one I wanted.&lt;/p&gt;
&lt;h2&gt;Using udev&lt;/h2&gt;
&lt;p&gt;Now that I had the scancode, I cd&amp;rsquo;ed to &lt;code&gt;/etc/udev/hwdb.d&lt;/code&gt; and added a file
&lt;code&gt;90-keyboard-sysrq.hwdb&lt;/code&gt; with the content&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;evdev&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;b0003&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;KEYBOARD_KEY_70068&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sysrq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One then updates &lt;code&gt;hwdb.bin&lt;/code&gt; by running the command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;udevadm&lt;span class="w"&gt; &lt;/span&gt;hwdb&lt;span class="w"&gt; &lt;/span&gt;--update
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;udevadm&lt;span class="w"&gt; &lt;/span&gt;trigger
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The latter command makes the changes take effect immediately.
You should be able to test this by running &lt;code&gt;sudo evtest&lt;/code&gt; again;
&lt;code&gt;evtest&lt;/code&gt; should now report the new keycode (but the same scancode).&lt;/p&gt;
&lt;p&gt;One can test the SysRQ key by running Alt+SysRq+H,
and then checking the &lt;code&gt;dmesg&lt;/code&gt; output to see if anything happened:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;dmesg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;283&lt;/span&gt;.001240&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sysrq:&lt;span class="w"&gt; &lt;/span&gt;SysRq&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;HELP&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;loglevel&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;-9&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;reboot&lt;span class="o"&gt;(&lt;/span&gt;b&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;crash&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Enable SysRq&lt;/h2&gt;
&lt;p&gt;It remains to actually enable SysRQ,
according to the &lt;a href="https://www.kernel.org/doc/Documentation/sysrq.txt"&gt;bitmask described here&lt;/a&gt;.
My system default was apparently 16:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;kernel.sysrq
kernel.sysrq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For my purposes, I then edited &lt;code&gt;/etc/sysctl.d/99-sysctl.conf&lt;/code&gt; and added the line&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;kernel.sysrq=254
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This gave me everything except the nicing of real-time tasks.
Of course the choice of value here is just personal preference.&lt;/p&gt;
&lt;p&gt;Personally, my main use for this is killing Chromium,
which has a bad habit of freezing up my computer (especially if Firefox is open too).
I remedy the situation by repeatedly running Alt+SysRq+F to kill off the memory hogs.
If this doesn&amp;rsquo;t work, just Alt+SysRq+K kills off all the processes in the current TTY.&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>DNSCrypt Setup with PDNSD</title><link href="https://toa.evanchen.cc/dnscrypt/" rel="alternate"/><published>2016-11-10T13:37:00-05:00</published><updated>2016-11-10T13:37:00-05:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2016-11-10:/dnscrypt/</id><summary type="html">&lt;p&gt;Here are notes for setting up &lt;a href="https://dnscrypt.org/"&gt;DNSCrypt&lt;/a&gt; on Arch Linux,
using &lt;a href="https://wiki.archlinux.org/index.php/Pdnsd"&gt;pdnsd&lt;/a&gt; as a DNS cache,
assuming the use of &lt;a href="https://wiki.archlinux.org/index.php/NetworkManager"&gt;NetworkManager&lt;/a&gt;.
I needed it one day since the network I was using blocked traffic to external
DNS servers (parental controls),
and the DNS server provided had an outdated entry for &lt;a href="https://www.hmmt.co/"&gt;hmmt.co&lt;/a&gt;.
(My dad then pointed out to me I could have just hard-coded the necessary IP address in &lt;code&gt;/etc/hosts&lt;/code&gt;, oops.)&lt;/p&gt;
&lt;p&gt;For the whole process, useful commands to test with are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nslookup hmmt.co&lt;/code&gt; will tell you the IP used and the server from which it came.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dig www.hmmt.co&lt;/code&gt; gives much more detailed information to this effect. (From &lt;code&gt;bind-tools&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dig @127.0.0.1 www.hmmt.co&lt;/code&gt; lets you query a specific DNS server (in this case 127.0.0.1).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drill @127.0.0.1 www.hmmt.co&lt;/code&gt; behaves similarly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, &lt;code&gt;pacman -S pdnsd dnscrypt-proxy&lt;/code&gt; (with …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here are notes for setting up &lt;a href="https://dnscrypt.org/"&gt;DNSCrypt&lt;/a&gt; on Arch Linux,
using &lt;a href="https://wiki.archlinux.org/index.php/Pdnsd"&gt;pdnsd&lt;/a&gt; as a DNS cache,
assuming the use of &lt;a href="https://wiki.archlinux.org/index.php/NetworkManager"&gt;NetworkManager&lt;/a&gt;.
I needed it one day since the network I was using blocked traffic to external
DNS servers (parental controls),
and the DNS server provided had an outdated entry for &lt;a href="https://www.hmmt.co/"&gt;hmmt.co&lt;/a&gt;.
(My dad then pointed out to me I could have just hard-coded the necessary IP address in &lt;code&gt;/etc/hosts&lt;/code&gt;, oops.)&lt;/p&gt;
&lt;p&gt;For the whole process, useful commands to test with are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nslookup hmmt.co&lt;/code&gt; will tell you the IP used and the server from which it came.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dig www.hmmt.co&lt;/code&gt; gives much more detailed information to this effect. (From &lt;code&gt;bind-tools&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dig @127.0.0.1 www.hmmt.co&lt;/code&gt; lets you query a specific DNS server (in this case 127.0.0.1).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drill @127.0.0.1 www.hmmt.co&lt;/code&gt; behaves similarly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, &lt;code&gt;pacman -S pdnsd dnscrypt-proxy&lt;/code&gt; (with &lt;code&gt;sudo&lt;/code&gt; ostensibly, but I&amp;rsquo;ll leave that out here and henceforth).&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;systemctl edit dnscrypt-proxy.socket&lt;/code&gt; and fill in &lt;code&gt;override.conf&lt;/code&gt; with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Socket]&lt;/span&gt;
&lt;span class="na"&gt;ListenStream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="na"&gt;ListenDatagram&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="na"&gt;ListenStream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:40&lt;/span&gt;
&lt;span class="na"&gt;ListenDatagram&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:40&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Optionally, one can also specify which server which DNS serve to use with
&lt;code&gt;systemctl edit dnscrypt-proxy.service&lt;/code&gt;. For example for cs-uswest I write&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/dnscrypt-proxy&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="na"&gt;-R cs-uswest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The empty &lt;code&gt;ExecStart=&lt;/code&gt; is necessary,
since otherwise &lt;code&gt;systemctl&lt;/code&gt; will complain about multiple ExecStart commands.&lt;/p&gt;
&lt;p&gt;This thus configures &lt;code&gt;dnscrypt-proxy&lt;/code&gt; to listen on 127.0.0.1, port 40.&lt;/p&gt;
&lt;p&gt;Now we configure &lt;code&gt;pdnsd&lt;/code&gt; to listen on port 53 (default) for cache,
and relay cache misses to &lt;code&gt;dnscrypt-proxy&lt;/code&gt;. This is accomplished by using the following for &lt;code&gt;/etc/pdnsd.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;perm_cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cache_dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/cache/pdnsd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;run_as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pdnsd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;server_ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;status_ctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;query_method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;udp_tcp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;min_ttl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# Retain cached entries at least 15 minutes.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;max_ttl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# One week.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# Global timeout option (10 seconds).&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;neg_domain_pol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;udpbufsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# Upper limit on the size of UDP messages.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dnscrypt-proxy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;127.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;proxy_only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc/hosts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now it remains to change the DNS server from whatever default is used into 127.0.0.1.
For NetworkManager users, it is necessary to edit
&lt;code&gt;/etc/NetworkManager/NetworkManager.conf&lt;/code&gt; to prevent it from overriding this file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[main]&lt;/span&gt;
&lt;span class="na"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;dns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will cause &lt;code&gt;resolv.conf&lt;/code&gt; to be written as an empty file by NetworkManager: in this case,
the default 127.0.0.1 is used as the nameserver, which is what we want.&lt;/p&gt;
&lt;p&gt;Needless to say, one finishes with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;systemctl enable dnscrypt-proxy
systemctl start dnscrypt-proxy
systemctl enable pdnsd
systemctl start pdnsd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>Shifting PDF's using gs</title><link href="https://toa.evanchen.cc/pdf-shift/" rel="alternate"/><published>2016-04-03T13:37:00-04:00</published><updated>2016-04-03T13:37:00-04:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2016-04-03:/pdf-shift/</id><summary type="html">&lt;p&gt;Some time ago I was reading &lt;a href="http://ocw.mit.edu/courses/mathematics/18-785-analytic-number-theory-spring-2007/lecture-notes/"&gt;the 18.785 analytic NT notes&lt;/a&gt;
to try and figure out some sections of Davenport that I couldn&amp;rsquo;t understand.
These notes looked nice enough that I decided I should probably print them out,
But much to my annoyance, I found that
almost all the top margins were too tiny, and the bottom margins too big.
(I say &amp;ldquo;almost all&amp;rdquo; since the lectures 19 and 24 (Bombieri proof and elliptic curves) were totally fine,
for inexplicable reasons).&lt;/p&gt;
&lt;p&gt;Thus, instead of reading Davenport like I told myself to,
I ended up learning enough GhostScript flags to write the following short script,
which I&amp;rsquo;m going to share today so that other people can find better things to do with their time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Shifting &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt; ...&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;gs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-sDEVICE&lt;span class="o"&gt;=&lt;/span&gt;pdfwrite&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;shifted-&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-dPDFSETTINGS&lt;span class="o"&gt;=&lt;/span&gt;/prepress&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;&amp;lt;/PageOffset [0 -36]&amp;gt;&amp;gt; setpagedevice&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$file …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Some time ago I was reading &lt;a href="http://ocw.mit.edu/courses/mathematics/18-785-analytic-number-theory-spring-2007/lecture-notes/"&gt;the 18.785 analytic NT notes&lt;/a&gt;
to try and figure out some sections of Davenport that I couldn&amp;rsquo;t understand.
These notes looked nice enough that I decided I should probably print them out,
But much to my annoyance, I found that
almost all the top margins were too tiny, and the bottom margins too big.
(I say &amp;ldquo;almost all&amp;rdquo; since the lectures 19 and 24 (Bombieri proof and elliptic curves) were totally fine,
for inexplicable reasons).&lt;/p&gt;
&lt;p&gt;Thus, instead of reading Davenport like I told myself to,
I ended up learning enough GhostScript flags to write the following short script,
which I&amp;rsquo;m going to share today so that other people can find better things to do with their time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Shifting &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt; ...&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;gs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-sDEVICE&lt;span class="o"&gt;=&lt;/span&gt;pdfwrite&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;shifted-&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-dPDFSETTINGS&lt;span class="o"&gt;=&lt;/span&gt;/prepress&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;&amp;lt;/PageOffset [0 -36]&amp;gt;&amp;gt; setpagedevice&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The arguments 0 and -36 indicate to not change the left/right margins,
but to &lt;strong&gt;shift the content vertically downwards by 36pt (a half inch)&lt;/strong&gt;.
Of course, they can and should be adjusted depending on specific task.
Invocation is the standard &lt;code&gt;./script-name.sh *.pdf&lt;/code&gt; (or whatever).&lt;/p&gt;
&lt;p&gt;(Aside: ironically, this decreased the file sizes of the affected PDF&amp;rsquo;s.)&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>Git Aliases</title><link href="https://toa.evanchen.cc/git-aliases/" rel="alternate"/><published>2015-10-25T13:37:00-04:00</published><updated>2015-10-25T13:37:00-04:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2015-10-25:/git-aliases/</id><summary type="html">&lt;p&gt;For Git users:&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve recently discovered the joy that is git aliases,
courtesy of &lt;a href="http://durdn.com/blog/2012/11/22/must-have-git-aliases-advanced-examples/"&gt;this blog post&lt;/a&gt;.
To return to the favor, I thought I&amp;rsquo;d share the ones that I came up with.&lt;/p&gt;
&lt;p&gt;For those of you that don&amp;rsquo;t already know, Git allows you to make aliases &amp;ndash; shortcuts for commands.
Specifically, if you add the following lines to your .gitconfig:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[alias]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;cm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;commit&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;co&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;checkout&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then running &lt;code&gt;git cm&lt;/code&gt; will expand as &lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git co master&lt;/code&gt; is &lt;code&gt;git checkout master&lt;/code&gt;, and so on.
You can see how this might make you happy because it could save a few keystrokes.
But I think it&amp;rsquo;s more useful than that &amp;ndash; let me share what I did.&lt;/p&gt;
&lt;p&gt;The first thing I did was add&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pu = pull origin
psh = push origin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and permanently save myself the frustration of forgetting to type &lt;code&gt;origin&lt;/code&gt;. Not bad.
Even more helpful was …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For Git users:&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve recently discovered the joy that is git aliases,
courtesy of &lt;a href="http://durdn.com/blog/2012/11/22/must-have-git-aliases-advanced-examples/"&gt;this blog post&lt;/a&gt;.
To return to the favor, I thought I&amp;rsquo;d share the ones that I came up with.&lt;/p&gt;
&lt;p&gt;For those of you that don&amp;rsquo;t already know, Git allows you to make aliases &amp;ndash; shortcuts for commands.
Specifically, if you add the following lines to your .gitconfig:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[alias]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;cm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;commit&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;co&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;checkout&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then running &lt;code&gt;git cm&lt;/code&gt; will expand as &lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git co master&lt;/code&gt; is &lt;code&gt;git checkout master&lt;/code&gt;, and so on.
You can see how this might make you happy because it could save a few keystrokes.
But I think it&amp;rsquo;s more useful than that &amp;ndash; let me share what I did.&lt;/p&gt;
&lt;p&gt;The first thing I did was add&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pu = pull origin
psh = push origin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and permanently save myself the frustration of forgetting to type &lt;code&gt;origin&lt;/code&gt;. Not bad.
Even more helpful was the command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;undo = reset --soft HEAD~1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thus if I make a commit and then decide I want to undo it, rather than having
to remember (or Google) what the correct incantations were, I just have to type &lt;code&gt;git undo&lt;/code&gt;.
It&amp;rsquo;s really an undo button!&lt;/p&gt;
&lt;p&gt;Now for the fun part &amp;ndash; some of Git&amp;rsquo;s useful commands are pretty verbose and take up lots of space.
For example, here&amp;rsquo;s what git status looks like:&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://toa.evanchen.cc/git-aliases/images/git-status.png" rel="noopener" target="_blank"&gt;&lt;img alt="git status" src="https://toa.evanchen.cc/git-aliases/images/git-status.png"&gt;&lt;/a&gt;&lt;figcaption&gt;git status&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Kind of verbose if you ask me, and by now I know what &amp;ldquo;git pull&amp;rdquo; does.
Fortunately, it turns out that there are some options you can run to make this look nicer.
All you have to do is say &lt;code&gt;git status -s -b&lt;/code&gt;, or in the context of this post, set the alias&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ss = status -s -b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you get&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://toa.evanchen.cc/git-aliases/images/git-alias-ss.png" rel="noopener" target="_blank"&gt;&lt;img alt="git ss" src="https://toa.evanchen.cc/git-aliases/images/git-alias-ss.png"&gt;&lt;/a&gt;&lt;figcaption&gt;git ss&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;which is much cooler.&lt;/p&gt;
&lt;p&gt;Similarly, &lt;code&gt;git log&lt;/code&gt; takes up a lot of space. I have the following format,
which I&amp;rsquo;ve edited from the above blog post to suit my own tastes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ls = log -n 16 --pretty=format:&amp;quot;%C(yellow)%h\\ %C(cyan)[%cn]\\ %C(reset)%s\\ %C(red)%d&amp;quot; --decorate
ll = log -n 6 --pretty=format:&amp;quot;%C(yellow)%h\\ %C(cyan)[%cn]\\ %C(reset)%s\\ %C(red)%ad&amp;quot; --decorate --date=short --stat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These give in my opinion the much more readable format&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://toa.evanchen.cc/git-aliases/images/git-alias-l.png" rel="noopener" target="_blank"&gt;&lt;img alt="git ls and git ll" src="https://toa.evanchen.cc/git-aliases/images/git-alias-l.png"&gt;&lt;/a&gt;&lt;figcaption&gt;git ls and git ll&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you&amp;rsquo;re on a branch that does merges, you might also have fun with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tree = log -n 16 --pretty=format:&amp;quot;%C(yellow)%h\\ %C(cyan)[%cn]\\ %C(reset)%s\\ %C(red)%d&amp;quot; --decorate --graph
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will put these into a graphical tree for your viewing pleasure.&lt;/p&gt;
&lt;p&gt;And finally a few more that I find nice, some again taken directly from the link above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;amend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;avoid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;stupid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;oops typo&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;commits&lt;/span&gt;
&lt;span class="nv"&gt;rb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rebase&lt;/span&gt;
&lt;span class="nv"&gt;rbc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rebase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="nv"&gt;bis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bisect&lt;/span&gt;
&lt;span class="nv"&gt;dc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;checkout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;
&lt;span class="nv"&gt;assume&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;update&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;assume&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;unchanged&lt;/span&gt;
&lt;span class="nv"&gt;unassume&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;update&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;no&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;assume&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;unchanged&lt;/span&gt;
&lt;span class="nv"&gt;assumed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;!git ls-files -v | grep ^h | cut -c 3-&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Here &amp;ldquo;dc&amp;rdquo; is short for &amp;ldquo;discard&amp;rdquo;, since &lt;code&gt;git dc file&lt;/code&gt; discards the changes to that file.)
And that&amp;rsquo;s just the beginning of what you can do!&lt;/p&gt;
&lt;p&gt;Preemptive answer: I&amp;rsquo;m also using
&lt;a href="https://github.com/git/git/blob/master/contrib/completion/git-completion.bash"&gt;git-completion&lt;/a&gt; (for
tab-completing in git) and
&lt;a href="https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh"&gt;git-prompt&lt;/a&gt; with the line&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s1"&gt;[0;32m]${debian_chroot:+($debian_chroot)}\u@\h [&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s1"&gt;[0;33m]\w$(__git_ps1 &amp;quot; [&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s1"&gt;[1;31m]#&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot;)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;[&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s1"&gt;[0m]\$ &amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;in my bashrc. That&amp;rsquo;s where the branch indicators are coming from.
The terminal is XFCE4.&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>Arch Linux on a Mac Mini</title><link href="https://toa.evanchen.cc/mac-mini/" rel="alternate"/><published>2014-10-07T13:37:00-04:00</published><updated>2014-10-07T13:37:00-04:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2014-10-07:/mac-mini/</id><summary type="html">&lt;!-- rumdl-disable MD046 --&gt;

&lt;p&gt;This post briefly outlines the process of setting up a dual boot OSX and Arch Linux on a Mac Mini.
This is mostly for my reference in the likely event that I will be doing anything similar in some years,
so it assumes some competence; fortunately,
the Arch Wiki&amp;rsquo;s &lt;a href="https://wiki.archlinux.org/index.php/Beginners'_guide"&gt;Beginner&amp;rsquo;s Guide&lt;/a&gt; probably fills in any
gaps I left out. Obligatory Disclaimer: Use at your own risk or not at all.&lt;/p&gt;
&lt;p&gt;This is almost the same as
&lt;a href="https://wiki.archlinux.org/index.php/installation_guide"&gt;any other installation of Arch Linux&lt;/a&gt;,
with a few changes that took some hours of frustration to figure out because of the EFI booter.
My method is to create the partitions in Disk Utility, install rEFInd,
and then install the grub bootloader into /dev/sda1.&lt;/p&gt;
&lt;h2&gt;Setup done in OSX&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;First, install &lt;a href="http://www.rodsbooks.com/refind/"&gt;rEFInd&lt;/a&gt;.
    This worked out of the box for me, and makes it possible to boot via USB.&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://wiki.archlinux.org/index.php/USB_flash_installation_media"&gt;Arch Linux …&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;!-- rumdl-disable MD046 --&gt;

&lt;p&gt;This post briefly outlines the process of setting up a dual boot OSX and Arch Linux on a Mac Mini.
This is mostly for my reference in the likely event that I will be doing anything similar in some years,
so it assumes some competence; fortunately,
the Arch Wiki&amp;rsquo;s &lt;a href="https://wiki.archlinux.org/index.php/Beginners'_guide"&gt;Beginner&amp;rsquo;s Guide&lt;/a&gt; probably fills in any
gaps I left out. Obligatory Disclaimer: Use at your own risk or not at all.&lt;/p&gt;
&lt;p&gt;This is almost the same as
&lt;a href="https://wiki.archlinux.org/index.php/installation_guide"&gt;any other installation of Arch Linux&lt;/a&gt;,
with a few changes that took some hours of frustration to figure out because of the EFI booter.
My method is to create the partitions in Disk Utility, install rEFInd,
and then install the grub bootloader into /dev/sda1.&lt;/p&gt;
&lt;h2&gt;Setup done in OSX&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;First, install &lt;a href="http://www.rodsbooks.com/refind/"&gt;rEFInd&lt;/a&gt;.
    This worked out of the box for me, and makes it possible to boot via USB.&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://wiki.archlinux.org/index.php/USB_flash_installation_media"&gt;Arch Linux installer
    USB&lt;/a&gt; by
    &lt;code&gt;dd&lt;/code&gt;-ing (or anything else) the latest installation medium onto a USB drive.&lt;/li&gt;
&lt;li&gt;Set up the partitions; I find it easier (and less dangerous) to just use the
    OSX &lt;a href="http://support.apple.com/kb/ht1782"&gt;Disk Utility&lt;/a&gt; to do this.
    See, for example, &lt;a href="https://wiki.archlinux.org/index.php/MacBook#Mac_OS_X_with_Arch_Linux"&gt;the procedure
    here&lt;/a&gt;.
    My OSX installations appear to come with three partitions, a small one called &amp;ldquo;EFI&amp;rdquo;,
    a main &amp;ldquo;OS X HD&amp;rdquo; partition, and then a small &amp;ldquo;Recovery HD&amp;rdquo;, like so:&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  NAME LABEL TYPE SIZE
  sda disk 931.5G
  |-sda1 EFI part 200M
  |-sda2 OS X HD part 927.9G
  `-sda3 Recovery HD part 619.9M
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(This output is from lsblk, and is not what Disk Utility looks like).
  I like to create a partition for my Arch Linux system (which I name &amp;ldquo;Arch&amp;rdquo;)
  and a fifth partition just for the /home directory (which I name Home&amp;rdquo;).
  This leaves me to something like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  NAME LABEL TYPE SIZE
  sda disk 931.5G
  |-sda1 EFI part 200M
  |-sda2 OS X HD part 476.9G
  |-sda3 Recovery HD part 619.9M
  |-sda4 Arch part 179G
  `-sda5 Home part 272G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Booting into the USB and finishing up the partitions&lt;/h2&gt;
&lt;p&gt;Now that the partitions and rEFInd is set up, and the USB is written,
we can proceed with the actual installation.
At this point, one can basically follow &lt;a href="https://wiki.archlinux.org/index.php/Beginners'_guide"&gt;the standard
procedure&lt;/a&gt; with a few changes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Reboot the device into the USB.
    Since rEFInd is installed, it should give you the option of booting into the USB.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Establish an Internet as required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We&amp;rsquo;ve already created the partitions in Disk Utility above,
    so there is no need to change the partitions themselves now.
    However, it is necessary to format the newcly created partitions above.
    In my case, the relevant commands are&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  # mkfs.ext4 /dev/sda4
  # mkfs.ext4 /dev/sda5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Please, please make sure that you are formatting the right partitions.
  The command &lt;code&gt;lsblk -f&lt;/code&gt; will print out the partitions and their labels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we need to mount the directories.
    There are three directories we need to mount, the main filesystem and the home directory,
    as well as the EFI boot directory.
    The part that was non-obvious to me is that the boot directory we want is
    actually the &amp;ldquo;EFI&amp;rdquo; directory (likely &lt;code&gt;/dev/sda1&lt;/code&gt;) that OSX already provides.
    The relevant commands in my case were&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  # mount /dev/sda4 /mnt
  # mkdir /mnt/home
  # mount /dev/sda5 /mnt/home
  # mkdir /mnt/boot
  # mount /dev/sda1 /mnt/boot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now you can happily install the base system and generate an fstab file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;  # genfstab -U -p /mnt &amp;gt;&amp;gt; /mnt/etc/fstab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Configuring the base system and installing the bootloader&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Now we can &lt;a href="https://wiki.archlinux.org/index.php/Beginners%27_guide#Chroot_and_configure_the_base_system"&gt;chroot into the system&lt;/a&gt;
    and follow all the directions, up to (but not including) installing the bootloader.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I could not get &lt;code&gt;gummiboot&lt;/code&gt; to work but maybe you will have better luck.
    Fortunately, with &lt;code&gt;/dev/sda1/&lt;/code&gt; mounted as &lt;code&gt;/boot&lt;/code&gt;, I got GRUB to work nicely.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# pacman -S grub&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=arch_grub --recheck&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# grub-mkconfig -o /boot/grub/grub.cfg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we can exit the chroot environment and power down the system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If all goes well, upon rebooting, rEFInd will now boot into the complete Arch Linux system.&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry><entry><title>PDF Compression</title><link href="https://toa.evanchen.cc/pdf-compress/" rel="alternate"/><published>2014-02-01T13:37:00-05:00</published><updated>2014-02-01T13:37:00-05:00</updated><author><name>Evan Chen 《陳誼廷》</name></author><id>tag:toa.evanchen.cc,2014-02-01:/pdf-compress/</id><content type="html">&lt;p&gt;I always scan copies of letters into my computer before I send them out.
So I had a bunch of large PDF&amp;rsquo;s sitting around hogging my Dropbox space.&lt;/p&gt;
&lt;p&gt;One day I found &lt;a href="http://pandemoniumillusion.wordpress.com/2008/05/07/compress-a-pdf-with-pdftk/"&gt;this blog post&lt;/a&gt;
which claimed that simply running (in Bash) the commands&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ pdf2ps original.pdf temp.ps
$ ps2pdf temp.ps new.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;would decrease the file size.
(The two commands are part of GhostScript,
which I had installed on my Linux boxes anyways.) I couldn&amp;rsquo;t resist trying it &amp;ndash; and miraculously, it worked.
It generally decreases my scans by a factor of 10 (from 20MB to 2MB or so).&lt;/p&gt;
&lt;p&gt;I have no clue why this works,
although it probably has something to do with the fact that the PDF&amp;rsquo;s are scanned pages .
Anyone care to enlighten me?&lt;/p&gt;</content><category term="Hacking"/><category term="linux"/></entry></feed>