<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>By George!</title><link href="https://www.kj4jzy.org/" rel="alternate"></link><link href="https://www.kj4jzy.org/feeds/all.atom.xml" rel="self"></link><id>https://www.kj4jzy.org/</id><updated>2025-03-12T00:00:00-04:00</updated><entry><title>npins + colmena personal configuration</title><link href="https://www.kj4jzy.org/posts/2025/03/npins-colmena" rel="alternate"></link><published>2025-03-12T00:00:00-04:00</published><updated>2025-03-12T00:00:00-04:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2025-03-12:/posts/2025/03/npins-colmena</id><summary type="html">&lt;p&gt;In which I explain how I migrated away from a Nix Flake for my personal&amp;nbsp;config.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Inspired by various blog posts,
amongst which Jade&amp;#8217;s &lt;a href="https://jade.fyi/blog/pinning-nixos-with-npins/"&gt;Pinning NixOS with npins, or how to kill channels forever without flakes&lt;/a&gt;,
I decided to migrate my Flake-based configuration,
which included &lt;code&gt;nixosConfigurations&lt;/code&gt;,
&lt;a href="https://nix-community.github.io/home-manager/"&gt;Home Manager&lt;/a&gt; &lt;code&gt;homeConfigurations&lt;/code&gt;,
&lt;a href="https://github.com/numtide/system-manager"&gt;system-manager&lt;/a&gt; &lt;code&gt;systemConfigs&lt;/code&gt;,
and a &lt;code&gt;devShell&lt;/code&gt;,
away from Flakes and to &lt;a href="https://github.com/andir/npins"&gt;npins&lt;/a&gt;.
I don&amp;#8217;t claim that this is inherently better than Flakes,
but it was an interesting process
and I think I learned some things working on&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;One npins feature I was particularly interested in
is the ability to follow the tags of a Git repository.
A Flake can only follow a ref
(which can be a tag, but doesn&amp;#8217;t automatically update).
It&amp;#8217;s also interesting to be able to follow a nixpkgs channel
instead of the corresponding Git branch,
though that doesn&amp;#8217;t seem to have any observable&amp;nbsp;effects.&lt;/p&gt;
&lt;p&gt;If you want to follow along at home,
the last Flake-based commit is &lt;a href="https://github.com/gmacon/dotfiles/tree/last-flake"&gt;&lt;code&gt;last-flake&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Rather than the wrapper-script approach described by Jade,
I decided to use &lt;a href="https://colmena.cli.rs/unstable/"&gt;colmena&lt;/a&gt;
to deploy NixOS systems.
While I&amp;#8217;m gaining experience with tools,
I might as well gain experience with two tools at&amp;nbsp;once.&lt;/p&gt;
&lt;h1&gt;System&amp;nbsp;Configurations&lt;/h1&gt;
&lt;p&gt;Before I started the conversion,
I did some general cleanup.
For example,
I switched from the Lix overlay module
to using the Lix included in nixpkgs
so I could take advantage of Hydra&amp;nbsp;builds.&lt;/p&gt;
&lt;p&gt;I started by migrating the &lt;code&gt;nixosConfigurations&lt;/code&gt; to colmena.
This was pretty straightforward.
The only thing that tripped me up is that colmena
checks for the presence of &lt;code&gt;flake.nix&lt;/code&gt; to decide
if it should use Flakes or not,
so I renamed my &lt;code&gt;flake.nix&lt;/code&gt; so I could
have it for reference during the conversion
and have colmena read from &lt;code&gt;hive.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the initial conversion,
I lost only &lt;code&gt;nix-index-database&lt;/code&gt;
since I couldn&amp;#8217;t immediately figure out
how to reference its home-manager module without
going through the flakes&amp;nbsp;interface.&lt;/p&gt;
&lt;p&gt;Initially,
I tried to configure cross compilation for my Raspberry Pi.
Unfortunately,
this basically requires building everything
since I can&amp;#8217;t take advantage of Hydra builds,
so I switched to using &lt;code&gt;buildOnHost = true&lt;/code&gt;.
That was faster even though I end up building some software on the Pi
since &lt;em&gt;most&lt;/em&gt; of the software is available from the cache.
The ideal thing would be if I had a more powerful aarch64-linux machine,
I could configure it as a remote builder and do the builds there,
but I don&amp;#8217;t have&amp;nbsp;one.&lt;/p&gt;
&lt;p&gt;While writing this blog post,
I tried building the configuration for the Pi
under emulation but not cross compiling.
This worked, and did substitute most of the configuration,
and it&amp;#8217;s slightly faster than building directly on the Pi,
so I&amp;#8217;m going to leave that in place for&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Home&amp;nbsp;Manager&lt;/h1&gt;
&lt;p&gt;Home manager was a little harder.
When not running in Flake mode,
the &lt;code&gt;home-manager&lt;/code&gt; command uses &lt;code&gt;&amp;lt;nixpkgs&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;home-manager&amp;gt;&lt;/code&gt; from &lt;code&gt;NIX_PATH&lt;/code&gt;.
I used the wrapper script approach described by Jade
to have these reference the proper pinned&amp;nbsp;values.&lt;/p&gt;
&lt;h1&gt;system-manager&lt;/h1&gt;
&lt;p&gt;On my work laptop,
which runs Linux but not NixOS,
I was using system-manager to set up &lt;span class="caps"&gt;GPU&lt;/span&gt; drivers for Nix-built software.
When I first did this conversion,
there was no documented way to use system-manager without Flakes,
and I didn&amp;#8217;t look into it.
When I came back a few weeks later,
system-manager had had modifications
that simplified using the Nix components without Flakes,
though still no documentation.
The &lt;code&gt;system-manager&lt;/code&gt; command still assumes Flakes,
but I was able to write a shell script
that uses raw Nix commands to build, register, and activate
the system-manager&amp;nbsp;configuration.&lt;/p&gt;
&lt;h1&gt;nix-index-database&lt;/h1&gt;
&lt;p&gt;nix-index-database is also designed to be consumed as a Flake.
It has a &lt;code&gt;default.nix&lt;/code&gt; that provides the wrapped packages,
that works fine,
but the Home Manager module is provided as a functor that expects
the Flake (&lt;code&gt;self&lt;/code&gt;) as the argument.
Even so,
we have all the tools available to make this work.
I wrote this adapter&amp;nbsp;module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; pkgs&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;../../npins&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; sources&lt;span class="o"&gt;.&lt;/span&gt;nix-index-database&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;inherit&lt;/span&gt; pkgs&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;dummyFlake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    packages&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;stdenv&lt;span class="o"&gt;.&lt;/span&gt;system&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; packages&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="ss"&gt;hmModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;sources&lt;span class="o"&gt;.&lt;/span&gt;nix-index-database&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/home-manager-module.nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; dummyFlake&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; hmModule &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;I read the home manager module functor
to figure out what attributes were needed,
which turns out just to be the packages for the current system.
It re-imports the npins &lt;code&gt;sources&lt;/code&gt; since using the sources
that I provided through &lt;code&gt;extraSpecialArgs&lt;/code&gt;
caused an infinite recursion&amp;nbsp;error.&lt;/p&gt;
&lt;p&gt;And there you have it:
a Flake-free pinned configuration for all the&amp;nbsp;things.&lt;/p&gt;</content><category term="Code"></category><category term="nix"></category></entry><entry><title>Why to prefer Option, in one table</title><link href="https://www.kj4jzy.org/posts/2024/10/optional-reference" rel="alternate"></link><published>2024-10-14T00:00:00-04:00</published><updated>2024-10-14T00:00:00-04:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2024-10-14:/posts/2024/10/optional-reference</id><summary type="html">&lt;p&gt;Some time back,
I came across Logan Smith&amp;#8217;s &lt;a href="https://www.youtube.com/watch?v=6c7pZYP_iIE"&gt;Choose the Right Option&lt;/a&gt; video,
and the other day I was trying to summarize it for a&amp;nbsp;colleague.&lt;/p&gt;
&lt;p&gt;I think it boils down to this:
If we assume &lt;code&gt;T: ?Clone&lt;/code&gt;,&amp;nbsp;then&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;to convert&amp;#8230;&lt;/th&gt;
&lt;th&gt;to &lt;code&gt;&amp;amp;Option&amp;lt;T&amp;gt;&lt;/code&gt;&amp;#8230;&lt;/th&gt;
&lt;th&gt;to &lt;code&gt;Option&amp;lt;&amp;amp;T&amp;gt;&lt;/code&gt;&amp;#8230;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: T …&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</summary><content type="html">&lt;p&gt;Some time back,
I came across Logan Smith&amp;#8217;s &lt;a href="https://www.youtube.com/watch?v=6c7pZYP_iIE"&gt;Choose the Right Option&lt;/a&gt; video,
and the other day I was trying to summarize it for a&amp;nbsp;colleague.&lt;/p&gt;
&lt;p&gt;I think it boils down to this:
If we assume &lt;code&gt;T: ?Clone&lt;/code&gt;,&amp;nbsp;then&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;to convert&amp;#8230;&lt;/th&gt;
&lt;th&gt;to &lt;code&gt;&amp;amp;Option&amp;lt;T&amp;gt;&lt;/code&gt;&amp;#8230;&lt;/th&gt;
&lt;th&gt;to &lt;code&gt;Option&amp;lt;&amp;amp;T&amp;gt;&lt;/code&gt;&amp;#8230;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;Some(x)&lt;/code&gt; (moves &lt;code&gt;x&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Some(&amp;amp;x)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: &amp;amp;T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;not possible&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Some(x)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: Option&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x.as_ref()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: Option&amp;lt;Box&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;not possible&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x.as_deref()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x: &amp;amp;Option&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x.as_ref()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;plus &lt;a href="https://doc.rust-lang.org/std/option/index.html#representation"&gt;niche optimization&lt;/a&gt;.&lt;/p&gt;</content><category term="Code"></category><category term="rustlang"></category></entry><entry><title>Four ways to get or insert in a Rust map</title><link href="https://www.kj4jzy.org/posts/2024/09/four-ways-to-get-or-insert" rel="alternate"></link><published>2024-09-07T00:00:00-04:00</published><updated>2024-09-08T00:00:00-04:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2024-09-07:/posts/2024/09/four-ways-to-get-or-insert</id><summary type="html">&lt;p&gt;Using the entry &lt;span class="caps"&gt;API&lt;/span&gt; to insert things in more complicated&amp;nbsp;situations.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The Rust standard library contains two map types:
&lt;a href="https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html"&gt;&lt;code&gt;HashMap&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://doc.rust-lang.org/std/collections/struct.BTreeMap.html"&gt;&lt;code&gt;BTreeMap&lt;/code&gt;&lt;/a&gt;.
Both of them implement the &lt;a href="https://doc.rust-lang.org/std/collections/index.html#entries"&gt;&lt;code&gt;entry&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;
to allow efficient insert-or-update behavior.
I will give examples using &lt;code&gt;HashMap&lt;/code&gt;,
but &lt;code&gt;BTreeMap&lt;/code&gt; implements the same &lt;span class="caps"&gt;API&lt;/span&gt;,&amp;nbsp;too.&lt;/p&gt;
&lt;h1&gt;The Simplest Case: Inserting the&amp;nbsp;default&lt;/h1&gt;
&lt;p&gt;This one is pretty trivial.
If the value type implements &lt;a href="https://doc.rust-lang.org/std/default/trait.Default.html"&gt;&lt;code&gt;Default&lt;/code&gt;&lt;/a&gt; with the right behavior,
you can just use &lt;a href="https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_default"&gt;&lt;code&gt;Entry::or_default&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a snippet that consumes an iterator
and returns a map containing the counts of each&amp;nbsp;element:&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="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counts&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;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&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="n"&gt;iter&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_owned&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;or_default&lt;/span&gt;&lt;span class="p"&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="mi"&gt;1&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;For example,
if &lt;code&gt;iter&lt;/code&gt; is &lt;code&gt;"abracadabra".chars()&lt;/code&gt;,
then &lt;code&gt;counts&lt;/code&gt; ends up being
&lt;code&gt;{'b': 2, 'a': 5, 'd': 1, 'c': 1, 'r': 2}&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Still Simple Case: A very cheap&amp;nbsp;constructor&lt;/h1&gt;
&lt;p&gt;If the value you want to insert isn&amp;#8217;t the default,
but has a literal representation or is otherwise cheap,
you can use &lt;a href="https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert"&gt;&lt;code&gt;Entry::or_insert&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The example is a little contrived
(you could easily use &lt;code&gt;Entry::or_default&lt;/code&gt;
and increment before printing instead of after)
but it shows how it&amp;nbsp;works:&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="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&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;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&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="s"&gt;&amp;quot;abracadabra&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;()&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="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&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;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;or_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{x}: {number}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;number&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="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;Output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;a: 1&lt;/span&gt;
&lt;span class="go"&gt;b: 1&lt;/span&gt;
&lt;span class="go"&gt;r: 1&lt;/span&gt;
&lt;span class="go"&gt;a: 2&lt;/span&gt;
&lt;span class="go"&gt;c: 1&lt;/span&gt;
&lt;span class="go"&gt;a: 3&lt;/span&gt;
&lt;span class="go"&gt;d: 1&lt;/span&gt;
&lt;span class="go"&gt;a: 4&lt;/span&gt;
&lt;span class="go"&gt;b: 2&lt;/span&gt;
&lt;span class="go"&gt;r: 2&lt;/span&gt;
&lt;span class="go"&gt;a: 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Moderately Complicated: An expensive&amp;nbsp;constructor&lt;/h1&gt;
&lt;p&gt;Suppose now that the value type has a constructor,
but you want to avoid running it when the value already exists.
In this case, use &lt;a href="https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_insert_with"&gt;&lt;code&gt;Entry::or_insert_with&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This example is again contrived
(&lt;code&gt;Entry::or_default&lt;/code&gt; would also work here)
but it shows how it&amp;nbsp;works:&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="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;words_by_length&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;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&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="s"&gt;&amp;quot;Four score and seven years ago&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split_ascii_whitespace&lt;/span&gt;&lt;span class="p"&gt;()&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;words_by_length&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entry&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="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;or_insert_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&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="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&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="n"&gt;to_owned&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{words_by_length:?}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;{5: [&amp;quot;score&amp;quot;, &amp;quot;seven&amp;quot;, &amp;quot;years&amp;quot;], 3: [&amp;quot;and&amp;quot;, &amp;quot;ago&amp;quot;], 4: [&amp;quot;Four&amp;quot;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Hard case: A fallible or async&amp;nbsp;constructor&lt;/h1&gt;
&lt;p&gt;Here&amp;#8217;s the reason for this blog post&amp;#8217;s existence:
if the constructor isn&amp;#8217;t a synchronous, infallible function,
you have to reach for the full generality of the &lt;code&gt;entry&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt; to get the job&amp;nbsp;done.&lt;/p&gt;
&lt;p&gt;This writes lines into many files,
where (file, line) pairs arrive in random order,
but the files are kept open to avoid the overhead of opening each one multiple times.
I&amp;#8217;ll show this one in its full glory,
including imports and function&amp;nbsp;boilerplate:&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;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hash_map&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&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;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&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="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;This is file B&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;This is file A&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c.txt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;This is file C&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&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="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&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="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_owned&lt;/span&gt;&lt;span class="p"&gt;())&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;Entry&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Occupied&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;into_mut&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Vacant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;),&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="fm"&gt;writeln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{line}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&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="nb"&gt;Ok&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;The thing that tripped me up (twice) about this example
is that it &lt;em&gt;feels like&lt;/em&gt; &lt;code&gt;OccupiedEntry::get_mut&lt;/code&gt; is
the right thing to use in the &lt;code&gt;Entry::Occupied&lt;/code&gt; branch
because it has the same return type as &lt;code&gt;VacantEntry::insert&lt;/code&gt;,
but that actually results in the borrow not living long&amp;nbsp;enough:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;error[E0597]: `o` does not live long enough&lt;/span&gt;
&lt;span class="go"&gt;  --&amp;gt; examples/fallible.rs:17:39&lt;/span&gt;
&lt;span class="go"&gt;   |&lt;/span&gt;
&lt;span class="go"&gt;16 |         let file = match files.entry(path.to_owned()) {&lt;/span&gt;
&lt;span class="go"&gt;   |             ---- borrow later stored here&lt;/span&gt;
&lt;span class="go"&gt;17 |             Entry::Occupied(mut o) =&amp;gt; o.get_mut(),&lt;/span&gt;
&lt;span class="go"&gt;   |                             -----     ^         - `o` dropped here while still borrowed&lt;/span&gt;
&lt;span class="go"&gt;   |                             |         |&lt;/span&gt;
&lt;span class="go"&gt;   |                             |         borrowed value does not live long enough&lt;/span&gt;
&lt;span class="go"&gt;   |                             binding `o` declared here&lt;/span&gt;

&lt;span class="go"&gt;For more information about this error, try `rustc --explain E0597`.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Final&amp;nbsp;Thoughts&lt;/h1&gt;
&lt;p&gt;I feel like this may be pointing to a gap in the documentation somewhere,
but I&amp;#8217;m undecided about where I think the documentation needs to go.
For the moment,
I&amp;#8217;m happy having written this down where I can find it again,
and I hope it&amp;#8217;s helpful for you,&amp;nbsp;too.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve posted &lt;a href="https://github.com/gmacon/rust-map-entry"&gt;fully-runnable examples&lt;/a&gt; if you want to see all the&amp;nbsp;detail.&lt;/p&gt;
&lt;h1&gt;Update&amp;nbsp;History&lt;/h1&gt;
&lt;h2&gt;2024-09-08&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Updated &amp;#8220;expensive&amp;#8221; example from &lt;code&gt;Vec::with_capacity(1)&lt;/code&gt; to &lt;code&gt;Vec::with_capacity(4)&lt;/code&gt;,
  as &lt;a href="https://fosstodon.org/@mo8it/113099707266699217"&gt;suggested&lt;/a&gt; by&amp;nbsp;@mo8it.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Code"></category><category term="rustlang"></category></entry><entry><title>Generating secure passwords</title><link href="https://www.kj4jzy.org/posts/2022/05/generating-secure-passwords" rel="alternate"></link><published>2022-05-12T00:00:00-04:00</published><updated>2023-02-11T17:56:52-05:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2022-05-12:/posts/2022/05/generating-secure-passwords</id><summary type="html">&lt;p&gt;How to generate passwords in accordance with&amp;nbsp;rules&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve used password managers for many years now,
and they have many security benefits,
including secure password generation.
One pain point is,
and always has been,
that websites have random rules
for what constitutes an &amp;#8220;acceptable&amp;#8221; password.
I&amp;#8217;ve ended up with an extremely basic solution:
a&amp;nbsp;shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tr -cd &amp;#39;!-~&amp;#39; &amp;lt;/dev/urandom | head -c 16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That example gives a random password consisting
of all printable &lt;span class="caps"&gt;ASCII&lt;/span&gt; characters uniformly.
Here&amp;#8217;s an example I used recently
for a site that only accepted a subset of special&amp;nbsp;characters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tr -cd &amp;#39;a-zA-Z0-9!@#$%^&amp;amp;*&amp;#39; &amp;lt;/dev/urandom | head -c 16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This doesn&amp;#8217;t help with other rules,
like &amp;#8220;you must include one character of each type&amp;#8221;
or &amp;#8220;you can&amp;#8217;t include more than three characters of the same type in a row&amp;#8221;,
but I can usually just draw a couple times until
the conditions are all&amp;nbsp;satisfied.&lt;/p&gt;</content><category term="Code"></category></entry><entry><title>2020 Stewardship Testimonial</title><link href="https://www.kj4jzy.org/posts/2020/09/stewardship-testimonial" rel="alternate"></link><published>2020-09-20T00:00:00-04:00</published><updated>2023-02-11T17:56:52-05:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2020-09-20:/posts/2020/09/stewardship-testimonial</id><summary type="html">&lt;p&gt;This is the text of the Stewardship Testimonial I gave &lt;a href="https://youtube.com/watch?v=JoPWR4WsWiA&amp;amp;t=2660"&gt;during the service&lt;/a&gt; on September 20,&amp;nbsp;2020.&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is the text of the Stewardship Testimonial I gave
&lt;a href="https://youtube.com/watch?v=JoPWR4WsWiA&amp;amp;t=2660"&gt;during the service&lt;/a&gt; on September 20,&amp;nbsp;2020.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Good morning.
My name is George Macon, and I am one of the Stewardship Co-chairs for this&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d like to unpack my title a little bit here.
I&amp;#8217;m a &amp;#8220;co-chair&amp;#8221; with Barbara Begner.
Together, we run the Stewardship Committee,
that is, in parliamentary language,
we &amp;#8220;chair&amp;#8221; it.
That&amp;#8217;s pretty straightforward, so that brings us to&amp;nbsp;&amp;#8220;stewardship&amp;#8221;.&lt;/p&gt;
&lt;p&gt;This is where it gets&amp;nbsp;deep.&lt;/p&gt;
&lt;p&gt;A &amp;#8220;steward&amp;#8221; is a person who manages or maintains something
on behalf of, and in the interest of, another, usually absent, person.
This has two parts:
what thing are we, as a committee, managing,
and on whose behalf are we managing&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;The obvious thing that the committee does is raise money to fund the congregation&amp;#8217;s operational budget.
That doesn&amp;#8217;t really fit in with the &amp;#8220;maintain&amp;#8221; part of the definition, though.
So you look around for something that&amp;#8217;s being&amp;nbsp;maintained.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s no obvious &amp;#8220;property&amp;#8221; in the traditional sense.
While &lt;span class="caps"&gt;UUCA&lt;/span&gt; does have an endowment, it&amp;#8217;s stewarded by the &lt;span class="caps"&gt;UUCA&lt;/span&gt; Endowment Fund,
a separate legal entity, so that can&amp;#8217;t be the answer.
The Stewardship Committee is stewarding something intangible:
the congregation itself, or &amp;#8220;church&amp;#8221; in its original meaning of a group of people.
Our goal is to ensure that this community, this congregation, continues to exist into the future.
That takes money, certainly, but the money is not the&amp;nbsp;point.&lt;/p&gt;
&lt;p&gt;So, the stewardship committee is maintaining the congregation on behalf of … itself.
But, importantly, on behalf of the future congregation&amp;#8217;s selves.
We all maintain this community, this loving community,
so that it will exist for those people who will find it in the future,
not only those of us who&amp;nbsp;stay.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s important for this community not to stagnate,
but to continue to grow, not just in size,
but also in our positive impact on Atlanta,
on Georgia, on the United States, and on the world at&amp;nbsp;large.&lt;/p&gt;
&lt;p&gt;This community is built by every member giving generously of their time, talent, and treasure.
If you have the time to volunteer to help with something, I encourage you to do so.
If you have the talent to enrich this community, I encourage you to use it.
If you have the treasure to enable the amazing things happening here, I encourage you to give&amp;nbsp;generously.&lt;/p&gt;
&lt;p&gt;We cannot do our work in the world without your financial support,
whether it takes the form of a pledge to the Capital Campaign,
a stewardship pledge to our operating budget,
or a virtual dollar bill placed in our virtual offering basket at &lt;a href="https://www.uuca.org/give/"&gt;uuca.org/give&lt;/a&gt;.
We thank you very much for your gifts to all of these&amp;nbsp;efforts.&lt;/p&gt;
&lt;p&gt;The offering will now be given, and very gratefully&amp;nbsp;received.&lt;/p&gt;</content><category term="UUCA"></category></entry><entry><title>A limerick which must be seen</title><link href="https://www.kj4jzy.org/posts/2015/11/a-limerick-which-must-be-seen" rel="alternate"></link><published>2015-11-26T00:00:00-05:00</published><updated>2023-02-11T17:56:52-05:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2015-11-26:/posts/2015/11/a-limerick-which-must-be-seen</id><content type="html">&lt;blockquote&gt;
&lt;p&gt;You can&amp;#8217;t call the British Queen Ms.&lt;br&gt;
Tain&amp;#8217;t as nice as Elizabeth is.&lt;br&gt;
But I think that the Queen&lt;br&gt;
Would be even less keen&lt;br&gt;
To have herself mentioned as&amp;nbsp;Ls.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Asimov, Isaac. “Out of Sight”. Ellery Queen&amp;#8217;s Mystery Magazine Dec. 1973.&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="Misc"></category></entry><entry><title>A Tool to Handle /etc/passwd.pacnew and Friends</title><link href="https://www.kj4jzy.org/posts/2014/07/automerge-passwd-group" rel="alternate"></link><published>2014-07-11T00:00:00-04:00</published><updated>2023-02-11T17:56:52-05:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2014-07-11:/posts/2014/07/automerge-passwd-group</id><summary type="html">&lt;p&gt;The last several times I&amp;#8217;ve updated &lt;code&gt;filesystem&lt;/code&gt;, &lt;code&gt;.pacnew&lt;/code&gt; files were created for &lt;code&gt;/etc/passwd&lt;/code&gt;, &lt;code&gt;/etc/shadow&lt;/code&gt;, &lt;code&gt;/etc/group&lt;/code&gt;, and &lt;code&gt;/etc/gshadow&lt;/code&gt;. My default approach for merging &lt;code&gt;.pacnew&lt;/code&gt; files is to use &lt;code&gt;vimdiff&lt;/code&gt; to edit the original and new files simultaneously. Unfortunately, this doesn&amp;#8217;t work very well for &lt;code&gt;/etc/passwd&lt;/code&gt; and friends because they are &lt;em&gt;databases&lt;/em&gt;, not configuration&amp;nbsp;files.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The last several times I&amp;#8217;ve updated &lt;code&gt;filesystem&lt;/code&gt;,
&lt;code&gt;.pacnew&lt;/code&gt; files were created for &lt;code&gt;/etc/passwd&lt;/code&gt;, &lt;code&gt;/etc/shadow&lt;/code&gt;, &lt;code&gt;/etc/group&lt;/code&gt;, and &lt;code&gt;/etc/gshadow&lt;/code&gt;.
My default approach for merging &lt;code&gt;.pacnew&lt;/code&gt; files is to use &lt;code&gt;vimdiff&lt;/code&gt; to edit the original and new files simultaneously.
Unfortunately, this doesn&amp;#8217;t work very well for &lt;code&gt;/etc/passwd&lt;/code&gt; and friends
because they are &lt;em&gt;databases&lt;/em&gt;, not configuration&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;My first thought was to make the files friendlier to &lt;code&gt;vimdiff&lt;/code&gt; by sorting all the lines.
That works well enough, but I decided that it would be better to use the tools provided for updating the password database to update the password database,
so I wrote a Python script that reads
&lt;code&gt;/etc/passwd&lt;/code&gt;, &lt;code&gt;/etc/passwd.pacnew&lt;/code&gt;, &lt;code&gt;/etc/group&lt;/code&gt;, and &lt;code&gt;/etc/group.pacnew&lt;/code&gt;
and suggests &lt;code&gt;useradd&lt;/code&gt;, &lt;code&gt;usermod&lt;/code&gt;, &lt;code&gt;groupadd&lt;/code&gt;, and &lt;code&gt;groupmod&lt;/code&gt;
commands to run to bring the live versions up to&amp;nbsp;date.&lt;/p&gt;
&lt;p&gt;The script looks at each user and group present in both files
and users and groups present only in the &lt;code&gt;.pacnew&lt;/code&gt; files.
Users and groups existing only in the live files are ignored;
these are the users that I have added or that were added by packages.
If either (or both) of the &lt;code&gt;.pacnew&lt;/code&gt; files are missing, the live copy is used instead.
This allows the script to be run if only one or the other of the files was&amp;nbsp;updated.&lt;/p&gt;
&lt;p&gt;Group membership is evaluated as part of the user for two reasons.
First, because &lt;code&gt;usermod&lt;/code&gt; is used to modify group memberships, not &lt;code&gt;groupmod&lt;/code&gt;.
Second, because this avoids printing suggestions to remove all my users from the predefined groups (like &lt;code&gt;systemd-journal&lt;/code&gt;, for&amp;nbsp;instance).&lt;/p&gt;
&lt;p&gt;You can &lt;a href="https://www.kj4jzy.org/downloads/merge_passwd_group.py"&gt;download the script&lt;/a&gt; and use it yourself.
It&amp;#8217;s licensed under the 2-clause &lt;span class="caps"&gt;BSD&lt;/span&gt;&amp;nbsp;license.&lt;/p&gt;</content><category term="Code"></category><category term="archlinux"></category></entry><entry><title>Liars and Outliers Review</title><link href="https://www.kj4jzy.org/posts/2013/10/liars-and-outliers-review" rel="alternate"></link><published>2013-10-30T00:00:00-04:00</published><updated>2023-02-11T17:56:52-05:00</updated><author><name>George Macon</name></author><id>tag:www.kj4jzy.org,2013-10-30:/posts/2013/10/liars-and-outliers-review</id><summary type="html">&lt;p class="first last"&gt;This is a review of Bruce Schneier&amp;#8217;s &lt;em&gt;Liars and Outliers&lt;/em&gt;, a book
about security.  He works from first principles to develop an
understanding of what happens&amp;nbsp;today.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I&amp;#8217;ve just finished reading &lt;a class="reference external" href="https://www.schneier.com/book-lo.html"&gt;&lt;em&gt;Liars and Outliers&lt;/em&gt;&lt;/a&gt; by Bruce Schneier.
I received a signed copy thanks to Schneier&amp;#8217;s &lt;a class="reference external" href="https://www.schneier.com/blog/archives/2012/08/liars_and_outli_10.html"&gt;discounted signed book
offer&lt;/a&gt;
of $11 plus a review. So here&amp;#8217;s a&amp;nbsp;review:&lt;/p&gt;
&lt;p&gt;In this book, Schneier takes on all of security: What is it, and why
does it work? The answer flows through diverse areas of study, from
evolutionary psychology to game theory. He begins (appropriately enough)
with history; a discussion of predators and prey. From microbiology, we
move rapidly forward through time to modern&amp;nbsp;society.&lt;/p&gt;
&lt;p&gt;After taking a look at history, Schneier moves into a discussion of the
four societal pressures: moral, reputational, institutional, and
security. Each kind of pressure is built off of the previous ones, with
security being the most&amp;nbsp;advanced.&lt;/p&gt;
&lt;p&gt;Once these basics are established, he moves into discussion of the real
world. In this part, he examines conflicting interests, organizations as
actors, corporations specifically, and institutions covering all the
ways that the theory breaks down in&amp;nbsp;practice.&lt;/p&gt;
&lt;p&gt;One of the most important things covered is the “security gap”:
defectors are faster to pick up on new technologies than defenders. This
means that security cannot solve all the problems. There are many
examples of this, the classic one being the arms race: attackers use
bows and arrows, so defenders wear armor. Then firearms are developed,
and the armor is no longer effective, so the defenders lose the armor
and hide in ditches. Defenders don&amp;#8217;t invest in new technology without a
reason, and better attacks are the best&amp;nbsp;reason.&lt;/p&gt;
&lt;p&gt;This is another book I&amp;#8217;ve read recently that is long on a description of
the problem and short on specific solutions. Near the end of the book,
Schneier gives the following list of&amp;nbsp;principles:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Understand the societal&amp;nbsp;dilemma.&lt;/li&gt;
&lt;li&gt;Consider all four social&amp;nbsp;pressures.&lt;/li&gt;
&lt;li&gt;Pay attention to&amp;nbsp;scale.&lt;/li&gt;
&lt;li&gt;Foster empathy and community, increasing moral and reputational&amp;nbsp;pressures.&lt;/li&gt;
&lt;li&gt;Use security systems to scale moral and reputational&amp;nbsp;pressures.&lt;/li&gt;
&lt;li&gt;Harmonize institutional pressures across related&amp;nbsp;technologies.&lt;/li&gt;
&lt;li&gt;Ensure that financial penalties account for the likelihood that a defection will be&amp;nbsp;detected.&lt;/li&gt;
&lt;li&gt;Choose general and reactive security&amp;nbsp;systems.&lt;/li&gt;
&lt;li&gt;Reduce concentrations of&amp;nbsp;power.&lt;/li&gt;
&lt;li&gt;Require transparency&amp;#8212;especially in corporations and government&amp;nbsp;institutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These principles provide an excellent foundation on top of which
solutions can be built, and, given the scope of what he&amp;#8217;s chosen to
tackle, it seems reasonable not to propose solutions to narrow issues
like airline security. However, I would have liked to see a specific
proposal for getting society&amp;#8217;s &amp;#8220;agent&amp;#8221;, &lt;em&gt;i.e.&lt;/em&gt; the government, to follow
these principles when implementing&amp;nbsp;policy.&lt;/p&gt;
</content><category term="Books"></category></entry></feed>