<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on Hannes Hauswedell</title>
    <link>https://hannes.hauswedell.net/post/</link>
    <description>Recent content in Posts on Hannes Hauswedell</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en_GB</language>
    <copyright>Unless otherwise noted: text is CC-by-sa; inline code is CC0; pictures are GNU GPL</copyright>
    <lastBuildDate>Sat, 17 May 2025 16:00:00 +0200</lastBuildDate>
    
        <atom:link href="https://hannes.hauswedell.net/post/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Owning and non-owning C&#43;&#43; Ranges</title>
      <link>https://hannes.hauswedell.net/post/2025/05/17/non-owning-range/</link>
      <pubDate>Sat, 17 May 2025 16:00:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2025/05/17/non-owning-range/</guid>
      <description>&lt;p&gt;This is the first article in a series discussing some of the underlying properties of C++ ranges and in particular &lt;em&gt;range adaptors&lt;/em&gt;. At the same time, I introduce the design of an experimental library which aims to solve some of the problems discussed here.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;This is the first article in a series discussing some of the underlying properties of C++ ranges and in particular &lt;em&gt;range adaptors&lt;/em&gt;. At the same time, I introduce the design of an experimental library which aims to solve some of the problems discussed here.&lt;/p&gt;
&lt;h2 id=&#34;preface&#34;&gt;Preface&lt;/h2&gt;
&lt;p&gt;C++ Ranges are one of the major features of C++20. See my &lt;a href=&#34;https://hannes.hauswedell.net/post/2019/11/30/range_intro/&#34; title=&#34;previous post&#34;&gt;previous post&lt;/a&gt; for a detailed introduction.
I am a big fan of C++ Ranges and have used them extensively in multiple projects (mostly bioinformatics, data science, …), but I have had difficulty convincing other people of the benefits and have seen many programmers struggle with even basic usage.
Furthermore, there have been significant conceptual changes to the Ranges part of ISO standard &lt;em&gt;after&lt;/em&gt; initial publication of C++20, showing the volatility of the design and making it even more difficult for non-expert users to understand what&amp;rsquo;s going on.
Even now, there are still controversial discussions within the ISO C++ committee regarding vary basic aspects of C++ Ranges and views.&lt;/p&gt;
&lt;p&gt;I see multiple challenges with the current design—that I will each write a blog post on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Owning and non-owning ranges.&lt;/li&gt;
&lt;li&gt;tbd&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will try give just enough detail to keep the read light, while providing enough information to understand what all the fuss is about! Finally, I will introduce my own experimental library design to address some of the challenges discovered. This is the first article in the series.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;DISCLAIMER:&lt;/em&gt; I have been using Ranges for a while, but I am very aware that other people did the heavy lifting of bringing them into the standard. It is quite possible that there are things I haven&amp;rsquo;t considered.
I also think it was right to try and improve the design of views.
In fact, I have reversed my own opinion on several problems several times, and I am sure I wouldn&amp;rsquo;t have come to the conclusions drawn here without the previous iterations of the design. Or to use a wiser person&amp;rsquo;s words: &lt;br&gt;
&lt;em&gt;“Why do you go away? So that you can come back. So that you can see the place you came from with new eyes and extra colors. […] Coming back to where you started is not the same as never leaving.”&lt;/em&gt; —  Terry Pratchett, A Hat Full of Sky&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;h2 id=&#34;c17-standard-library&#34;&gt;C++17 Standard Library&lt;/h2&gt;
&lt;p&gt;We will begin by having a look at ranges from the standard library prior to C++20, since this is what people are most used to.
Note that although the ranges themselves are from C++17, I will use some terminology/concepts/algorithms introduced later to explain how they relate to each other.
Remember that to count as a &lt;em&gt;range&lt;/em&gt; in C++, a type needs to have just &lt;code&gt;begin()&lt;/code&gt; and &lt;code&gt;end()&lt;/code&gt;.
Everything else is bonus 😉.&lt;/p&gt;
&lt;h3 id=&#34;multi-pass-ranges--containers-owning&#34;&gt;Multi-pass ranges | Containers (owning)&lt;/h3&gt;
&lt;p&gt;Containers are the ranges everybody already used before &lt;em&gt;Ranges&lt;/em&gt; were a thing.
They &lt;em&gt;own&lt;/em&gt; their elements, i.e. the storage of the elements is managed by the container and the elements disappear when the container does.
Containers are &lt;em&gt;multi-pass ranges&lt;/em&gt;, i.e. you can iterate over them multiple times and will always observe the same elements.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=halfimg&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2025/05/string.webp#center&#34; alt=&#34;&#34; title=&#34;Physically accurate rendering of a &#39;string&#39;.&#34;&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;em&gt;A string of characters as the example for a container.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;This rendering shows how you can imagine a &amp;ldquo;container&amp;rdquo;: a bunch of elements (letters) and some control data structures (in this case a cord and pegs). There is a clear &lt;code&gt;begin&lt;/code&gt; (first letter) and &lt;code&gt;end&lt;/code&gt; (end of cord).
Importantly, the elements are attached to the control data structures. When you move the whole thing, the elements and the container move together. Take down the cord, and the letters disappear.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* construction and copying */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string s  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// copies characters from static storage into string [O(n)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string s2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s;             &lt;span style=&#34;color:#75715e&#34;&gt;// copies all characters from s into s2              [O(n)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* find the smallest character in a string */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;min_element(s);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert(c &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* the same thing with a temporary */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// char d = *std::ranges::min_element(std::string{&amp;#34;foobar&amp;#34;});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// assert(d == &amp;#39;a&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;p&gt;&lt;em&gt;Examples illustrating &amp;ldquo;container semantics&amp;rdquo;.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Although the &lt;code&gt;&amp;quot;foobar&amp;quot;&lt;/code&gt; string literal itself has static storage, a new string is allocated&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; and the characters are copied into it.
Now the container manages the memory of the elements.
Copying the container itself, copies the elements (&lt;em&gt;O(n)&lt;/em&gt; complexity).&lt;sup id=&#34;fnref1:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;We can subsequently call &lt;code&gt;std::ranges::min_element&lt;/code&gt; on it to get the iterator pointing to the lexicographically smallest character.
The same does not work for a temporary of a string, because its elements go out-of-scope together with the container when &lt;code&gt;min_element&lt;/code&gt; returns; the iterator would be dangling.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&#34;multi-pass-ranges--non-owning&#34;&gt;Multi-pass ranges | Non-owning&lt;/h3&gt;
&lt;p&gt;If containers are &lt;em&gt;owning ranges&lt;/em&gt;, what are &lt;em&gt;non-owning ranges&lt;/em&gt;?
C++17 introduced a first example: &lt;code&gt;std::string_view&lt;/code&gt;, a range that consists just of a &lt;code&gt;begin&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; pointer&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; into another range&amp;rsquo;s elements.&lt;/p&gt;
&lt;p&gt;In general, &lt;em&gt;non-owning ranges&lt;/em&gt; are the subset of ranges that do not manage the memory of their elements.
&lt;code&gt;std::string_view&lt;/code&gt; is such a range, and it even fulfils the stricter requirements of a &lt;em&gt;borrowed range&lt;/em&gt;:
A range that stores nothing beside the iterators, and where the iterators may not refer back to the range object. This has the important implication that the iterators of a borrowed range remain valid when the borrowed range itself goes out-of-scope.
For a &lt;code&gt;string_view&lt;/code&gt;, this design seems natural, but we will later encounter ranges where a trade-off has to be made.&lt;/p&gt;
&lt;div class=halfimg&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2025/05/string_view.webp#center&#34; alt=&#34;&#34; title=&#34;A container casting a shadow on a wall (beware of the floating comma!)&#34;&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;em&gt;If the string of letters is a container, you can imagine a string_view as the shadow cast by a string.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;The above image illustrates the &lt;code&gt;string_view&lt;/code&gt; as the shadow of a string: You can read the same letters in the shadow and observe very similar properties to the string (sans colour in my example 😅).
But the lifetime of the shadow fundamentally depends on the object casting the shadow.
If the latter is moved or destroyed, the shadow disappears, as well, and the &lt;code&gt;string_view&lt;/code&gt; becomes dangling.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* construction and copying */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string_view s  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#34;binds&amp;#34; s to the static storage   [O(1)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string_view s2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s;             &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#34;binds&amp;#34; s2 to the static storage  [O(1)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* find the smallest character in a string */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;min_element(s);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert(c &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* the same thing with a temporary */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;min_element(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string_view{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert(d &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;p&gt;&lt;em&gt;Examples illustrating &amp;ldquo;borrowed range semantics&amp;rdquo;.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;The &lt;code&gt;std::string_view s1&lt;/code&gt; binds to the static storage of the string literal; no allocation or character copies take place.
This is also true for &lt;code&gt;s2&lt;/code&gt; which refers to the same static storage (and not &lt;code&gt;s&lt;/code&gt;!).
Thus, copying &lt;code&gt;string_view&lt;/code&gt;s is in &lt;em&gt;O(1)&lt;/em&gt;.
While it is particularly useful to wrap string literals in &lt;code&gt;std::string_view&lt;/code&gt;, you can also have a &lt;code&gt;std::string_view&lt;/code&gt; refer to a &lt;code&gt;std::string&lt;/code&gt;, a substring of a &lt;code&gt;std::string&lt;/code&gt; or even a &lt;code&gt;std::vector&amp;lt;char&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finding the smallest character works in the same way as for the &lt;code&gt;std::string&lt;/code&gt;, however, we can now also search a temporary, because iterators into that &lt;code&gt;string_view&lt;/code&gt; are not dependent on the &lt;code&gt;string_views&lt;/code&gt;&amp;rsquo;s lifetime (and the literal has static storage).&lt;/p&gt;
&lt;h3 id=&#34;single-pass-ranges&#34;&gt;Single-pass ranges&lt;/h3&gt;
&lt;p&gt;A single-pass range is one that does not offer the multi-pass guarantee, i.e. you may not be able to iterate over it multiple times, or might encounter different elements when you do.
Iterating over the range, changes the range.
It is not even guaranteed that you can call &lt;code&gt;.begin()&lt;/code&gt; more than once.&lt;/p&gt;
&lt;div class=quarterimg&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2025/05/printer.webp#center&#34; alt=&#34;&#34; title=&#34;A &#39;generator&#39; of characters.&#34;&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;em&gt;Think of a single-pass range of characters like a printer printing pages with letters on them.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Conceptionally, a single-pass ranges is more &amp;ldquo;a machine that produces elements&amp;rdquo; than &amp;ldquo;a collection of elements&amp;rdquo;.
This is illustrated by the printer in the image above.
You can use it to generate a series of pages, but the pages aren&amp;rsquo;t part of the printer, and the printer is in a different state after each page printed.
Printing could go on indefinitely, but the printer might also just stop working. Some printers may be restarted, others not 😁&lt;/p&gt;
&lt;!-- And the iterator of such a range is not an &#34;observer object&#34;, instead it is part of the machine. --&gt;
&lt;p&gt;No dedicated single-pass range exists in pre C++20 times, and few single-pass iterators do, e.g. &lt;code&gt;std::istream_iterator&lt;/code&gt; which exposes the characters of an input stream.&lt;/p&gt;
&lt;p&gt;The relationship of single-pass ranges to the question of &amp;ldquo;owning vs non-owning&amp;rdquo; is complicated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are often move-only types that cannot be copied (neither &lt;em&gt;O(1)&lt;/em&gt; nor &lt;em&gt;O(n)&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;It is difficult to argue if the elements are &amp;ldquo;owned&amp;rdquo; at all, since they are usually &amp;ldquo;produced&amp;rdquo; and &amp;ldquo;consumed&amp;rdquo; immediately; iterators to previous elements become invalid.&lt;/li&gt;
&lt;li&gt;It doesn&amp;rsquo;t make sense to borrow from single-pass ranges, because you can only have one valid iterator anyway.&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus I suggest keeping single-pass ranges as their own separate category, and will not cover them further in this blog post.&lt;sup id=&#34;fnref2:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;!--### Summary


| Range                   | Iterators  |                        |                      |
|-------------------------|------------|------------------------|----------------------|
| owning + multi-pass     | observing  | mutually independent   | lifetime-dependent   |
| borrowed + multi-pass   | observing  | mutually independent   | lifetime-independent |
| single-pass             | mutating   |interdependent/singular | (lifetime-dependent) |--&gt;
&lt;h2 id=&#34;c2x-standard-library&#34;&gt;C++2x Standard Library&lt;/h2&gt;
&lt;p&gt;C++20 is when &lt;em&gt;ranges&lt;/em&gt; actually became a thing, and the entire machinery including concepts and algorithms became part of the standard library.
But the significant new features that were introduced are &lt;em&gt;range adaptors&lt;/em&gt;.
Range adaptors are ranges that are created on top of other ranges,&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; typically exposing a subset of the underlying range or a transformation thereof.
See my &lt;a href=&#34;https://hannes.hauswedell.net/post/2019/11/30/range_intro/&#34; title=&#34;previous post&#34;&gt;previous post&lt;/a&gt; for an introduction.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;VIEW1 &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;VIEW2; &lt;span style=&#34;color:#75715e&#34;&gt;// non-owning multi-pass range adaptor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is what a typical &amp;ldquo;pipeline&amp;rdquo; looks like. It creates &lt;code&gt;v&lt;/code&gt; which is a range adaptor on &lt;code&gt;vec&lt;/code&gt;, applying the transformations implied by &lt;code&gt;VIEW1&lt;/code&gt; and &lt;code&gt;VIEW2&lt;/code&gt;.
While &lt;code&gt;std::string_view&lt;/code&gt; was mainly used for string literals and sub-strings, the operations we can now do are much more powerful and include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;filtering (e.g. &amp;ldquo;only non-space characters&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;transformations (e.g. &amp;ldquo;to upper case&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;splitting and joining (e.g. &amp;ldquo;split into words&amp;rdquo;, &amp;ldquo;join with different delimiter&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these adaptor have state, e.g. the filtering adaptor needs to store the predicate for filtering, and the joining adaptor needs to store the delimiter for joining; other adaptors have a cache.
This state can either be stored in the adaptor, or in the iterator(s) of the adaptor.
The former can save space in the iterator, but prevents the adaptor from being a borrowed range (the iterator needs to store a pointer to the adaptor to access the state).&lt;/p&gt;
&lt;h3 id=&#34;views-in-range-v3-and-original-c20&#34;&gt;Views in range-v3 and original C++20&lt;/h3&gt;
&lt;p&gt;The standard library ranges design is based on the &lt;a href=&#34;https://github.com/ericniebler/range-v3&#34;&gt;range-v3 library&lt;/a&gt; by Eric Niebler.
This library popularised the term &lt;em&gt;&lt;strong&gt;view&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;(Range-v3-)&lt;em&gt;&lt;strong&gt;Views&lt;/strong&gt;&lt;/em&gt; are defined as ranges that are copyable in &lt;em&gt;O(1)&lt;/em&gt;.
This definition for &amp;ldquo;non-owning&amp;rdquo; is broader than for &lt;em&gt;borrowed ranges&lt;/em&gt;; views can store state within the range, as long as it is in &lt;em&gt;O(1)&lt;/em&gt;.
Borrowed ranges are thus a subset of views.&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I will discuss below whether this additional flexibility is worth it, but it should be noted that—so far—the definition of view is still clear and primarily relates to ownership: it means &amp;ldquo;copyable in &lt;em&gt;O(1)&lt;/em&gt;&amp;rdquo;!
Note however that already at this point, &amp;ldquo;view&amp;rdquo; did not mean &amp;ldquo;range adaptor&amp;rdquo;.
Both range-v3 and early C++20 already contain standalone ranges that are also called &lt;em&gt;views&lt;/em&gt;, e.g. &lt;code&gt;std::ranges::iota_view&lt;/code&gt; and &lt;code&gt;std::ranges::empty_view&lt;/code&gt; (which are also copyable in constant time).&lt;/p&gt;
&lt;h3 id=&#34;views-post-p2415-current-state&#34;&gt;Views post P2415 (current state)&lt;/h3&gt;
&lt;p&gt;Just before C++20 landed, the committee accepted &lt;a href=&#34;https://wg21.link/p1456&#34;&gt;P1456&lt;/a&gt; which allowed views to be move-only&lt;sup id=&#34;fnref3:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and then, &lt;strong&gt;after&lt;/strong&gt; C++20 was released, &lt;a href=&#34;https://wg21.link/p2325&#34;&gt;P2325&lt;/a&gt; was applied as a defect report to C++20 which allows views to not be default-constructible.
I will discuss both of these in the next blog post.&lt;/p&gt;
&lt;p&gt;However, the most important (and controversial) change came by way of &lt;a href=&#34;https://wg21.link/p2415&#34;&gt;P2415&lt;/a&gt;, which allowed views to become owning ranges. It was also applied to C++20 as a defect report, although it was quite a significant design change.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; to_upper &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [] (&lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;toupper(c); };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* this has always been possible; v_indiri depends on s */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v_indiri &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;transform(to_upper);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* this is &amp;#34;new&amp;#34;; v_owning is standalone */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v_owning &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;move(s) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;transform(to_upper);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a useful feature, however, it resulted in the &lt;code&gt;std::ranges::view&lt;/code&gt; concept being changed to where it no longer means &amp;ldquo;non-owning range&amp;rdquo;.
While the concept still provides &lt;em&gt;some&lt;/em&gt; value in combination with other concepts,&lt;sup id=&#34;fnref4:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I don&amp;rsquo;t see it being used outside the standard library&amp;rsquo;s own view machinery.
In particular, I don&amp;rsquo;t think anybody uses it to constrain their algorithms, which generally is the whole point of a concept.&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Beyond these (im-)practical implications, there is a severe lack of clarity/teachability.
Since the previous definition was so widespread (and memorable), I still encounter experienced C++ programmers and even committee members who are surprised that view does not imply &amp;ldquo;non-owning range&amp;rdquo;.
Considering that &amp;ldquo;views&amp;rdquo; are one of the biggest selling points of C++ Ranges, not being able to explain what &amp;ldquo;view&amp;rdquo; means is a serious problem.&lt;/p&gt;
&lt;p&gt;But since it&amp;rsquo;s too late to &amp;ldquo;fix&amp;rdquo; the definition (and changing it again would likely just increase confusion), &lt;strong&gt;I suggest avoiding the term &amp;ldquo;view&amp;rdquo; altogether.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &amp;ldquo;range adaptor&amp;rdquo; to describe range types that operate on (or wrap) other ranges.&lt;/li&gt;
&lt;li&gt;Use &amp;ldquo;range adaptor object&amp;rdquo; to describe the objects that can be chained in pipelines to create &amp;ldquo;range adaptors&amp;rdquo;.&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Use &amp;ldquo;non-owning range&amp;rdquo; to denote a range that is copyable in O(1).&lt;/li&gt;
&lt;li&gt;Use &amp;ldquo;borrowed range&amp;rdquo; to denote a range that is copyable in O(1) and where the iterators can outlive the range.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-radr-library&#34;&gt;The RADR library&lt;/h2&gt;
&lt;blockquote&gt;
&lt;center&gt;
&lt;div class=&#34;gianttext&#34;&gt;
📡
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/h-2/radr&#34;&gt;https://github.com/h-2/radr&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;I have just made public my own experimental ranges library, called &amp;ldquo;ℝange 𝔸𝕕aptors ℝeimagined&amp;rdquo; (radr).&lt;/p&gt;
&lt;p&gt;It builds on C++20 concepts and algorithms but replaces &lt;code&gt;std::views::*&lt;/code&gt;—while offering very similar usage patterns.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Please check it out and provide feedback! I will only cover the design choices regarding ownership in this post, but it addresses numerous other issues, and more blog posts will follow. There is extensive documentation in the &lt;a href=&#34;https://github.com/h-2/radr/tree/main/docs&#34;&gt;docs-folder&lt;/a&gt; of the github repo.&lt;/p&gt;
&lt;h3 id=&#34;non-owning-range-adaptors&#34;&gt;Non-owning range adaptors&lt;/h3&gt;
&lt;p&gt;All non-owning (multi-pass) range adaptors in &lt;code&gt;radr&lt;/code&gt; are borrowed ranges.
This means that all functionality is implemented in terms of the iterator-sentinel-pair, and that the ranges store no further state.
The cost of this is an increase in iterator size, but it dramatically reduces overall complexity and provides a much simpler mental model to users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have one concept of &amp;ldquo;non-owning range&amp;rdquo;, not two. The view concept is entirely irrelevant in our library.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;borrowed range&amp;rdquo; definition is both the strongest and the most useful &amp;ldquo;non-owning range&amp;rdquo; definition.&lt;/li&gt;
&lt;li&gt;If you put a borrowed range into our range pipelines, you always get a borrowed range out (this is not true for &lt;code&gt;std::&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While I do believe that &amp;ldquo;borrowed range&amp;rdquo; is superior to even the old/range-v3 view concept, being able to avoid the new/confusing view concept was a major motivation for making &lt;code&gt;radr&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Finding the smallest non-negative number in a vector */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; non_neg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [] (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; it1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;min_element(vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;filter(non_neg));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// assert(*it == 1);   // broken, because filter_view is never borrowed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; it2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;min_element(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ref(vec) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; radr&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;filter(non_neg));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;it &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);      &lt;span style=&#34;color:#75715e&#34;&gt;// works, because all radr adaptors on lvalues are
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;p&gt;&lt;em&gt;This example highlights one of the practical advantages of the design choice.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;The syntax for creating an indirection in &lt;code&gt;radr::&lt;/code&gt; is explicit (it requires using &lt;code&gt;std::ref()&lt;/code&gt;; more on this in a future blog post), but otherwise the usage patterns (pipes etc) are identical to &lt;code&gt;std::&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The important difference is that the returned range always models &amp;ldquo;borrowed range&amp;rdquo;, so you can reliably re-use the iterators.
This is similar to how &lt;a href=&#34;https://www.boost.io/doc/libs/latest/libs/range/doc/html/index.html&#34;&gt;Boost range-v2&lt;/a&gt; designed their adaptors.
In the standard library, some adaptors return borrowed ranges, but many important ones like &lt;code&gt;filter&lt;/code&gt; do not.
Whether or not a specific adaptor does, is hard to predict for users.&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;In general, RADR tries to follow the example of &lt;code&gt;std::string_view&lt;/code&gt; for non-owning range adaptors. It has been around since C++17; people understand it; people like it.&lt;/p&gt;
&lt;h3 id=&#34;owning-range-adaptors&#34;&gt;Owning range adaptors&lt;/h3&gt;
&lt;p&gt;While P2415 is often criticised for introducing &amp;ldquo;owning views&amp;rdquo;, I don&amp;rsquo;t think having owning range adaptors is the problem (and can indeed be quite useful!).
The problem is that the definition of &amp;ldquo;view&amp;rdquo; was changed to also include &amp;ldquo;owning range adaptors&amp;rdquo;; thereby removing the basic, core part of its definition, i.e. being a non-owning range.&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;By all prior art, a range that manages the memory of its elements is a container. A range adaptor that wraps an rvalue of a container, thereby managing its memory including the elements… is also a container… because it contains the elements!
No concept is necessary to express this. The range concept by default implies that a range can have arbitrary ownership; the only things that needs to be modelled explicitly, are, whether a range is non-owning and if it is borrowed.&lt;/p&gt;
&lt;div class=&#34;two_columns&#34;&gt;
&lt;div padding-right=10px&gt;
&lt;p&gt;&lt;code&gt;std::&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* create adaptor on temporary */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; vue0 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;} &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* move existing */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; vue1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;move(vec) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;code&gt;radr::&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* create adaptor on temporary */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; rad0 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;} &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; radr&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* move existing */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; rad1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;move(vec) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; radr&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With respect to wrapping rvalues of containers, you can do the same things with &lt;code&gt;radr&lt;/code&gt; as with the standard library, and the syntax is identical.
But RADR considers the returned range a container, and you can copy it in &lt;em&gt;O(n)&lt;/em&gt;.&lt;sup id=&#34;fnref5:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2025/05/diagram0.svg#center&#34; alt=&#34;&#34; title=&#34;A diagram showing borrowed ranges as a subset of non-owning ranges which in turn are a subset of all (potentially owning) ranges. An arrow indicates the amount of managed state (in addition to the iterators).&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;There are owning and non-owning ranges, and borrowed ranges are a stricter version of the latter.
&amp;ldquo;View&amp;rdquo; used to be synonymous with &amp;ldquo;non-owning range&amp;rdquo;, but the view concept was redefined multiple times and is not useful by itself anymore. It is best to use other, unambiguous terms to describe ranges.
On the other hand, we have established &lt;em&gt;range adaptor&lt;/em&gt; as a term for ranges doing something on top of other ranges.
This is &lt;strong&gt;orthogonal to ownership&lt;/strong&gt;, i.e. the range adaptor can point to the underlying range—or wrap it.&lt;/p&gt;
&lt;p&gt;Two important design questions can be distilled from this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How are non-owning range adaptors implemented?
&lt;ul&gt;
&lt;li&gt;Are all/some/none of them borrowed?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Do we want owning range adaptors, and if so, how do we model those?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The standard library, like &lt;a href=&#34;https://github.com/ericniebler/range-v3&#34;&gt;range-v3&lt;/a&gt;, chooses to have some non-owning range adaptors that are borrowed, but most are not.
RADR, like &lt;a href=&#34;https://www.boost.io/doc/libs/latest/libs/range/doc/html/index.html&#34;&gt;Boost range-v2&lt;/a&gt;, chooses to make all non-owning range adaptors borrowed ranges.&lt;/p&gt;
&lt;p&gt;The standard library and RADR offer owning range adaptors while &lt;a href=&#34;https://www.boost.io/doc/libs/latest/libs/range/doc/html/index.html&#34;&gt;Boost range-v2&lt;/a&gt; and &lt;a href=&#34;https://github.com/ericniebler/range-v3&#34;&gt;range-v3&lt;/a&gt; do not.
Owning range adaptors in the standard library are a specific kind of view; in RADR they are simply containers.&lt;/p&gt;
&lt;p&gt;I did my best to break this complicated topic down, but I hope that I also explained that &amp;ldquo;views&amp;rdquo; being hard to explain is part of the problem.
The &lt;a href=&#34;https://github.com/h-2/radr&#34;&gt;radr library&lt;/a&gt; offers very similar features to std::views but tries to avoid some of the complexity.&lt;/p&gt;
&lt;!--It needs multiple concepts to model these types, as the following table illustrates:

| Library                 | borrowed range                |  non-owning range                             | (potentially owning) range |
|-------------------------|-------------------------------|-----------------------------------------------|----------------------------|
| range-v3                | `ranges::borrowed_range`      | `ranges::view`                                | `ranges::range`            |
| `std::`                 | `std::ranges::borrowed_range` | `std::ranges::view &amp;&amp; std::ranges::copyable`  | `std::ranges::range`       |
| `radr::`                | `std::ranges::borrowed_range` | `std::ranges::borrowed_range`                 | `std::ranges::range`       |

This table illustrates the concepts for the inclusive range categories shown in the above diagram.
While the standard library line is already the most complicated, trying to express exclusive categories like &#34;owning range&#34; already

| non-owning + !borrowed            |  &amp;&amp;`&lt;br&gt; `!std::ranges::borrowed_range`   | n/a  |
| owning                  | `!std::ranges::view ❘❘ !std::ranges::copyable`| `!std::ranges::borrowed_range` |



Most other libraries, such as [Boost range-v2](https://www.boost.io/doc/libs/latest/libs/range/doc/html/index.html) and [range-v3](https://github.com/ericniebler/range-v3)

1. Non-owning range adaptors are implemented as ranges that model `std::ranges::view` and that are copyable; this implies copyable-in-*O(1)*.
    * A subset of those ranges also models `std::ranges::borrowed_range` which guarantees the features discussed above.[^borrowed_view]
2. Owning range adaptors also model `std::ranges::view` but are marked as move-only. This is only done to differentiate them from non-owning range adaptors.



Other libraries give different answers. As mentioned, [range-v3](https://github.com/ericniebler/range-v3) does not have owning range adaptors, and their &#34;view&#34; means &#34;non-owning&#34;.
[Boost range-v2](https://www.boost.io/doc/libs/latest/libs/range/doc/html/index.html) also does not have owning range adaptors; all its non-owning range adaptors are implemented as borrowed ranges.--&gt;
&lt;!--
### Summary ownership in RADR

| Range                   | `std::`                                        |  `radr::`                      |
|-------------------------|------------------------------------------------|--------------------------------|
| non-owning + borrowed   | `std::ranges::borrowed_range`                  | `std::ranges::borrowed_range`  |
| non-owning + !borrowed            | `std::ranges::view &amp;&amp; std::ranges::copyable &amp;&amp;`&lt;br&gt; `!std::ranges::borrowed_range`   | n/a  |
| owning                  | `!std::ranges::view ❘❘ !std::ranges::copyable`| `!std::ranges::borrowed_range` |

`radr` chooses to make all non-owning ranges borrowed, so there is exactly one concept we use to differentiate owning and non-owning (multi-pass) ranges: `std::ranges::borrowed_range`.
This is very simple, if you compare this to the standard library which uses three different concepts and needs a combination of at least two concepts to express ownership.--&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;We will explore this in more depth in the next blog post.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref2:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref3:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref4:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref5:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Most containers store their elements on the heap, but &lt;code&gt;std::array&lt;/code&gt; and C++26&amp;rsquo;s &lt;code&gt;std::inplace_vector&lt;/code&gt; store on the stack. &lt;code&gt;std::string&lt;/code&gt; is a special case, because small strings are stored on the stack and bigger ones on the heap. However, both cases lead to undefined behaviour.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;em&gt;Actually,&lt;/em&gt; &lt;code&gt;std::ranges::min_element&lt;/code&gt; is smart enough to know that the iterator would dangle and returns &lt;code&gt;std::ranges::dangling&lt;/code&gt; instead. This prevents undefined behaviour, but it also results in us not getting the smallest character.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Or a &lt;code&gt;begin&lt;/code&gt; + size, which is equivalent.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Subsequent blog posts will explain that you cannot have a &amp;ldquo;read-only&amp;rdquo; borrow on a single-pass range, because single-pass ranges are not const-iterable. In addition, having a mutable borrow on a single-pass range provides no benefits over just passing the range itself; you cannot use the range anymore once you have borrowed from it.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;There is some ambiguity as to whether &amp;ldquo;range adaptor&amp;rdquo; refers to the returned type (e.g. specialisations of &lt;code&gt;std::ranges::reverse_view&amp;lt;&amp;gt;&lt;/code&gt;) or the thing that creates the type (e.g. &lt;code&gt;std::views::reverse&lt;/code&gt;) or both. I use &amp;ldquo;range adaptor&amp;rdquo; to refer to the type and &amp;ldquo;range adaptor object&amp;rdquo; to refer to the object used in a pipeline. The same ambiguity exists for &amp;ldquo;view&amp;rdquo;, as will be discussed later.&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;If one follows the standard very literally, borrowed ranges are &lt;em&gt;not&lt;/em&gt; required to &lt;em&gt;not&lt;/em&gt; have any state. However, since a borrowed forward range&amp;rsquo;s iterators are copyable in &lt;em&gt;O(1)&lt;/em&gt; and they are completely independent of the range, one could simply take the iterators and make a new range out of them (that would then be copyable in &lt;em&gt;O(1)&lt;/em&gt;).&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;Eric Niebler, the father of C++ Ranges, once said: &lt;em&gt;»Generic Programming pro tip: Although Concepts are constraints on types, you don&amp;rsquo;t find them by looking at the types in your system. You find them by studying the algorithms.«&lt;/em&gt; People not using the concept, suggests that it is not useful. It is also noteworthy that this change was not back-ported into range-v3.&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;Boost ranges calls these &amp;ldquo;range adaptor generator&amp;rdquo;, but the term &amp;ldquo;generator&amp;rdquo; is now associated with single-pass ranges.&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;Recently, papers such as &lt;a href=&#34;https://wg21.link/P3117&#34;&gt;P3117&lt;/a&gt; have suggested more range adaptors should have been made borrowed.&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;To be fair, the options were quite limited since P2415 was introduced so late (after C++20 was released).&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded>
    </item>
    
    <item>
      <title>A fast fileserver with FreeBSD, NVMEs, ZFS and NFS</title>
      <link>https://hannes.hauswedell.net/post/2024/04/26/fileserver/</link>
      <pubDate>Fri, 26 Apr 2024 16:30:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2024/04/26/fileserver/</guid>
      <description>&lt;p&gt;I have a small server running in my flat that serves files locally via NFS and remotely via Nextcloud. This post documents
the slightly overpowered upgrade of the hardware and subsequent performance / efficiency optimisations.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have a small server running in my flat that serves files locally via NFS and remotely via Nextcloud. This post documents
the slightly overpowered upgrade of the hardware and subsequent performance / efficiency optimisations.&lt;/p&gt;
&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I can fully saturate a 10Gbit LAN connection, achieving more than 1100 MiB/s throughput.&lt;/li&gt;
&lt;li&gt;I can perform a &lt;code&gt;zpool scrub&lt;/code&gt; with 11 GiB/s, completing a 6.8TiB scrub in 11min.&lt;/li&gt;
&lt;li&gt;Idle power usage can be brought down to 34W.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;old-setup-and-requirements&#34;&gt;Old setup and requirements&lt;/h2&gt;
&lt;p&gt;What the server does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serve files via NFS to
&lt;ul&gt;
&lt;li&gt;my workstation (high traffic)&lt;/li&gt;
&lt;li&gt;a couple of Laptops (low traffic)&lt;/li&gt;
&lt;li&gt;the TV running Kodi (medium traffic)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Host a Nextcloud which provides file storage, PIM etc. for a handful of people&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not a lot of compute is necessary, and I have tried to keep power usage low. The old hardware served me well really long:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD 630 CPU&lt;/li&gt;
&lt;li&gt;16GiB RAM&lt;/li&gt;
&lt;li&gt;2+1 * 4TiB spinning disk RAIDZ1 with SSD ZIL (&amp;ldquo;write-cache&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main pain point was slow disk access resulting in poor performance when large files were read by the Nextcloud.
Browsing through my photo collection via NFS was also very slow, because thumbnail generation needed to pull all the images.
Furthermore, low speed meant that I was not doing as much on the remote storage as I would have liked (e.g. storing
games), resulting in my workstation&amp;rsquo;s storage always running out.
&lt;em&gt;And&lt;/em&gt; I was just reaching the limits of my ZFS pool anyway, so it was time for an upgrade!&lt;/p&gt;
&lt;h2 id=&#34;new-setup&#34;&gt;New setup&lt;/h2&gt;
&lt;p&gt;To get better I/O, I thought about switching from HDD to SSD, but then realised that SSD performance is very low compared
to NVME performance, although the price difference is not that much. Also, NFS+ZFS leads to quite a bit of I/O, typically
requiring the use of faster caching devices, further complicating the setup.
Consequently, I decided to go for a pure NVME setup.
Of course, the new server would also need 10GBit networking, so that I can use all that speed in the LAN!&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2024/04/stuff.jpg#center&#34; alt=&#34;&#34; title=&#34;The new hardware.&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;This is the new hardware! I will discuss the details below.&lt;/p&gt;
&lt;h2 id=&#34;mainboard-cpu-and-ram&#34;&gt;Mainboard, CPU and RAM&lt;/h2&gt;
&lt;p&gt;The main requirement for the mainboard is to offer connectivity for four NVME disks. And to be prepared for the future,
I would actually like 1-2 extra NVME slots.
There are two ways to attach NVMEs to a motherboard:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;directly (&amp;ldquo;natively&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;via an extension card that is plugged into a PCIexpress slot&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Initially, I had assumed no mainboard would offer sufficient native slots, so I did a lot of research on option 2.
The summery: it is quite messy. If you want to use a single extension card that hosts multiple NVMEs (which is required
in this case), you need so called &amp;ldquo;bifurcation support&amp;rdquo; on the mainboard.
This lets you e.g. put a PCIe x8 card with two NVME 4x disks into a PCIe 8x slot on the mainboard.
However, this feature is really poorly documented,&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and and varies between mainboard &lt;strong&gt;AND&lt;/strong&gt; CPU whether they
support no bifurcation, only 8x → 4x4x or also 16x → 4x4x4x4x.
The different PCIe versions and speeds, and the difference between the actually supported speed and the electrical
interface add further complications.&lt;/p&gt;
&lt;p&gt;In the end, I decided to not do any experiments and look for a board that natively supports a high number of NVME slots.
For some reasons, this feature is very rare on AMD mainboards, so I switched to Intel (although actually I am a bit of
an AMD fanboy). I probably could have gone with a board that has 5 slots, but I use hardware for a long time and wanted
to be safe, so I took board that has 6 NVME slots (2 free slots):&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2024/04/board2.png#center&#34; alt=&#34;&#34; title=&#34;ASRock Z790 NOVA WiFi.&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://geizhals.de/asrock-z790-nova-wifi-90-mxbmb0-a0uayz-a3045663.html&#34;&gt;ASRock Z790 NOVA WiFi&lt;/a&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;None of the available boards had a &lt;em&gt;proper&lt;/em&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; 10GBit network adaptor, so having a usable PCIe slot for a dedicated card
was also a requirement.
It is important to check whether PCIe slots can still be used when all NVME slots are occupied; sometimes they
internally share the bandwidth. But for the above board this is not the case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; To be able to boot FreeBSD on this board, you need to add the following to &lt;code&gt;/boot/device.hints&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hint.uart.0.disabled&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hint.uart.1.disabled&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the CPU, I just went with something on the low TDP end of the current Intel CPU range, the &lt;a href=&#34;https://geizhals.de/intel-core-i3-12100t-cm8071504651106-a2660333.html&#34;&gt;Intel Core i3-12100T&lt;/a&gt;.
Four cores + four threads was exactly what I was looking for, and 35W TDP sounded good.
I paired that with some off-the-shelf &lt;a href=&#34;https://geizhals.de/patriot-viper-venom-dimm-kit-32gb-pvv532g600c36k-a2724586.html&#34;&gt;32GiB RAM kit&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;case-power-supply--cooling&#34;&gt;Case, power supply &amp;amp; cooling&lt;/h2&gt;
&lt;p&gt;Strictly speaking a 2U case would have been sufficient, but I thought a 3U case might offer better air circulation.
I ended up with the &lt;a href=&#34;https://geizhals.de/gembird-19cc-3u-01-a1552078.html&#34;&gt;Gembird 19CC-3U-01&lt;/a&gt;.
For unknown reasons, I chose a &lt;a href=&#34;https://www.amazon.de/dp/B0BTPH45QS&#34;&gt;2U horizontal CPU fan&lt;/a&gt;, instead of a 3U one.
The latter would definitely have provided better airflow, but since the fan barely runs at all, it doesn&amp;rsquo;t make much of
a difference.&lt;/p&gt;
&lt;p&gt;I was unsuccessful in finding a good PSU that is super efficient in the average case of around 40W power usage but also
covers spikes well above 100W, so I just chose the cheapest 300W one I could get :)&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2024/04/case.jpg#center&#34; alt=&#34;&#34; title=&#34;The case with everything in place.&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The case with everything in place.&lt;/em&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;The built in fans are very noisy. I chose to replace one of the intake fans with a spare one I had lying around and
only connect one of the rear outtake fans. But I added an extra fan where the extension slots are to divert some
airflow around the NIC—which otherwise gets quite warm. This should also blow some air over the NVME heatsinks!
All fans can be regulated and fine-tuned from the BIOS of the mainboard which I totally recommend you do. At the current
temperatures and average workloads the whole setup is almost silent.&lt;/p&gt;
&lt;h2 id=&#34;storage&#34;&gt;Storage&lt;/h2&gt;
&lt;p&gt;Now, the fun begins. Since I needed more space than before, I clearly want a 3+1 x 4TiB RAIDZ1.&lt;/p&gt;
&lt;p&gt;My goal was to be able to saturate a 10GBit connection (so get around 1GiB/s throughput) and still
have the server be able to serve the Nextcloud without slowing down significantly. Currently the WAN upload is quite
slow, but I hope to have fibre in the future. In any case, I thought that any modern NVME should be fast enough, because
they all advertise speeds of multiple GiB/s.&lt;/p&gt;
&lt;h3 id=&#34;choice-of-disks&#34;&gt;Choice of disks&lt;/h3&gt;
&lt;p&gt;Anyway, I got two &lt;a href=&#34;https://geizhals.de/crucial-p3-plus-ssd-4tb-ct4000p3pssd8-a2761835.html&#34;&gt;Crucial P3 Plus 4TB&lt;/a&gt; (which were on sale at Amazon for ~190€), as well as two &lt;a href=&#34;https://geizhals.de/lexar-nm790-4tb-lnm790x004t-rnnn-a2980705.html&#34;&gt;Lexar NM790 4TB&lt;/a&gt; (which were also a lot cheaper than they are now).
My assumption that that they were very comparable, was very wrong:&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Disk&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS rand-read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&amp;ldquo;cat speed&amp;rdquo; MB/s&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Crucial&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;53,500&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;794,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;455,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,600&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,983&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;~700&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Lexar&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;53,700&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;796,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;456,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,578&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5,737&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;~2,700&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;I used &lt;a href=&#34;https://forums.servethehome.com/index.php?threads/nfs-iops-performance-on-freebsd-nvme-storage.30960/&#34;&gt;this fellow&amp;rsquo;s fio-script&lt;/a&gt; to
generate all columns except the last. The last column was generated by simply cat&amp;rsquo;ing a 10GiB file of random numbers to &lt;code&gt;/dev/null&lt;/code&gt; which
roughly corresponds to the read portion of copying a 4k movie file.
Since I had two disks each, I actually took the time to test all of them in different mainboard slots, but the results
were very consistent: in real-life tasks, the Crucial disk underperformed significantly, while the Lexar disks were
super fast.
I decided to return the Crucial disks and get two more by Lexar 😎&lt;/p&gt;
&lt;h3 id=&#34;disk-encryption&#34;&gt;Disk encryption&lt;/h3&gt;
&lt;p&gt;I always store my data encrypted at rest. FreeBSD offers GELI block-level encryption (similar to LUKS on Linux).
But OpenZFS also provides a dataset/filesystem-level encryption since a while.
I previously used GELI, but I wanted to switch to ZFS native encryption, because it provides some advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flexibility: I can choose later which datasets to encrypt; I can encrypt different datasets with different keys.&lt;/li&gt;
&lt;li&gt;Zero-knowledge backups: I can send incremental backups off-site that are received and fully integrated into the target
pool &lt;em&gt;without that server ever getting the decryption keys.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Forward-compatibility: I can upgrade to better encryption algorithms later.&lt;/li&gt;
&lt;li&gt;Linux-compatibility: I can import the existing pool in a Linux environment for debugging or benchmarking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, I had also heard that ZFS native encryption was slower, so I decided to do some benchmarks:&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Disk&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS rand-read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&amp;ldquo;cat speed&amp;rdquo; MB/s&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;no encryption&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;54,700&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;809,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;453,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,796&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5,868&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,732&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;geli-aes-256-xts&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;40,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;793,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;446,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,332&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,334&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;952&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;zfs-enc-aes-256-gcm&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;26,100&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;513,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;285,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,871&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,648&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,638&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;zfs-enc-aes-128-gcm&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;29,300&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;532,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;353,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,971&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,794&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,631&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;Interestingly, GELI&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; performs much better on the IOPS, but much worse on throughput, especially on our real-life test
case. Maybe some smart person knows the reason for this, but I took this benchmark as an assurance that going with
native encryption was the right choice.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; One reason for the good performance of the native encryption seems
to be that it makes use of the CPU&amp;rsquo;s avx2 extensions.&lt;/p&gt;
&lt;p&gt;At this point, I feel like I do need to warn people about some ZFS encryption related issues that I learned about later.
&lt;a href=&#34;https://github.com/openzfs/openzfs-docs/issues/494&#34;&gt;&lt;strong&gt;Please read this&lt;/strong&gt;&lt;/a&gt;. I have had no problems to date, but make
up your own mind.&lt;/p&gt;
&lt;h3 id=&#34;raidz1&#34;&gt;RaidZ1&lt;/h3&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;recordsize&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;compr.&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;encrypt&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS rand-read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&amp;ldquo;cat speed&amp;rdquo; MB/s&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;128 KiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;50,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;869,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;418,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,964&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5,745&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,019&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;128 KiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;on&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;49,800&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;877,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;458,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,929&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4,654&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1,448&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;128 KiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;aes128&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;26,300&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;484,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;230,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,589&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5,331&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,142&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;128 KiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;on&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;aes128&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;27,400&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;501,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;228,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,510&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,927&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,120&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;These are the numbers after creation of the RAIDZ1 based pool. They are quite similar to the numbers measured before.
The impact of encryption on IOPS is clearly visible, less so on sequential read/write throughput.
Compression seems to impact write throughput but not read throughput which is expected for &lt;code&gt;zstd&lt;/code&gt;. It is unclear why
&amp;ldquo;cat speed&amp;rdquo; is lower here.&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;recordsize&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;compr.&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;encrypt&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS rand-read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&amp;ldquo;cat speed&amp;rdquo; MB/s&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1 MiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;7,235&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;730,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;404,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,686&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,548&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,142&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1 MiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;on&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;7,112&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;800,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;470,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,624&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,447&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,064&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1 MiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;off&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;aes128&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,259&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;497,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;258,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,029&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,422&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,227&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1 MiB&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;on&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;aes128&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,697&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;506,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;249,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,137&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3,361&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2,237&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;Many optimisation guides suggest setting the zfs &lt;code&gt;recordsize&lt;/code&gt; to 1 MiB for most use-cases, especially storage of media
files.
But this seems to drastically penalise random read IOPS while providing little to no benefit in the sequential
read/write scenarios. This is actually a bit surprising and I will need to investigate this more.
Is it perhaps because NVMEs are good at parallel access and therefor suffer less from fragmentation anyway?&lt;/p&gt;
&lt;p&gt;In any case, the main take away message is that overall read and
write throughputs are over 3,000 MiB/s in the synthetic case and over 2,000 MiB/s in the manual case, which is great.&lt;/p&gt;
&lt;h3 id=&#34;other-disk-performance-metrics&#34;&gt;Other disk performance metrics&lt;/h3&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Operation&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Speed [MiB/s]&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Copying 382 GiB between two datasets (both enc+comp)&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1,564&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Copying 505 GiB between two datasets (both enc+comp)&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;800&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;zfs scrub&lt;/code&gt; of the full pool&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;11,000&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;These numbers further illustrate some real world use-cases. It&amp;rsquo;s interesting to see the difference between the
first two, but it&amp;rsquo;s also important to keep in mind that this is reading and writing at the same time.
Maybe some internal caches are exhausted after a while? I didn&amp;rsquo;t debug these numbers further, but I think the speed is
quite good after such a long read/write.&lt;/p&gt;
&lt;p&gt;More interesting is the speed for scrubbing, and, yes, I have checked this a couple of times. A scrub of 6.84TiB
happens in 10m - 11m, which is pretty amazing, I think, considering that it is reading the data &lt;em&gt;and&lt;/em&gt; calculating
checksums. I am assuming that sequential read is just very fast and that access to the different disks happens in
parallel. The checksum implementation is apparently also avx2 optimised.&lt;/p&gt;
&lt;h2 id=&#34;lan&#34;&gt;LAN&lt;/h2&gt;
&lt;h3 id=&#34;network-adapter&#34;&gt;Network adapter&lt;/h3&gt;
&lt;p&gt;Based on recommendations, I decided to buy an Intel card. Cheaper 10GBit network cards are available from
Marvell/Aquantia, but the driver support in FreeBSD is poor, and the performance is supposedly also not close
to that of Intel.&lt;/p&gt;
&lt;p&gt;Many people suggested I go for SFP+ (fibre) instead of
10GBase-T (copper), but I already have CAT7 cables in my flat. While I could have used fibre purely for connecting
the server to the switch (and this would likely save some power), I would have had to buy a new switch and
the options were just not economical—I already have
a switch with two 10GBase-T ports which I had bought for exactly this setup.&lt;/p&gt;
&lt;p&gt;The cheapest Intel 10GBase-T card out there is the X540 which is quite old and available on Amazon for around 80€.
I bought two of those (one for the server and one for the workstation). More modern cards are supposedly more energy
efficient, but also a lot more expensive.&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&#34;nfs-performance&#34;&gt;NFS Performance&lt;/h3&gt;
&lt;p&gt;On server and client, I set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kern.ipc.maxsockbuf=4737024&lt;/code&gt; in &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mtu 9000 media 10gbase-t&lt;/code&gt; in the &lt;code&gt;/etc/rc.conf&lt;/code&gt; (ifconfig)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only on the server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nfs_server_maxio=&amp;quot;1048576&amp;quot;&lt;/code&gt; in &lt;code&gt;/etc/rc.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only on the client:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nfsv4,nconnect=8,readahead=8&lt;/code&gt; as the mount options for the nfs mount.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vfs.maxbcachebuf=1048576&lt;/code&gt; in &lt;code&gt;/boot/loader.conf&lt;/code&gt;  (not sure any more if this makes a difference).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These settings allow larger buffers and increase the amount of readahead. This favours large sequential reads/writes over small random reads/writes.&lt;/p&gt;
&lt;p&gt;The full options on the client end up being:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# nfsstat -m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;X.Y.Z.W:/ on /mnt/server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nfsv4,minorversion=2,tcp,resvport,nconnect=8,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=1048576,wsize=1048576,readdirsize=1048576,readahead=8,wcommitsize=16777216,timeout=120,retrans=2147483647
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I use NFS4 for my workstation and NFS3 for everyone else. I have performed no benchmarks on NFS3, but I see no reason
why it would be slower.&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS rand-read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;IOPS write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s read&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;MB/s write&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&amp;ldquo;cat speed&amp;rdquo; MB/s&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;283&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;292,000&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;33,200&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1,156&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;594&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1,164&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;This benchmark was performed on a dataset with 1M recordsize, encryption, but no compression.
Random read IOPS are pretty bad, and I see a strong correlation here to the &lt;code&gt;rsize&lt;/code&gt; (if I halve it, I double the IOPS; not shown in table).
It&amp;rsquo;s possible that every 4KiB read actually triggers a 1MiB read in NFS which would explain this.
On the other hand, the sequential read and write performance is pretty good with synthetic and real world read speeds
being very close to the theoretical maximum of the 10GBit connection.&lt;/p&gt;
&lt;p&gt;One thing to keep in mind: The blocksize when reading has a very strong impact on the performance. This
can be seen when using &lt;code&gt;dd&lt;/code&gt; with different &lt;code&gt;bs&lt;/code&gt; arguments. Of course, 1MiB is optimal if that is also used by NFS, and
&lt;code&gt;cat&lt;/code&gt; seems to do this. However, &lt;code&gt;cp&lt;/code&gt; does not which results in a much slower performance than if using &lt;code&gt;dd if=.. of=.. bs=1M&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have done measurements with plain &lt;code&gt;nc&lt;/code&gt; over the wire (also reaching 1,160 MiB/s) and &lt;code&gt;iperf3&lt;/code&gt; which achieves 1,233 MiB/s just below the 1,250 MiB/s equivalent of 10Gbit.&lt;/p&gt;
&lt;h2 id=&#34;power-consumption-and-thermals&#34;&gt;Power consumption and thermals&lt;/h2&gt;
&lt;p&gt;For a computer running 24/7 in my flat, power consumption is of course important. I bought a device to measure
power consumption at the outlet to get an accurate picture.&lt;/p&gt;
&lt;h3 id=&#34;idle&#34;&gt;idle&lt;/h3&gt;
&lt;p&gt;Because the computer is idle most of the time, optimising idle power usage is most important.&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Change&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;W/h&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;default&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;50&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;*_cx_lowest=&amp;quot;Cmax&amp;quot;&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;45&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;disable WiFi and BT&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;42&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;media 10gbase-t&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;45&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;machdep.hwpstate_pkg_ctrl=0&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;41&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;turn on chassis fans&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;42&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;ASPM modes to L0s+L1 / enabled&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;34&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;I assume that the same setup on Linux would be slightly more efficient, but 34W in idle is acceptable.&lt;/p&gt;
&lt;p&gt;Clearly, the most impactful changes were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Activating &lt;a href=&#34;https://en.wikipedia.org/wiki/Active_State_Power_Management&#34;&gt;ASPM&lt;/a&gt; for the PCIe devices in the BIOS.&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;performance_cx_lowest=&amp;quot;Cmax&amp;quot;&lt;/code&gt; and &lt;code&gt;economy_cx_lowest=&amp;quot;Cmax&amp;quot;&lt;/code&gt; to &lt;code&gt;/etc/rc.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;machdep.hwpstate_pkg_ctrl=0&lt;/code&gt; to &lt;code&gt;/boot/loader.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can find online resources on what these options do. You might need to update the BIOS to be able to disable
WiFi and Bluetooth devices completely. You can also use hints in the &lt;code&gt;/boot/device.hints&lt;/code&gt;, but this doesn&amp;rsquo;t save
as much power.&lt;/p&gt;
&lt;p&gt;Using 10GBase-T speed on the network device (instead of 1000Base-T) unfortunately increases power usage notably, but
there is nothing I could find to mitigate this.&lt;/p&gt;
&lt;p&gt;Things that are often recommended but that did not help me (at least not in idle):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NVME power states (more on this below)&lt;/li&gt;
&lt;li&gt;lower values for &lt;code&gt;sysctl dev.hwpstate_intel.*.epp&lt;/code&gt; (more on this below)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hw.pci.do_power_nodriver=3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;idle temperatures&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;°C&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;CPU&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;37-40&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;NVMEs&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;52-55&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;The latter was particularly interesting, because I had heard that newer NVMEs, and especially those by Lexar get
very warm. It should be noted though, that the mainboard comes with a large heatsink that covers all NVMEs.&lt;/p&gt;
&lt;h3 id=&#34;under-load&#34;&gt;under load&lt;/h3&gt;
&lt;p&gt;The only &amp;ldquo;load test&amp;rdquo; that I performed was a scrub of the pool.
Since this puts stress on the NVMEs and also the CPUs, it should be at least indicative of how things are going.&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;during &lt;code&gt;zpool scrub&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;°C&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;CPU&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;55-59&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;NVMEs&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;69-75&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;The power usage fluctuates &lt;strong&gt;between 85W and 98W.&lt;/strong&gt; I think all of these values are acceptable.&lt;/p&gt;
&lt;!--#### NVME tuning--&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;NVME power state hint&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;scrub speed GiB/s&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;W/h&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;0 (default)&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;11&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&amp;lt; 100&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;8&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&amp;lt; 93&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&amp;lt; 70&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;You can use &lt;code&gt;nvmecontrol&lt;/code&gt; to tell the NVME disks to save energy. More information on this &lt;a href=&#34;https://nvmexpress.org/resource/technology-power-features/&#34;&gt;here&lt;/a&gt;
and &lt;a href=&#34;https://www.truenas.com/community/threads/nvme-autonomous-power-state-transition-apst-not-working-in-core-works-in-scale.113947/&#34;&gt;here&lt;/a&gt;.
I was surprised that all of this works reliably on FreeBSD, but it does! The man-page is not great though. Simply
call &lt;code&gt;nvmecontrol power -p X nvmeYns1&lt;/code&gt; to set the hint to X on device Y, if desired. Note that this needs to be repeated after
every reboot.&lt;/p&gt;
&lt;!--#### CPU tuning--&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;&lt;code&gt;dev.hwpstate_intel.*.epp&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;scrub speed GiB/s&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;W/h&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;50 (default)&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;11.0&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&amp;lt; 100&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;100&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3.3&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&amp;lt; 60&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;You can use the &lt;code&gt;dev.hwpstate_intel.*.epp&lt;/code&gt; sysctls for you cores to tune the eagerness of that core to scale up with
higher number meaning less eagerness.&lt;/p&gt;
&lt;!--#### Summary--&gt;
&lt;p&gt;In the end, &lt;strong&gt;I decided not to apply any of these &amp;ldquo;under load optimisations&amp;rdquo;.&lt;/strong&gt;
It is just very difficult, because, as shown, all optimisations that reduce watts per time also increase time.
I am not certain of any good ways to quantify this, but it feels like keeping the system at 70W for 30min instead of 100W for 10min, is not really worth it.
And I kind of also want the system to be fast, that&amp;rsquo;s why I spent so much money on it 🙃&lt;/p&gt;
&lt;p&gt;The CPU does have a cTDP mode that can be activated via the BIOS and which is &amp;ldquo;worth it&amp;rdquo;, according to some articles
I have read. I might give this a try in the future.&lt;/p&gt;
&lt;h2 id=&#34;final-remarks&#34;&gt;Final remarks&lt;/h2&gt;
&lt;p&gt;What a ride! I spent a lot of time optimising and benchmarking this and I am quite happy with the outcome.
I am able to exhaust the 10GBit LAN connection completely, and still have resources left on the server :)&lt;/p&gt;
&lt;p&gt;Thanks to the people at &lt;a href=&#34;https://www.bsdforen.de&#34;&gt;www.bsdforen.de&lt;/a&gt; who had quite a few helpful suggestions.&lt;/p&gt;
&lt;p&gt;If you see anything that I missed, or have suggestions on how to improve this setup, let me know in the comments!&lt;/p&gt;
&lt;h2 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h2&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;With ASUS being &lt;a href=&#34;https://www.asus.com/de/support/faq/1037507/&#34;&gt;the only exception&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;em&gt;Proper&lt;/em&gt; in this context means well-supported by FreeBSD and with a good performance.
Usually, that means an Intel NIC. Unfortunately all the modern boards come Marvell/Aquantia AQtion adaptors which
are not well-supported by FreeBSD.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;The geli device was created with: &lt;code&gt;geli init -b -s4096 -l256&lt;/code&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;I wanted to perform all these tests with Linux as well, but I ran out of time 🙈&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;I did try a slightly more more modern adapter with Intel 82599EN chip. This is a SFP+ chip, but I found an
adaptor with built-in 10GBase-T for around 150€. It ended up having some driver issues (you needed to plug and unplug
the CAT cable for the device to go UP), and it used more energy than the X540, so I sent it back.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded>
    </item>
    
    <item>
      <title>🌓 Commandline dark-mode switching for Qt, GTK and websites 🌓</title>
      <link>https://hannes.hauswedell.net/post/2023/12/10/darkmode/</link>
      <pubDate>Sun, 10 Dec 2023 16:30:00 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2023/12/10/darkmode/</guid>
      <description>&lt;p&gt;This post documents how to toggle your entire desktop between light and dark themes, including your apps
and the websites in your browser.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;This post documents how to toggle your entire desktop between light and dark themes, including your apps
and the websites in your browser.&lt;/p&gt;
&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Like many other people, I use my computer(s) with varying degrees of ambient light. When there is lots of light,
I want a bright theme, but in the evenings, I prefer a dark theme. Switching this for Firefox and several toolkits
manually almost drove me crazy, so I will document here how I automated the entire process.&lt;/p&gt;
&lt;p&gt;I use the Sway window manager which makes things a bit more difficult, because neither the UI unification mechanisms
of GNOME nor KDE automatically kick in.
I use Firefox as a browser, and I also want the websites to switch themes.
And of course, I want the theme switch to be applied immediately and not just on restartet apps.&lt;/p&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&lt;video autoplay=&#34;true&#34; loop&gt;
  &lt;source src=&#34;https://hannes.hauswedell.net/post/2023/12/video_small.webm&#34; type=&#34;video/webm&#34;&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;This is what it looks like when it&amp;rsquo;s done. Dolphin (KDE5), Firefox, the website inside Firefox, and GEdit (GTK) all switch together.&lt;/p&gt;
&lt;h2 id=&#34;primary-script&#34;&gt;Primary script&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;gsettings get org.gnome.desktop.interface color-scheme&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;current&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;prefer-dark&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Switching to dark.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface color-scheme prefer-dark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface gtk-theme Adwaita-dark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface icon-theme breeze-dark
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# already dark&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Switching to light.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface color-scheme default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface gtk-theme Adwaita
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    gsettings set org.gnome.desktop.interface icon-theme breeze
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the primary script. It works by manipulating the gsettings, so we will have to make everything else follow these settings.
The script operates in a toggle-mode, i.e. running it repeatedly switches between light and dark.
I had hoped that the color-scheme preference would be the only thing needing change, but the gtk-theme needs to
also be switched explicitly.
I am not aware of any theme other than Adwaita that works on all toolkits.&lt;/p&gt;
&lt;p&gt;Switching the icon-theme is not necessary, but recommended. To get a list of installed icon themes,
&lt;code&gt;ls /usr/share/icons&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;packages&#34;&gt;Packages&lt;/h2&gt;
&lt;p&gt;This is the list of packages I installed on Ubuntu 23.10. Note that if you miss certain packages, things will not work
without telling you why. I started this install with a Kubuntu ISO, so depending on your setup, you might need
to install more packages, e.g. &lt;code&gt;libglib2.0-bin&lt;/code&gt; provides the &lt;code&gt;gsettings&lt;/code&gt; binary.&lt;/p&gt;
&lt;p&gt;Package list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;libadwaita                  &lt;span style=&#34;color:#75715e&#34;&gt;# GTK3 theme (auto-installed)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adwaita-qt                  &lt;span style=&#34;color:#75715e&#34;&gt;# Qt5 theme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adwaita-qt6                 &lt;span style=&#34;color:#75715e&#34;&gt;# Qt6 theme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gnome-themes-extra          &lt;span style=&#34;color:#75715e&#34;&gt;# GTK2 theme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gnome-themes-extra-data     &lt;span style=&#34;color:#75715e&#34;&gt;# GTK2 theme and GTK3 dark theme support&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qgnomeplatform-qt5          &lt;span style=&#34;color:#75715e&#34;&gt;# Needed to tell Qt5 and KDE to use gsettings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#qgnomeplatform-qt6         # If your distro has it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am not exactly sure where the GTK4 theme comes from, and I have no app to test that. If you want to use the breeze
icon theme, also install &lt;code&gt;breeze-icon-theme&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;h3 id=&#34;gtk-apps&#34;&gt;GTK apps&lt;/h3&gt;
&lt;p&gt;You should already be able to switch GTK apps by running the script. Give it a try!&lt;/p&gt;
&lt;h3 id=&#34;firefox-app&#34;&gt;Firefox app&lt;/h3&gt;
&lt;p&gt;Firefox should also switch its own theme after invoking the script. If it does not, check the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your XDG session is treated by Firefox as being GNOME or something similiar.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;about:addons&lt;/code&gt;, then &amp;ldquo;Themes&amp;rdquo; and make sure you have selected &amp;ldquo;System-Theme (automatic)&amp;rdquo;. &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;about:support&lt;/code&gt; and look for &amp;ldquo;Windows Protocol&amp;rdquo;. It should list &lt;code&gt;wayland&lt;/code&gt;. If it does not, restart your Firefox with &lt;code&gt;MOZ_ENABLE_WAYLAND=1&lt;/code&gt; set in the environment.&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;about:support&lt;/code&gt; and look for &amp;ldquo;Operating System theme&amp;rdquo;. It should list &lt;code&gt;Adwaita / Adwaita&lt;/code&gt;. If it does not, you are likely missing some crucial packages.&lt;/li&gt;
&lt;li&gt;Double-check the &lt;code&gt;gnome-themes-extra&lt;/code&gt; or similar packages on your distro. I didn&amp;rsquo;t have these initially and it prevented Firefox from picking up the theme.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven&amp;rsquo;t tried any of this with Chromium, but I might at some point in the future.&lt;/p&gt;
&lt;h3 id=&#34;firefox-websites&#34;&gt;Firefox (websites)&lt;/h3&gt;
&lt;p&gt;Next are the websites &lt;em&gt;inside&lt;/em&gt; Firefox. Make sure your Firefox propagates its own theme settings to its websites:&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2023/12/website_theme.png#center&#34; alt=&#34;&#34; title=&#34;This can be found in your settings.&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Websites like &lt;a href=&#34;https://google.com&#34;&gt;https://google.com&lt;/a&gt; should now respect your system&amp;rsquo;s theme. However, running our script will not affect open tabs; you need to reload the tab or open a new tabe to see the effects.&lt;/p&gt;
&lt;p&gt;Many other sites do not have a dark theme, though, or do not apply it automatically. To change these sites, install the great &lt;a href=&#34;https://addons.mozilla.org/de/firefox/addon/darkreader/&#34;&gt;dark reader firefox plugin&lt;/a&gt;!&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2023/12/dark_reader.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Configure the plugin for automatic bahaviour based on the system colours (as shown above). Now is the time to test the script again! Websites controlled by Dark Reader should update immediately without a refresh. This is one reason to prefer Dark Reader&amp;rsquo;s handling over native switching (like that of &lt;a href=&#34;https://google.com&#34;&gt;https://google.com&lt;/a&gt; ).&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; If this is the behaviour you want, make sure that websites are not disabled-by-default in Dark Reader (configurable through the small ⚙ under the website URL in the plugin-popup); this is the case for e.g. &lt;a href=&#34;https://mastodon.social&#34;&gt;https://mastodon.social&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An option you might want to play with is found under &amp;ldquo;more → Change Browser Theme&amp;rdquo;. This makes the plugin control the Firefox application theme. This is a bit of a logic loop (script changes Firefox theme → triggers Plugin → triggers update of theme), but it often works well and usually gives a slightly different &amp;ldquo;dark theme look&amp;rdquo; for the application.&lt;/p&gt;
&lt;h3 id=&#34;qt-and-kde-apps&#34;&gt;Qt and KDE apps&lt;/h3&gt;
&lt;p&gt;There are multiple ways to make Qt5 and KDE apps look like GTK apps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the Adwaita / Adwaita-Dark theme as the native Qt theme (&lt;code&gt;QT_QPA_PLATFORMTHEME=Adwaita&lt;/code&gt; / &lt;code&gt;QT_QPA_PLATFORMTHEME=Adwaita-dark&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Select &amp;ldquo;gtk2&amp;rdquo; as the native Qt theme (&lt;code&gt;QT_QPA_PLATFORMTHEME=gtk2&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Select &amp;ldquo;gnome&amp;rdquo; as the native Qt theme (&lt;code&gt;QT_QPA_PLATFORMTHEME=gnome&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of these work to a certain degree, and I would have liked to use first option. But for neither 1. nor 2., I was able to achieve &amp;ldquo;live switching&amp;rdquo; of already open applications upon invocation of the script.
In theory, one should also be able to use KDE&amp;rsquo;s &lt;code&gt;lookandfeeltool&lt;/code&gt; to switch between the native Adwaita and Adwaita-dark themes (or any other pair of themes), but I was not able to make this work reliably.&lt;sup id=&#34;fnref1:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Note that for Qt6 applications to switch theme with the rest, &lt;code&gt;qgnomeplatform-qt6&lt;/code&gt; needs to be installed, which is not available on Ubuntu. Other platforms (&lt;a href=&#34;https://aur.archlinux.org/packages/qgnomeplatform-qt6-git&#34;&gt;like Arch&amp;rsquo;s AUR&lt;/a&gt;) seemed to have it, though.&lt;/p&gt;
&lt;p&gt;Note also that in Sway you need to make sure that &lt;code&gt;QT_QPA_PLATFORMTHEME&lt;/code&gt; is defined in the context where your applications are started. This is typically not the case within the sway config, so I do the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;bindsym $mod+space exec /home/hannes/bin/preload_profile krunner
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &lt;code&gt;preload_profile&lt;/code&gt; executes all arguments given to it, but imports &lt;code&gt;~/.profile&lt;/code&gt; before.&lt;/p&gt;
&lt;h2 id=&#34;possible-extensions&#34;&gt;Possible extensions&lt;/h2&gt;
&lt;h3 id=&#34;screen-brightness&#34;&gt;Screen brightness&lt;/h3&gt;
&lt;p&gt;Before I managed to setup theme-switching correctly, I used a script to control brightness. Now that theme switching works, I don&amp;rsquo;t do this anymore, but in case you want this additionally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use &lt;code&gt;brightnessctl&lt;/code&gt; to adjust the brightness of the built-in screen of your Laptop.&lt;/li&gt;
&lt;li&gt;You can use &lt;code&gt;ddcutil&lt;/code&gt; to adjust the brightness of an external monitor (this affects actual display brightness not Gamma).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;automation&#34;&gt;Automation&lt;/h3&gt;
&lt;p&gt;If desired, you could automate theme switching with cron or map hotkeys to the script.&lt;/p&gt;
&lt;h2 id=&#34;closing-remarks&#34;&gt;Closing remarks&lt;/h2&gt;
&lt;p&gt;I am really happy I got this far; the only thing that does not update live is the icon theme in KDE applications. If anyone has advice on that, I would be grateful!&lt;/p&gt;
&lt;p&gt;I have used the method of having everything behave like being on GNOME here. In theory, it should also be possible to set XDG portal to &lt;code&gt;kde&lt;/code&gt; and use &lt;code&gt;lookandfeeltool&lt;/code&gt; instead of &lt;code&gt;gsettings&lt;/code&gt;, but I did not yet manage to make that work.If you have, please let me know!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I have verified that an XDG desktop portal of &lt;code&gt;wlr&lt;/code&gt; or &lt;code&gt;gtk&lt;/code&gt; works, and also that a value of &lt;code&gt;kde&lt;/code&gt; does not work; so this won&amp;rsquo;t work within a KDE session.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;If you get spurious flashes of white between website loading or tab-switches, you can later switch this to the &amp;ldquo;Dark&amp;rdquo; theme and it should still turn bright when in global bright mode.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Native dark themes may or may not look better than whatever Dark Reader is doing. I often prefer Dark Reader, because it allows backgrounds that are not fully black.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded>
    </item>
    
    <item>
      <title>Configuring algorithms in Modern C&#43;&#43;</title>
      <link>https://hannes.hauswedell.net/post/2023/03/30/algo_config/</link>
      <pubDate>Thu, 30 Mar 2023 22:00:00 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2023/03/30/algo_config/</guid>
      <description>&lt;p&gt;When designing library code, one often wonders: &lt;em&gt;&amp;ldquo;Are these all the parameters this function will ever need?&amp;rdquo;&lt;/em&gt; and
&lt;em&gt;&amp;ldquo;How can a user conveniently change one parameter without specifying the rest?&amp;rdquo;&lt;/em&gt; This post introduces some Modern C++
techniques you can use to make passing configuration options easy for your users while allowing you to
add more options later on.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;When designing library code, one often wonders: &lt;em&gt;&amp;ldquo;Are these all the parameters this function will ever need?&amp;rdquo;&lt;/em&gt; and
&lt;em&gt;&amp;ldquo;How can a user conveniently change one parameter without specifying the rest?&amp;rdquo;&lt;/em&gt; This post introduces some Modern C++
techniques you can use to make passing configuration options easy for your users while allowing you to
add more options later on.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Most people who have programmed in C++ before should have no problems understanding this article, although you
will likely appreciate it more, if you are a library developer or have worried about the forward-compatibility of
your code.&lt;/p&gt;
&lt;p&gt;Some of the features introduced in this post do not yet work with Clang. Most &lt;em&gt;should&lt;/em&gt; work with MSVC, but
I only double-checked the code with GCC12 (any version &amp;gt;= 10 should work).&lt;/p&gt;
&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you are writing an algorithm with the following signature:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, size_t threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It takes some kind of data input, does lots of magic computation on it and returns some other data. An actual
algorithm should of course clearly state what kind of input data it expects (specific type or constrained template
parameter), but we want to focus on the other parameters in this post.
The only configuration option that you want to expose is the number of threads it shall use. It defaults to &lt;code&gt;4&lt;/code&gt;,
because you know that the algorithm scales well at four threads and also you assume that most of your users
have at least four cores on their system.&lt;/p&gt;
&lt;p&gt;Now, a bit later, you have added an optimisation to the algorithm called &lt;code&gt;heuristic42&lt;/code&gt;. It improves the results in
almost all cases, but there are a few corner cases where users might want to switch it off. The interface now looks
like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, size_t threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is not too bad, you might think, but there are already two ugly things about this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To overwrite the second &amp;ldquo;config option&amp;rdquo;, the user needs to also specify the first, i.e. &lt;code&gt;algo(&amp;quot;data&amp;quot;, 4, false);&lt;/code&gt;.
This means that they need to look up (and enter correctly) the first config option&amp;rsquo;s default value. Also, if you change
that default in a future release of the code, this change will not be reflected in the user&amp;rsquo;s invocation who
unknowingly enforces the old default.&lt;/li&gt;
&lt;li&gt;Since passing arguments to the function does not involve the parameter&amp;rsquo;s name, it is very easy to confuse the order
of the parameters. Implicit conversions make this problem even worse, so invoking the above interface with
&lt;code&gt;algo(&amp;quot;data&amp;quot;, false, 4);&lt;/code&gt; instead of &lt;code&gt;algo(&amp;quot;data&amp;quot;, 4, false);&lt;/code&gt; generates no warning, even with &lt;code&gt;-Wall -Wextra -pedantic&lt;/code&gt;!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Wow, what a usability nightmare, and we only have two config options! Imagine adding a few more…&lt;/p&gt;
&lt;h2 id=&#34;dedicated-config-object&#34;&gt;Dedicated config object&lt;/h2&gt;
&lt;p&gt;As previously mentioned, the parameter name cannot be used when passing arguments. However, C++20 did add
&lt;a href=&#34;https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers&#34;&gt;designated initialisers&lt;/a&gt;
for certain class types.
So you can use the name of a member variable when initialising an object.
We can use that!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    size_t threads   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, algo_config &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; cfg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* implementation */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* create the config object beforehand (e.g. after argument parsing) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo_config cfg{.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, cfg);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* create the config object ad-hoc */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});   &lt;span style=&#34;color:#75715e&#34;&gt;// set both paramaters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});                         &lt;span style=&#34;color:#75715e&#34;&gt;// set only one parameter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* providing the config type&amp;#39;s name is optional */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, {.threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;a href=&#34;https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGe1wAyeAyYAHI%2BAEaYxHoADqgKhE4MHt6%2BcQlJAkEh4SxRMVy2mPaOAkIETMQEqT5%2BRXaYDskVVQQ5YZHRegqV1bXpDX3twZ353VwAlLaoXsTI7BzmAMzByN5YANQmy27IvehYVDvYJhoAgmfnvcReDptiwKgA%2BmgMNMBXJgDsVhebAM2EVQnk2CEwczwvTwyEkZm2ywAIpsCLdMDs/udAZtEgAvTDPAgohDETBMdAKQE7ZGSLy0WgYr7fRGMi5XJheIgPWhPCAcrnoJiVUjcp6vAQfTZvXrbMwANilVGAkyZmOxAHoAFSbPAsWL0NiCIXJTaa9VMllsi7BIksJjBCAqtm/K4a7XIUlCzDE71vSWoCLaJpEqL8UkIQzoTYQTAAOmAsYeVAI0QexGAPkYRNiVUSRkmpvN/0BjxefrwwEVn1%2BsfBkOhsPh1M2VDEShFsYIJLJFIRyIAHD8Wcs1SWeagIOYzILKlORcglSqR19iwCtVLPSmfVKJRXNgGg/dyQBaBCoZCF11j3lTmdMOeisu76sWWsQ4hQxyNvsttuYDtdp6vbNoOzJLhYgLquqOKYCGqBdpsObEKwXrEAoV4AqWk5mNOQr3jhIqluK7wVj8r6AT2lIgUO4HYnR9EMZB0FKESAi0AAnvuISIVUrCwdEK5YpB2qxMQqAAG54PgRjbuWlYEOxsTelC%2B6xGUzC0Jeq6PthuGzgR2w1hR5JUUimygYi4GCUOHDTLQnAAKy8H4HBaKQqCcG41jWDiszzN6Kw8KQBCaLZ0wANYgA5Gj6JwkjOaF7mcLwCggDFIWubZpBwLAMCICgqB6nQ0TkJQaBFfQMTAFwBFYJJCwAGp4JgADuADySkuUFNC0CmaGUBEiURMEVTsZwQXDcwxDsW1gbBuNvDlYaBBtQwHGJVgdpGOImWkPgpLNOJmCpbtmCqE0nKLEFNolIltB4BEyHTR4WCJaiuoLdMVAGMAChNa1HWMAtMiCCIYjsFIIPyEoaiJboRQGEYKDeZY%2BgPalkDTKganJCdx4HNSpiWNYZhuY0zTODGDDuJ4dT%2BNTHR5AUGSJOpAz1KQ8Ss8kjNdIUxSlC0wzsz0JTBkLbS8%2BM/O9G0ItDJLoxMxM0wKH5CwSHZjkJbtHkcJsqj9nKx5ypImzAMgF41bG8IQLghAkLKyxTLwGVaJMEVRTF9kcPFpAsF7pAuW5espWlwWhdMOX5bMBCxJypUQOVsTFcQoR8ZwhvG6b5uW5s1tmLwmD4EQH7oHo/Cg6I4iQ5X0MqOou3w6QLXIbEn2xRwTlB4lettZy8esVQBtGybZsW1bZg29GHgVamgWTK7kfTOC5LdI6nd%2BwH0U97ryW2OHbthaQkU7z7yw6yH%2B9Hx7neF7vV8cEvmW30daHJCAkhAA%3D%3D%3D&#34;&gt;Compile and edit online (via godbolt)&lt;/a&gt;
&lt;/center&gt;
&lt;p&gt;As you can see, this solves both of the problems mentioned previously! We refer to the config elements by name
to avoid mixups, and we can choose to overwrite only those parameters that we actually want to change; other
configuration elements will be whatever they are set to by default.
Conveniently, this allows changing the default later on, and all invocations that don&amp;rsquo;t overwrite it will pick up the
new default.&lt;/p&gt;
&lt;p&gt;Another great feature is that the API maintainer of the algorithm can easily add more members to the configuration
object without invalidating any existing invocations.
This allows users of the API to gradually adopt new opt-in features.&lt;/p&gt;
&lt;p&gt;As the name of the config type can even be omitted (see last invocation), the syntactic overhead for the &amp;ldquo;ad-hoc&amp;rdquo;
initialisation is very low, almost like providing the arguments directly to the function-call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is an important catch:&lt;/strong&gt; The order in which the designated initialisers are given has to correspond to the
order in which the respective members are defined in the type of the config.
It is okay to omit initialisers at the beginning, middle or end (as long as defaults are given), but the relative
order of all the initialisers that you do provide has to be correct.
This might sound like a nuisance, but in contrast to the problem discussed initially (mixed up order of function
arguments), you will actually get a compiler-error that tells you that you got the order wrong; so the problem is
easily detected and fixed.
And there is a nice rule that you can follow for such config objects: always sort the members alphabetically! That way users
intuitively know the order and don&amp;rsquo;t have to look it up 💡&lt;/p&gt;
&lt;h2 id=&#34;types-as-config-elements&#34;&gt;Types as config elements&lt;/h2&gt;
&lt;p&gt;Now, sometimes you want to pass a type as kind of parameter to an algorithm. Imagine that the algorithm internally
juggles a lot of integers. Maybe it even does &lt;a href=&#34;https://en.wikipedia.org/wiki/Single_instruction,_multiple_data&#34;&gt;SIMD&lt;/a&gt;
with them.
In those cases, the size of the integers could affect performance noticeably.&lt;/p&gt;
&lt;p&gt;Some algorithms might be able to infer from the data input&amp;rsquo;s type which integers to use for computation, but
in other cases you want the user to be able to override this.
Thus we need the ability to pass the desired type to the algorithm.
The canonical way of doing this is via template arguments:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; int_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; algo(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, size_t threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But this is has the same problems that we discussed initially: as soon as multiple types are passed, it is possible
confuse the order (and not be notified); to set a later parameters, you need to also set previous ones; et cetera.
There might also be weird interactions with the type of the data parameter, in case that is a template parameter.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s add the &amp;ldquo;type parameter&amp;rdquo; to our config object instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* We define a &amp;#34;type tag&amp;#34; so we can pass types as values */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;inline&lt;/span&gt; constinit std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;type_identity&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; ttag{};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* The config now becomes a template */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; Tint_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decltype&lt;/span&gt;(ttag&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; heuristic42    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tint_type int_type  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ttag&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    size_t threads      &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* And also the algorithm */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; ...Ts&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; algo(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, algo_config&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Ts...&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; cfg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* implementation */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* Setting just &amp;#34;value parameters&amp;#34; still works with and without &amp;#34;algo_config&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;,            {.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* When setting a &amp;#34;type parameter&amp;#34;, we need to add &amp;#34;algo_config&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.int_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ttag&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;a href=&#34;https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:&#39;1&#39;,fontScale:14,fontUsePx:&#39;0&#39;,j:1,lang:c%2B%2B,selection:(endColumn:19,endLineNumber:1,positionColumn:19,positionLineNumber:1,selectionStartColumn:19,selectionStartLineNumber:1,startColumn:19,startLineNumber:1),source:&#39;%23include+%3Ccstdint%3E%0A%23include+%3Ccstddef%3E%0A%23include+%3Ctype_traits%3E%0A%0A/*+We+define+a+%22type+tag%22+so+we+can+pass+types+as+values+*/%0Atemplate+%3Ctypename+T%3E%0Ainline+constinit+std::type_identity%3CT%3E+ttag%7B%7D%3B%0A%0A/*+The+config+now+becomes+a+template+*/%0Atemplate+%3Ctypename+Tint_type+%3D+decltype(ttag%3Cuint64_t%3E)%3E%0Astruct+algo_config%0A%7B%0A++++bool+heuristic42++++%3D+true%3B%0A++++Tint_type+int_type++%3D+ttag%3Cuint64_t%3E%3B%0A++++size_t+threads++++++%3D+4ull%3B%0A%7D%3B%0A%0A/*+And+also+the+algorithm+*/%0Atemplate+%3Ctypename+...Ts%3E%0Aauto+algo(auto+data,+algo_config%3CTs...%3E+const+%26+cfg)%0A%7B%0A++++/*+implementation+*/%0A%7D%0A%0Aint+main()%0A%7B%0A++++/*+Setting+just+%22value+parameters%22+still+works+with+and+without+%22algo_config%22+*/%0A++++algo(%22data%22,+algo_config%7B.heuristic42+%3D+false,+.threads+%3D+8%7D)%3B%0A++++algo(%22data%22,++++++++++++%7B.heuristic42+%3D+false,+.threads+%3D+8%7D)%3B%0A%0A++++/*+When+setting+a+%22type+parameter%22,+we+need+to+add+%22algo_config%22+*/%0A++++algo(%22data%22,+algo_config%7B.int_type+%3D+ttag%3Cuint32_t%3E,+.threads+%3D+8%7D)%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((g:!((h:compiler,i:(compiler:g122,deviceViewOpen:&#39;1&#39;,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,binaryObject:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,libraryCode:&#39;0&#39;,trim:&#39;1&#39;),flagsViewOpen:&#39;1&#39;,fontScale:14,fontUsePx:&#39;0&#39;,j:1,lang:c%2B%2B,libs:!(),options:&#39;-std%3Dc%2B%2B20&#39;,selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;+x86-64+gcc+12.2+(Editor+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,m:50,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:output,i:(compilerName:&#39;x86-64+gcc+12.2&#39;,editorid:1,fontScale:14,fontUsePx:&#39;0&#39;,j:1,wrap:&#39;1&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;Output+of+x86-64+gcc+12.2+(Compiler+%231)&#39;,t:&#39;0&#39;)),header:(),l:&#39;4&#39;,m:50,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),k:50,l:&#39;3&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34;&gt;Compile and edit online (via godbolt)&lt;/a&gt;
&lt;/center&gt;
&lt;p&gt;There are a few things happening here. In the beginning, we use
&lt;a href=&#34;https://en.cppreference.com/w/cpp/language/variable_template&#34;&gt;variable templates&lt;/a&gt; to define an object
that &amp;ldquo;stores&amp;rdquo; a type. This can later be used to initialise members of our config object.&lt;/p&gt;
&lt;p&gt;Next, we need to make &lt;code&gt;algo_config&lt;/code&gt; a template. Unfortunately, we need to default the template parameter
as well as giving the member a default value. Finally, &lt;code&gt;algo()&lt;/code&gt; needs template parameters for the config, as well.
It is handy to just use a parameter pack here, because it means we don&amp;rsquo;t need to change it if we add more
template parameters the config type.
This is all a bit more verbose than before, after all we are still writing C++ 😅 But most of this will be hidden
from the user anyway.&lt;/p&gt;
&lt;p&gt;The invocation of the algorithm is almost unchanged from before, we just use &lt;code&gt;ttag&amp;lt;uint32_t&amp;gt;&lt;/code&gt; to initialise
the &amp;ldquo;type parameter&amp;rdquo; of the config.
There is one caveat: when passing such &amp;ldquo;type parameters&amp;rdquo;, it is now necessary to add &lt;code&gt;algo_config&lt;/code&gt;, although,
fortunately, you do not need to spell out the template arguments.
In general, this may be a bit surprising, so I recommend always including the config-name in examples to teach
your users a single syntax.&lt;/p&gt;
&lt;h2 id=&#34;constants-as-config-elements&#34;&gt;Constants as config elements&lt;/h2&gt;
&lt;p&gt;Using a similar technique to the one above, we can also pass compile-time constants to the config object.
This allows the algorithm to conveniently use &lt;code&gt;if constexpr&lt;/code&gt; to choose between different codepaths, e.g.
between a SIMD-based codepath and a regular one.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* We define a &amp;#34;value tag&amp;#34; type so we can pass values as types...*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vtag_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; v;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* ...and then we define a variable template to pass the type as value again! */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;inline&lt;/span&gt; constinit vtag_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;v&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; vtag{};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* The config is a template */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; Tuse_simd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vtag_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;false&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algo_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; heuristic42    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; true;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    size_t threads      &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4ull&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Tuse_simd use_simd  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vtag&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;false&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* The algorithm */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; ...Ts&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; algo(&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; data, algo_config&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Ts...&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; cfg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* implementation */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* Setting just &amp;#34;value parameters&amp;#34; still works with and without &amp;#34;algo_config&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;,            {.heuristic42 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; false, .threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* When setting a &amp;#34;constant parameter&amp;#34;, we need to add &amp;#34;algo_config&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    algo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, algo_config{.threads &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;, .use_simd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vtag&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;
&lt;a href=&#34;https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:&#39;1&#39;,fontScale:14,fontUsePx:&#39;0&#39;,j:1,lang:c%2B%2B,selection:(endColumn:29,endLineNumber:37,positionColumn:29,positionLineNumber:37,selectionStartColumn:18,selectionStartLineNumber:37,startColumn:18,startLineNumber:37),source:&#39;%23include+%3Ccstddef%3E%0A%0A/*+We+define+a+%22value+tag%22+type+so+we+can+pass+values+as+types...*/%0Atemplate+%3Cauto+v%3E%0Astruct+vtag_t%0A%7B%0A++++static+constexpr+auto+value+%3D+v%3B%0A%7D%3B%0A%0A/*+...and+then+we+define+a+variable+template+to+pass+the+type+as+value+again!!+*/%0Atemplate+%3Cauto+v%3E%0Ainline+constinit+vtag_t%3Cv%3E+vtag%7B%7D%3B%0A%0A/*+The+config+is+a+template+*/%0Atemplate+%3Ctypename+Tuse_simd+%3D+vtag_t%3Cfalse%3E%3E%0Astruct+algo_config%0A%7B%0A++++bool+heuristic42++++%3D+true%3B%0A++++size_t+threads++++++%3D+4ull%3B%0A++++Tuse_simd+use_simd++%3D+vtag%3Cfalse%3E%3B%0A%7D%3B%0A%0A/*+The+algorithm+*/%0Atemplate+%3Ctypename+...Ts%3E%0Aauto+algo(auto+data,+algo_config%3CTs...%3E+const+%26+cfg)%0A%7B%0A++++/*+implementation+*/%0A%7D%0A%0Aint+main()%0A%7B%0A++++/*+Setting+just+%22value+parameters%22+still+works+with+and+without+%22algo_config%22+*/%0A++++algo(%22data%22,+algo_config%7B.heuristic42+%3D+false,+.threads+%3D+8%7D)%3B%0A++++algo(%22data%22,++++++++++++%7B.heuristic42+%3D+false,+.threads+%3D+8%7D)%3B%0A%0A++++/*+When+setting+a+%22constant+parameter%22,+we+need+to+add+%22algo_config%22+*/%0A++++algo(%22data%22,+algo_config%7B.threads+%3D+8,+.use_simd+%3D+vtag%3Ctrue%3E%7D)%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((g:!((h:compiler,i:(compiler:g122,deviceViewOpen:&#39;1&#39;,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,binaryObject:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,libraryCode:&#39;0&#39;,trim:&#39;1&#39;),flagsViewOpen:&#39;1&#39;,fontScale:14,fontUsePx:&#39;0&#39;,j:1,lang:c%2B%2B,libs:!(),options:&#39;-std%3Dc%2B%2B20&#39;,selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;+x86-64+gcc+12.2+(Editor+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,m:50,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:output,i:(compilerName:&#39;x86-64+gcc+12.2&#39;,editorid:1,fontScale:14,fontUsePx:&#39;0&#39;,j:1,wrap:&#39;1&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;Output+of+x86-64+gcc+12.2+(Compiler+%231)&#39;,t:&#39;0&#39;)),header:(),l:&#39;4&#39;,m:50,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),k:50,l:&#39;3&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34;&gt;Compile and edit online (via godbolt)&lt;/a&gt;
&lt;/center&gt;
&lt;p&gt;As you can see, this is very similar to the previous example. The only difference is, that we need another initial step
to encode the value as a type.
It is even possible to have parameters that are (run-time) values by default, but can be configured as (compile-time)
constants in the way shown above.
And, of course, all kinds of config options can be combined.&lt;/p&gt;
&lt;p&gt;Note that the definitions of the &amp;ldquo;tagging&amp;rdquo; features would happen in your utility code. Users only need to know
that they can pass constants via &lt;code&gt;vtag&amp;lt;42&amp;gt;&lt;/code&gt; and types via &lt;code&gt;ttag&amp;lt;int32_t&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;post-scriptum&#34;&gt;Post scriptum&lt;/h2&gt;
&lt;p&gt;I hope this post was helpful to some of you. I think this is a big step forward for usability, and I hope Clang
catches up with the required features as soon as possible!&lt;/p&gt;
&lt;p&gt;There are two things here that could be improved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If a template parameter can be deduced from member initialisers, it should be. This would allow us to omit
the default template arguments for &lt;code&gt;algo_config&lt;/code&gt;, i.e. &lt;code&gt;= decltype(ttag&amp;lt;uint64_t&amp;gt;)&lt;/code&gt; and &lt;code&gt;= vtag_t&amp;lt;false&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When a brace-enclosed initialiser list is passed to a function template to initialise a parameter of deduced type,
consider the contents of that initialiser list. This would allow us to omit
&lt;code&gt;align_config&lt;/code&gt; also when passing &amp;ldquo;type parameters&amp;rdquo; or constants.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I have the feeling that 1. might not be too difficult and also not too controversial. But I suspect that 2. would
be more complicated as it interacts with function overloading and I can imagine situations were this change
would break existing code.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;d love to here other people&amp;rsquo;s opinion on the matter!&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;p&gt;The ISO WG21 papers that added these features to C++:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://wg21.link/P0329R4&#34;&gt;P0329 Designated Initialisers&lt;/a&gt;, C++20&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wg21.link/p1816&#34;&gt;P1816&lt;/a&gt; and &lt;a href=&#34;https://wg21.link/p2082&#34;&gt;P2082&lt;/a&gt; Class template argument deduction for aggregates, C++20, &lt;a href=&#34;https://github.com/llvm/llvm-project/issues/50743&#34;&gt;not yet in Clang&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
    </item>
    
    <item>
      <title>👾 Game-streaming without the &#34;cloud&#34; 🌩️</title>
      <link>https://hannes.hauswedell.net/post/2020/04/20/gamestream/</link>
      <pubDate>Mon, 20 Apr 2020 19:10:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2020/04/20/gamestream/</guid>
      <description>&lt;p&gt;With increasing bandwidths, live-streaming of video games is becoming more and more popular &amp;ndash; and might further accelerate the demise of the desktop computer.
Most options are &amp;ldquo;cloud-gaming&amp;rdquo; services based on subscriptions where you don&amp;rsquo;t own the games and are likely to be tracked and monetised for your data.
In this blog post I present the solution I built at home to replace my &amp;ldquo;living room computer&amp;rdquo;.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;With increasing bandwidths, live-streaming of video games is becoming more and more popular &amp;ndash; and might further accelerate the demise of the desktop computer.
Most options are &amp;ldquo;cloud-gaming&amp;rdquo; services based on subscriptions where you don&amp;rsquo;t own the games and are likely to be tracked and monetised for your data.
In this blog post I present the solution I built at home to replace my &amp;ldquo;living room computer&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;tl-dr&#34;&gt;TL; DR&lt;/h2&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/summary.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/summary-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;I describe how to stream a native Windows game (&lt;a href=&#34;https://divinity.game/&#34;&gt;Divinity Original Sin 2&lt;/a&gt; &amp;ndash; installed DRM-free from &lt;a href=&#34;https://www.gog.com/game/divinity_original_sin_2&#34;&gt;GOG&lt;/a&gt;) via &lt;a href=&#34;https://store.steampowered.com/app/353380/Steam_Link/&#34;&gt;Steam Remote Play&lt;/a&gt; from my Desktop (running &lt;a href=&#34;https://devuan.org/&#34;&gt;Devuan GNU/Linux&lt;/a&gt;) in 4K resolution and maximum quality directly to my TV (running Android).
On the TV I then play the game with my flatmate using two controllers: one Xbox Controller connected via USB, one Steam-Controller connected via Bluetooth.
The process of getting there is not trivial or flawless, but gaming itself works perfectly without artefacts or lag.&lt;/p&gt;
&lt;p&gt;(The computer in the above photo is not used any longer.)&lt;/p&gt;
&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;The big &amp;ldquo;cloud&amp;rdquo; streaming services for audio and video are incredibly convenient.
In my opinion they address the following problems very well:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They make content available on hardware that wouldn&amp;rsquo;t have the capability to store the content.&lt;/li&gt;
&lt;li&gt;This includes &lt;em&gt;all&lt;/em&gt; devices of the user, not just a single (desktop/laptop) computer.&lt;/li&gt;
&lt;li&gt;They provide access to a lot of content at a fixed monthly price (especially useful for people who haven&amp;rsquo;t had the possibility to build up their &amp;ldquo;library&amp;rdquo;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the other hand, they usually force you to use software that is non-free and/or not trustworthy (if they support your OS at all).
You risk losing access to all content when the subscription is terminated.
And &amp;ndash; often overlooked &amp;ndash; they monitor you very closely: what you watch/listen to, when and where you do it, when you press pause and for how long etc.
I suspect that at some point this data will be more valuable than the income generated from subscription fees, but this is not important here.&lt;/p&gt;
&lt;p&gt;It was only a matter of time before video-gaming would also become part of the streaming business and there are now multiple contenders: &lt;a href=&#34;https://stadia.google.com/&#34;&gt;Google Stadia&lt;/a&gt; and &lt;a href=&#34;http://playstationnetwork.com/&#34;&gt;Playstation Now&lt;/a&gt; are typical &amp;ldquo;streaming services&amp;rdquo; like Netflix for video; the games are included in the monthly fee.
They have all the benefits and problems discussed above.
Other services like &lt;a href=&#34;https://www.nvidia.com/en-us/geforce-now/&#34;&gt;GeForce Now&lt;/a&gt; and &lt;a href=&#34;https://shadow.tech/&#34;&gt;Blade Shadow&lt;/a&gt; provide computation and streaming infrastructure but leave it to you to provide the games (manually or via gaming platforms).
This has slightly different implications, but I dont&amp;rsquo; want to discuss these further, because I haven&amp;rsquo;t used any of them and likely won&amp;rsquo;t in the future.&lt;/p&gt;
&lt;p&gt;In any case, I am of course not a big fan of being tracked and anything I can set up with my own infrastructure at home, I try to do!
[I actually don&amp;rsquo;t really spend that much time gaming nowadays, but setting this up was still fun].
In the past I have had an extra (older) computer beside the TV that I used for casual gaming.
This has become to old (and noisy) to play current games, so instead I want stream the game from my own desktop computer in a different room.&lt;/p&gt;
&lt;p&gt;Disclaimer: It should be noted that this &amp;ldquo;only&amp;rdquo; provides feature 2. above, i.e. convergence of different devices.
Also this setup includes using various non-free software components, i.e. it also does not solve all of the problems mentioned above.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-host&#34;&gt;Setting up the host&lt;/h2&gt;
&lt;p&gt;The &amp;ldquo;host&amp;rdquo; is the computer that renders the game, in my case the desktop computer.
Before attempting to stream anything, we need to make sure that everything works on the host, i.e. we need to be able to play the game, use the controllers etc.&lt;/p&gt;
&lt;h3 id=&#34;hardware&#34;&gt;Hardware&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;CPU&lt;/th&gt;
          &lt;th&gt;RAM&lt;/th&gt;
          &lt;th&gt;GPU&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;AMD Ryzen 6c/12t @ 3.6Ghz&lt;/td&gt;
          &lt;td&gt;32GB&lt;/td&gt;
          &lt;td&gt;GeForce RTX 2060S&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Since the host needs to render the game, it needs decent hardware.
Note that it needs to be able to encode the video-stream at the same time as rendering the game which means the requirements are even higher than usual.
But of course all of this also depends on the exact games that you are playing and which resolution you want to stream.
My specs are shown above.&lt;/p&gt;
&lt;h3 id=&#34;the-game&#34;&gt;The game&lt;/h3&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/dos2.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/dos2-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;I chose &lt;a href=&#34;https://divinity.game/&#34;&gt;Divinity Original Sin 2&lt;/a&gt; for this article because that&amp;rsquo;s what I am playing right now and because I wanted to demonstrate that this even works with games that are not native to Linux (although I usually don&amp;rsquo;t buy games that don&amp;rsquo;t have native versions).
If you buy it, I recommend getting it on &lt;a href=&#34;https://www.gog.com/game/divinity_original_sin_2&#34;&gt;GOG&lt;/a&gt;, because games are DRM-free there (they work without internet connection and stay working even if GOG goes bankrupt).
The important thing here is that the game does not need to be a Steam game even though we will use Steam Remote Play for streaming.
Buying it on Steam will make the process a little easier though.&lt;/p&gt;
&lt;p&gt;Install the game using &lt;a href=&#34;https://www.winehq.org/&#34;&gt;wine&lt;/a&gt; (&lt;code&gt;wine&lt;/code&gt; in Devuan/Debian repos).
I assume that you have installed it to &lt;code&gt;/games/DOS2&lt;/code&gt; and that you have setup a &amp;ldquo;windows disk G:&amp;quot; for &lt;code&gt;/games&lt;/code&gt;.
If not, adjust paths accordingly.&lt;/p&gt;
&lt;h3 id=&#34;steam&#34;&gt;Steam&lt;/h3&gt;
&lt;p&gt;If you haven&amp;rsquo;t done so already, install Steam.
It is available in Debian/Devuan non-free repositories as &lt;code&gt;steam&lt;/code&gt; but will install and self-update itself in a hidden subfolder of your home-directory upon first start.
You need a steam-account (free) and you need to be logged in for everything to work.
I really dislike this and it means that Steam quite likely does gather data about you.
I suspect that using non-Steam games makes it more difficult to track you, but I have not done any research on this.
See the end of this post for possible &lt;a href=&#34;#alternatives&#34;&gt;alternatives&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first important thing to know about Steam on Linux is that it ships many system libraries, but it doesn&amp;rsquo;t ship everything that it needs and it gives you no diagnostic about missing stuff nor are UI elements correctly disabled when the respective feature is not available.
This includes support for hardware video encoding and for playing windows games.&lt;/p&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/advanced_host_settings.png&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/advanced_host_settings-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Hardware-video encoding is a feature you really want because it reduces latency and load on your CPU.
For reasons I don&amp;rsquo;t understand, Steam uses neither &lt;code&gt;libva&lt;/code&gt; (the standard interface for video acceleration on free operating systems) nor &lt;code&gt;vdpau&lt;/code&gt; (NVIDIA-specific but also free/open).
Instead it uses the proprietary NVENC interface.
On Debian / Devuan his has been patched out of all the libraries and applications, so you need to make sure that you get your libraries and apps like &lt;code&gt;ffmpeg&lt;/code&gt; from the &lt;a href=&#34;http://www.debt-multimedia.org/&#34;&gt;Debian multimedia project&lt;/a&gt; which has working versions.
I am not entirely sure which set of libraries/apps is required, for me it was sufficient to install &lt;code&gt;libnvidia-encode1&lt;/code&gt; and do an &lt;code&gt;apt upgrade&lt;/code&gt; after adding the debian multimedia repo.
Note that only installing &lt;code&gt;libnvidia-encode1&lt;/code&gt; from the official repo was not sufficient.
See the &lt;a href=&#34;#troubleshooting&#34;&gt;troubleshooting section&lt;/a&gt; on how to diagnose problems with hardware video encoding.&lt;/p&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/proton_everywhere.png&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/proton_everywhere-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;To play Windows games with Steam, you can use Steam&amp;rsquo;s builtin windows emulator called Proton (&lt;a href=&#34;https://boilingsteam.com/proton-brought-about-6000-games-to-linux-so-far/&#34;&gt;here&amp;rsquo;s a current articel on it&lt;/a&gt;).
It&amp;rsquo;s a fork of &lt;a href=&#34;https://www.winehq.org/&#34;&gt;Wine&lt;/a&gt; with additional patches (most of which are upstreamed to official wine later).
Unfortunately it is not installed after a fresh install of Steam on Linux and I found no explicit way of installing it (the interface still suggests it&amp;rsquo;s there, though!).
To get it, select &amp;ldquo;Enable Steam Play for all titles&amp;rdquo; in the &amp;ldquo;Advanced&amp;rdquo; &amp;ldquo;Steam Play Settings&amp;rdquo; in the settings.
This activates usage of Proton for Windows games not officially supported. Then install the free Windows game &lt;a href=&#34;https://store.steampowered.com/app/639650/1982/&#34;&gt;1982&lt;/a&gt; from inside Steam.
This will automatically install Proton which is then listed as an installed application and updated automatically in the future.
You can try the game to make sure Proton works as expected.
Alternatively, buy the actual game on Steam and skip the next paragraph.&lt;/p&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/edit_properties.png&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/edit_properties-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Now go to &amp;ldquo;Games&amp;rdquo; → &amp;ldquo;Add a Non-Steam Game to my Library&amp;hellip;&amp;rdquo;, then go to &amp;ldquo;BROWSE&amp;rdquo;, show all extensions and find the executable file of the game.
In our case this is &lt;code&gt;/games/DOS2/DefEd/bin/EoCApp.exe&lt;/code&gt; or &lt;code&gt;G:\DOS2\DefEd\bin\EoCApp.exe&lt;/code&gt; (yes, it&amp;rsquo;s not in the top-level directory of the game).
If your path contains spaces, it will break (without diagnostics).
To fix this, simply edit the shortcut created for the game again and make sure the path is right and &amp;ldquo;set launch options&amp;rdquo; is empty (part of your path may have ended up there).
In this dialog you can also explicitly state that you wish to use Proton to run the game (confusingly it will show multiple versions even if none of those are installed).
You can also give the game a nicer name or icon if desired.&lt;/p&gt;
&lt;h3 id=&#34;test-the-game&#34;&gt;Test the game&lt;/h3&gt;
&lt;p&gt;You are now ready to test the game.
Simply click on the respective button.
Now is also a good time for testing the controller(s), because if they don&amp;rsquo;t work now, they likely won&amp;rsquo;t later on.
There are many tutorials on using the (Steam) controller on Linux and there are also some notes in the &lt;a href=&#34;#troubleshooting&#34;&gt;troubleshooting section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is also a good point in time to update the firmware of the steam controller to the newest version; we will need that later on.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-client&#34;&gt;Setting up the client&lt;/h2&gt;
&lt;p&gt;The client is my TV, because that runs Android TV and there is a SteamLink application for Android.
If your TV has a different OS, you could probably use a small set-top-box built around a cheap embedded board and use Android (or Linux) as the client OS from that.
I suppose all of this would be possible on an Android Tablet, as well.
I recommend connecting the TV via wired network to the host, but WiFi works at lower resolutions, too.&lt;/p&gt;
&lt;h3 id=&#34;controllers-and-android&#34;&gt;Controllers and Android&lt;/h3&gt;
&lt;p&gt;The Xbox controller is just plugged into the USB-port of the TV and required no further configuration.
The Steam controller was a little more tricky, and I had no luck getting it to work via USB.
However, it comes with Bluetooth support (only after upgrading the firmware!).&lt;/p&gt;
&lt;p&gt;Establishing the initial Bluetooth connection between the TV and the controller was surprisingly difficult.
Start the Steam-controller with Steam+Y pressed or alternatively with Steam+B pressed and only do so after initiating device search on the TV.
If it does not work immediately, keep trying!
After a few attempts, the TV should state that it found the device; it calls it SteamController but recognises it as a Keyboard+Mouse.
That&amp;rsquo;s ok.&lt;/p&gt;
&lt;p&gt;After the connection has been established once, the controller will auto-connect when turned off and on again (do not press Y or B during start!).
The controller&amp;rsquo;s mouse feature is surprisingly useful in the Android TV when you use Android apps that are not optimised for the TV.&lt;/p&gt;
&lt;h3 id=&#34;steamlink--steam-remote-play&#34;&gt;SteamLink / Steam Remote Play&lt;/h3&gt;
&lt;p&gt;You need to install the &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.valvesoftware.steamlink&#34;&gt;SteamLink application from GooglePlay&lt;/a&gt; or through another channel like the &lt;a href=&#34;https://auroraoss.com/&#34;&gt;Aurora Store&lt;/a&gt; (my Android TV is not associated with a Google account so I cannot use GooglePlay).
After opening the app, Android will ask whether it should allow the app to access the Xbox controller which you have to agree to everytime (the &amp;ldquo;do this in the future&amp;rdquo; checkbox has no effect).
Confusingly the TV then notifies you that the controller has been disconnected.
This just means that the app controls it, I think.
The app takes control of the Steam controller without asking and switches it from Keyboard+Mouse mode into Controller mode, so you can use the Joystick to navigate the buttons in the app.&lt;/p&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/steamlink.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/steamlink-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;It should automatically detect Steam running on the host and offer to make a connection.
Press A on the controller or select &amp;ldquo;Start Playing&amp;rdquo;.
The connection has to be verified once on the host for obvious reasons, but if everything works well you should now see the &amp;ldquo;Steam Big Picture Mode&amp;rdquo; interface on you TV.
Your Desktop has switched to this at the same time (in general, the TV will now mirror your desktop).
Maybe first try a native Steam game like the aforementioned &amp;ldquo;1982&amp;rdquo; to see if everything works.&lt;/p&gt;
&lt;p&gt;Next try to start the Game we setup above via its regular entry in your Steam Library.
Note that upon starting, the screen will initially flash black and return to Steam; the game is starting in the background, do not start it again, it just needs a second!&lt;/p&gt;
&lt;p&gt;Everything should work now!
If you hear audio but your screen stays black and shows a &amp;ldquo;red antenna symbol&amp;rdquo;, see the &lt;a href=&#34;#troubleshooting&#34;&gt;troubleshooting section&lt;/a&gt; below.&lt;/p&gt;
&lt;p&gt;You can press the Steam-Button to return to Steam (although this sometimes breaks for non-native Steam games).
You can also long-press the &amp;ldquo;back/select&amp;rdquo;-button on the controller to get a SteamLink specific menu provided by the Client.
It can be used to launch an on-screen keyboard and force-quit the connection to the host and return to the SteamLink interface.&lt;/p&gt;
&lt;h3 id=&#34;video-resolutions-and-codecs&#34;&gt;Video resolutions and codecs&lt;/h3&gt;
&lt;p align=&#34;center&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2020/04/advanced_settings.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2020/04/advanced_settings-small.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;If everything worked so far you are likely playing in 1080p.
To change this to 4k resolution, go to the SteamLink app&amp;rsquo;s settings (wheel symbol) and then to &amp;ldquo;streaming settings&amp;rdquo; and then to &amp;ldquo;advanced&amp;rdquo;.
You can increase the resolution limit there and also enable &amp;ldquo;HEVC Video&amp;rdquo; which improves video quality / reduces bitrate.
If your desktop does not support streaming HEVC, SteamLink will establish no connection at all.
See the &lt;a href=&#34;#troubleshooting&#34;&gt;troubleshooting section&lt;/a&gt; below if you get a black screen and the &amp;ldquo;red antenna symbol&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;The only viable alternative to Steam&amp;rsquo;s Remote Play for streaming your own games from your own hardware is &lt;a href=&#34;https://www.nvidia.com/en-us/shield/support/shield-tv/gamestream/&#34;&gt;NVIDIA GameStream&lt;/a&gt; &amp;ndash; not to be confused with NVIDIA GeForce Now, the &amp;ldquo;cloud gaming&amp;rdquo; service.
The advantages of GameStream over Steam Remote Play seem to be the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The protocol is documented and there are good &lt;a href=&#34;https://moonlight-stream.org/&#34;&gt;Free and Open Source client implementations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It claims better performance by tying closer into the host&amp;rsquo;s drivers.&lt;/li&gt;
&lt;li&gt;No online-connection or sign-up required like with Steam.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also NVIDIA is a hardware company and even if the software is proprietary, it might be less likely to spy on you.
The disadvantages are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The host software is only available for Windows.&lt;/li&gt;
&lt;li&gt;Only works with NVIDIA GPUs on the host machine, not AMD.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I could not try this, because I don&amp;rsquo;t have a Windows host and I wanted to stream from GNU/Linux.&lt;/p&gt;
&lt;h2 id=&#34;post-scriptum&#34;&gt;Post scriptum&lt;/h2&gt;
&lt;p&gt;As you have seen the process really still has some rough edges, but I am honestly quite surprised that I did manage to set this up and that it works with really good quality in the end.
Although I don&amp;rsquo;t like Steam because of its DRM, I have to admit that its impressive how much work they put into improving the driver situation on GNU/Linux and supporting such setups as discussed here.
Consider that I didn&amp;rsquo;t even buy a game from Steam!&lt;/p&gt;
&lt;p&gt;I would still love to see a host implementation of NVIDIA GameStream that runs on GNU/Linux.
Even better would of course be a fully Free and Open Source solution.&lt;/p&gt;
&lt;p&gt;On a sidenote: the setup I showed here can be used to stream any kind of application, even just the regular desktop if you want to (check out the advanced client options!).&lt;/p&gt;
&lt;p&gt;Hopefully Steam Remote Play (and NVIDIA GameStream) can delay the full transition to &amp;ldquo;cloud gaming&amp;rdquo; a little.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h2&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
&lt;summary&gt;No hardware video encoding&lt;/summary&gt;
To see if Steam is actually using your hardware encoding, look in the following log-file:
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;~/.steam/debian-installation/logs/streaming_log.txt
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should have something like:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;CaptureDescriptionID&amp;#34;  &amp;#34;Desktop OpenGL NV12 + NVENC HEVC&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;NVENC&lt;/code&gt; part is important. If you instead have the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;CaptureDescriptionID&amp;#34;  &amp;#34;Desktop OpenGL NV12 + libx264 main (4 threads)&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It means you have software encoding.
Play around with &lt;code&gt;ffmpeg&lt;/code&gt; to verify that NVENC works on your system. The following two commands should work:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% ffmpeg -h encoder=h264_nvenc
% ffmpeg -h encoder=hevc_nvenc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second one is for the HEVC codec. If you are told that the selected encoder is not available, something is broken.
Check to see if you correctly upgraded to the libraries from the &lt;a href=&#34;http://www.debt-multimedia.org/&#34;&gt;Debian multimedia project&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
&lt;summary&gt;Controller not working at all on host&lt;/summary&gt;
Likely your user account does not have permissions to access the device.
It worked for me after making sure that my user was in the following groups:
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;audio dip video plugdev games scanner netdev input
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
&lt;summary&gt;Controller working in Steam but not in game&lt;/summary&gt;
&lt;p&gt;When you start Steam but leave BigPicture mode (Alt+Tab or minimise), Steam usually switches the controller config back to &amp;ldquo;Desktop mode&amp;rdquo; which means Keyboard+Mouse emulation.
If a game is started then, it will not detect any controller.
The same thing seams to happen for certain non-steam games started through Steam.
A workaround is going into the Steam controller settings and selecting the &amp;ldquo;Gamepad&amp;rdquo; configuration also as default for &amp;ldquo;Desktop mode&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
&lt;summary&gt;Black screen and &#34;red antenna symbol&#34;&lt;/summary&gt;
&lt;p&gt;This happens when there is a resolution mismatch somewhere.
Note that we have multiple places and layers where resolution can be set and that steam doesn&amp;rsquo;t always manage to sync these: the host (operating system, Steam, In-Game), the client (operating system, SteamLink).
Additionally, Steam apparently can stream in a lower resolution than is set on either host or target.&lt;/p&gt;
&lt;p&gt;I initially had this problem when streaming from 4k-host onto a SteamLink app that was configured to only accept 1080p.
Changing the host resolution manually to 1080p before starting Steam solved this problem.&lt;/p&gt;
&lt;p&gt;Now that everything (Host, In-Game, SteamLink on client) are configured to 4k, I still get this problem, because apparently Steam still attempts to reduce transmission resolution when starting the game.
For obscure reasons the following workaround is possible: After starting the game, long-press &amp;ldquo;back/select&amp;rdquo; on the Controller to get to the SteamLink menu and select &amp;ldquo;Stop Game&amp;rdquo; there.
This fixes the Black Screen and the regular game screen appears at 4K resolution.
I suspect that &amp;ldquo;Stop game&amp;rdquo; terminates Steam&amp;rsquo;s wrapper around the game&amp;rsquo;s process that screws up the resolution.
The devil knows why this does not terminate the game.&lt;/p&gt;
&lt;/details&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
&lt;summary&gt;SteamLink produces black screen and nothing else&lt;/summary&gt;
&lt;p&gt;When switching in out of SteamLink via Android (e.g. TV remote), SteamLink sometimes doesn&amp;rsquo;t recover.
Probably something goes wrong with putting the app to standby, but it&amp;rsquo;s also not something you typically would. Just quit the app correctly.&lt;/p&gt;
&lt;p&gt;In any case, only a full reboot of the TV seems to fix this and make SteamLink usable again.&lt;/p&gt;
&lt;/details&gt;</content:encoded>
    </item>
    
    <item>
      <title>A beginner&#39;s guide to C&#43;&#43; Ranges and Views.</title>
      <link>https://hannes.hauswedell.net/post/2019/11/30/range_intro/</link>
      <pubDate>Sat, 30 Nov 2019 18:10:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2019/11/30/range_intro/</guid>
      <description>&lt;p&gt;C++ Ranges are one of the major new things in C++20 and &amp;ldquo;views&amp;rdquo; are a big part of ranges.
This article is a short introduction for programmers that are new to C++ Ranges.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;C++ Ranges are one of the major new things in C++20 and &amp;ldquo;views&amp;rdquo; are a big part of ranges.
This article is a short introduction for programmers that are new to C++ Ranges.&lt;/p&gt;
&lt;h1 id=&#34;preface&#34;&gt;Preface&lt;/h1&gt;
&lt;p&gt;You don&amp;rsquo;t need to have any prior knowledge of C++ Ranges, but you should have basic knowledge of C++ iterators and you should have heard of C++ Concepts before.
There are various resources on C++ Concepts, e.g. &lt;a href=&#34;http://www.stroustrup.com/good_concepts.pdf&#34;&gt;Good Concepts&lt;/a&gt;, &lt;a href=&#34;https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)&#34;&gt;Wikipedia&lt;/a&gt; (although both contain slightly outdated syntax).&lt;/p&gt;
&lt;p&gt;This article is based on library documentation that I wrote for the &lt;a href=&#34;https://github.com/seqan/seqan3/&#34;&gt;SeqAn3 library&lt;/a&gt;.
The original is available &lt;a href=&#34;http://docs.seqan.de/seqan/3-master-user/tutorial_ranges.html&#34;&gt;here&lt;/a&gt;.
There is also beginner&amp;rsquo;s documentation on C++ Concepts &lt;a href=&#34;http://docs.seqan.de/seqan/3-master-user/tutorial_concepts.html&#34;&gt;over there&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since none of the large standard libraries ship C++ Ranges right now, you need to use the
&lt;a href=&#34;https://github.com/ericniebler/range-v3/&#34;&gt;range-v3 library&lt;/a&gt; if you want to try any of this.
If you do, you need to replace the &lt;code&gt;std::ranges::&lt;/code&gt; prefixes with just &lt;code&gt;ranges::&lt;/code&gt; and any &lt;code&gt;std::views::&lt;/code&gt; prefixes
with &lt;code&gt;ranges::views::&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;motivation&#34;&gt;Motivation&lt;/h1&gt;
&lt;p&gt;Traditionally most generic algorithms in the C++ standard library, like &lt;code&gt;std::sort&lt;/code&gt;, take a pair of iterators
(e.g. the object returned by &lt;code&gt;begin()&lt;/code&gt;).
If you want to sort a &lt;code&gt;std::vector v&lt;/code&gt;, you have to call &lt;code&gt;std::sort(v.begin(), v.end())&lt;/code&gt; and not &lt;code&gt;std::sort(v)&lt;/code&gt;.
Why was this design with iterators chosen?
It is more flexible, because it allows e.g.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sorting only all elements after the fifth one:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, v.end())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;using non-standard iterators like reverse iterators (sorts in reverse order):&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(v.rbegin(), v.rend());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;combine both (sorts all elements except the last 5 in reverse order):&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(v.rbegin() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, v.rend());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But this interface is less intuitive than just calling &lt;code&gt;std::sort&lt;/code&gt; on the entity that you wish to sort and
it allows for more mistakes, e.g. mixing two incompatible iterators.
C++20 introduces the notion of &lt;em&gt;ranges&lt;/em&gt; and provides algorithms that accept such in the namespace &lt;code&gt;std::ranges::&lt;/code&gt;, e.g.
&lt;code&gt;std::ranges::sort(v)&lt;/code&gt; now works if &lt;code&gt;v&lt;/code&gt; is range – and vectors are ranges!&lt;/p&gt;
&lt;p&gt;What about the examples that suggest superiority of the iterator-based approach? In C++20 you can do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sorting only all elements after the fifth one:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;drop(v, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;sorting in reverse order:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse(v));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;combine both:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;sort(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;drop(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse(v), &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We will discuss later what &lt;code&gt;std::views::reverse(v)&lt;/code&gt; does, for now it is enough to understand that it returns something
that appears like a container and that &lt;code&gt;std::ranges::sort&lt;/code&gt; can sort it.
Later you will see that this approach offers even more flexibility than working with iterators.&lt;/p&gt;
&lt;h1 id=&#34;ranges&#34;&gt;Ranges&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Ranges&lt;/em&gt; are an abstraction of &amp;ldquo;a collection of items&amp;rdquo;, or &amp;ldquo;something iterable&amp;rdquo;. The most basic definition
requires only the existence of &lt;code&gt;begin()&lt;/code&gt; and &lt;code&gt;end()&lt;/code&gt; on the range.&lt;/p&gt;
&lt;h2 id=&#34;range-concepts&#34;&gt;Range concepts&lt;/h2&gt;
&lt;p&gt;There are different ways to classify ranges, the most important one is by the capabilities of its iterator.&lt;/p&gt;
&lt;p&gt;Ranges are typically input ranges (they can be read from),
output ranges (they can be written to) or both.
E.g. a &lt;code&gt;std::vector&amp;lt;int&amp;gt;&lt;/code&gt; is both, but a &lt;code&gt;std::vector&amp;lt;int&amp;gt; const&lt;/code&gt; would only be an input range.&lt;/p&gt;
&lt;p&gt;Input ranges have different &lt;em&gt;strengths&lt;/em&gt; that are realised through more
refined concepts (i.e. types that model a stronger concept, always also model the weaker one):&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Concept&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::input_range&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;can be iterated from beginning to end &lt;strong&gt;at least once&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::forward_range&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;can be iterated from beginning to end &lt;strong&gt;multiple times&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::bidirectional_range&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;iterator can also move backwards with &lt;code&gt;--&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::random_access_range&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;you can jump to elements &lt;strong&gt;in constant-time&lt;/strong&gt; &lt;code&gt;[]&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::contiguous_range&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;elements are always stored consecutively in memory&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These concepts are derived directly from the respective concepts on the iterators, i.e. if the iterator of a range models &lt;code&gt;std::forward_iterator&lt;/code&gt;, than the range is a &lt;code&gt;std::ranges::forward_range&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the well-known containers from the standard library this matrix shows which concepts they model:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;code&gt;std::forward_list&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;code&gt;std::list&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;code&gt;std::deque&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;code&gt;std::array&lt;/code&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;code&gt;std::vector&lt;/code&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::input_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::forward_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::bidirectional_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::random_access_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::contiguous_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There are also range concepts that are independent of input or output or one of the above concepts, e.g.
&lt;code&gt;std::ranges::sized_range&lt;/code&gt; which requires that the size of a range is retrievable by &lt;code&gt;std::ranges::size()&lt;/code&gt;
(in constant time).&lt;/p&gt;
&lt;h2 id=&#34;storage-behaviour&#34;&gt;Storage behaviour&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Containers&lt;/strong&gt; are the ranges most well known, they own their elements.
The standard library already provides many containers, see above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Views&lt;/strong&gt; are ranges that are usually defined on another range and transform the underlying range
via some algorithm or operation.
&lt;del&gt;Views do not own any data beyond their algorithm and the time it takes to construct, destruct or copy them should not
depend on the number of elements they represent.&lt;/del&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit on 2025-05-17:&lt;/strong&gt; &lt;br&gt;
There was an important change after C++20 was released that resulted in &amp;ldquo;view&amp;rdquo; no longer meaning &amp;ldquo;non-owning range&amp;rdquo;. I discuss this in detail in a &lt;a href=&#34;https://hannes.hauswedell.net/post/2025/05/17/non-owning-range/&#34;&gt;new blog post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The algorithm is required to be lazy-evaluated so it is feasible to combine multiple views. More on this below.&lt;/p&gt;
&lt;p&gt;The storage behaviour is orthogonal to the range concepts defined by the iterators mentioned above, i.e. you
can have a container that satisfies &lt;code&gt;std::ranges::random_access_range&lt;/code&gt; (e.g. &lt;code&gt;std::vector&lt;/code&gt; does, but &lt;code&gt;std::list&lt;/code&gt;
does not) and you can have views that do so or don&amp;rsquo;t.&lt;/p&gt;
&lt;h1 id=&#34;views&#34;&gt;Views&lt;/h1&gt;
&lt;h2 id=&#34;lazy-evaluation&#34;&gt;Lazy-evaluation&lt;/h2&gt;
&lt;p&gt;A key feature of views is that whatever transformation they apply, they do so at the moment you request an
element, not when the view is created.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse(vec);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;v&lt;/code&gt; is a view; creating it neither changes &lt;code&gt;vec&lt;/code&gt;, nor does &lt;code&gt;v&lt;/code&gt; store any elements.
The time it takes to construct &lt;code&gt;v&lt;/code&gt; and its size in memory is independent of the size of &lt;code&gt;vec&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse(vec);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will print &amp;ldquo;6&amp;rdquo;, but the important thing is that resolving the first element of &lt;code&gt;v&lt;/code&gt; to the last element of &lt;code&gt;vec&lt;/code&gt;
happens &lt;strong&gt;on-demand&lt;/strong&gt;.
This guarantees that views can be used as flexibly as iterators, but it also means that if the view performs an
expensive transformation, it will have to do so repeatedly if the same element is requested multiple times.&lt;/p&gt;
&lt;h2 id=&#34;combinability&#34;&gt;Combinability&lt;/h2&gt;
&lt;p&gt;You may have wondered why I wrote&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse(vec);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and not&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse v{vec};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s because &lt;code&gt;std::views::reverse&lt;/code&gt; is not the view itself, it&amp;rsquo;s an &lt;em&gt;adaptor&lt;/em&gt; that takes the underlying range
(in our case the vector) and returns a view object over the vector.
The exact type of this view is hidden behind the &lt;code&gt;auto&lt;/code&gt; statement.
This has the advantage, that we don&amp;rsquo;t need to worry about the template arguments of the view type, but more importantly
the adaptor has an additional feature: it can be &lt;em&gt;chained&lt;/em&gt; with other adaptors!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;drop(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What will this print?&lt;/p&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
  &lt;summary&gt;&lt;i&gt;Here is the solution&lt;/i&gt;&lt;/summary&gt;
It will print &#34;4&#34;, because &#34;4&#34; is the 0-th element of the reversed string after dropping the first two.
&lt;/details&gt;
&lt;p&gt;In the above example the vector is &amp;ldquo;piped&amp;rdquo; (similar to the unix command line) into the reverse adaptor and then into
the drop adaptor and a combined view object is returned.
The pipe is just a different notation that improves readability, i.e. &lt;code&gt;vec | foo | bar(3) | baz(7)&lt;/code&gt; is equivalent to
&lt;code&gt;baz(bar(foo(vec), 3), 7)&lt;/code&gt;.
Note that accessing the 0th element of the view is still lazy, determining which element it maps to happens at the time
of access.&lt;/p&gt;
&lt;h3 id=&#34;exercise&#34;&gt;Exercise&lt;/h3&gt;
&lt;p&gt;Create a view on &lt;code&gt;std::vector vec{1, 2, 3, 4, 5, 6};&lt;/code&gt; that filters out all uneven numbers and squares the
remaining (even) values, i.e.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// ...?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// should print 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To solve this you can use &lt;code&gt;std::views::transform&lt;/code&gt; and &lt;code&gt;std::views::filter&lt;/code&gt;.
Both take a invocable as argument, e.g. a lambda expression.
&lt;code&gt;std::views::transform&lt;/code&gt; applies the lambda on each element in the underlying range and &lt;code&gt;std::views::filter&lt;/code&gt;
&amp;ldquo;removes&amp;rdquo; those elements that its lambda function evaluates to false for.&lt;/p&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
  &lt;summary&gt;&lt;i&gt;Here is the solution&lt;/i&gt;&lt;/summary&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;filter(   [] (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; i) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;transform([] (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; i) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;i; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// prints 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;br&gt;
&lt;h2 id=&#34;view-concepts&#34;&gt;View concepts&lt;/h2&gt;
&lt;p&gt;Views are a specific kind of range that is formalised in the &lt;code&gt;std::ranges::view&lt;/code&gt; concept.
Every view returned by a view adaptor models this concept, but which other range concepts are modeled by a view?&lt;/p&gt;
&lt;p&gt;It depends on the underlying range and also the view itself.
With few exceptions, views don&amp;rsquo;t model more/stronger range concepts than their underlying range (except that they are
always a &lt;code&gt;std::ranges::view&lt;/code&gt;) and they try to preserve as much of the underlying range&amp;rsquo;s concepts as possible.
For instance the view returned by &lt;code&gt;std::views::reverse&lt;/code&gt; models &lt;code&gt;std::ranges::random_access_range&lt;/code&gt; (and weaker concepts)
iff the underlying range also models the respective concept.
It never models &lt;code&gt;std::ranges::contiguous_range&lt;/code&gt;, because the third element of the view is not located immediately after
the second in memory (but instead before the second).&lt;/p&gt;
&lt;p&gt;Perhaps surprising to some, many views also model &lt;code&gt;std::ranges::output_range&lt;/code&gt; if the underlying range does, i.e. &lt;strong&gt;views
are not read-only&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;reverse &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;views&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;drop(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;v.begin() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// now vec == {1, 2, 3, 42, 5, 6 } !!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;exercise-1&#34;&gt;Exercise&lt;/h3&gt;
&lt;p&gt;Have a look at the solution to the previous exercise (filter+transform).
Which of the following concepts do you think &lt;code&gt;v&lt;/code&gt; models?&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Concept&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;yes/no?&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::input_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::forward_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::bidirectional_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::random_access_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::contiguous_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::view&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::sized_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::output_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
  &lt;summary&gt;&lt;i&gt;Here is the solution&lt;/i&gt;&lt;/summary&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Concept&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;yes/no?&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::input_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::forward_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::bidirectional_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::random_access_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::contiguous_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::view&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;✅&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::sized_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;std::ranges::output_range&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The filter does not preserve random-access and therefore not contiguity, because it doesn&amp;rsquo;t &amp;ldquo;know&amp;rdquo; which element
of the underlying range is the i-th one in constant time.
It cannot &amp;ldquo;jump&amp;rdquo; there, it needs to move through the underlying range element-by-element.
This also means we don&amp;rsquo;t know the size.&lt;/p&gt;
&lt;p&gt;The transform view would be able to jump, because it always performs the same operation on every element independently
of each other; and it would also preserve sized-ness because the size remains the same.
In any case, both properties are lost due to the filter.
On the other hand the transform view produces a new element on every access (the result of the multiplication), therefore
&lt;code&gt;v&lt;/code&gt; is not an output range, you cannot assign values to its elements.
This would have prevented modelling contiguous-range as well – if it hadn&amp;rsquo;t been already by the filter – because
values are created on-demand and are not stored in memory at all.&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;Understanding which range concepts &amp;ldquo;survive&amp;rdquo; which particular view needs some practice.
For the SeqAn3 library we try to &lt;a href=&#34;https://docs.seqan.de/seqan/3-master-user/group__views.html&#34;&gt;document this in detail&lt;/a&gt;,
I hope we will see something similar on cppreference.com.&lt;/p&gt;
&lt;h1 id=&#34;post-scriptum&#34;&gt;Post scriptum&lt;/h1&gt;
&lt;p&gt;I am quite busy currently with my PhD thesis, but I plan to publish some smaller articles on ranges and views before
the holiday season.
Most will be based on text pieces I have already written but that never found their way to this blog
(library documentation, WG21 papers, snippets from the thesis, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;Thanks for reading, I hope this article was helpful! If you have any questions, please comment here or on
twitter/mastodon.&lt;/p&gt;</content:encoded>
    </item>
    
    <item>
      <title>A good firewall for a small network</title>
      <link>https://hannes.hauswedell.net/post/2019/06/24/firewall/</link>
      <pubDate>Mon, 24 Jun 2019 00:15:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2019/06/24/firewall/</guid>
      <description>&lt;p&gt;In this article I will outline the setup of my (not so) new firewall at home.
I explain how I decided which hardware to get and which software to choose, and I cover the entire process of assembling the machine and installing the operating system.
Hopefully this will be helpful to poeple in similar situations.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;In this article I will outline the setup of my (not so) new firewall at home.
I explain how I decided which hardware to get and which software to choose, and I cover the entire process of assembling the machine and installing the operating system.
Hopefully this will be helpful to poeple in similar situations.&lt;/p&gt;
&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/fire.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;While the ability of firewalls to protect against all the evils of the internets
is certainly exaggerated, there are some important use cases for them: you want to prevent certain inbound
traffic and manipulate certain outbound traffic e.g. route it through a VPN.&lt;/p&gt;
&lt;p&gt;For a long time I used my home server (whose main purpose is network attached storage) to also do
some basic routing and VPN, but this had a couple of important drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Just one NIC on the server meant traffic to/from the internet wasn&amp;rsquo;t physically
required to go through the server.&lt;/li&gt;
&lt;li&gt;Less reliable due to more complex setup → longer downtimes during upgrades, higher chance of failure due
to hard drives.&lt;/li&gt;
&lt;li&gt;I wouldn&amp;rsquo;t give someone else the root password to my data storage, but I did want my flat-mates to be
able to reset and configure basic network components that they depend on (Router/Port-forwarding and WiFi).&lt;/li&gt;
&lt;li&gt;I wanted to isolate the ISP-provided router more strongly from the LAN as they have a history of security
vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The different off-the-shelf routers I had used over the years had also worked only so-so (even those that were customisable) so I decided I needed a proper router.
Since WiFi access was already out-sourced to dedicated devices I really only needed a filtering and routing device.&lt;/p&gt;
&lt;h1 id=&#34;hardware&#34;&gt;Hardware&lt;/h1&gt;
&lt;h2 id=&#34;board--cpu&#34;&gt;Board &amp;amp; CPU&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/mainboard_small.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The central requirements for the device were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;low energy consumption&lt;/li&gt;
&lt;li&gt;enough CPU power to route traffic at Gbit-speed, run Tor and OpenVPN (we don&amp;rsquo;t have Gbit/s internet in Berlin, yet, but I still have hopes for the future)&lt;/li&gt;
&lt;li&gt;hardware crypto support to unburden the CPU for crypto tasks&lt;/li&gt;
&lt;li&gt;two NICs, one for the LAN and one for the WAN&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I briefly thought about getting an ARM-based embedded board, but most reviews suggested that the performance
wouldn&amp;rsquo;t be enough to satisfy my requirements and also the *BSD support was mixed at best and I didn&amp;rsquo;t want
to rule out running OpenBSD or FreeBSD.&lt;/p&gt;
&lt;p&gt;Back to x86-land: I had previously used &lt;a href=&#34;https://pcengines.ch/&#34;&gt;PC Engines&lt;/a&gt; ALIX boards as routers and
was really happy with them at the time.
Their new APU boards promised better performance, but thanks to the valuable feedback and some benchmarking
done by the community over at &lt;a href=&#34;https://bsdforen.de&#34;&gt;BSDForen.de&lt;/a&gt;, I came to the conclusion that they wouldn&amp;rsquo;t
be able to push more than 200Mbit/s through an OpenVPN tunnel.&lt;/p&gt;
&lt;p&gt;In the end I decided on the &lt;a href=&#34;https://www.amazon.de/dp/B071R4P6QG/?tag=fsfe-21&#34;&gt;Gigabyte J3455N-D3H&lt;/a&gt; displayed at the top.
It sports a rather atypical Intel CPU
(&lt;a href=&#34;https://ark.intel.com/content/www/us/en/ark/products/95594/intel-celeron-processor-j3455-2m-cache-up-to-2-3-ghz.html&#34;&gt;Celeron J3455&lt;/a&gt;) with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;four physical cores @ 1.5Ghz&lt;/li&gt;
&lt;li&gt;AESNI support&lt;/li&gt;
&lt;li&gt;10W TDP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having four actual cores (instead of 2 cores + hyper threading) is pretty cool now that many security-minded
operating systems have started deactivating hyper threading to mitigate CPU bugs
[&lt;a href=&#34;https://www.mail-archive.com/source-changes@openbsd.org/msg99141.html&#34;&gt;OpenBSD&lt;/a&gt;]
[&lt;a href=&#34;https://hardenedbsd.org/article/op/2018-12-17/stable-release-hardenedbsd-stable-12-stable-v1200058&#34;&gt;HardenedBSD&lt;/a&gt;].
And the power consumption is also quite low.&lt;/p&gt;
&lt;p&gt;I would have liked for the two NICs on the mainboard to be from Intel, but I couldn&amp;rsquo;t find a mainboard at the time that offered this (other than super-expensive SuperMicro boards).
At least the driver support on modern Realteks is quite good.&lt;/p&gt;
&lt;h2 id=&#34;storage--memory&#34;&gt;Storage &amp;amp; Memory&lt;/h2&gt;
&lt;p&gt;The board has two memory slots and supports a maximum of 4GiB each.
I decided 4GiB are enough for now and gave it one module to allow for future extensions (I know that&amp;rsquo;s
suboptimal for speed).&lt;/p&gt;
&lt;p&gt;Storage-wise I originally planned on putting a left-over SATA-SSD into the case, but in the end, I decided
a tiny USB3-Stick would provide sufficient performance and be much easier to replace/debug/&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;case--power&#34;&gt;Case &amp;amp; Power&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/case1.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Since I installed a real 19&amp;quot; wrack in my new flat, of course the case for the firewall would have to fit
nicely into that.
I had a surprisingly difficult time finding a good case, because I wanted one were the board&amp;rsquo;s ports
would be front-facing.
That seems to be quite a rare requirement, although I really don&amp;rsquo;t understand why.
Obviously having the network ports, serial ports and USB-Ports to the front makes changing the setup and
debugging so much easier &lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I also couldn&amp;rsquo;t find a good power supply for such a low-power device, but I still had a 60W PicoPSU supply lying around.&lt;/p&gt;
&lt;p&gt;Even though it came with an overpowered PSU and a proprietary IO-Shield (more on that below), I decided on the SuperMicro &lt;a href=&#34;https://www.supermicro.com/products/chassis/1u/505/SC505-203B&#34;&gt;SC505-203B&lt;/a&gt;.
It really does look quite good, I have to say!&lt;/p&gt;
&lt;h2 id=&#34;assembly&#34;&gt;Assembly&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/cut1.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Mounting the mainboard in the case is pretty straight-forward.
The biggest issue was the aforementioned proprietary I/O-Shield that came with the SuperMicro case (and was
designed only for SuperMicro-boards).
It was possible to remove it, however, the resulting open space did not conform to ATX spec
so it wasn&amp;rsquo;t possible to just fit the Gigabyte board&amp;rsquo;s shield into it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/cut2.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I quickly took the measurements and starting cutting away on the shield to make it fit.
This worked ok-ish in the end, but is more dangerous than it looks (be smarter than me, wear gloves ☝ ).
In retrospect I also recommend that you do not remove the bottom fold on the shield, only left, right and top;
that will make it hold a lot better in the case opening.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/assembled.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The board can be fit into the case using standard screws in the designated places.
As mentioned above, I removed the original (actively cooled) power supply unit and used the 60W PicoPSU that I had lying around from before.
Since it doesn&amp;rsquo;t have the 4-pin CPU cable I had improvise. There are adaptors for this, but if you have a left-over power supply, you can also tape together something.
I also put the transformer into the case (duck-tape, yeah!) so that one can plug in the power cord from the back of the case as usual.&lt;/p&gt;
&lt;h1 id=&#34;software&#34;&gt;Software&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://opnsense.org/&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/opnsense.png#center&#34; alt=&#34;OPNSense logo&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;choice&#34;&gt;Choice&lt;/h2&gt;
&lt;p&gt;There are many operating systems I could have chosen since I decided to use an x86 platform.
My criteria were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;free software (obviously)&lt;/li&gt;
&lt;li&gt;intuitive web user interface to do at least the basic things&lt;/li&gt;
&lt;li&gt;possibility to login via SSH if things don&amp;rsquo;t go as planned&lt;/li&gt;
&lt;li&gt;OpenVPN client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I feel better with operating systems based on &lt;a href=&#34;https://www.freebsd.org/&#34;&gt;FreeBSD&lt;/a&gt; or &lt;a href=&#34;https://www.openbsd.org/&#34;&gt;OpenBSD&lt;/a&gt;, mainly because I have more experience with them than with GNU/Linux distributions nowadays.
In previous flats I had also used &lt;a href=&#34;https://openwrt.org/&#34;&gt;OpenWRT&lt;/a&gt; and &lt;a href=&#34;https://dd-wrt.com/&#34;&gt;dd-wrt&lt;/a&gt; based routers, but whenever I needed to tweak something beyond what the web interface offered, it got really painful.
In general the whole IPtables based stack on Linux seems overly complicated, but maybe that&amp;rsquo;s just me.&lt;/p&gt;
&lt;p&gt;In any case, there are no OpenBSD-based router operating systems with web interfaces (that I am aware of) so I had the choice between&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://www.pfsense.org/&#34;&gt;pfsense&lt;/a&gt; (&lt;a href=&#34;https://www.freebsd.org/&#34;&gt;FreeBSD&lt;/a&gt;-based)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://opnsense.org/&#34;&gt;OPNSense&lt;/a&gt;, fork of pfsense, based on &lt;a href=&#34;https://hardenedbsd.org/&#34;&gt;HardenedBSD&lt;/a&gt; / &lt;a href=&#34;https://www.freebsd.org/&#34;&gt;FreeBSD&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There seem to be historic tensions between the people involved in both operating systems and I couldn&amp;rsquo;t find out if there were actual distinctions in the goals of the projects.
In the end, I asked other people for recommendations and found the interface and feature list of OPNSense more convincing.
Also, being based on HardenedBSD sounds good (although I am not sure if HardenedBSD-specifica will really ever play out on the router).&lt;/p&gt;
&lt;p&gt;Initially I had some issues with the install and OPNSense people were super-friendly and responded immediately. Also the interface was a lot better than I expected so I am quite sure I made the right decision.&lt;/p&gt;
&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;
&lt;p&gt;Setup is very easy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;a href=&#34;https://opnsense.org/download/&#34;&gt;https://opnsense.org/download/&lt;/a&gt;, select &lt;code&gt;amd64&lt;/code&gt; and &lt;code&gt;nano&lt;/code&gt; and download the image.&lt;/li&gt;
&lt;li&gt;Unzip the image (easy to forget this).&lt;/li&gt;
&lt;li&gt;Write the image to the USB-stick with &lt;code&gt;dd&lt;/code&gt; (as always with &lt;code&gt;dd&lt;/code&gt;: &lt;strong&gt;be careful about the target device!&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Optionally plug a serial cable into the top serial port (the mainboard has two) and connect your Laptop/Desktop with baud rate 115200&lt;/li&gt;
&lt;li&gt;Plug the USB-stick into the firewall and boot it up.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There will be some beeping when you start the firewall. Some of this is due to the mainboard complaining that no keyboard is attached (can be ignored) and also OPNSense will play a melody when it is booted.
If you are attached to the serial console you can select which interface will be WAN and which will be LAN (and their IP addresses).
Otherwise you might need to plug around the LAN cables a bit to find out which is configured as which.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;&lt;i&gt; When I built this last year there were some more issues, but all of them have been resolved by the OPNSense people so it really is &amp;ldquo;plug&amp;rsquo;n&amp;rsquo;play&amp;rdquo;; I verified by doing a re-install!&lt;/i&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&#34;post-install&#34;&gt;Post-install&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/opnsense_login.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Go to the configured IP-address (&lt;code&gt;192.168.1.1&lt;/code&gt; by default) and login (&lt;code&gt;root&lt;/code&gt;: &lt;code&gt;opnsense&lt;/code&gt; by default).
If the web-interface comes up everything has worked fine and you can disconnect serial console and do the rest via the web-interface.&lt;/p&gt;
&lt;p&gt;After login, I would to the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;change the password&lt;/li&gt;
&lt;li&gt;activate SSH on the LAN interface&lt;/li&gt;
&lt;li&gt;configure internet access and DHCP&lt;/li&gt;
&lt;li&gt;setup any of the other services you want&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For me setting up the internet meant doing a &amp;ldquo;double-NAT&amp;rdquo; with the ISP-provided router, because I need its modem and nowadays it seems impossible to get a stand-alone VDSL modem. If you do something similar just configure internet as being over DHCP.&lt;/p&gt;
&lt;p&gt;If you want hardware accelerated SSL (also OpenVPN), go to &lt;code&gt;System → Firmware → Setting&lt;/code&gt; and change the firmware flavour to &lt;code&gt;OpenSSL&lt;/code&gt; (instead of &lt;code&gt;LibreSSL&lt;/code&gt;). After that check for updates and upgrade.
In the OpenVPN profile, under &lt;code&gt;Hardware Crypto&lt;/code&gt;, you can now select &lt;code&gt;Intel RDRAND engine - RAND&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2019/06/opnsense_dashboard.png#center&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Take your time to look through the interface! I found some pretty cool things like automatic backup of the configuration to a nextcloud server! The entire config of the firewall rests in one file so it&amp;rsquo;s really easy to setup a clean system from scratch.&lt;/p&gt;
&lt;p&gt;All-in-all I am very happy with the system. Even though my setup is non-trivial, with only selected outgoing traffic going through the VPN (based on rules), I never had to get my hands dirty on the command line – everything can be done through the Web-UI.&lt;/p&gt;</content:encoded>
    </item>
    
    <item>
      <title>Tutorial: Writing your first view from scratch (C&#43;&#43;20 / P0789)</title>
      <link>https://hannes.hauswedell.net/post/2018/04/11/view1/</link>
      <pubDate>Wed, 11 Apr 2018 13:45:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2018/04/11/view1/</guid>
      <description>&lt;p&gt;C++17 was officially released last year and the work on C++20 quickly took off.
A subset of the Concepts TS was merged and the first part of the Ranges TS has been accepted, too.
Currently the next part of the Ranges TS is under review:
&lt;a href=&#34;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0789r0.pdf&#34;&gt;&amp;ldquo;Range Adaptors and Utilities&amp;rdquo;&lt;/a&gt;.
It brings the much-hyped &amp;ldquo;Views&amp;rdquo; to C++, but maybe you have been using them already via the
&lt;a href=&#34;https://ericniebler.github.io/range-v3/&#34;&gt;Range-V3 library&lt;/a&gt;?
In any case you might have wondered what you need to do to actually write your own view.
This is the first in a series of blog posts describing complete view implementations (not just adaptations of existing ones).&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;C++17 was officially released last year and the work on C++20 quickly took off.
A subset of the Concepts TS was merged and the first part of the Ranges TS has been accepted, too.
Currently the next part of the Ranges TS is under review:
&lt;a href=&#34;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0789r0.pdf&#34;&gt;&amp;ldquo;Range Adaptors and Utilities&amp;rdquo;&lt;/a&gt;.
It brings the much-hyped &amp;ldquo;Views&amp;rdquo; to C++, but maybe you have been using them already via the
&lt;a href=&#34;https://ericniebler.github.io/range-v3/&#34;&gt;Range-V3 library&lt;/a&gt;?
In any case you might have wondered what you need to do to actually write your own view.
This is the first in a series of blog posts describing complete view implementations (not just adaptations of existing ones).&lt;/p&gt;
&lt;h1 id=&#34;disclaimer-2023-02-27&#34;&gt;DISCLAIMER 2023-02-27&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;This article does not reflect the final state of ranges and views (although nothing about them is really final as
they keep changing even within C++20). It likely does not work with current ranges from the standard libary!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I might write a new post at some point, but the current one is outdated.&lt;/p&gt;
&lt;h1 id=&#34;introduction-skip-this-if-you-have-used-views-before&#34;&gt;Introduction (skip this if you have used views before)&lt;/h1&gt;
&lt;p&gt;Ranges are an abstraction of &amp;ldquo;a collection of items&amp;rdquo;, or &amp;ldquo;something iterable&amp;rdquo;.
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/Range&#34;&gt;The most basic definition&lt;/a&gt; requires only the
existence of begin() and end(), their comparability and begin being incrementable,
but more refined range concepts add more requirements.&lt;/p&gt;
&lt;p&gt;The ranges most commonly known are containers, e.g. std::vector.
Containers are types of ranges that &lt;em&gt;own&lt;/em&gt; the elements in the collection, but in this blog post we are more interested &lt;em&gt;views&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What are views?&lt;/p&gt;
&lt;p&gt;Views are ranges that usually (but not always!) performs an operation on another range.
They are &lt;a href=&#34;https://en.wikipedia.org/wiki/Lazy_evaluation&#34;&gt;lazy-evaluated&lt;/a&gt; stateful algorithms on ranges that present their result again as a range.
And they can be chained to combine different algorithms which can be done via the &lt;code&gt;|&lt;/code&gt; operator like on the UNIX command line.&lt;/p&gt;
&lt;p&gt;Ok, sounds cool, what does this mean in practice?&lt;/p&gt;
&lt;p&gt;Well, you can, e.g. take a vector of ints, apply a view that computes the square of every element,
and then apply a view that drops the first two elements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; vec{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; vec &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;transform([] (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; i) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;i; }) &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;drop(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;begin(v) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// prints &amp;#39;36&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the point here is that only one &amp;ldquo;squaring-operation&amp;rdquo; actually happens and that it happens when we dereference the iterator,
not before (because of lazy evaluation!).&lt;/p&gt;
&lt;p&gt;What type is &lt;code&gt;v&lt;/code&gt;?  It is some implementation defined type that is guaranteed to satisfy certain range concepts:
the &lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/View&#34;&gt;View concept&lt;/a&gt; and the
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/InputRange&#34;&gt;InputRange concept&lt;/a&gt;.
The view concept has some important requirements, among them that the type is &amp;ldquo;light-weight&amp;rdquo;,
i.e. copy&amp;rsquo;able in constant time. So while views &lt;em&gt;appear&lt;/em&gt; like containers, they behave more like iterators.&lt;/p&gt;
&lt;p&gt;If you are lost already, I recommend you check out some of the following resources&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fluentcpp.com/2018/02/09/introduction-ranges-library/&#34;&gt;Introduction to the C++ Ranges Library&lt;/a&gt; on FluentCpp (Blog Post and Video)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=mFUXNMfaciE&#34;&gt;Ranges for the Standard Library&lt;/a&gt; – CppCon2015 talk by EricNiebler&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ericniebler.github.io/range-v3/&#34;&gt;Range-V3 Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h1&gt;
&lt;p&gt;The following sections assume you have a basic understanding of what a view does and have at least tried some of the toy examples yourself.&lt;/p&gt;
&lt;p&gt;DISCLAIMER: Although I have been working with views and range-v3 for a while now, I am surprised by things again and again.
If you think I missed something important in this article I would really appreciate feedback!&lt;/p&gt;
&lt;p&gt;In general this post is aimed at interested intermediate C++ programmers, I try to be verbose with explanations and also provide many links for
further reading.&lt;/p&gt;
&lt;p&gt;You should have a fairly modern compiler to test the code, I test with GCC7 and Clang5 and compile with &lt;code&gt;-std=c++17 -Wall -Wextra&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I refer to &lt;a href=&#34;http://en.cppreference.com/w/cpp/language/constraints&#34;&gt;constraints and concepts&lt;/a&gt; in some of the examples.
These are not
crucial for the implementation so if they are entirely unfamiliar to you, just skip over them. If you use GCC on the
other hand, you can uncomment the respective sections and add &lt;code&gt;-fconcepts&lt;/code&gt; to your compiler call to activate them.&lt;/p&gt;
&lt;p&gt;While the views we are implementing are self-contained and independent of the range-v3 library, you should
&lt;a href=&#34;https://github.com/ericniebler/range-v3/&#34;&gt;get it now&lt;/a&gt; as some of our checks and examples require it.&lt;/p&gt;
&lt;p&gt;And you should be curious of how to make your own view, of course 😄&lt;/p&gt;
&lt;h1 id=&#34;adapting-existing-views&#34;&gt;Adapting existing views&lt;/h1&gt;
&lt;p&gt;Our task in this post is to write a view that works on input ranges of &lt;code&gt;uint64_t&lt;/code&gt; and always adds the number 42,
i.e. we want the following to work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; in{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; i : in &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;add_constant)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// should print: 43 46 48 131 98 87 49
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;// combine it with other views:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; i : in &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;add_constant &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// should print: 43 46 48
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most of the time it will be sufficient to adapt an existing view and whenever this is feasible it is of course recommended.
So the &lt;em&gt;recommended solution&lt;/em&gt; to the task is to just re-use &lt;code&gt;ranges::view::transform&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;range/v3/view/transform.hpp&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;range/v3/view/take.hpp&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; add_constant &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;transform([] (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; in)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                   {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; in &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                   });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; in{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; i : in &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;add_constant)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// should print: 43 47 64 131 98 87 49
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;// combine it with other views:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; i : in &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;add_constant &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;take(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// should print: 43 47 64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it&amp;rsquo;s very easy to adapt existing views!&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s not always possible to re-use existing views and the task was to get our hands dirty with writing our own view.
The &lt;a href=&#34;https://ericniebler.github.io/range-v3/#tutorial-quick-start&#34;&gt;official manual&lt;/a&gt; has some notes on this, but while abstractions
are great for code-reuse in a large library and make the code easier to understand for those that know what lies behind them,
I would argue that they can also obscure the actual implementation for developers new to the code base who need to puzzle together
the different levels of inheritance and template specialisation typical for C++ abstractions.&lt;/p&gt;
&lt;p&gt;So in this post we will develop a view that does not depend on range-v3, especially not the internals.&lt;/p&gt;
&lt;h1 id=&#34;the-components-of-a-view&#34;&gt;The components of a view&lt;/h1&gt;
&lt;p&gt;What is commonly referred to as a view usually consists of multiple entities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the actual class (template) that meets the requirements of the &lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/View&#34;&gt;View concept&lt;/a&gt; and at least also &lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/InputRange&#34;&gt;InputRange concept&lt;/a&gt;;
by convention of the range-v3 library it is called &lt;code&gt;view_foo&lt;/code&gt; for the hypothetical view &amp;ldquo;foo&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;an adaptor type which overloads the &lt;code&gt;()&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt; operators that facilitate the &amp;ldquo;piping&amp;rdquo; capabilities and &lt;em&gt;return an instance of 1.&lt;/em&gt;;
by convention of range-v3 it is called &lt;code&gt;foo_fn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;an instance of the adaptor class that is the only user-facing part of the view;
by convention of range-v3 it is called &lt;code&gt;foo&lt;/code&gt;, in the namespace &lt;code&gt;view&lt;/code&gt;, i.e. &lt;code&gt;view::foo&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the view you are creating is just a combination of existing views, you may not need to implement 1. or even 2.,
but we will go through all parts now.&lt;/p&gt;
&lt;h1 id=&#34;the-actual-implementation&#34;&gt;The actual implementation&lt;/h1&gt;
&lt;h2 id=&#34;preface&#34;&gt;preface&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;range/v3/all.hpp&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; iterator_t &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decltype&lt;/span&gt;(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;begin(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;declval&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;gt;&lt;/span&gt;()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; range_reference_t &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decltype&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;begin(std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;declval&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;gt;&lt;/span&gt;()));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;As mentionend previously, including range-v3 is optional, we only use it for concept checks – and in production
code you will want to select concrete headers and not &amp;ldquo;all&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;iterator_t&lt;/code&gt; metafunction retrieves the iterator type from a range by checking the return type of &lt;code&gt;begin()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;range_reference_t&lt;/code&gt; metafunction retrieves the reference type of a range which is what you get when
dereferencing the iterator. It is only needed in the concept checks. &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Both of these functions are defined in the range-v3 library, as well, but I have given minimal definitions here
to show that we are not relying on any sophisticated magic somewhere else.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;view_add_constant&#34;&gt;&lt;code&gt;view_add_constant&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We start with the first real part of the implementation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//     requires (bool)ranges::InputRange&amp;lt;urng_t&amp;gt;() &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//              (bool)ranges::CommonReference&amp;lt;range_reference_t&amp;lt;urng_t&amp;gt;, uint64_t&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;view_add_constant&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;view_base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;view_add_constant&lt;/code&gt; is a class template, because it needs to hold a reference to the underlying range it operates on;
that range&amp;rsquo;s type &lt;code&gt;urng_t&lt;/code&gt; is passed in a as template parameter.&lt;/li&gt;
&lt;li&gt;If you use GCC, you can add &lt;code&gt;-fconcepts&lt;/code&gt; and uncomment the requires-block. It enforces certain constraints
on &lt;code&gt;urng_t&lt;/code&gt;, the most basic constraint being that it is an &lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/InputRange&#34;&gt;InputRange&lt;/a&gt;.
The second constraint is that the underlying range is actually a range over &lt;code&gt;uint64_t&lt;/code&gt; (possibly with reference or &lt;code&gt;const&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Please note&lt;/em&gt; that these constraints are specific to the view we are just creating. Other views will have different requirements
on the reference type or even the range itself (e.g. it could be required to satisfy
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/RandomAccessRange&#34;&gt;RandomAccessRange&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;We inherit from &lt;code&gt;view_base&lt;/code&gt; which is an empty base class, because being derived from it signals to some library checks that this
class is really trying to be a view (which is otherwise difficult to detect sometimes); in our example we could also
omit it.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* data members == &amp;#34;the state&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data_members_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        urng_t urange;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;shared_ptr&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;data_members_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; data_members;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The only data member we have is (the reference to) the original range. It may look like we are saving a value here,
but depending on the actual specialisation of the class template, &lt;code&gt;urng_t&lt;/code&gt; may also contain &lt;code&gt;&amp;amp;&lt;/code&gt; or &lt;code&gt;const &amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Why do we put the member variables inside an extra data structure stored in a smart pointer? A requirement of views
is that they be copy-able in constant time, e.g. there should be no expensive operations like allocations during copying.
An easy and good way to achieve implicit sharing of the data members is to put them inside a &lt;code&gt;shared_ptr&lt;/code&gt;.
Thereby all copies share the data_members and they get deleted with the last copy. &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;In cases where we only hold a reference, this is not strictly required, but in those cases we still benefit from the
fact that storing the reference inside the smart pointer makes our view default-constructible. This is another
requirement of views – and having a top-level reference member prevents this. [Of course you can use a top-level
pointer instead of a reference, but we don&amp;rsquo;t like raw pointers anymore!]&lt;/li&gt;
&lt;li&gt;Other more complex views have more variables or &amp;ldquo;state&amp;rdquo; that they might be saving in &lt;code&gt;data_members&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* the iterator type */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;iterator_type&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; iterator_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; base &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; iterator_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; reference &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        iterator_type() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        iterator_type(base &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; b) &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; base{b} {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        iterator_type &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static_cast&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;base&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;gt;&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        iterator_type &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static_cast&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;base&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;gt;&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        reference &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static_cast&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;base&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Next we define an iterator type. Since &lt;code&gt;view_add_constant&lt;/code&gt; needs to satisfy basic range requirements,
you need to be able to iterate over it. In our case we can stay close to the original and inherit from the original iterator.&lt;/li&gt;
&lt;li&gt;For the iterator to satisfy the
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/iterator/InputIterator&#34;&gt;InputIterator concept&lt;/a&gt; we need to
overload the increment operators so that their return type is of our class
and not the base class. The important overload is that of the dereference operation, i.e. actually getting the value.
This is the place where we interject and call the base class&amp;rsquo;s dereference, but then add the constant 42.
Note that this changes the return type of the operation (&lt;code&gt;::reference&lt;/code&gt;); it used to be &lt;code&gt;uint64_t &amp;amp;&lt;/code&gt;
(possibly &lt;code&gt;uint64_t const &amp;amp;&lt;/code&gt;), now it&amp;rsquo;s &lt;code&gt;uint64_t&lt;/code&gt; → A new value is always generated as the result of adding &lt;code&gt;42&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note&lt;/em&gt; that more complex views might require drastically more complex iterators and it might make sense to define those externally.
In general iterators involve a lot of &lt;a href=&#34;https://en.wikipedia.org/wiki/Boilerplate_code&#34;&gt;boilerplate code&lt;/a&gt;, depending on the scope of your
project it might make sense to add your own iterator base classes. Using &lt;a href=&#34;https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&#34;&gt;CRTP&lt;/a&gt;
also helps re-use code and reduce &amp;ldquo;non-functional&amp;rdquo; overloads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We continue with the public interface:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* member type definitions */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; reference         &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; const_reference   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; value_type        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; iterator          &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; iterator_type;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; const_iterator    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; iterator_type;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;First we define the member types that are common for input ranges. Of course our value type is &lt;code&gt;uint64_t&lt;/code&gt; as we only operate on ranges
over &lt;code&gt;uint64_t&lt;/code&gt; and we are just adding a number. As we mentioned above, our iterator will always generate new values when dereferenced
so the reference types are also value types.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note:&lt;/em&gt; Other view implementation might be agnostic of the actual value type, e.g. a view that reverses the elements can do so
independent of the type. AND views might also satisfy
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/OutputRange&#34;&gt;OutputRange&lt;/a&gt;, i.e. they allow writing to the
underlying range by passing
through the reference. To achieve this behaviour you would write &lt;code&gt;using reference = range_reference_t&amp;lt;urng_t&amp;gt;;&lt;/code&gt;.
The value type would then be the reference type with any references stripped
(&lt;code&gt;using value_type = std::remove_cv_t&amp;lt;std::remove_reference_t&amp;lt;reference&amp;gt;&amp;gt;;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The iterator type is just the type we defined above.&lt;/li&gt;
&lt;li&gt;In general views are not required to be const-iterable, but if they are the &lt;code&gt;const_iterator&lt;/code&gt; is the same as the &lt;code&gt;iterator&lt;/code&gt; and
&lt;code&gt;const_reference&lt;/code&gt; is the same as &lt;code&gt;reference&lt;/code&gt;. &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* constructors and deconstructors */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    view_add_constant() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;view_add_constant&lt;/span&gt;(view_add_constant &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; rhs) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;view_add_constant&lt;/span&gt;(view_add_constant &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rhs) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; view_add_constant &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(view_add_constant &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; rhs) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; view_add_constant &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(view_add_constant &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rhs) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;view_add_constant() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    view_add_constant(urng_t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; urange)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; data_members{&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; data_members_t{std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;forward&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(urange)}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The constructors are pretty much standard. We have an extra constructor that initialises our urange from the value passed in.
Note that this constructor covers all cases of input types (&lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;const &amp;amp;&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;), because more attributes can be stuck in the
actual &lt;code&gt;urng_t&lt;/code&gt; and because of &lt;a href=&#34;http://en.cppreference.com/w/cpp/language/reference&#34;&gt;reference collapsing&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* begin and end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    iterator &lt;span style=&#34;color:#a6e22e&#34;&gt;begin&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;begin(data_members&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;urange);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    iterator &lt;span style=&#34;color:#a6e22e&#34;&gt;cbegin&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; begin();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;end&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;end(data_members&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;urange);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cend&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; end();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Finally we add &lt;code&gt;begin()&lt;/code&gt; and &lt;code&gt;end()&lt;/code&gt;. Since we added a constructor for this above, we can create our view&amp;rsquo;s iterator
from the underlying range&amp;rsquo;s iterator implicitly when returning from &lt;code&gt;begin()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For some ranges the sentinel type (the type returned by &lt;code&gt;end()&lt;/code&gt;) is not the same as the type returned by &lt;code&gt;begin()&lt;/code&gt;,
this is only true for &lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/BoundedRange&#34;&gt;BoundedRanges&lt;/a&gt;;
the only requirement is that the types are comparable with &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt;.
We need to take this into account here, that&amp;rsquo;s why the end function returns &lt;code&gt;auto&lt;/code&gt; and not the iterator
(the underlying sentinel is still comparable with our new iterator, because it inherits from the underlying range&amp;rsquo;s
iterator).&lt;/li&gt;
&lt;li&gt;As noted above, some views may not be const-iterable, in that case you can omit &lt;code&gt;cbegin()&lt;/code&gt; and &lt;code&gt;cend()&lt;/code&gt; and not
mark &lt;code&gt;begin()&lt;/code&gt; and &lt;code&gt;end()&lt;/code&gt; as &lt;code&gt;const&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note&lt;/em&gt; that if you want your view to be stronger that an
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/InputRange&#34;&gt;InputRange&lt;/a&gt;, e.g. also be a
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/SizedRange&#34;&gt;SizedRange&lt;/a&gt; or even a
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/range/RandomAccessRange&#34;&gt;RandomAccessRange&lt;/a&gt;,
you might want to define additional member types (&lt;code&gt;size_type&lt;/code&gt;, &lt;code&gt;difference_type&lt;/code&gt;) and additional
member functions (&lt;code&gt;size()&lt;/code&gt;, &lt;code&gt;operator[]&lt;/code&gt;&amp;hellip;). &lt;em&gt;Although strictly speaking the range &amp;ldquo;traits&amp;rdquo; are now deduced completely
from the range&amp;rsquo;s iterator so you don&amp;rsquo;t &lt;em&gt;need&lt;/em&gt; additional member functions on the range.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//     requires (bool)ranges::InputRange&amp;lt;urng_t&amp;gt;() &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//              (bool)ranges::CommonReference&amp;lt;range_reference_t&amp;lt;urng_t&amp;gt;, uint64_t&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;view_add_constant(urng_t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; view_add_constant&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;We add a &lt;a href=&#34;http://en.cppreference.com/w/cpp/language/class_template_argument_deduction&#34;&gt;user-defined type deduction guide&lt;/a&gt;
for our view.&lt;/li&gt;
&lt;li&gt;Class template argument deduction enables people to use your class template without having to manually specify the template parameter.&lt;/li&gt;
&lt;li&gt;In C++17 there is automatic deduction, as well, but we need user defined deduction here, if we want to cover both cases
of &lt;code&gt;urng_t&lt;/code&gt; (value tpye and reference type) and don&amp;rsquo;t want to add more complex constructors.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static_assert&lt;/span&gt;((&lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;InputRange&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;view_add_constant&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static_assert&lt;/span&gt;((&lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)ranges&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;View&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;view_add_constant&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Now is a good time to check whether your class satisfies the concepts it needs to meet, this also works on Clang
without the Concepts TS or C++20. We have picked &lt;code&gt;std::vector&amp;lt;uint64_t&amp;gt;&lt;/code&gt; as an underlying type, but others would work, too.&lt;/li&gt;
&lt;li&gt;If the checks fail, you have done something wrong somewhere. The compilers don&amp;rsquo;t yet tell you why certain concept
checks fail (especially when using the range library&amp;rsquo;s hacked concept implementation) so you need to add more basic
concept checks and try which ones succeed and which break to get hints on which requirements you are failing. A
likely candidate is your iterator not meeting the
&lt;a href=&#34;http://en.cppreference.com/w/cpp/experimental/ranges/iterator/InputIterator&#34;&gt;InputIterator concept&lt;/a&gt;
(&lt;a href=&#34;http://en.cppreference.com/w/cpp/concept/InputIterator&#34;&gt;old, but complete documentation&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;add_constant_fn&#34;&gt;&lt;code&gt;add_constant_fn&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Off to our second type definition, the functor/adaptor type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add_constant_fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//         requires (bool)ranges::InputRange&amp;lt;urng_t&amp;gt;() &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//                  (bool)ranges::CommonReference&amp;lt;range_reference_t&amp;lt;urng_t&amp;gt;, uint64_t&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;()(urng_t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; urange) &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; view_add_constant{std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;forward&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(urange)};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typename&lt;/span&gt; urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//         requires (bool)ranges::InputRange&amp;lt;urng_t&amp;gt;() &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//                  (bool)ranges::CommonReference&amp;lt;range_reference_t&amp;lt;urng_t&amp;gt;, uint64_t&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;friend&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;(urng_t &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; urange, add_constant_fn &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; view_add_constant{std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;forward&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;urng_t&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(urange)};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The first operator facilitates something similar to the constructor, it enables traditional usage of the view in
the so called function-style: &lt;code&gt;auto v = view::add_constant(other_range);&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The second operator enables the pipe notation: &lt;code&gt;auto v = other_range | view::add_constant;&lt;/code&gt;. It needs to be
&lt;code&gt;friend&lt;/code&gt; or a free function and takes two arguments (both sides of the operation).&lt;/li&gt;
&lt;li&gt;Both operators simply delegate to the constructor of &lt;code&gt;view_add_constant&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;viewadd_constant&#34;&gt;&lt;code&gt;view::add_constant&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Finally we add an instance of the adaptor to namespace &lt;code&gt;view&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; view
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add_constant_fn &lt;span style=&#34;color:#66d9ef&#34;&gt;constexpr&lt;/span&gt; add_constant;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since the adapter has no state (in contrast to the view it generates), we can make it &lt;code&gt;constexpr&lt;/code&gt;. You can now use
the adaptor in the above example.&lt;/p&gt;
&lt;p&gt;We are done 😊&lt;/p&gt;
&lt;p&gt;Here is the full code: &lt;a href=&#34;../../view_add_constant.cpp&#34;&gt;view_add_constant.cpp&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;post-scriptum&#34;&gt;Post scriptum&lt;/h1&gt;
&lt;p&gt;I will follow up on this with a second tutorial, it will cover writing a view that takes arguments, i.e.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; in{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; in &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; view&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;add_number(&lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// decide this at run-time     ^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you found mistakes (of which I am sure there are some) or if you have questions, please comment below via GitHub, Gitea, Twitter
or Mastodon!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;If you are confused that we are dealing with the &amp;ldquo;reference type&amp;rdquo; and not the &amp;ldquo;value type&amp;rdquo;, remember that member functions like &lt;code&gt;at()&lt;/code&gt; and &lt;code&gt;operator[]&lt;/code&gt; on plain old containers also always return the &lt;code&gt;::reference&lt;/code&gt; type.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;This is slightly different than in range-v3 where views only accept temporaries of other views, not of e.g. containers (containers can only be given as lvalue-references). This enables constant time copying of the view even without implicit sharing of the underlying range, but it mandates a rather complicated set of techniques to tell apart views from other ranges (the time complexity of a function is not encoded in the language so tricks like inheriting ranges::view are used). I find the design used here more flexible and robust.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;This might be confusing to wrap your head around, but remember that the &lt;code&gt;const_iterator&lt;/code&gt; of a container is like an iterator over the &lt;code&gt;const&lt;/code&gt; version of that container. The same is true for views, except that since the view does not own the elements its own const-ness &lt;strong&gt;does not &amp;ldquo;protect&amp;rdquo; the elements from being written to.&lt;/strong&gt; Ranges behave similar to iterators in this regard, an &lt;code&gt;iterator const&lt;/code&gt; on a vector can also be used to write to the value it points to. More on this in &lt;a href=&#34;https://github.com/ericniebler/range-v3/issues/385&#34;&gt;this range-v3 issue&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded>
    </item>
    
    <item>
      <title>The - surprisingly limited - usefulness of function multiversioning in GCC</title>
      <link>https://hannes.hauswedell.net/post/2017/12/09/fmv/</link>
      <pubDate>Sat, 09 Dec 2017 18:00:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2017/12/09/fmv/</guid>
      <description>&lt;p&gt;Modern CPUs have quite a few features that generic amd64/intel64 code cannot make use of, simply because they are not
available everywhere and including them would break the code on unsupporting platforms. The solution is to not use
these features, or ship different specialised binaries for different target CPUs. The problem with the first approach
is that you miss out on possible optimisations and the problem with the second approach is that most users don&amp;rsquo;t know
which features their CPUs support, possibly picking a wrong executable (which won&amp;rsquo;t run → bad user experience) or a less
optimised one (which is again problem 1). &lt;strong&gt;But&lt;/strong&gt; there is an elegant GCC-specific alternative: Function multiversioning!&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Modern CPUs have quite a few features that generic amd64/intel64 code cannot make use of, simply because they are not
available everywhere and including them would break the code on unsupporting platforms. The solution is to not use
these features, or ship different specialised binaries for different target CPUs. The problem with the first approach
is that you miss out on possible optimisations and the problem with the second approach is that most users don&amp;rsquo;t know
which features their CPUs support, possibly picking a wrong executable (which won&amp;rsquo;t run → bad user experience) or a less
optimised one (which is again problem 1). &lt;strong&gt;But&lt;/strong&gt; there is an elegant GCC-specific alternative: Function multiversioning!&lt;/p&gt;
&lt;p&gt;But does it really solve our problems? Let&amp;rsquo;s have a closer look!&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;basic understanding of C++ and compiler optimisations (you should have heard of &amp;ldquo;inlining&amp;rdquo; before, but you don&amp;rsquo;t
need to know assembler, in fact I am not an assembly expert either)&lt;/li&gt;
&lt;li&gt;Most code snippets are demonstrated via &lt;a href=&#34;https://gcc.godbolt.org/&#34;&gt;Compiler Explorer&lt;/a&gt;, but the benchmarks require
you to have GCC ≥ version 7 locally installed.&lt;/li&gt;
&lt;li&gt;You might want to open a second tab or window to display the Compiler Explorer along side this post (two screens
work best 😎).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;population-counts&#34;&gt;Population counts&lt;/h2&gt;
&lt;p&gt;Many of the CPU features used in machine-optimised code relate to &lt;a href=&#34;https://en.wikipedia.org/wiki/SIMD&#34;&gt;SIMD&lt;/a&gt;, but for
our example, I will use a more simple operation: population count or short &lt;strong&gt;popcount&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The popcount of an integral number is the number of bits that are set to 1 in its bit-representation.
[More details on &lt;a href=&#34;https://en.wikipedia.org/wiki/Hamming_weight&#34;&gt;Wikipedia&lt;/a&gt; if you are interested.]&lt;/p&gt;
&lt;p&gt;Popcounts are used in many algorithms, and are important in bioinformatics (one of the reasons I am writing this post).
You could implement a naive popcount by iterating over the bits, but GCC already has us covered with a &amp;ldquo;builtin&amp;rdquo;,
called &lt;code&gt;__builtin_popcountll&lt;/code&gt; (the &amp;ldquo;ll&amp;rdquo; in the end is for &lt;code&gt;long long&lt;/code&gt;, i.e. 64bit integers). Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __builtin_popcountll(&lt;span style=&#34;color:#ae81ff&#34;&gt;6ull&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// == 2, because 6ull&amp;#39;s bit repr. is `...00000110`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To get a feeling for how slow/fast this function is, we are going to call it a billion times. The golden rule
of optimisation is to &lt;strong&gt;always measure&lt;/strong&gt; and not make wild assumptions about what you think the compiler or
the CPU is/isn&amp;rsquo;t doing!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; __builtin_popcountll(v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;&lt;a href=&#34;https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:&#39;%23include+%3Ccstdint%3E%0A%0Auint64_t+pc(uint64_t+const+v)%0A%7B%0A++++return+__builtin_popcountll(v)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc(i)%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g72,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,trim:&#39;0&#39;),libs:!(),options:&#39;&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+7.2+(Editor+%231,+Compiler+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34; target=&#34;_blank&#34;&gt;
view in compiler explorer&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;This code should should be fairly easy to understand, the volatile modifier is only used to make sure
that this code is always generated (if not used the compiler will see that the return values are not actually
used and optimise &lt;strong&gt;all the code&lt;/strong&gt; away!). In any case, before you compile this locally, click on the link
and check out the compiler explorer. Using the colour code you can easily see that our call to &lt;code&gt;__builtin_popcountll&lt;/code&gt;
in line 5 is translated to another function &lt;code&gt;__popcountdi2&lt;/code&gt; internally. Before you continue, add &lt;code&gt;-03&lt;/code&gt; to the
compiler arguments in compiler explorer, this will add machine-independent optimisations. The assembly code should
change, but you will still be able to find &lt;code&gt;__popcountdi2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a generic function that works on all amd64/intel64 platforms and counts the set bits. What does it actually do?
You can search the net and find explanations that say it does some bit-shifting and table-lookups, but the important
part is that it performs &lt;strong&gt;multiple operations&lt;/strong&gt; to compute the popcount in a generic way.&lt;/p&gt;
&lt;p&gt;Modern CPUs, however, have a feature that does popcount in hardware (or close). Again, we don&amp;rsquo;t need to know
exactly how this works, but we would expect that this single operation function is better than
anything we can do (for very large bit-vectors this is &lt;a href=&#34;http://0x80.pl/articles/sse-popcount.html&#34;&gt;not true entirely&lt;/a&gt;,
but that&amp;rsquo;s a different issue).&lt;/p&gt;
&lt;p&gt;How do we use this magic builtin? Just go back to the compiler explorer, and add &lt;code&gt;-mpopcnt&lt;/code&gt; to the compiler flags,
this tells GCC to expect this feature from the hardware and optimise for it.
Voila, the assembly code generated now resolves to &lt;code&gt;popcnt rsi, rsi&lt;/code&gt; instead of &lt;code&gt;call __popcountdi2&lt;/code&gt; (GCC is smart
and it&amp;rsquo;s builtin resolves to whatever is best on the architecture we are targeting).&lt;/p&gt;
&lt;p&gt;But how much better is this actually? Compile both versions locally and measure, e.g. with the &lt;code&gt;time&lt;/code&gt; command.&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;compiler flags&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;time on my pc&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;-O3&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3.1s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;-O3 -mpopcnt&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6s&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;A speed-up of 5x, nice!&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2017/12/happy.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;But what happens when the binary is run on a CPU that doesn&amp;rsquo;t have builtin popcnt?
The program crashes with &amp;ldquo;Illegal hardware instruction&amp;rdquo; 💀&lt;/p&gt;
&lt;h2 id=&#34;function-multiversioning&#34;&gt;Function multiversioning&lt;/h2&gt;
&lt;p&gt;This is where function multiversioning (&amp;ldquo;FMV&amp;rdquo;) comes to the rescue. It is a GCC specific feature, that inserts
a branching point in place of our original function and then dispatches to one of the available &amp;ldquo;clones&amp;rdquo;
&lt;strong&gt;at run-time&lt;/strong&gt;. You can specify how many of these &amp;ldquo;clones&amp;rdquo; you want and for which features or architectures each are
built, then the dispatching function chooses the most highly optimised automatically.
You can even manually write different function bodies for the different clones, but we will focus on the simpler kind of
FMV where you just compile the same function body with different optimisation strategies.&lt;/p&gt;
&lt;p&gt;Enough of the talking, here is our adapted example from above:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((target_clones(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;popcnt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; pc(&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__builtin_popcountll&lt;/span&gt;(v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;&lt;a href=&#34;https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:&#39;%23include+%3Ccstdint%3E%0A%0A__attribute__((target_clones(%22default%22,+%22popcnt%22)))%0Auint64_t+pc(uint64_t+const+v)%0A%7B%0A++++return+__builtin_popcountll(v)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc(i)%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g72,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,trim:&#39;0&#39;),libs:!(),options:&#39;-O3&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+7.2+(Editor+%231,+Compiler+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34; target=&#34;_blank&#34;&gt;
view in compiler explorer&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;The only difference is that line 3 was inserted.
The syntax is quite straight-forward insofar as anything in the C++ world is straight-forward 😉 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We are telling GCC that we want two clones for the targets &amp;ldquo;default&amp;rdquo; and &amp;ldquo;popcnt&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Everything else gets taken care of.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Follow the link to compiler explorer and check the assembly code (please make sure that you are &lt;strong&gt;not&lt;/strong&gt; specifying
&lt;code&gt;-mpopcnt&lt;/code&gt;!). It is a little longer, but we immediately see
via the colour code of &lt;code&gt;__builtin_popcountll(v)&lt;/code&gt; that two functions are generated, one with the generic version and
one with optimised version, similar to what we had above, but now in one program. The &amp;ldquo;function signatures&amp;rdquo; in the
assembly code also tell us that one of them is &amp;ldquo;the original&amp;rdquo; and one is &amp;ldquo;popcnt clone&amp;rdquo;. Some further analysis will
reveal a third function, the &amp;ldquo;clone .resolver&amp;rdquo; which is the dispatching function. Even without knowing any assembly
you might be able to pick out the statement that looks up the CPU feature and calls the correct clone.&lt;/p&gt;
&lt;p&gt;Great! So we have a single binary that is as fast as possible &lt;strong&gt;and&lt;/strong&gt; works on older hardware. But is it really as
fast as possible? Compile and run it!&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;version&lt;/th&gt;
          &lt;th&gt;compiler flags&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;time on my pc&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;original&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3.1s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;original&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3 -mpopcnt&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;FMV&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3 &lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.2s&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;Ok, we are faster than the original generic code so we are probably using the optimised popcount call, but
we are nowhere near our 5x speed-up. What&amp;rsquo;s going on?&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2017/12/hm.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;h2 id=&#34;nested-function-calls&#34;&gt;Nested function calls&lt;/h2&gt;
&lt;p&gt;We have replaced the core of our computation, the function &lt;code&gt;pc()&lt;/code&gt; with a dispatcher that chooses the
best implementation. As noted above this decision happens at run-time (it has to, because we can&amp;rsquo;t know
beforehand if the target CPU will support native popcount, it&amp;rsquo;s the whole point of the exercise),
&lt;strong&gt;but now this happens one billion times!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wow, this check seems to be more expensive than the actual popcount call. If you write a lot of optimised code, this won&amp;rsquo;t
be a surprise, decision making at run-time just is very expensive.&lt;/p&gt;
&lt;p&gt;What can we do about it? Well, we could decide between generic VS optimised &lt;em&gt;before&lt;/em&gt; running our algorithm, instead
of deciding &lt;em&gt;in our algorithm&lt;/em&gt; on every iteration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; __builtin_popcountll(v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((target_clones(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;popcnt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      loop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;&lt;a href=&#34;https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:&#39;%23include+%3Ccstdint%3E%0A%0Auint64_t+pc(uint64_t+const+v)%0A%7B%0A++++return+__builtin_popcountll(v)%3B%0A%7D%0A%0A__attribute__((target_clones(%22default%22,+%22popcnt%22)))%0Avoid+loop()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc(i)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++++loop()%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g72,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,trim:&#39;0&#39;),libs:!(),options:&#39;-O3&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+7.2+(Editor+%231,+Compiler+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34; target=&#34;_blank&#34;&gt;
view in compiler explorer&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;The assembly of this gets a little more messy, but you can follow around the &lt;code&gt;jmp&lt;/code&gt; instructions or just scan
the assembly for our above mentioned instructions and you will see that we still have the two versions (although
the actual &lt;code&gt;pc()&lt;/code&gt; function is not called, because it was inlined and is moved around a bit).&lt;/p&gt;
&lt;p&gt;Compile the code and measure the time:&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;version&lt;/th&gt;
          &lt;th&gt;compiler flags&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;time on my pc&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;original&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3.1s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;original&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3 -mpopcnt&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;FMVed &lt;code&gt;pc()&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3 &lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.2s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;FMVed loop&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;-O3 &lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6s&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;Hurray, we are back to our original speed-up!&lt;/p&gt;
&lt;p&gt;If you expected this, than you likely have dealt with strongly templated code before and also heard
of &lt;a href=&#34;https://arne-mertz.de/2016/10/tag-dispatch/&#34;&gt;tag-dispatching&lt;/a&gt;, a technique that can be used to translate
arbitrary run-time decisions to different code-paths beneath which you can treat your run-time decision
as a compile-time one.&lt;/p&gt;
&lt;p&gt;Our simplified callgraph for the above cases looks like this (the dotted line is where the dispatching takes place):&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2017/12/graph.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;In real world code the graph is of course bigger, but it should become obvious that by moving
the decision making further to the left, the code becomes faster – because we have to decide less
often –, but also the size of the generated executable becomes larger – because more functions
are actually compiled. [There are corner cases where the executable being bigger actually results
in certain things becoming slower, but lets not get into that now.]&lt;/p&gt;
&lt;p&gt;Anyway, &lt;em&gt;I thought&lt;/em&gt; that FMV would be like dispatching a tag down the call-graph, &lt;strong&gt;but it&amp;rsquo;s not!&lt;/strong&gt;
In fact we just got lucky in our above example, because the &lt;code&gt;pc()&lt;/code&gt; call was inlined.
&lt;a href=&#34;https://en.wikipedia.org/wiki/Inline_expansion&#34;&gt;Inlining&lt;/a&gt; means that the function itself is
optimised away entirely and its code is inserted at the place in the
calling function where the function call would have been otherwise. &lt;strong&gt;Only because &lt;code&gt;pc()&lt;/code&gt; is
inlined, do we actually get the opimisation!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How do you know? Well you can force GCC to not inline &lt;code&gt;pc()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((noinline))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; pc(&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__builtin_popcountll&lt;/span&gt;(v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((target_clones(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;popcnt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      loop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;&lt;a href=&#34;https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:&#39;%23include+%3Ccstdint%3E%0A%0A__attribute__((noinline))%0Auint64_t+pc(uint64_t+const+v)%0A%7B%0A++++return+__builtin_popcountll(v)%3B%0A%7D%0A%0A__attribute__((target_clones(%22default%22,+%22popcnt%22)))%0Avoid+loop()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc(i)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++++loop()%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g72,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,trim:&#39;0&#39;),libs:!(),options:&#39;-O3&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+7.2+(Editor+%231,+Compiler+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34; target=&#34;_blank&#34;&gt;
view in compiler explorer&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;Just add the third line to your previous Compiler Explorer window, or open the above link. You can
see that the optimised &lt;code&gt;popcnt&lt;/code&gt; call has disappeared from the assembly and &lt;code&gt;pc()&lt;/code&gt; only
appears once. So in fact our callgraph is (no optimised &lt;code&gt;pc()&lt;/code&gt; contained):&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2017/12/graph2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;But how serious is this, you may ask? Didn&amp;rsquo;t the compiler inline automatically?
Well, the problem about inlining is, that it is entirely
up to the compiler whether it inlines a function or not (prefixing the function with &lt;code&gt;inline&lt;/code&gt;
does in fact not force it to). The deeper the call-graph gets, the more
likely it is for the compiler not to inline all the way from the FMV invocation point.&lt;/p&gt;
&lt;h2 id=&#34;trying-to-save-fmv-for-our-use-case&#34;&gt;Trying to save FMV for our use case&lt;/h2&gt;
&lt;details style=&#39;border:1px solid; padding: 2px; margin: 2px&#39;&gt;
  &lt;summary&gt;&lt;i&gt;click to see some more complex but futile attempts&lt;/i&gt;&lt;/summary&gt;
&lt;p&gt;It&amp;rsquo;s possible to force the compiler to use inlining, but it&amp;rsquo;s also non-standard
and it obviously doesn&amp;rsquo;t work if the called functions are not customisable by us
(e.g. stable interfaces or external code / a library).
Furthermore it might not even be desirable to force inline every function / function template,
because they might be used in other places or with differently typed arguments
resulting in an even higher increase of executable size.&lt;/p&gt;
&lt;p&gt;An alternative to inlining would be to use the original form of FMV where you actually
have different function bodies and in those add a custom layer of (tag-)dispatching yourself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;template&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; is_optimised&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((noinline))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; pc(&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__builtin_popcountll&lt;/span&gt;(v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((target(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;false&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  __attribute__((target(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;popcnt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; loop()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&amp;#39;000&amp;#39;000&amp;#39;000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ret &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pc&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      loop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;center&gt;&lt;a href=&#34;https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:&#39;%23include+%3Ccstdint%3E%0A%0Atemplate+%3Cbool+is_optimised%3E%0A__attribute__((noinline))%0Auint64_t+pc(uint64_t+const+v)%0A%7B%0A++++return+__builtin_popcountll(v)%3B%0A%7D%0A%0A__attribute__((target(%22default%22)))%0Avoid+loop()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc%3Cfalse%3E(i)%3B%0A%7D%0A%0A__attribute__((target(%22popcnt%22)))%0Avoid+loop()%0A%7B%0A++++for+(uint64_t+i+%3D+0%3B+i+%3C+1!&#39;000!&#39;000!&#39;000%3B+%2B%2Bi)%0A++++++++volatile+uint64_t+ret+%3D+pc%3Ctrue%3E(i)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++++loop()%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g72,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,trim:&#39;0&#39;),libs:!(),options:&#39;-O1&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+7.2+(Editor+%231,+Compiler+%231)&#39;,t:&#39;0&#39;)),k:50,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4&#34; target=&#34;_blank&#34;&gt;
view in compiler explorer&lt;/a&gt;&lt;/center&gt;
&lt;p&gt;In this code example we have turned &lt;code&gt;pc()&lt;/code&gt; into a function template, customisable by a bool variable. This
means that two versions of this function can be instantiated. We then also implement the loops separately and
make each pass a different bool value to &lt;code&gt;pc()&lt;/code&gt; as a template argument. If you look at the assembly in compiler
explorer you can see that two functions are created for &lt;code&gt;pc()&lt;/code&gt;, but unfortunately they both contain the
unoptimised popcount call¹. This is due to the compiler not knowing/assuming that one of the functions is only called in an
optimised context. → This method won&amp;rsquo;t solve our problem.&lt;/p&gt;
&lt;p&gt;And while it is of course possible to add C++17&amp;rsquo;s &lt;code&gt;if constexpr&lt;/code&gt; to &lt;code&gt;pc()&lt;/code&gt; and start hacking custom code into the
the function depending on the template parameter, it does further complicate the solution moving us further
and further away from our original goal of a thin dispatching layer.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;¹ Since the resulting function bodies are the same they are actually merged into a single one at optimisation levels &amp;gt; 1 (but this
is independent of our problem).&lt;/small&gt;&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Function multiversioning is a good thing, because it aims to solve an actual problem:
delivering optimised binary code to users that can&amp;rsquo;t or don&amp;rsquo;t want to build themselves.&lt;/li&gt;
&lt;li&gt;Unfortunately it does not multiversion the functions called by a versioned function,
forcing developers to move FMV very close to the intended function call.&lt;/li&gt;
&lt;li&gt;This has the drawback of invoking the dispatch much more often than theoretically
needed, possibly incurring a penalty in run-time that might exceed the gain from
more highly optimised code.&lt;/li&gt;
&lt;li&gt;It would be great if GCC developers could address this by adding a version of FMV
that recursively clones the indirectly invoked functions (without further branching),
as well as providing the machine-aware context to these clones, i.e. the presumed CPU features.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;further-reading&#34;&gt;Further reading&lt;/h2&gt;
&lt;p&gt;On popcnt and CPU specific features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/i386-and-x86-64-Options.html#i386-and-x86-64-Options&#34;&gt;Overview of CPU specific features and support in GCC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://0x80.pl/articles/sse-popcount.html&#34;&gt;Different popcount implementations benchmark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On FMV:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A good article on LWN: &lt;a href=&#34;https://lwn.net/Articles/691932/&#34;&gt;https://lwn.net/Articles/691932/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The GCC wiki with more details: &lt;a href=&#34;https://gcc.gnu.org/wiki/FunctionMultiVersioning&#34;&gt;https://gcc.gnu.org/wiki/FunctionMultiVersioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded>
    </item>
    
    <item>
      <title>Using Gitea and/or Github to host blog comments</title>
      <link>https://hannes.hauswedell.net/post/2017/10/21/blog-comments/</link>
      <pubDate>Sat, 21 Oct 2017 18:00:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2017/10/21/blog-comments/</guid>
      <description>&lt;p&gt;After having moved from FSFE&amp;rsquo;s wordpress instance I thought long about whether I still want to have comments on the new blog.
And how I would be able to do it with a statically generated site.
I think I have found/created a pretty good solution that I document below.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;After having moved from FSFE&amp;rsquo;s wordpress instance I thought long about whether I still want to have comments on the new blog.
And how I would be able to do it with a statically generated site.
I think I have found/created a pretty good solution that I document below.&lt;/p&gt;
&lt;h2 id=&#34;how-it-was-before&#34;&gt;How it was before&lt;/h2&gt;
&lt;p&gt;To be honest, Wordpress was a spam &lt;strong&gt;nightmare&lt;/strong&gt;! I ended up excluding all non-(FSFE-)members, because it was just too difficult
to get right. On the other hand I value feedback to posts so what to do?&lt;/p&gt;
&lt;p&gt;This blog is now statically generated so it is not &lt;em&gt;designed&lt;/em&gt; for comments anyway.
The most common solution seems to be &lt;a href=&#34;https://disqus.com/&#34;&gt;Disqus&lt;/a&gt; which seems to work well, but be a privacy nightmare.
It hosts your comments on their server and integrates with all sorts of authentication services, of course sharing data with them et cetera.
Not exposing my site visitors to tracking is very important to me and I also don&amp;rsquo;t want to advertise using your Facebook login or some such nonsense.&lt;/p&gt;
&lt;h2 id=&#34;a-good-idea&#34;&gt;A good idea&lt;/h2&gt;
&lt;p&gt;However, I had vague memories of having read this article a while ago so I read up on it again:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://donw.io/post/github-comments/&#34;&gt;http://donw.io/post/github-comments/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The idea is to host your comments in a GitHub bug tracker and load them dynamically via Javascript and the GitHub-API.
It integrates with GoHugo, the site-generator I am also using, so I thought I&amp;rsquo;d give it a try.
&lt;em&gt;Please read the linked article to get a clearer picture of the idea.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;privacy-improvements-and-other-changes&#34;&gt;Privacy improvements and other changes&lt;/h2&gt;
&lt;p&gt;It all worked rather well, but there were a few things I was unhappy with so I changed the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In addition to GitHub, it now works with &lt;a href=&#34;https://gitea.io/&#34;&gt;Gitea&lt;/a&gt;, a Free Software alternative, too;
this includes dynamically generating Markdown from the comments via &lt;a href=&#34;https://github.com/showdownjs/showdown&#34;&gt;ShowdownJS&lt;/a&gt;, because
Gitea&amp;rsquo;s API is less powerful than GitHub&amp;rsquo;s.&lt;/li&gt;
&lt;li&gt;The comments are not loaded automatically, but on-demand (so visitors don&amp;rsquo;t automatically make requests to other servers).&lt;/li&gt;
&lt;li&gt;It is possible to have multiple instances of the script running, with different server types, target domains and/or repos.&lt;/li&gt;
&lt;li&gt;Gracefully degrade and offer external links if no Javascript is available.&lt;/li&gt;
&lt;li&gt;Some visual changes to fit with my custom theme.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the results below. I am quite happy with the solution as many of my previous readers from FSFE can still use FSFE&amp;rsquo;s
infrastructure to reply (in this case FSFE&amp;rsquo;s gitea instance).
I expect many other visitors to have a GitHub account so they don&amp;rsquo;t need to sign up for another service.
I am aware this still relies on third parties and that GitHub may at some point commodify the use of its API, but right now it is much
better than to store and share the data with a company whose business model this already is. &lt;em&gt;And it is optional.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And of course the blog itself will remain entirely free of Javascript!&lt;/p&gt;
&lt;p&gt;The important files are available in this blog&amp;rsquo;s repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://git.fsfe.org/h2/hannes.hauswedell.net/src/master/static/js/hosted-comments.js&#34;&gt;static/js/hosted-comments.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git.fsfe.org/h2/hannes.hauswedell.net/src/master/layouts/partials/comments.html&#34;&gt;layouts/partials/comments.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What do you think? Feel free to adapt this for your blog and thanks to Don Williamson for the original implementation!&lt;/p&gt;</content:encoded>
    </item>
    
    <item>
      <title>New blog</title>
      <link>https://hannes.hauswedell.net/post/2017/09/18/new-blog/</link>
      <pubDate>Mon, 18 Sep 2017 16:00:00 +0200</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2017/09/18/new-blog/</guid>
      <description>&lt;p&gt;I have moved my blog from &lt;a href=&#34;https://blogs.fsfe.org/h2&#34;&gt;https://blogs.fsfe.org/h2&lt;/a&gt; to my own web-space. On the way I have switched from Wordpress to GoHugo.
I hope to publish more often and will increasingly cover programming topics.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have moved my blog from &lt;a href=&#34;https://blogs.fsfe.org/h2&#34;&gt;https://blogs.fsfe.org/h2&lt;/a&gt; to my own web-space. On the way I have switched from Wordpress to GoHugo.
I hope to publish more often and will increasingly cover programming topics.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Retroactively replacing git subtree with git submodule</title>
      <link>https://hannes.hauswedell.net/post/2016/07/27/retroactively-replacing-git-subtree-with-git-submodule/</link>
      <pubDate>Wed, 27 Jul 2016 13:38:26 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2016/07/27/retroactively-replacing-git-subtree-with-git-submodule/</guid>
      <description>&lt;p&gt;Combining multiple git repositories today is rather common, although the means of doing so are far from perfect. Usually people use &lt;code&gt;git submodule&lt;/code&gt; or &lt;code&gt;git subtree&lt;/code&gt;. If you have used neither or are happy with either method this post is completely irrelevant to you. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;But maybe you decided to use &lt;code&gt;git subtree&lt;/code&gt; and like me are rather unhappy with the choice. I will not discuss the upsides and downsides of either approach, I assume you want to change this, and you wish you could go back in time and make it right for all subsequent development. So this is what we are going to do :)&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Combining multiple git repositories today is rather common, although the means of doing so are far from perfect. Usually people use &lt;code&gt;git submodule&lt;/code&gt; or &lt;code&gt;git subtree&lt;/code&gt;. If you have used neither or are happy with either method this post is completely irrelevant to you. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;But maybe you decided to use &lt;code&gt;git subtree&lt;/code&gt; and like me are rather unhappy with the choice. I will not discuss the upsides and downsides of either approach, I assume you want to change this, and you wish you could go back in time and make it right for all subsequent development. So this is what we are going to do :)&lt;/p&gt;
&lt;p&gt;This was an exercise in git for me so I am sure more experienced people might know shortcuts, but since it took me quite some time to figure out right, I hope it is going to be helpful to others. &lt;strong&gt;It is however strongly recommended to read the shell scripts and possibly adapt them to your situation. I will not be held responsible for any problems!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It should be noted that by definition any changes in your git history will break current clones and forks of your repository so only do this if you are very sure what you are doing. And be nice and inform your users about this ASAP.&lt;/p&gt;
&lt;h1 id=&#34;pre-conditions&#34;&gt;Pre conditions&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;you have a git subtree, e.g. of a library, inside your repo and you want to replace it with git submodule&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;going back to a commit in your history you should still get the same version of the library that you had previously included with git subtree&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;i.e. every subtree update should be replaced with a submodule update of the same contents and also timestamp (because this is timetravel, right?)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;all tags should be preserved / rewritten to their corresponding new IDs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;when updating your git subtree previously you used the &amp;ldquo;squash&amp;rdquo; feature (if you didn&amp;rsquo;t do this, it is going to be a lot harder)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you have a mostly straight branch history and are ok with loosing merge commits; all branches other than master will be rebased on master&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When I say &amp;ldquo;preserve timestamp&amp;rdquo; it is important to clarify what this means: git has two notions of &amp;ldquo;timestamp&amp;rdquo;, the &amp;ldquo;author date&amp;rdquo; and the &amp;ldquo;committer date&amp;rdquo;.
The author date is the date where the commit was actually created. It is apparently entirely without relevance for git branches and their structure.
The committer date on the other hand is the time where the commit was included in the branch.
This is often the same, but when doing operations on a branch like cherry-picking or rebasing then it is overwritten with the current date.
Unfortunately git interfaces like github don&amp;rsquo;t use either date consistently so if you want a consistent appearance you need to also preserve the committer dates.
Editing these however can have adverse effects potentially breaking branches or tags, because the correct chronological order of committer dates is important.
We will take extra precautions below, but if you branches somehow get mangeled, or a commit appears out of place with gitg than you should double check the committer dates.&lt;/p&gt;
&lt;h1 id=&#34;preperation&#34;&gt;Preperation&lt;/h1&gt;
&lt;p&gt;Make a local clone of the repository and after that remove all your &amp;ldquo;remotes&amp;rdquo; with &lt;code&gt;git remote remove &lt;/code&gt;. This ensures that you don&amp;rsquo;t accidentally push any changes&amp;hellip;&lt;/p&gt;
&lt;p&gt;I assume that you have checked out the master branch and that you have exported the following environment variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLONE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/devel/myapp&amp;#34;&lt;/span&gt;                      &lt;span style=&#34;color:#75715e&#34;&gt;# the directory of your clone&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SUBDIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;include/mylib&amp;#34;&lt;/span&gt;                     &lt;span style=&#34;color:#75715e&#34;&gt;# the subdir of the subtree/submodule relative to CLONE &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SUBNAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mylib&amp;#34;&lt;/span&gt;                            &lt;span style=&#34;color:#75715e&#34;&gt;# name of the submodule (can be anything)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SUBREPO&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;git://github.com/mylib/mylib.git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# submodules&amp;#39; repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ATTENTION: don&amp;rsquo;t screw up any of the above paths since we might be calling rm -rf on them.&lt;/p&gt;
&lt;p&gt;If you are uncomfortable with doing search and replace operations on the command line, you can set your editor to something easy like kwrite:
&lt;code&gt;export EDITOR=kwrite&lt;/code&gt;&lt;/p&gt;
&lt;h1 id=&#34;replacing-the-subtree-and-subtree-updates&#34;&gt;Replacing the subtree and subtree updates&lt;/h1&gt;
&lt;p&gt;Since we are going to delete all the merge commits and also the commits that represent changes to the subtree, we need to remember at which places we later re-insert commits. To do this, run the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%at:::%an:::%ae:::%s&amp;#39;&lt;/span&gt; --no-merges | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;(PRINT == 1) &amp;amp;&amp;amp; !($4 ~ /^Squashed/) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    PRINT=0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    printf    $1 &amp;#34;:::&amp;#34; $2    &amp;#34;:::&amp;#34; $3    &amp;#34;:::&amp;#34; $4   &amp;#34;:::&amp;#34;  # commit that we work on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    printf tTIME &amp;#34;:::&amp;#34; tNAME &amp;#34;:::&amp;#34; tMAIL &amp;#34;:::&amp;#34; tREF &amp;#34;\n&amp;#34;   # commit that we insert
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;(PRINT != 1) &amp;amp;&amp;amp; ($4 ~ /^Squashed/) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    PRINT=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    tTIME=$1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    tNAME=$2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    tMAIL=$3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    tREF=substr($0, length($0) - 6, length($0)) # cut commit id from subj
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}; &amp;#39;&lt;/span&gt; &amp;gt; /tmp/refinserts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What it does is find for every commit that starts with &amp;ldquo;Squashed&amp;rdquo; the subsequent commit&amp;rsquo;s subject and associate with it time of the subtree update and the subtree&amp;rsquo;s commitID, seperated with &amp;ldquo;&lt;code&gt;:::&lt;/code&gt;&amp;rdquo;. We are paring this information with the subject line and not the commit ID, because the commit IDs in our branch are going to change! It also collapses subsequent updates to one. NOTE that if you have other commits that start wit &amp;ldquo;Squashed&amp;rdquo; in there subject line but don&amp;rsquo;t belong to the subtree, instead filter for &lt;code&gt;Squashed &#39;${SUBDIR}&#39;&lt;/code&gt; (beware of the quotes!!).&lt;/p&gt;
&lt;p&gt;Now create a little helper script, e.g. as &lt;code&gt;/tmp/rebasehelper&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reset&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TIME_NAME_MAIL_SUBJ&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%at:::%an:::%ae:::%s:::&amp;#39;&lt;/span&gt; -1&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# next commit time is last commit time if not overwritten&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_AUTHOR_DATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%at&amp;#39;&lt;/span&gt; -1&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /tmp/refinserts /tmp/refinserts.actual
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reset
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;grep -q -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TIME_NAME_MAIL_SUBJ&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; /tmp/refinserts.actual&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LINE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;grep -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TIME_NAME_MAIL_SUBJ&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; /tmp/refinserts.actual&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export  GIT_AUTHOR_DATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo $LINE | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{ print $5 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export  GIT_AUTHOR_NAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo $LINE | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{ print $6 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_AUTHOR_EMAIL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo $LINE | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{ print $7 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        REF&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo $LINE | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{ print $8 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; ! -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBDIR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** First commit with submodule, initializing...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        git submodule --quiet add --force --name &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBNAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBREPO&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBDIR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; &amp;gt; /tmp/rebasehelper.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; $? -ne &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** failed:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cat /tmp/rebasehelper.log &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; break
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** done.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** Updating submodule...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBDIR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git checkout --quiet $REF &amp;gt; /tmp/rebasehelper.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; $? -ne &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** failed:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cat /tmp/rebasehelper.log &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; break
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** Committing changes...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cd &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CLONE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git commit --quiet -am &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBNAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;] update to &lt;/span&gt;$REF&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /tmp/rebasehelper.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; $? -ne &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** failed:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cat /tmp/rebasehelper.log &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; break
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;** Continuing rebase.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rm /tmp/rebasehelper.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    grep -v -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TIME_NAME_MAIL_SUBJ&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; /tmp/refinserts.actual &amp;gt; /tmp/refinserts.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mv /tmp/refinserts.new /tmp/refinserts.actual
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git rebase --continue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    reset
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CLONE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/.git/rebase-merge&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CLONE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/.git/rebase-apply&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The current rebase step is not related to subtree-submodule operation or needs manual resolution.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Try &amp;#39;git mergetool&amp;#39;, followed by &amp;#39;git rebase --continue&amp;#39; or just the latter.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We will call this later.&lt;/p&gt;
&lt;h2 id=&#34;filter-tree&#34;&gt;Filter-Tree&lt;/h2&gt;
&lt;p&gt;Now we actually remove references to the subtree from our history so that future operations create no conflicts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git filter-branch --tree-filter &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rm -rf &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBDIR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; HEAD
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This may take some time. Other sources recommend &lt;code&gt;--index-filter&lt;/code&gt; but that will not work because the file-references in the subtree are not relative to our repository, but to the SUBDIR. If this command doesn&amp;rsquo;t actually remove the directory, make sure to run &lt;code&gt;rm -rf &amp;quot;${SUBDIR}&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;rebase&#34;&gt;Rebase&lt;/h2&gt;
&lt;p&gt;Now we do the rebase:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git rebase --interactive &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%H&amp;#39;&lt;/span&gt; | tail -n 1&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which will open your commit history in the EDITOR that you configured. NOTE that this is in chronological order, not reverse chronological like the &lt;code&gt;git log&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;In the editor you now want to remove all lines that contain &amp;ldquo;Squashed&amp;rdquo; and mark the previous commit for being edited. This is multiline-regex with substitution, but in kwrite this is very straightforward:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Search:  pick&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;.*&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;.*Squashed.*&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Replace: e &lt;span style=&#34;color:#ae81ff&#34;&gt;\1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will only miss subsequent &amp;ldquo;double&amp;rdquo; updates which can safely be removed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Search:  .*Squashed.*&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Replace: 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save and close the editor, you will now be at the first commit that you are editing. This is the original point in time where you added your subtree, source the helper script with &lt;code&gt;. /tmp/rebasehelper&lt;/code&gt;. If there were never any conflicts in your tree the script should run through completely and you are done. It is important to source the script with a leading . because it sets some environment variables also for your manual commits.&lt;/p&gt;
&lt;p&gt;However, if you did have conflicts, you will be interrupted to resolve these manually, usually by &lt;code&gt;git mergetool&lt;/code&gt; and then &lt;code&gt;git rebase --continue&lt;/code&gt;. Whenever the rebase tells you &amp;ldquo;Stopped at&amp;hellip;&amp;rdquo;, just call &lt;code&gt;. /tmp/rebasehelper&lt;/code&gt; again and keep repeating the last steps, until the rebase is finished. If you are doing the whole thing on multiple branches you might want to run &lt;code&gt;git rerere&lt;/code&gt; before every &lt;code&gt;git mergetool&lt;/code&gt;, it might save you some merge steps.&lt;/p&gt;
&lt;p&gt;Unfortunately the rebase will set all commit dates to the current date (although the &amp;ldquo;author date&amp;rdquo; is preserved). There is a an option that prevents exactly this, but which cannot be used together with interactivity, because the interactivity introduces commits with a newer author date (which is okay in itself but committer dates need to be chronological for rebase). We write this little scriplet to /tmp/redate to help us out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git filter-branch --force --env-filter &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    LAST_DATE=$(cat /tmp/redate_old);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    GIT_COMMITTER_DATE=$( (echo $LAST_DATE; echo $GIT_AUTHOR_DATE) | awk &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;substr($1, 2) &amp;gt; MAX { MAX = substr($1, 2); LINE=$0}; END { print LINE }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    echo $GIT_COMMITTER_DATE &amp;gt; /tmp/redate_old;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    export GIT_COMMITTER_DATE&amp;#39;&lt;/span&gt; $@
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What it does is set the COMMITTER_DATE to the AUTHOR_DATE unless the COMMITTER_DATE would be older than the last COMMITTER_DATE (which is illegal) &amp;ndash; in that case it uses the same COMMITTER_DATE as the previous commit. This ensures correct chronology while still having sensible dates in all cases.&lt;/p&gt;
&lt;p&gt;And then we call the script with some pre and post commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;@0 +0000&amp;#39;&lt;/span&gt; &amp;gt; /tmp/redate_old
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/tmp/redate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%ad&amp;#39;&lt;/span&gt; --date&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;raw -1 | awk &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{ print &amp;#34;@&amp;#34; $1+1 &amp;#34; &amp;#34; $2 }&amp;#39;&lt;/span&gt; &amp;gt; /tmp/redate_master  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(initialization and saving master&amp;rsquo;s final timestamp+1 for later)&lt;/p&gt;
&lt;h2 id=&#34;multiple-branches&#34;&gt;Multiple Branches&lt;/h2&gt;
&lt;p&gt;For all other affected branches it is now much simpler. First checkout the branch. If your subtree/submodule is large, you might have to delete ${SUBDIR} before that with &lt;code&gt;rm -rf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then filter the tree as described above, you might need to add force to overwrite some backups:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git filter-branch -f --tree-filter &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rm -rf &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;SUBDIR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; HEAD
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Followed by a rebase on the already-fixed master branch:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git rebase --interactive master
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should now see all diverging commits, plus all the &amp;ldquo;Squashed*&amp;rdquo; commits. If you did make subtree updates on other branches and you want to retain them, then apply the same mechanism as for the master branch. If subtree changes in the other branch are nor important, you can just remove all of them from the file.&lt;/p&gt;
&lt;p&gt;Now the committer dates in the part of the branch that are identical to master are correct (because we fixed those earlier), but those in the new part have updated commit times. We can just use our previous scriptlet, but this time we initialize with the master&amp;rsquo;s last timestamp and we only operate on the commits that are actually new:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /tmp/redate_master /tmp/redate_old
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/tmp/redate_master master..HEAD
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;voila, and repeat for the other branches!&lt;/p&gt;
&lt;h1 id=&#34;rewiring-the-tags&#34;&gt;Rewiring the tags&lt;/h1&gt;
&lt;p&gt;Currently all your tags should still be there and also still be valid. Print them to a tmpfile and open them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git tag -l &amp;gt; /tmp/oldtags
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$EDITOR /tmp/oldtags
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Review the list of tags and remove all tags that belonged to the submodule or that you don&amp;rsquo;t want to keep in the new repository from the file.&lt;/p&gt;
&lt;p&gt;Now checkout master again, then run this nifty script (reed the note below first!):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OLDIFS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$IFS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IFS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;cat /tmp/oldtags&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; TAG_NAME in $TAGS; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IFS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$OLDIFS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TAG_COMMIT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(objectname)&amp;#34;&lt;/span&gt; refs/tags/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TAG_MESSAGE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(contents)&amp;#34;&lt;/span&gt; refs/tags/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# the commit that is referenced by the annotated tag in the original branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ORIGINAL_COMMIT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%H&amp;#39;&lt;/span&gt; --no-walk &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_COMMIT&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ORIGINAL_COMMIT_DATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%at&amp;#39;&lt;/span&gt; --no-walk &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ORIGINAL_COMMIT&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ORIGINAL_COMMIT_SUBJECT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%s&amp;#39;&lt;/span&gt; --no-walk &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ORIGINAL_COMMIT&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# the same commit in our rewritten branch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NEW_COMMIT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git log --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%H:::%at:::%s&amp;#39;&lt;/span&gt; | awk -F &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;:::&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    $2 == &amp;#34;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ORIGINAL_COMMIT_DATE&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34; &amp;amp;&amp;amp; $3 == &amp;#34;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$ORIGINAL_COMMIT_SUBJECT&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#34; { print $1 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# overwrite git environment variables directly:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_COMMITTER_DATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(taggerdate:rfc)&amp;#34;&lt;/span&gt; refs/tags/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_COMMITTER_NAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(taggername)&amp;#34;&lt;/span&gt; refs/tags/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_COMMITTER_EMAIL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(taggeremail)&amp;#34;&lt;/span&gt; refs/tags/&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_AUTHOR_DATE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$GIT_COMMITTER_DATE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_AUTHOR_NAME&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$GIT_COMMITTER_NAME
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    export GIT_AUTHOR_EMAIL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$GIT_COMMITTER_EMAIL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# add the new tag&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     git -c user.name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;GIT_COMMITTER_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -c user.email&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;GIT_COMMITTER_EMAIL&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; tag -f -a &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_NAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; -m &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;TAG_MESSAGE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; $NEW_COMMIT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    IFS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;NOTE that for this to work, all tags must be contained in the master branch (or whichever branch you are currently on.
If this is not the case, you need to create individual files with the tags of each branch and run this script repeatedly on the specific file while being on the corresponding branch.&lt;/p&gt;
&lt;p&gt;NOTE2: This does assume that the COMMITTER_DATE of the tag will fit in at the place it is being added.
I am not sure if there are edge cases where one would have to double-check the committer date similarly to how we do it above&amp;hellip;&lt;/p&gt;
&lt;p&gt;Since your tags are all fixed, now would be a good time to checkout some of them and verify that your software builds, passes its unit checks et cetera.
Remember that in contrast to git subtree you need to manually reset your submodule via &lt;code&gt;submodule update&lt;/code&gt; after you checkout the tag if you actually want the submodule&amp;rsquo;s revision that belonged to the tag (which is the whole point of our exercise).&lt;/p&gt;
&lt;h1 id=&#34;cleanup&#34;&gt;Cleanup&lt;/h1&gt;
&lt;p&gt;Ok, so the new branches and tags are in place, but the folder is even bigger than before :o Now we get to clean up.&lt;/p&gt;
&lt;p&gt;First make sure that absolutely nothing references the old stuff, i.e. delete all tags that you did not change in the previous step with &lt;code&gt;git tag -d&lt;/code&gt;.
Also make sure that you have no remotes set. If in doubt, open a git-gui like gitk or gitg with the &lt;code&gt;--all&lt;/code&gt; parameter and confirm that only your new trees are listed.&lt;/p&gt;
&lt;p&gt;Then perform the actual clean-up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;-each-ref --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%(refname)&amp;#34;&lt;/span&gt; refs/original/ | xargs -n &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; git update-ref -d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git reflog expire --expire&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;now --all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git gc --prune&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;now --aggressive
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To double-check call something like &lt;code&gt;du -c .&lt;/code&gt; in your directory and look at the output. You should now see that the big directories are all related to the submodule.&lt;/p&gt;
&lt;h1 id=&#34;pushing-the-changes&#34;&gt;Pushing the changes&lt;/h1&gt;
&lt;p&gt;Finally we will publish the changes. This is the part that is irreversible.
You can take extra pre-cautions by forking your upstream and pushing to the fork first, e.g. if your repository is at &lt;a href=&#34;https://github.com/alice/myapp&#34;&gt;https://github.com/alice/myapp&lt;/a&gt; make a fork to &lt;a href=&#34;https://github.com/alicia/myapp&#34;&gt;https://github.com/alicia/myapp&lt;/a&gt; or something like that.&lt;/p&gt;
&lt;p&gt;To work on alicia:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git remote add alicia git@github.com:alicia/myapp.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In any case you need to delete all tags that are not in your local repository anymore.
If you decided to get rid of some branches locally, also remove them on the remote.
You can do this via the command line or github&amp;rsquo;s interface (or gitlab or whatever). The command line for removing a remote tag is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git push alicia :tagname
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also backup your releases, i.e. save the release messages and any downloads you added somewhere (I don&amp;rsquo;t have an automatic way for that).&lt;/p&gt;
&lt;p&gt;Then force push, including the updated tags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git push --force --tags alicia master
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Repeat the last step for every branch and look at your results! Do a fresh clone of the remote somewhere to verify that everything is right.
Github should have rewired your releases, to the updated tags, but if something went wrong, you can fix it through the web interface.&lt;/p&gt;
&lt;p&gt;That was easy, right? :-)&lt;/p&gt;
&lt;p&gt;If you have any ideas how to simplify this, please feel free to comment (FSFE account required) or reply on &lt;a href=&#34;https://twitter.com/__h2__/status/758303895470895104&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Why Privacy is more than Crypto</title>
      <link>https://hannes.hauswedell.net/post/2016/05/31/why-privacy-is-more-than-crypto/</link>
      <pubDate>Tue, 31 May 2016 15:57:02 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2016/05/31/why-privacy-is-more-than-crypto/</guid>
      <description>&lt;p&gt;During the last year hell seems to have frozen over: our corporate &lt;del&gt;overlords&lt;/del&gt; &lt;em&gt;neighbours&lt;/em&gt; at Apple, Google and Facebook have all pushed for crypto in one way or another.
For &lt;a href=&#34;https://whispersystems.org/blog/whatsapp-complete/&#34;&gt;Facebook (WhatsApp) &lt;/a&gt; and &lt;a href=&#34;https://whispersystems.org/blog/allo/&#34;&gt;Google (Allo)&lt;/a&gt; the messenger crypto has even been implemented by none less than the famous,
&lt;a href=&#34;https://twitter.com/Snowden/status/661313394906161152&#34;&gt;endorsed-by-Edward-Snowden&lt;/a&gt; anarchist and hacker Moxie Marlinspike! So all is well on the privacy front! &amp;hellip; but is it really?&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;&lt;em&gt;EDIT: A &lt;a href=&#34;http://framablog.org/2016/06/27/le-chiffrement-ne-suffira-pas/&#34;&gt;French version of this post is available here&lt;/a&gt;.
I can&amp;rsquo;t verify its correctness, but I trust the translators to have done their best and thank them for the effort!&lt;/em&gt;&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;During the last year hell seems to have frozen over: our corporate &lt;del&gt;overlords&lt;/del&gt; &lt;em&gt;neighbours&lt;/em&gt; at Apple, Google and Facebook have all pushed for crypto in one way or another.
For &lt;a href=&#34;https://whispersystems.org/blog/whatsapp-complete/&#34;&gt;Facebook (WhatsApp) &lt;/a&gt; and &lt;a href=&#34;https://whispersystems.org/blog/allo/&#34;&gt;Google (Allo)&lt;/a&gt; the messenger crypto has even been implemented by none less than the famous,
&lt;a href=&#34;https://twitter.com/Snowden/status/661313394906161152&#34;&gt;endorsed-by-Edward-Snowden&lt;/a&gt; anarchist and hacker Moxie Marlinspike! So all is well on the privacy front! &amp;hellip; but is it really?&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;&lt;em&gt;EDIT: A &lt;a href=&#34;http://framablog.org/2016/06/27/le-chiffrement-ne-suffira-pas/&#34;&gt;French version of this post is available here&lt;/a&gt;.
I can&amp;rsquo;t verify its correctness, but I trust the translators to have done their best and thank them for the effort!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Contents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Encryption&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Software Freedom and Device Integrity&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(De-)centrality, vendor control and metadata&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Summary (go here if you are lazy)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have argued some points on mobile messaging security &lt;a href=&#34;https://hannes.hauswedell.net/post/2014/06/25/secure-texting-and-why-fsfe-cares/&#34;&gt;before&lt;/a&gt;
&lt;a href=&#34;https://hannes.hauswedell.net/post/2015/02/23/secure-texting-part-ii/&#34;&gt;already&lt;/a&gt; and I have also spoken about this in a &lt;a href=&#34;http://www.pietcast.com/folge-0020-messenger/&#34;&gt;podcast&lt;/a&gt; (in German),
but I fealt I needed to write about it again since there is a lot of confusion about what privacy and security actually mean (in general, but especially in the context of messaging) and
recent developments give a false sense of security in my opinion.&lt;/p&gt;
&lt;p&gt;I will discuss WhatsApp and the Facebook Messenger (both owned by Facebook), Skype (owned by Microsoft), Telegram (?), Signal (Open Whisper Systems), Threema (owned by Threema GmbH),
Allo (owned by Google) and some XMPP clients, as well as briefly touching on ToX and Briar.
I will not discuss &amp;ldquo;features&amp;rdquo; even if privacy related like &amp;ldquo;message has been read&amp;rdquo;-notifiers which are obviously bad. I will also not discuss anonymity which is a related subject,
but from my point of view less important if dealing with &amp;ldquo;SMS-replacement apps&amp;rdquo; as you actually do know your peers anyway. &lt;/p&gt;
&lt;h1 id=&#34;encryption&#34;&gt;Encryption&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/computer-1294045_640.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;When most people speak of privacy and security of their communication in regard to messaging it is usually about &lt;strong&gt;encryption&lt;/strong&gt; or more precisely the encryption of &lt;em&gt;data in motion&lt;/em&gt;,
or the protection of your chat message while it is traveling to your peer.&lt;/p&gt;
&lt;p&gt;There are basically three ways of doing this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;no encryption&lt;/strong&gt;: everyone on your local WiFi or some random sysadmin on the internet backbone can read it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**transport encryption: **connections to and from service provider e.g. WhatsApp server and in between service providers are safe, but service provider can read the message&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;end-to-end encryption:&lt;/strong&gt; message is only readable by your peer, but time of communication and participants still known to service provider&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also there is something called &lt;em&gt;perfect forward secrecy&lt;/em&gt; which (counter-intuitively) means that past communications cannot be decrypted even if your long-term key is revealed/stolen.&lt;/p&gt;
&lt;p&gt;Back in the day most apps including WhatsApp where actually of category 1, but today I expect almost all apps to be at least of category 2.
This reduces the chance of large-scale unnoticed eaves-dropping (that is still possible with e-mail for example),
but it is obviously not enough, as service providers &lt;del&gt;could be&lt;/del&gt; &lt;a href=&#34;https://nakedsecurity.sophos.com/2013/05/22/microsofts-reading-skype-messages/&#34;&gt;are evil&lt;/a&gt; or
can be &lt;a href=&#34;https://en.wikipedia.org/wiki/Lavabit&#34;&gt;forced to cooperate&lt;/a&gt; with potentially evil governments or spy agencies lacking democratic control.&lt;/p&gt;
&lt;p&gt;Therefore you really want your messenger to do end-to-end and right now the following all do (sorted by estimated size): &lt;strong&gt;WhatsApp&lt;/strong&gt;, &lt;strong&gt;Signal&lt;/strong&gt;, &lt;strong&gt;Threema&lt;/strong&gt;, XMMP-Clients with GPG/OTR/Omemo (&lt;strong&gt;ChatSecure&lt;/strong&gt;, &lt;strong&gt;Conversations&lt;/strong&gt;, &lt;strong&gt;Kontalk&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Messengers that have a special operating mode (&amp;ldquo;secret chat&amp;rdquo; or &amp;ldquo;incognito mode&amp;rdquo;) providing (3) are &lt;strong&gt;Telegram&lt;/strong&gt; and &lt;strong&gt;Google Allo&lt;/strong&gt;.
It is very unfortunate that it is not turned on by default so I wouldn&amp;rsquo;t recommend them.
If you are forced to use one of these, always make sure to select the private mode.
It should be noted that Telegram&amp;rsquo;s end-to-end encryption is viewed as &lt;a href=&#34;https://en.wikipedia.org/wiki/Telegram_(software)#Encryption_scheme&#34;&gt;less robust by experts&lt;/a&gt; although most experts agree that actual text-recovery attacks are not feasible.&lt;/p&gt;
&lt;p&gt;Other popular programs like the &lt;strong&gt;Facebook messenger&lt;/strong&gt; or &lt;strong&gt;Skype&lt;/strong&gt; do not provide end-to-end encryption and should definitely be avoided.
It is actually proven that &lt;a href=&#34;https://nakedsecurity.sophos.com/2013/05/22/microsofts-reading-skype-messages/&#34;&gt;Skype parses your messages&lt;/a&gt; so I won&amp;rsquo;t discuss these two any further.&lt;/p&gt;
&lt;h1 id=&#34;software-freedom-and-device-integrity&#34;&gt;Software Freedom and device integrity&lt;/h1&gt;
&lt;p&gt;Ok, so now the data is safe while traveling from you to your friend, but what about before and after it is sent?
Can&amp;rsquo;t you also try to eavesdrop on the phone of the sender or the recipient before it is send / after it is received?
Yes, you can and in Germany the government has already actively used &lt;a href=&#34;https://de.wikipedia.org/wiki/Telekommunikations%C3%BCberwachung#Quellen-Telekommunikations.C3.BCberwachung&#34;&gt;&amp;ldquo;Quellen-Telekommunikationsüberwachung&lt;/a&gt;&amp;rdquo;
(communication surveillance at the source) precisely so they can circumvent encryption.&lt;/p&gt;
&lt;p&gt;Let us revisit the distinction of (2.) and (3.) above. The main difference between transport encryption and end-to-end is that you don&amp;rsquo;t have to trust the service provider anymore&amp;hellip;
WRONG: In almost all cases the entity running the server is the same as the entity providing you with the program so of course you must trust the program to actually do what it claims it does.
Or more precisely, there must be social and technical means that provide you with sufficient certainty that the program is trustworthy. Otherwise there is little gained from end-to-end encryption.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://fsfe.org/about/basics/freesoftware.en.html&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/fourism_correct_flat-300x225.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;software-freedom&#34;&gt;Software Freedom&lt;/h3&gt;
&lt;p&gt;This is where &lt;a href=&#34;https://fsfe.org/about/basics/freesoftware.en.html&#34;&gt;Software Freedom&lt;/a&gt; comes into the picture.
If the source code is public there are going to be lot&amp;rsquo;s of hackers and volunteers that check whether the program actually encrypts the content.
While even this public scrutiny cannot give you 100% security it is widely recognized as the best process to ensure that a program is generally secure and security problems become known (and then also fixed). Software Freedom also enables unofficial or competing implementations of the Messenger app that are still compatible; so if there are certain things that you don&amp;rsquo;t like or mistrust about the official app you can chose another one and still chat with your friends.&lt;/p&gt;
&lt;p&gt;Some companies like &lt;strong&gt;Threema&lt;/strong&gt; that don&amp;rsquo;t provide you their source of course claim that it is not required for trust.
&lt;a href=&#34;https://threema.ch/de/blog/posts/unabhangiger-sicherheits-audit-bestatigt-threema-halt-was-es-verspricht&#34;&gt;They say&lt;/a&gt; that they had their source code audited by some other
company (which they usually paid to do this), but if you don&amp;rsquo;t trust the original company, why would you trust someone contracted by them? More importantly,
how do you know the version checked by the third party actually is the same as the version installed on your phone? [you get updates quite often or not?]&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/exhaust-517799_640.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This is also true for governmental or public entities that do these kind of audits.
Depending on your threat model or your assumptions about society you might be inclined to trust public institutions more than private institutions (or the other way around),
but if you look at e.g. Germany, with the TÜV there is actually one organisation that checks both the trust-worthiness of messenger apps and whether cars produce the correct amount of pollution. &lt;strong&gt;And we all know how well that went!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;trust&#34;&gt;Trust&lt;/h3&gt;
&lt;p&gt;So when deciding on trusting a party, you need to consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;benevolence&lt;/strong&gt;: the party doesn&amp;rsquo;t &lt;em&gt;want to&lt;/em&gt; compromise your privacy and/or is itself affected&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;competence&lt;/strong&gt;: the party is &lt;em&gt;technically capable&lt;/em&gt; of protecting your privacy and identifying/fixing issues&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;integrity&lt;/strong&gt;: the party cannot be bought, bribed or infiltrated by secret services or other malicious third parties&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After the Snowden revelations it should be very obvious that &lt;strong&gt;the public is the only party that can collectively fulfill these requirements&lt;/strong&gt; so the public availability of the source code is absolutely crucial.
This rules out &lt;strong&gt;WhatsApp&lt;/strong&gt;, &lt;strong&gt;Google Allo&lt;/strong&gt; and &lt;strong&gt;Threema&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Wait a minute&amp;hellip; but are there no other ways to check that the data in motion is actually encrypted?&amp;rdquo;&lt;/em&gt; Ah, of course, there are, as &lt;a href=&#34;https://threema.ch/validation/&#34;&gt;Threema will point out,&lt;/a&gt; or
&lt;a href=&#34;http://www.heise.de/security/artikel/Test-Hinter-den-Kulissen-der-WhatsApp-Verschluesselung-3165567.html&#34;&gt;other people for WhatsApp&lt;/a&gt;.
But the important part is that the service provider controls the app on your device, so they can listen in before encryption/after decryption or just &amp;ldquo;steal&amp;rdquo; your decryption keys.
&lt;em&gt;&amp;ldquo;I don&amp;rsquo;t believe X would do such a thing&amp;rdquo;&lt;/em&gt; Please keep in mind that even if you trust Facebook or Google (which you shouldn&amp;rsquo;t), can you trust them to not comply with court orders?
If yes, why did you want end-to-end encryption in the first place? _&amp;ldquo;Wouldn&amp;rsquo;t someone notice?&amp;rdquo;  _Hard to say; if they always did this, you might be able to recognize it from analyzing the app. But maybe they do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (suspectList.contains(userID))
    sendSecretKeyToServer();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So not everyone is affected and the behaviour is never exhibited in &amp;ldquo;lab conditions&amp;rdquo;. Or the generation of your key is manipulated so that it is less random, follows a pattern that is more easily cracked.
There are multiple angles to this, most of whom could easily be deployed in a later update or hidden within other features.
Note also that being &amp;ldquo;on the list&amp;rdquo; is quite easy, current NSA regulations make sure that more &lt;a href=&#34;http://techcrunch.com/2016/05/17/stanford-quantifies-the-privacy-stripping-power-of-metadata/&#34;&gt;than 25,000 people&lt;/a&gt; can be added for each &amp;ldquo;seed&amp;rdquo; suspect.&lt;/p&gt;
&lt;p&gt;In light of this it is very bad that Open Whisper Systems and Moxie Marlinspike (the aforementioned famous author of Signal) publicly praise Facebook and Google,
thereby increasing trust in their apps [although it is not bad per se that they helped add the crypto of course].
I am fairly sure they cannot rule out any of the above, because they have not seen the full source code to the apps, nor do they know what future updates will contain &amp;ndash; nor would we want to have to rely on them for that matter!&lt;/p&gt;
&lt;h3 id=&#34;the-signal-messenger&#34;&gt;The Signal Messenger&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;“Ok, I got it. I will use Free and Open Source Software. Like the original &lt;strong&gt;Signal&lt;/strong&gt;.”&lt;/em&gt; Now it becomes tricky.
While the source code of the Signal client software is free/open/libre it requires other non-free/closed/proprietary components to run.
These pieces are not essential to the functionality, but they (a) leak some meta data to Google (more on metadata later) and (b) compromise the integrity of your device.&lt;/p&gt;
&lt;p&gt;The last part means that even if a small part of your application is not trustworthy, then the rest isn&amp;rsquo;t either.
This is even more severe for components running with system privileges as they can basically do anything at all with your phone.
And it is &amp;ldquo;especially impossible&amp;rdquo; to trust non-free components that regularly send/receive data to/from other computers like these google services.
Now it is true that these components are already included in most of the Android phones used in the world and it is also true that there are very few devices that actually run entirely free of non-free components,
so from my point of view it is not problematic per se to make use of them &lt;em&gt;when available&lt;/em&gt;.
But to &lt;em&gt;mandate&lt;/em&gt; their use means to exclude people who require a higher level of security (even if available!);
who use alternative more secure versions of Android like &lt;a href=&#34;https://copperhead.co/&#34;&gt;CopperheadOS&lt;/a&gt;;
or who just happen to have a phone without these Google Services (especially common in developing countries).
Ultimately Signal creates a &amp;ldquo;network effect&amp;rdquo; that discourages improving the overall trustworthiness of the mobile device, because it punishes users who do so.
This undermines many of the promises its authors gives.&lt;/p&gt;
&lt;p&gt;To make matters worse: OpenWhisperSystems not only don&amp;rsquo;t support fully free systems, but have threatened to take legal and technical action to prevent
independent developers from offering a modified version of the &lt;strong&gt;Signal&lt;/strong&gt; client app which would work without the non-free Google components and could still
interact with other Signal users (&lt;a href=&#34;https://github.com/WhisperSystems/Signal-Android/issues/127&#34;&gt;[1]&lt;/a&gt; &lt;a href=&#34;https://github.com/WhisperSystems/Signal-Android/issues/1000&#34;&gt;[2]&lt;/a&gt;
&lt;a href=&#34;https://github.com/LibreSignal/LibreSignal/issues/37&#34;&gt;[3]&lt;/a&gt;).
Because of this independent projects like &lt;a href=&#34;https://github.com/LibreSignal/LibreSignal&#34;&gt;LibreSignal&lt;/a&gt; are now stalled.
Very much in contrast to their &lt;a href=&#34;https://github.com/WhisperSystems/Signal-Android/blob/master/LICENSE&#34;&gt;Free Software license&lt;/a&gt;,
they oppose any clients to the Signal network not distributed by them. In this regard the Signal app is less usable and less trustworthy than e.g. &lt;strong&gt;Telegram&lt;/strong&gt; which
&lt;a href=&#34;https://en.wikipedia.org/wiki/Telegram_(software)#Client_applications&#34;&gt;encourages independent clients&lt;/a&gt; to their servers and has &lt;a href=&#34;https://github.com/slp/Telegram-FOSS&#34;&gt;fully free versions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just so that there is no wrong impression here: I don&amp;rsquo;t believe in some kind of conspiracy between Google and Moxie Marlinspike, and I thank him for making their positions clear in a
friendly manner (at least in the last statements), but I do think that the aggressive protection of their brand and their insistence on controlling all client software to their network are
damaging the overall struggle for trustworthy communication.&lt;/p&gt;
&lt;h1 id=&#34;de-centrality-vendor-control-and-metadata&#34;&gt;(De-)centrality, vendor control and metadata&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/networks_black.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;An important part of a communication network is its &lt;em&gt;topology&lt;/em&gt;, i.e. they way the network is structured. As can be seen in the picture above there are different approaches that are (more or less) widely used.
So while the last section dealt with what is happening on your phone, this one will discuss what is happening on the servers and which role they play.
It is important to note that even in centralized networks some communication might still be peer-to-peer (not going through the center), but the distinction is that they require central servers to operate.&lt;/p&gt;
&lt;h3 id=&#34;centralized-networks&#34;&gt;Centralized networks&lt;/h3&gt;
&lt;p&gt;Centralized networks are the most common, i.e. all of the aforementioned apps (WhatsApp, Telegram, Signal, Threema, Allo) are based on centralized networks.
While a lot internet services used to be decentral, like E-Mail or the World Wide Web, the last years have seen many centralized services appear.
One could for example say that Facebook is a centralized service built on the originally decentralized WWW structure.&lt;/p&gt;
&lt;p&gt;Usually centralized networks are part of a bigger brand or product that is marketed together as one solution (in our case to the issue of texting/SMS).
For companies selling/offering these solutions it has the advantage that it has full control over the entire system and can change it rather quickly, pushing new functionality to/on all users.&lt;/p&gt;
&lt;p&gt;Even if we assume that the service has end-to-end encryption and even if there is a client app that is Free Software, the following problems remain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata:&lt;/strong&gt; your messages&amp;rsquo; content is encrypted, but the who-when-where information is still readable by the service provider&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;denial of service:&lt;/strong&gt; you may be blocked from using the service by either the service provider or by your government&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is also the more general problem that a privately run centralized service can decide which features to add independently of whether its users actually consider them features or maybe &amp;ldquo;anti-features&amp;rdquo;,
e.g. telling other users whether you are &amp;ldquo;online&amp;rdquo; or not.
Some of these could be removed from the app on your phone if it actually is Free Software, but some are tied to centralized structure.
I might write more on this in a separate article some time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/the-chief-data-officers-quest-for-data-quality-and-data-governance-5-638.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;metadata&#34;&gt;Metadata&lt;/h3&gt;
&lt;p&gt;As explained above, metadata is all data, that is not the content of your message. You might think that this data is unimportant data, but &lt;a href=&#34;http://www.pnas.org/content/113/20/5536.full&#34;&gt;recent studies&lt;/a&gt; show that the opposite is true.
Metadata includes: when you are &amp;ldquo;online&amp;rdquo; / if your phone has internet; the time of your messages and who you are texting with; a rough estimate on the length of the messages;
your IP-address which can reveal rather accurately where you currently are (at work, or at home, out of town et cetera);
possibly also security related information about your device (which operating system, which phone model&amp;hellip;).
This information has a lot of privacy threatening value and the US secret services actually use it to justify targeted killings (see above)!!&lt;/p&gt;
&lt;p&gt;The amount of metadata a centralized service sees depends on the exact implementation, e.g. the &amp;ldquo;group chat&amp;rdquo; feature in Signal and supposedly also Threema is client-based so in
theory the server knows nothing about the groups. On the other hand the server has timestamps from your communication and can likely correlate these.
Again it is important to note that while your service provider may not log this information by default (some information &lt;em&gt;must&lt;/em&gt; be retained, some &lt;em&gt;could&lt;/em&gt; be deleted immediately),
it might be forced to log more data by secret agencies. Signal (as mentioned before) only works in conjunction with some non-free components from Google or Apple who then always get some of your metadata,
including your IP-address (and thus physical position) and the time you receive messages.&lt;/p&gt;
&lt;p&gt;More information on metadata &lt;a href=&#34;http://techcrunch.com/2016/05/17/stanford-quantifies-the-privacy-stripping-power-of-metadata/&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://www.nybooks.com/daily/2014/05/10/we-kill-people-based-metadata/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;denial-of-service&#34;&gt;Denial of service&lt;/h3&gt;
&lt;p&gt;Another major drawback of centralized services, is that they can decide not to serve you at all if they don&amp;rsquo;t want to or are obliged not to by law.
Since many of the services require your phone number to register and they operate from the US, they might deny you service if you are a Cuban for example.
This is especially important since we are dealing with encryption that is &lt;a href=&#34;https://en.wikipedia.org/wiki/Export_of_cryptography_from_the_United_States&#34;&gt;highly regulated in the US&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As part of Anti-Terrorism measures Germany has &lt;a href=&#34;http://www.tagesschau.de/inland/anti-terror-gesetze-101.html&#34;&gt;just introduced a new law&lt;/a&gt; that requires registering your ID when getting a SIM card, even prepaid.
While I don&amp;rsquo;t think that it is likely, it does open the possibility for black-listing people and pressuring companies to exclude them from service.&lt;/p&gt;
&lt;p&gt;Instead of working with the companies, a malicious government can of course also target the service directly.
Operating from a few central servers makes the infrastructure much more vulnerable to being blocked nationwide.
This has been reported for &lt;a href=&#34;https://www.reddit.com/r/China/comments/46uajl/signal_private_messenger/&#34;&gt;Signal&lt;/a&gt; and &lt;a href=&#34;https://www.hongkongfp.com/2015/07/13/china-blocks-telegram-messenger-blamed-for-aiding-human-rights-lawyers/&#34;&gt;Telegram&lt;/a&gt; in China.&lt;/p&gt;
&lt;h3 id=&#34;disconnected-networks&#34;&gt;Disconnected Networks&lt;/h3&gt;
&lt;p&gt;When the server source code of a service provider is Free and Open Source software, you can setup your own service if you distrust the provider.
This seems like a big advantage and &lt;a href=&#34;https://whispersystems.org/blog/the-ecosystem-is-moving/&#34;&gt;is argued by Moxie Marlinspike&lt;/a&gt; as such:&lt;/p&gt;
&lt;blockquote&gt;Where as before you could switch hosts, or even decide to run your own server, now users are simply switching entire networks. [...] If a centralized provider with an open source infrastructure ever makes horrible changes,
those that disagree have the software they need to run their own alternative instead.&lt;/blockquote&gt;
&lt;p&gt;And of course this is better than not having the possibility to roll your own, but the inherent value of a &amp;ldquo;social&amp;rdquo; network comes from the people who use it and
&lt;strong&gt;it is not easy to switch&lt;/strong&gt; if you loose the connection to your friends. This is why alternatives to Facebook have such a hard time. Even if they were better in every aspect, they just don&amp;rsquo;t have your friends.&lt;/p&gt;
&lt;p&gt;Yes, it is easier for mobile apps that identify people via phone number, because it means you at least quickly find your friends on a new network, but for every non-technical person
it is really confusing to keep 5 different apps around just so that they can keep in touch with most of their friends so switching networks should always be the &lt;em&gt;ultima ratio&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note that while OpenWhisperSystems claim that they are of this category, in reality they only publish &lt;a href=&#34;https://github.com/JavaJens/TextSecure/issues/54#issuecomment-160419089&#34;&gt;parts of the Signal server source code&lt;/a&gt;
so you are not able setup a server that has the same functionality (more precisely the telephoning part is missing).&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;federation&#34;&gt;Federation&lt;/h3&gt;
&lt;p&gt;Federation is a concept which solves the aforementioned problem by having the service providers speak with each other, as well.
So you can change the provider and possibly the app you are using, but you will still be able to communicate with people registered on the old server.
E-Mail is a typical example of a federated system: it doesn&amp;rsquo;t matter whether you are &lt;a href=&#34;mailto:tom@gmail.com&#34;&gt;tom@gmail.com&lt;/a&gt; or &lt;a href=&#34;mailto:jane@yahoo.com&#34;&gt;jane@yahoo.com&lt;/a&gt; or even &lt;a href=&#34;mailto:linda@server-in-my-basement.com&#34;&gt;linda@server-in-my-basement.com&lt;/a&gt;,
all people are able to reach all other people. Imagine how ridiculous it would be, if you could only reach people on your own provider!?&lt;/p&gt;
&lt;p&gt;The drawback from a developer&amp;rsquo;s and/or company&amp;rsquo;s perspective is that you have to publicly define the communication protocols and that because the standardization process can be complicated and lengthy you are
less flexible in changing the whole system. I do concur that it makes it more difficult for good features to quickly be available for most people, but as mentioned previously,
I think that from a privacy and security point of view it is clearly a feature, because it involves more people and weakens the possibility of the provider pushing unwanted features on the users;
and most importantly because there is no more lock-in-effect. As a bonus these kind of networks quickly produce different software implementations,
both for the software running at the end-user and for the software running on the servers. This makes the system more robust against attacks and ensures that weaknesses/bugs in one piece of software don&amp;rsquo;t effect the entire system.&lt;/p&gt;
&lt;p&gt;And, of course, as previously mentioned, the metadata is spread between different providers (which makes it harder to track all users at once) and you get to choose which of them gets yours or whether you want to operate your own.
Plus, it becomes very difficult to block all providers, and you could switch in case one discriminates against you (see &amp;ldquo;Denial of Service&amp;rdquo; above).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As a sidenote: It should be mentioned that federation does imply that some metadata will be seen by, both, your service provider and your peer&amp;rsquo;s service provider.
In the case of e-mail this is quite a lot, but this is not required by federation per se, i.e. a well designed federated system could avoid sharing almost all metadata in-between two service
providers &amp;ndash; other than the fact that there is a user account with a certain ID on that server.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/XMPP&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/05/XMPP_logo.svg_.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, is there such a system for instant messaging / texting? Yes, there is, it is called &lt;a href=&#34;https://en.wikipedia.org/wiki/XMPP&#34;&gt;XMPP&lt;/a&gt;. While originally not containing strong encryption,
there is now encryption that provides &lt;a href=&#34;https://conversations.im/omemo/&#34;&gt;the same level as security as the Signal Protocol&lt;/a&gt;.
There are also great mobile apps for Android (&lt;a href=&#34;https://conversations.im/&#34;&gt;&amp;ldquo;Conversations&amp;rdquo;&lt;/a&gt;) and iOS (&lt;a href=&#34;https://chatsecure.org/&#34;&gt;&amp;ldquo;ChatSecure&amp;rdquo;&lt;/a&gt;) and every other platform in the world, as well.&lt;/p&gt;
&lt;p&gt;The drawback? Like e-mail, you need to setup an account somewhere and there is no automatic association with telephone numbers so you need not only convince your
friends to use this fancy new program, but also manually find out which provider and username they have chosen. The independence of the phone number system might be seen as a feature by some, but as a replacement for SMS this seems unfit.&lt;/p&gt;
&lt;p&gt;The solution: &lt;a href=&#34;https://kontalk.org/&#34;&gt;Kontalk&lt;/a&gt;, a messenger based on XMPP that still does automatic contact discovery via phone numbers from your address book.
Unfortunately it is not yet as mature as other mentioned applications, i.e. it currently still lacks group chats and there is no support for iOS.
But Kontalk does prove that it is viable to have the same features built on XMPP that you have come to expect from applications like WhatsApp or Telegram.
So from my point of view it is only a matter of time until these federated solutions are on feature parity and similar in usability.
&lt;a href=&#34;http://blog.jonasoberg.net/is-this-the-end-of-decentralisation-2/&#34;&gt;Some agree&lt;/a&gt; with this point of view, &lt;a href=&#34;https://whispersystems.org/blog/the-ecosystem-is-moving/&#34;&gt;some don&amp;rsquo;t&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;peer-to-peer-networks&#34;&gt;Peer-to-Peer networks&lt;/h3&gt;
&lt;p&gt;Peer-to-peer networks completely eliminate the server and thereby all metadata at centralized locations.
This kind of network is unbeatable from a privacy and freedom perspective and it is also almost impossible to block by an authority.
An example of a peer-to-peer application is &lt;a href=&#34;https://tox.chat/&#34;&gt;ToX&lt;/a&gt;, another one is &lt;a href=&#34;https://ricochet.im/&#34;&gt;Ricochet&lt;/a&gt; (edit: not for mobile)
and there is still under development &lt;a href=&#34;https://briarproject.org/&#34;&gt;Briar&lt;/a&gt; which also adds anonymity so even your peer doesn&amp;rsquo;t know your IP address.
Unfortunately there are principle issues on mobile devices making it hard to maintain the many connections required for these networks.
Additionally it seems impossible right now to do a phone-number to user mapping so there can be no automatic contact discovery.&lt;/p&gt;
&lt;p&gt;While I don&amp;rsquo;t currently see the possibility of these kind of apps stealing market share from WhatsApp, there are use cases, especially when you are being actively targeted by surveillance and/or
you have group of people who collectively decide to move to such an app for their communication, e.g. political organisations.&lt;/p&gt;
&lt;h1 id=&#34;summary&#34;&gt;Summary&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Privacy is getting more and more attention and people are actively looking to protect themselves better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It can be considered positive that major software providers feel they have to react to this, adding encryption to their software; and who knows, maybe it does make life for the NSA a little bit harder.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;However there is no reason that we should trust them anymore than we have previously, as there is no way for us to know what their apps actually do, and there remain many ways they can spy on us.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you are currently using WhatsApp, Skype, Threema or Allo and expect a similar experience you might consider switching to &lt;a href=&#34;http://www.telegram.org&#34;&gt;Telegram&lt;/a&gt; or &lt;a href=&#34;https://whispersystems.org/&#34;&gt;Signal&lt;/a&gt;.
They are better than the previously mentioned (in different ways), but they are **far from perfect, **as I have shown. &lt;strong&gt;We need federation&lt;/strong&gt; in the medium to long-term.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Even if they seem to be nice people and very skilled hackers, we cannot trust OpenWhisperSystems to deliver us from surveillance as they are blind to certain issues and not very open to cooperation with the community.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some cool things are cooking in XMPP-land, keep an eye out for &lt;a href=&#34;https://conversations.im/&#34;&gt;Conversations&lt;/a&gt;, &lt;a href=&#34;https://chatsecure.org/&#34;&gt;ChatSecure&lt;/a&gt; and &lt;a href=&#34;http://kontalk.org&#34;&gt;Kontalk&lt;/a&gt;.
If you can, support them with coding skills, donations or friendly e-mails.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you want a zero-metadata approach and/or anonymity, try out &lt;a href=&#34;https://tox.chat/&#34;&gt;ToX&lt;/a&gt; or wait for &lt;a href=&#34;https://briarproject.org/&#34;&gt;Briar&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
    </item>
    
    <item>
      <title>OpenBSD on the Thinkpad X250</title>
      <link>https://hannes.hauswedell.net/post/2016/01/15/openbsd-on-the-thinkpad-x250/</link>
      <pubDate>Fri, 15 Jan 2016 16:17:30 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2016/01/15/openbsd-on-the-thinkpad-x250/</guid>
      <description>&lt;p&gt;Since posts like these often helped me setup some device, I thought I&amp;rsquo;d write one as well this time. Also it is advertising for a good free operating system.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2016/01/snap1.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/01/snap1-1024x576.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Everything works almost perfectly, good hardware, good software! You should give it a try :)&lt;/p&gt;
&lt;h2 id=&#34;hardware&#34;&gt;Hardware&lt;/h2&gt;
&lt;p&gt;I have got a fairly high-end config:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Intel® Core™ i7-5600U&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;16GB RAM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1920x1080 Display, non-glare, non-touch&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;512GB Samsung SSD&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Intel LAN + WLAN&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Since posts like these often helped me setup some device, I thought I&amp;rsquo;d write one as well this time. Also it is advertising for a good free operating system.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2016/01/snap1.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2016/01/snap1-1024x576.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Everything works almost perfectly, good hardware, good software! You should give it a try :)&lt;/p&gt;
&lt;h2 id=&#34;hardware&#34;&gt;Hardware&lt;/h2&gt;
&lt;p&gt;I have got a fairly high-end config:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Intel® Core™ i7-5600U&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;16GB RAM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1920x1080 Display, non-glare, non-touch&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;512GB Samsung SSD&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Intel LAN + WLAN&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pro-Dock&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installing-openbsd&#34;&gt;Installing OpenBSD&lt;/h2&gt;
&lt;p&gt;You need a current OpenBSD snapshot (or 5.9 once it is released).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;get the &lt;a href=&#34;//ftp.spline.de/pub/OpenBSD/5.8/amd64/install58.fs&#34;&gt;install58.fs&lt;/a&gt; from a server near you, dd it to a USB-Stick and boot from it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;follow the instructions on the screen to install 5.8&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;get the &lt;a href=&#34;//ftp.spline.de/pub/OpenBSD/snapshots/amd64/bsd.rd&#34;&gt;bsd.rd&lt;/a&gt; from a current snapshot and place it in &lt;code&gt;/&lt;/code&gt; (maybe backup the existing one)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reboot into it (enter &lt;code&gt;boot bsd.rd&lt;/code&gt; at the bootloader prompt)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;follow the intructions on the screen to update to the 5.9-snapshot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;after you have rebooted into 5.9, run &lt;code&gt;sysmerge&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Et voila, you are on a current branch of OpenBSD. You should have seen the virtual console resize after the update to the new version.&lt;/p&gt;
&lt;h2 id=&#34;bios&#34;&gt;BIOS&lt;/h2&gt;
&lt;p&gt;The BIOS has some useful settings, you might want to make, e.g. switching
&lt;code&gt;Fn&lt;/code&gt; and &lt;code&gt;lCtrl&lt;/code&gt; buttons and switching the meaning of the F*-keys to be F*-keys by default and not &amp;ldquo;media keys&amp;rdquo;. Unfortunately deactivating the keypad from the BIOS does not work ( it can however be deactivated by software, see below).&lt;/p&gt;
&lt;h2 id=&#34;xorg-and-periphals&#34;&gt;Xorg and periphals&lt;/h2&gt;
&lt;p&gt;No &lt;code&gt;xorg.conf&lt;/code&gt; nor any configuration like that is needed to bring up X since the new Intel driver takes care of everything. 3D acceleration works, however the direct rendering devices come with write access only given to root. It&amp;rsquo;s probably a security &amp;ldquo;feature&amp;rdquo;, but it prevents 3D for regular users so I created
&lt;code&gt;/etc/rc.local&lt;/code&gt; (this is run on startup) with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/sh
/bin/chmod g+rw /dev/drm*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should have setup the keyboard to your local layout during install, but if
you haven&amp;rsquo;t done so or want to deactivate dead keys you can edit &lt;code&gt;/etc/kbdtype&lt;/code&gt;, e.g. to &lt;code&gt;de.nodead&lt;/code&gt;. This affects both the console and Xorg. Inside Xorg the &amp;ldquo;media buttons&amp;rdquo; for display brightness and sound work automatically.&lt;/p&gt;
&lt;p&gt;To deactivate the mouse touchpad and make scrolling working with the pointer in combination with the middle mouse button, I have added the following to my &lt;code&gt;.xinitrc/.xsession&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# deactivate touchpad
synclient TouchpadOff=1

# activate scroll wheel button
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;WS Pointer Wheel Emulation&amp;quot; 1
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;WS Pointer Wheel Emulation Axes&amp;quot; 6 7 4 5
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;WS Pointer Wheel Emulation Button&amp;quot; 2
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;WS Pointer Wheel Emulation Timeout&amp;quot; 50
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;WS Pointer Wheel Emulation Inertia&amp;quot; 3

# increase pointer speed
xinput set-prop &amp;quot;/dev/wsmouse&amp;quot; &amp;quot;Device Accel Constant Deceleration&amp;quot; 0.4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have to note though that the Pointer Wheel Emulation does not work satisfactory, there is often some jitter and then scrolling stops working. Also the increased sensitivity produces very slight ghost movements of the mouse (very small, but noticable movements of the mouse in the bottom left direction). I still need to debug this, maybe its also a hardware issue.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;UPDATE: I was experiencing more problems with the keyboard, including the space bar not working reliably, so I had the hardware checked resulting in a replacement for the keyboard. After this, all problems related to the mouse disappeared, as well, so I am pretty sure it was actually a hardware issue.
But I also updated to a more recent snapshot so maybe the mouse problems were software related. In any case they are gone now.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The dock seems to work (charging and on/off), although I have not yet tested hooking up external input devices or screens.&lt;/p&gt;
&lt;h2 id=&#34;networking&#34;&gt;Networking&lt;/h2&gt;
&lt;p&gt;Both lan and wlan devices come with working drivers and the firmware for the wifi card is automatically downloaded upon install. It should be noted that OpenBSD does not have a service for managing networks and that it implements WPA[2] PSK inside its regular networking infrastructure (it doesn&amp;rsquo;t need wpa_supplicant). For enterprise WPA (like &lt;em&gt;eduroam&lt;/em&gt;) however, wpa_supplicant is needed.&lt;/p&gt;
&lt;p&gt;I have fiddled around with some solutions and ended up adapting a &lt;a href=&#34;https://hannes.hauswedell.net/post/2016/01/wifinwid.txt&#34;&gt;script&lt;/a&gt;. The original is &lt;a href=&#34;http://foad2.obtuse.com/beck/wifinwid&#34;&gt;wifinwid&lt;/a&gt;, but I changed it so that it restarts wpa_supplicant before trying every network and also only starts dhclient after it has attached to a network. This solution requires a file at &lt;code&gt;/usr/local/etc/nwids.iwm0&lt;/code&gt; with your saved networks in preferred order (every line is the arguments line for the ifconfig call), e.g.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nwid MYSSID -wpa wpa wpaakms psk wpakey SECRETYO up
nwid eduroam -wpa wpa wpaakms 802.1x up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the &amp;ldquo;enterprise&amp;rdquo; WPA networks like eduroam you have to additionally edit &lt;code&gt;/etc/wpa_supplicant.conf&lt;/code&gt; (but not for other WPA networks!). The exact values are the same as for other operating systems, see e.g. &lt;a href=&#34;//www.kariliq.nl/openbsd/eduroam-uva.html&#34;&gt;this site&lt;/a&gt;. You do however need to add a &lt;code&gt;wpa_supplicant_flags=-c /etc/wpa_supplicant.conf -D openbsd -i iwm0&lt;/code&gt; line &lt;code&gt;/etc/rc.conf.local&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ultimately you have make the script be started on boottime and also initially make it not connect to some random unencrypted network via &lt;code&gt;/etc/hostname.iwm0&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nwid NONEXISTANT
rtsol
!/usr/local/sbin/wifinwid \$if &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you have the behaviour that it only ever connects to known networks and that you can roam between different known networks, encrypted or unencrypted, PSK or with personal authentication.&lt;/p&gt;
&lt;h2 id=&#34;powermanagement&#34;&gt;Powermanagement&lt;/h2&gt;
&lt;p&gt;You need to activate the APM-daemon in your rc.conf.local:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apmd_flags=&amp;quot;-A&amp;quot;
apmd_enable=&amp;quot;YES&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enables speed-stepping and also suspend and resume. I have tested the &lt;code&gt;zzz&lt;/code&gt; command (suspend to RAM), but not yet &lt;code&gt;ZZZ&lt;/code&gt; (suspend to disk). There seem to be no problems at all with X and the wifi also automatically reconnects if setup like above.&lt;/p&gt;
&lt;p&gt;Brightness control works through keyboard shortcuts and the battery time seems to be good, although I haven&amp;rsquo;t done long-term tests, yet. With the large battery official number is &amp;ldquo;up to 20 hours&amp;rdquo;, if I get 12 hours that would be enough for me. A nice thing is that the notebook has an internal battery so you can change the external one without rebooting. The estimation of the remaining time via &lt;code&gt;apm&lt;/code&gt; or &lt;code&gt;sysctl&lt;/code&gt; seems to be accurate and my windows manager i3&amp;rsquo;s infobar supports these sensors automatically.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Altogether I am very happy about the hardware support, with the only annoyance being the mouse (which is not crucial, because I work more via keyboard anyway). Thanks to all the involved developers! I will probably update this post in the near future, once I have more things tested!&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Secure Texting Part II</title>
      <link>https://hannes.hauswedell.net/post/2015/02/23/secure-texting-part-ii/</link>
      <pubDate>Mon, 23 Feb 2015 21:33:47 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2015/02/23/secure-texting-part-ii/</guid>
      <description>&lt;p&gt;Last summer I &lt;a href=&#34;https://hannes.hauswedell.net/post/2014/06/25/secure-texting-and-why-fsfe-cares/&#34;&gt;blogged&lt;/a&gt; about secure messaging and why FSFE cares about it (and why you should, too!). Since then a few things have changed, and I want to give you an update on the situation.&lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;The conclusion of my last article was:&lt;/p&gt;
&lt;blockquote&gt;TextSecure and Kontalk are both good apps in our eyes, however, TextSecure has a much larger adoption and its protocol has gone through more reviews. The protool is integrated into CyanogenMod, recommended by leading security experts and the project just recently gained lots of media attention and $400.000 funding. So we believe if we are to have a chance at migrating people away from WhatsApp than TextSecure is the way to go.&lt;/blockquote&gt;
&lt;p&gt;We knew that TextSecure depended on Google Play Services last year, but we were hoping that this was a temporary problem, as virtually every other messaging app in existence has a fallback mode for delivery that does not require proprietary (Google) components. Unfortunately we were wrong: nearly a year later the development of a websocket based version of TextSecure &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000#issuecomment-68592064&#34;&gt;has&lt;/a&gt; &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000#issuecomment-74924059&#34;&gt;stalled&lt;/a&gt;. Lead developers at WhisperSystems have stated repeatedly that it is not important to them, and the many requests, tests and code contributions from external people did not result in the situation now being any better than it was a year ago.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Last summer I &lt;a href=&#34;https://hannes.hauswedell.net/post/2014/06/25/secure-texting-and-why-fsfe-cares/&#34;&gt;blogged&lt;/a&gt; about secure messaging and why FSFE cares about it (and why you should, too!). Since then a few things have changed, and I want to give you an update on the situation.&lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;The conclusion of my last article was:&lt;/p&gt;
&lt;blockquote&gt;TextSecure and Kontalk are both good apps in our eyes, however, TextSecure has a much larger adoption and its protocol has gone through more reviews. The protool is integrated into CyanogenMod, recommended by leading security experts and the project just recently gained lots of media attention and $400.000 funding. So we believe if we are to have a chance at migrating people away from WhatsApp than TextSecure is the way to go.&lt;/blockquote&gt;
&lt;p&gt;We knew that TextSecure depended on Google Play Services last year, but we were hoping that this was a temporary problem, as virtually every other messaging app in existence has a fallback mode for delivery that does not require proprietary (Google) components. Unfortunately we were wrong: nearly a year later the development of a websocket based version of TextSecure &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000#issuecomment-68592064&#34;&gt;has&lt;/a&gt; &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000#issuecomment-74924059&#34;&gt;stalled&lt;/a&gt;. Lead developers at WhisperSystems have stated repeatedly that it is not important to them, and the many requests, tests and code contributions from external people did not result in the situation now being any better than it was a year ago.&lt;/p&gt;
&lt;p&gt;Furthermore WhisperSystems has &lt;a href=&#34;https://f-droid.org/forums/topic/flock-secure-contact-and-calendar-syncing-application-for-android/&#34;&gt;repeatedly&lt;/a&gt; &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000#issuecomment-61114605&#34;&gt;demanded&lt;/a&gt; other people not distribute modified and unmodified versions of their software. While I believe that WhisperSystems is sincere about security, they seem to have no problem with the security implications of proprietary software, sharing meta-data with Google (by means of Google Push) and &lt;a href=&#34;https://whispersystems.org/blog/whatsapp/&#34;&gt;now working for WhatsApp&lt;/a&gt; / Facebook. This is all a sad example for a project that does license its code under Free licenses, but that otherwise is between uninterested and hostile towards community involvement and the Free Software landscape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fortunately, not all is lost!&lt;/strong&gt; The other program mentioned already a year ago, &lt;a href=&#34;http://kontalk.org/&#34;&gt;Kontalk&lt;/a&gt;, is doing great. Kontalk is community-based and is transparently financed &lt;a href=&#34;http://kontalk.net&#34;&gt;through donations&lt;/a&gt;. It is based on XMPP, actively develops new extensions and proposals for XMPP and their developers are very friendly towards suggestions and community involvement. The server side is even implemented as extensions on top of an existing XMPP server and you can of course run your own (the server isn&amp;rsquo;t even hardcoded in the app, can be changed via the options). It runs without any proprietary components and is &lt;a href=&#34;https://f-droid.org/repository/browse/?fdfilter=kontalk&amp;amp;fdid=org.kontalk&#34;&gt;available in F-Droid&lt;/a&gt;. There is also a desktop client, although I haven&amp;rsquo;t tried it, yet.&lt;/p&gt;
&lt;p&gt;Some of Kontalk&amp;rsquo;s features are:&lt;/p&gt;
&lt;p&gt;• contact discovery via phone numbers&lt;/p&gt;
&lt;p&gt;• transport and end-to-end encryption&lt;/p&gt;
&lt;p&gt;• working picture and file sharing&lt;/p&gt;
&lt;p&gt;• customizable privacy settings (per-user in future versions)&lt;/p&gt;
&lt;p&gt;It is currently still in beta, but some of the expected features for the 3.0 are:
• group chats&lt;/p&gt;
&lt;p&gt;• perfect forward secrecy&lt;/p&gt;
&lt;p&gt;• sharing of message history between multiple clients&lt;/p&gt;
&lt;p&gt;• federation with regular jabber servers(!!!)&lt;/p&gt;
&lt;p&gt;I use it day to day and have experienced only few issues. You should it give it a try! And maybe you can help with spreading the word, &lt;a href=&#34;https://github.com/kontalk/androidclient/issues&#34;&gt;reporting bugs&lt;/a&gt; or even contributing code?&lt;/p&gt;
&lt;p&gt;edit: see I am not big for Valentine&amp;rsquo;s day, but maybe this counts a slightly delayed #ilovefs for Kontalk ;)&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Encrypting cron&#39;s daily mail</title>
      <link>https://hannes.hauswedell.net/post/2014/11/04/encrypting-crons-daily-mail/</link>
      <pubDate>Tue, 04 Nov 2014 20:51:28 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/11/04/encrypting-crons-daily-mail/</guid>
      <description>&lt;p&gt;Most you have probably set your system aliases to receive root&amp;rsquo;s e-mail, and that of course is a very good idea so you are kept up to date. On the other hand you do send a lot of information about your system through the wire, often package diagnostics with information about locally installed vulnerable software and many other things that might help a person or entity gain access to your computer. Now living in a world, where we know that all unencrypted mail is automatically parsed and possibly filtered and stored that is something you might want to avoid. The natural answer is to encrypt the mail which is what I am going to explain in the following.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Most you have probably set your system aliases to receive root&amp;rsquo;s e-mail, and that of course is a very good idea so you are kept up to date. On the other hand you do send a lot of information about your system through the wire, often package diagnostics with information about locally installed vulnerable software and many other things that might help a person or entity gain access to your computer. Now living in a world, where we know that all unencrypted mail is automatically parsed and possibly filtered and stored that is something you might want to avoid. The natural answer is to encrypt the mail which is what I am going to explain in the following.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;This HowTo pertains to FreeBSD in particular, but I am sure all you GNUsers out there will figure out the necessary changes for their system. A note of warning: I will not be redirecting all of root&amp;rsquo;s mail, I will just be sending out the log files. If you want a more complete solution, you might want to check out &lt;a href=&#34;http://andsk.se/2014/09/17/encrypting-and-forwarding-local-email-to-an-external-email-address/&#34;&gt;this&lt;/a&gt;. For my situation it definitely was overkill, as it involves installing and configuring a new MTA, new user accounts, some other unmaintained software…&lt;/p&gt;
&lt;p&gt;First of all, get GnuPG from your ports or packages (security/gnupg)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pkg install security/gnupg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and add the public key of the receiver to your keyring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gpg --import your_pkey.asc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I am doing this as &lt;code&gt;root&lt;/code&gt;, but you can also setup an extra user for it or even use your regular account. As long as they are in the &lt;code&gt;wheel&lt;/code&gt; group, the permissions should be fine. Double-check that the key was added correctly by printing the list of keys!&lt;/p&gt;
&lt;p&gt;Next, tell your periodic script not to mail the log files to root, but instead save them to disk. Do so by appending the following lines to (or creating) &lt;code&gt;/etc/periodic.conf&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;daily_output=&amp;quot;/var/log/daily.log&amp;quot;
daily_status_security_inline=&amp;quot;YES&amp;quot;
weekly_output=&amp;quot;/var/log/weekly.log&amp;quot;
weekly_status_security_inline=&amp;quot;YES&amp;quot;
monthly_output=&amp;quot;/var/log/monthly.log&amp;quot;
monthly_status_security_inline=&amp;quot;YES&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now paste the following text into &lt;code&gt;/root/bin/gpgcron.sh&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/sh

# verify argc
[ $# -ne 1 ] &amp;amp;&amp;amp; exit 1

# verify argv
[ $1 != &amp;quot;daily&amp;quot; ] &amp;amp;&amp;amp;  [ $1 != &amp;quot;weekly&amp;quot; ] &amp;amp;&amp;amp; [ $1 != &amp;quot;monthly&amp;quot; ] \
 &amp;amp;&amp;amp; exit 1

LOG=&amp;quot;/var/log/${1}.log&amp;quot;
SENDER=&amp;quot;something@valid.com&amp;quot;                # could be == $RECEIVER
RECEIVER=&amp;quot;your@email.address&amp;quot;               # duh.
RECEIVER_KEY_ADDR=&amp;quot;public.keys@address.com&amp;quot; # usually == $RECEIVER
SUBJECT=&amp;quot;${1} run on $(hostname -s)&amp;quot;        # could be something else

cat &amp;quot;$LOG&amp;quot; | /usr/local/bin/gpg -e -a -r &amp;quot;$RECEIVER_KEY_ADDR&amp;quot; \
 --trust-model always --batch | mail -s &amp;quot;$SUBJECT&amp;quot; &amp;quot;$RECEIVER&amp;quot; \
-f &amp;quot;$SENDER&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and don&amp;rsquo;t forget to make the file executable.&lt;/p&gt;
&lt;p&gt;Verify that the script works by placing some random text in &lt;code&gt;/var/log/daily.log&lt;/code&gt; (iff it doesn&amp;rsquo;t exist) and running&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/root/bin/gpgcron.sh daily
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should receive an encrypted mail now that your MUA will decrypt for you. If this works, the last step is adding the script to your &lt;code&gt;/etc/crontab&lt;/code&gt;. I always have them run half an hour after the original script to make sure that it completed (although 5min might be enough):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Perform daily/weekly/monthly maintenance.
1      3      *      *      *     root   periodic daily
30     3      *      *      *     root   /root/bin/gpgcron.sh daily
15     4      *      *      6     root   periodic weekly
45     4      *      *      6     root   /root/bin/gpgcron.sh weekly
30     5      1      *      *     root   periodic monthly
1      6      1      *      *     root   /root/bin/gpgcron.sh monthly
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(only the lines with gpgcron were added!)&lt;/p&gt;
&lt;p&gt;Your next daily mail should come to you encrypted. Happy hacking!&lt;/p&gt;
&lt;p&gt;edit: give the full path to GPG if your crontab overwrites $PATH&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Photo of the Month — 2014-09</title>
      <link>https://hannes.hauswedell.net/post/2014/09/13/photo-of-the-month----2014-09/</link>
      <pubDate>Sat, 13 Sep 2014 15:07:33 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/09/13/photo-of-the-month----2014-09/</guid>
      <description>&lt;p&gt;With a minor delay, here is the photo of the month for September.  It was taken this February in Zermatt, Switzerland.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_final.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_final-1024x557.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;It is a Panorama consisting of eight individual Portrait-orientated shots, stitched together with Hugin. Unfortunately (again) the size limitations of this blog prevent me from giving you a better resolution / quality. The original is 8512x4634 and roughly 200MB big.&lt;/p&gt;
&lt;p&gt;Developing and editing was tricky on this one, and used the opportunity to learn about regional masks in Darktable. Before all editing, the stitch looked like this:&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;With a minor delay, here is the photo of the month for September.  It was taken this February in Zermatt, Switzerland.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_final.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_final-1024x557.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;It is a Panorama consisting of eight individual Portrait-orientated shots, stitched together with Hugin. Unfortunately (again) the size limitations of this blog prevent me from giving you a better resolution / quality. The original is 8512x4634 and roughly 200MB big.&lt;/p&gt;
&lt;p&gt;Developing and editing was tricky on this one, and used the opportunity to learn about regional masks in Darktable. Before all editing, the stitch looked like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_pre.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_pre-1024x557.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After the usual corrections (basecurve, lighting, local contrast), the picture looked like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_before.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/09/IMG_1031-IMG_1038_before-1024x557.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the snow on the Matterhorn itself was a little darker/greyer then the other snow which results in poor contrast with the surroundings, likely a result of different contrast in the original individual pictures. By creating a manually drawn mask around the Matterhorn and applying another brightness increase of about 0,10 EV just to the region the final photo is attained.
I love darktable, have I mentioned that?&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Photo of the Month — 2014-08</title>
      <link>https://hannes.hauswedell.net/post/2014/08/01/photo-of-the-month----2014-08/</link>
      <pubDate>Fri, 01 Aug 2014 04:00:32 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/08/01/photo-of-the-month----2014-08/</guid>
      <description>&lt;p&gt;Originally I had wanted to post a different picture, but sadly the war against the Palestinian people has seen yet another level of escalation, so here&amp;rsquo;s a picture in solidarity with the Palestinians and all other people suffering from war and oppression. I shot it in Ramallah, Westbank, 2011.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_02.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_02-1024x635.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Many things have been said about the situation and I don&amp;rsquo;t want to engage in political debate on this blog, so I will not say more than the solidarity expressed above. If you haven&amp;rsquo;t yet thought about the whole conflict, &lt;a href=&#34;https://www.youtube.com/watch?v=Y58njT2oXfE&#34;&gt;here&amp;rsquo;s a good video&lt;/a&gt; by the &lt;a href=&#34;http://jewishvoiceforpeace.org/&#34;&gt;Jewish Voice for Peace&lt;/a&gt;. If you agree, support groups and actions in your area.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Originally I had wanted to post a different picture, but sadly the war against the Palestinian people has seen yet another level of escalation, so here&amp;rsquo;s a picture in solidarity with the Palestinians and all other people suffering from war and oppression. I shot it in Ramallah, Westbank, 2011.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_02.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_02-1024x635.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Many things have been said about the situation and I don&amp;rsquo;t want to engage in political debate on this blog, so I will not say more than the solidarity expressed above. If you haven&amp;rsquo;t yet thought about the whole conflict, &lt;a href=&#34;https://www.youtube.com/watch?v=Y58njT2oXfE&#34;&gt;here&amp;rsquo;s a good video&lt;/a&gt; by the &lt;a href=&#34;http://jewishvoiceforpeace.org/&#34;&gt;Jewish Voice for Peace&lt;/a&gt;. If you agree, support groups and actions in your area.&lt;/p&gt;
&lt;p&gt;Concerning the technical background of the picture, this is the original shot taken, walking down a street, without stopping to get the angle right and better exposure:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_orig.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0534_orig-1024x682.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It was edited with Darktable using base curve and color curve corrections (weak sigmoidal curves for both), local contrast enhancement, lense correction, cropping and angle correction. The latter is not to my full satisfaction, but the best I could get from the picture, I think.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>[advertising] A nice Indie-Game</title>
      <link>https://hannes.hauswedell.net/post/2014/07/01/advertising-a-nice-indie-game/</link>
      <pubDate>Tue, 01 Jul 2014 18:42:07 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/07/01/advertising-a-nice-indie-game/</guid>
      <description>&lt;p&gt;I have just backed a wonderful looking independent dystopian RPG on Kickstarter! It&amp;rsquo;s called &lt;a href=&#34;https://www.kickstarter.com/projects/1892480689/insomnia-an-rpg-set-in-a-brutal-dieselpunk-univers&#34;&gt;Insomnia&lt;/a&gt;, it looks like it uses the Free Software Engine &lt;a href=&#34;http://www.ogre3d.org/&#34;&gt;Ogre3d&lt;/a&gt; (although its not Free Software itself) and it will feature native Linux support. They still need money, so if you enjoy special video games, go help them out and pre-order your DRM-free copy!&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have just backed a wonderful looking independent dystopian RPG on Kickstarter! It&amp;rsquo;s called &lt;a href=&#34;https://www.kickstarter.com/projects/1892480689/insomnia-an-rpg-set-in-a-brutal-dieselpunk-univers&#34;&gt;Insomnia&lt;/a&gt;, it looks like it uses the Free Software Engine &lt;a href=&#34;http://www.ogre3d.org/&#34;&gt;Ogre3d&lt;/a&gt; (although its not Free Software itself) and it will feature native Linux support. They still need money, so if you enjoy special video games, go help them out and pre-order your DRM-free copy!&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Photo of the Month -- 2014-07</title>
      <link>https://hannes.hauswedell.net/post/2014/06/30/photo-of-the-month-2014-07/</link>
      <pubDate>Mon, 30 Jun 2014 23:04:13 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/06/30/photo-of-the-month-2014-07/</guid>
      <description>&lt;p&gt;I decided to start a photo-of-the-month series; hopefully I will be able to keep it up. Unfortunately the upload limitation on this platform is 1MB per picture so you won&amp;rsquo;t get high-res for now. The picture was taken last fall in Oberengadin, Switzerland, close to &lt;a href=&#34;http://www.salecina.ch/&#34;&gt;Salecina House&lt;/a&gt;. It was a breath-taking sunset and I was very tired from a day of hiking, but thankful for having been there right at that moment!&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I decided to start a photo-of-the-month series; hopefully I will be able to keep it up. Unfortunately the upload limitation on this platform is 1MB per picture so you won&amp;rsquo;t get high-res for now. The picture was taken last fall in Oberengadin, Switzerland, close to &lt;a href=&#34;http://www.salecina.ch/&#34;&gt;Salecina House&lt;/a&gt;. It was a breath-taking sunset and I was very tired from a day of hiking, but thankful for having been there right at that moment!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_final.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_final-1024x678.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;These three bracketed shots were originally taken (+0.66EV, -1.33EV, +2.66EV):&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0526.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0526-300x200.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0527.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0527-300x200.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0528.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/IMG_0528-300x200.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;They were then joined into an HDR with Luminance HDR and afterwards two tonemappings were created, one with the Fattal algorithm and one with Mantiuk06:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_fattal.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_fattal-300x198.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_mantiuk06.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_mantiuk06-300x198.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have presets for the algorithms that I usually use, but I am not 100% sure if they were used in this case. For Fattal I usually use default settings, for Mantiuk06 I usually increase Saturation factor a little (to ~1.0) and sometime decrease contrast factor. These two images where then blended 50% each with ImageMagick into this shot:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_semifinal.jpeg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2014/07/pic_month_2014_07_semifinal-1024x678.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was then finalized with Darktable, only tuning the base curve (influences brightness and contrast) to the shot you see in the beginning. If it seems a little dark to you, that&amp;rsquo;s something I also realized when looking at my pictures on other screens. My color correctness is not very good and I usually have brightness cranked up to 100% because it gives a better picture&amp;hellip; I hope to get some nice 4k screen with better color correctness once they are cheaper.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;All my photos, as usual, dual-licensed under &lt;a href=&#34;http://creativecommons.org/licenses/by-nc-sa/4.0/&#34;&gt;CC-by-nc-sa&lt;/a&gt; and &lt;a href=&#34;http://www.gnu.org/copyleft/gpl.html&#34;&gt;GPLv3&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Secure Texting and why FSFE cares</title>
      <link>https://hannes.hauswedell.net/post/2014/06/25/secure-texting-and-why-fsfe-cares/</link>
      <pubDate>Wed, 25 Jun 2014 14:08:55 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/06/25/secure-texting-and-why-fsfe-cares/</guid>
      <description>&lt;p&gt;Heard of WhatsApp? If you haven&amp;rsquo;t used it before (I e.g. haven&amp;rsquo;t), you can think of it as a free-of-charge messaging app that knows which of your contacts also have the app and automatically routes messages to them over your dataplan instead of SMS, so it&amp;rsquo;s (usually) free of charge.
In the face of NSA and WhatsApp&amp;rsquo;s recent acquisition by Facebook, many of the million WhatsApp users are looking for secure and trustworthy alternatives.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Heard of WhatsApp? If you haven&amp;rsquo;t used it before (I e.g. haven&amp;rsquo;t), you can think of it as a free-of-charge messaging app that knows which of your contacts also have the app and automatically routes messages to them over your dataplan instead of SMS, so it&amp;rsquo;s (usually) free of charge.
In the face of NSA and WhatsApp&amp;rsquo;s recent acquisition by Facebook, many of the million WhatsApp users are looking for secure and trustworthy alternatives.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Because this effects so many people, we at the Free Software Foundation Europe would like to promote an alternative that respects your freedom and privacy. Therefore we decided to do some research and to hold a workshop on WhatsApp alternatives during our German-speaking FSFE team meeting ten days ago.&lt;/p&gt;
&lt;p&gt;While most tech-people including myself really didn&amp;rsquo;t see the point in WhatsApp &amp;ndash; after all there is XMPP &amp;ndash; I now understand better why it&amp;rsquo;s so popular. Easy integration with the operating system and automatic contact discovery seem to be crucial features for the masses. And I do have to admit that both, encryption (OTR) and file transfers, are not yet solved reliably and/or conveniently with popular XMPP clients.&lt;/p&gt;
&lt;p&gt;So we ruled out promoting Xabber or ChatSecure as a good alternatives to WhatsApp and turned our focus to other currently popular apps:&lt;/p&gt;
&lt;p&gt;· &lt;a href=&#34;http://kontalk.org/&#34;&gt;Kontalk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;· &lt;a href=&#34;https://telegram.org/&#34;&gt;Telegram&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;· &lt;a href=&#34;https://whispersystems.org/&#34;&gt;TextSecure&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;· &lt;a href=&#34;https://threema.ch&#34;&gt;Threema&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;· &lt;a href=&#34;https://www.surespot.me/&#34;&gt;Surespot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Of these, Threema seems to be quite popular and is recommended by many people although it is completely proprietary. And Telegram is proprietary on the server side, so we immediately ruled those two out. After all, the interception of communication (man-in-the-middle) is not the only surveillance scenario; the client software needs to be trustworthy as well. And depending on a single Server definitely is also not the path to freedom.&lt;/p&gt;
&lt;p&gt;Surespot is Free Software, but doesn&amp;rsquo;t have automatic contact discovery through phone numbers, so we think it will probably not be competitive in the market segment that is currently dominated by WhatsApp.&lt;/p&gt;
&lt;p&gt;TextSecure and Kontalk are both good apps in our eyes, however, TextSecure has a much larger adoption and its protocol has gone through more reviews. The protool is integrated into CyanogenMod, recommended by leading security experts and the project just recently gained lots of media attention and &lt;a href=&#34;http://www.knightfoundation.org/grants/201499909/&#34;&gt;$400.000 funding&lt;/a&gt;. So we believe if we are to have a chance at migrating people away from WhatsApp than TextSecure is the way to go.&lt;/p&gt;
&lt;p&gt;Unfortunately, TextSecure relies on Google Cloud Messaging for pushing messages to the user. This comes in form of a dependency on a proprietary Google library, part of the &amp;ldquo;Google Play Services&amp;rdquo;. This is unacceptable for many reasons, &lt;a href=&#34;http://arstechnica.com/gadgets/2013/10/googles-iron-grip-on-android-controlling-open-source-by-any-means-necessary/4/&#34;&gt;this page&lt;/a&gt; sums up some of them.&lt;/p&gt;
&lt;p&gt;As a consequence we have starting testing and supporting a version of TextSecure that provides an alternative mechanism for message distribution. We are confident that the issue will be solved sooner or later (as the announced desktop and iOS clients will have to work with something else anyway), but if you have free time, please &lt;a href=&#34;https://github.com/WhisperSystems/TextSecure/issues/1000&#34;&gt;help the effort&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once this is achieved, TextSecure will be a great alternative to WhatsApp, easy to use, free as in freedom and respecting your privacy.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>FreeBSD Port of luminance-hdr updated</title>
      <link>https://hannes.hauswedell.net/post/2014/04/20/freebsd-port-of-luminance-hdr-updated/</link>
      <pubDate>Sun, 20 Apr 2014 00:24:04 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2014/04/20/freebsd-port-of-luminance-hdr-updated/</guid>
      <description>&lt;p&gt;I finally managed to update &lt;a href=&#34;http://www.freshports.org/graphics/luminance/&#34;&gt;graphics/luminance&lt;/a&gt; to 2.3.1. Thanks to lme@freebsd and pawel@freebsd for feedback and commit.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;This is last version that runs with Qt4. As we recently got Qt5 into the ports I will try to update the port soon again. I also have some new ports coming and hope to get around to fixing/updating my other ones. Stay tuned.&lt;/p&gt;
&lt;p&gt;I am making strong use of &lt;a href=&#34;http://www.redports.org&#34;&gt;RedPorts&lt;/a&gt; now. In case you don&amp;rsquo;t know the service, I really recommend it.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I finally managed to update &lt;a href=&#34;http://www.freshports.org/graphics/luminance/&#34;&gt;graphics/luminance&lt;/a&gt; to 2.3.1. Thanks to lme@freebsd and pawel@freebsd for feedback and commit.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;This is last version that runs with Qt4. As we recently got Qt5 into the ports I will try to update the port soon again. I also have some new ports coming and hope to get around to fixing/updating my other ones. Stay tuned.&lt;/p&gt;
&lt;p&gt;I am making strong use of &lt;a href=&#34;http://www.redports.org&#34;&gt;RedPorts&lt;/a&gt; now. In case you don&amp;rsquo;t know the service, I really recommend it.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>A Good way to publish Photos copyleft</title>
      <link>https://hannes.hauswedell.net/post/2013/06/17/a-good-way-to-publish-photos-copyleft/</link>
      <pubDate>Mon, 17 Jun 2013 21:29:36 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/06/17/a-good-way-to-publish-photos-copyleft/</guid>
      <description>&lt;p&gt;I am looking for a good way to publish images as copyleft. The current state of the art in licensing non-software seems to be creative commons, but its copyleft is so weak, that I don&amp;rsquo;t see how it protects the end users&amp;rsquo; freedom. To be more precise, here is how I perceive the legal effects (please correct me if I am wrong):&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;· I publish a digital picture in high resolution, with intermediate files under CC-by-sa
· Magazine XY takes the picture, touches it up and prints it as part of some article in a small size
· user Z sees the picture in the article and doesn&amp;rsquo;t even know the associated rights, unless she looks in the table of figures; and even if she does she can only demand the ready-to-print down-scaled version of the photo, possibly with text covering it, in a non editable format&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I am looking for a good way to publish images as copyleft. The current state of the art in licensing non-software seems to be creative commons, but its copyleft is so weak, that I don&amp;rsquo;t see how it protects the end users&amp;rsquo; freedom. To be more precise, here is how I perceive the legal effects (please correct me if I am wrong):&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;· I publish a digital picture in high resolution, with intermediate files under CC-by-sa
· Magazine XY takes the picture, touches it up and prints it as part of some article in a small size
· user Z sees the picture in the article and doesn&amp;rsquo;t even know the associated rights, unless she looks in the table of figures; and even if she does she can only demand the ready-to-print down-scaled version of the photo, possibly with text covering it, in a non editable format&lt;/p&gt;
&lt;p&gt;→ what&amp;rsquo;s the point? Where is the freedom? What do I gain as an author, if I let commercial magazines use my photos, that in turn, don&amp;rsquo;t share with my fellow citizens?&lt;/p&gt;
&lt;p&gt;Why do we not treat pictures like software? Obviously there is a preferred way of making changes, which might be a format with layer and effects information, or even a non-destrucitve instruction set, like with darktable. This is != to the preferred form of distribution, which is some form of bitmap, so it makes sense to speak of source and non source in my opinion.&lt;/p&gt;
&lt;p&gt;I want to release my photos in a way that forces people to make the source of my photos as well as the source of their changes available to all third parties. So I thought about just stuffing the original image, with intermediate formats and/or instructions in a tarball, add a GPLv3 file and a note, on how I define that the GPL applies. Does that make sense? Or have you come over other, easier ways to achieve a similar effect?&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>A KISS GNU/Linux distro?</title>
      <link>https://hannes.hauswedell.net/post/2013/06/02/a-kiss-gnulinux-distro/</link>
      <pubDate>Sun, 02 Jun 2013 21:31:13 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/06/02/a-kiss-gnulinux-distro/</guid>
      <description>&lt;p&gt;As most of you know, I use FreeBSD as my main Desktop-OS. But I also keep a ArchLinux around that I use (almost exclusively) for gaming. After being disappointed with the way it is headed since a while already, I am now completely fed up with it and am desperately seeking an alternative. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;[rant]ArchLinux claims to keep it simple, but over the last year or two it has accumulated an increasing about of bloatware, especially all the stuff that Lennart Poettering is spewing out. Yes, I am conservative in a lot of techie ways, I am a little biased, as I heard lots of bad things about the software before actually using it, &lt;strong&gt;but&lt;/strong&gt; I did give all the stuff a fair try and it just failed epicly. For PulseAudio I was at least able to replace it with OSSv4, which had proper support on ArchLinux at the time. Not really proper, as some programs stopped producing audio (e.g. Chromium), but at least all the gaming stuff worked.
Then came systemd and it really is worse then everything I heard about it. Upgrading to systemd severely broke my system (I would never have switched, had I not been forced to by Arch), it took me a countless number of hours to make it boot again. But it is still really broken, and not broken, in the &amp;ldquo;I need to find the right config&amp;rdquo;-way, but in the &amp;ldquo;Let&amp;rsquo;s roll the dice&amp;rdquo;-Windows way were everything is unpredictable. First of all one in three boots fails, because systemd messes up the order of the nfs-mounts. OSS now has some weirdness as well, where it sometimes just doesn&amp;rsquo;t work and restarting the computer makes it work again. Shutting down the system actually never works, because on shutting down, it again messes up the order of nfs unmounts and never manages to stop OSS (the things actually &lt;em&gt;spawns jobs&lt;/em&gt; to stop other processes, see the irony?!). But the biggest issues is that after a random amount of minutes systemd or logind or whatever is responsible for logins just crashes, throwing me unto a console, which asks me to enter my root password or press Ctrl-D to continue and where my keyboard doesn&amp;rsquo;t work anymore (apparently that is handled by the same stuff). Wild button-pressing sometimes retuns me back to X, which then seems to just keep on working, with the exception of an ocasional flicker. And of course &amp;ndash; thanks to systemd &amp;ndash; there is nothing logged anywhere in any form that I can read&amp;hellip;
Really, most sysadmins I know warned me about the unreliability of systemd, but I didn&amp;rsquo;t expect it to be that bad. And all of it just to boot one second faster. The GNU/Linux desktop has really fallen far IMHO and I seriously doubt that the whole concept of making everything more integrated and removing modularity and other core unix concepts will help the Free Software movement in the end. Where we win people with some eye-candy and a faster boot, we will alienate more because the software becomes unstable, unreliable and unpredictable. &lt;strong&gt;Rebooting should never be the fix to a problem!&lt;/strong&gt; [/rant]&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;As most of you know, I use FreeBSD as my main Desktop-OS. But I also keep a ArchLinux around that I use (almost exclusively) for gaming. After being disappointed with the way it is headed since a while already, I am now completely fed up with it and am desperately seeking an alternative. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;[rant]ArchLinux claims to keep it simple, but over the last year or two it has accumulated an increasing about of bloatware, especially all the stuff that Lennart Poettering is spewing out. Yes, I am conservative in a lot of techie ways, I am a little biased, as I heard lots of bad things about the software before actually using it, &lt;strong&gt;but&lt;/strong&gt; I did give all the stuff a fair try and it just failed epicly. For PulseAudio I was at least able to replace it with OSSv4, which had proper support on ArchLinux at the time. Not really proper, as some programs stopped producing audio (e.g. Chromium), but at least all the gaming stuff worked.
Then came systemd and it really is worse then everything I heard about it. Upgrading to systemd severely broke my system (I would never have switched, had I not been forced to by Arch), it took me a countless number of hours to make it boot again. But it is still really broken, and not broken, in the &amp;ldquo;I need to find the right config&amp;rdquo;-way, but in the &amp;ldquo;Let&amp;rsquo;s roll the dice&amp;rdquo;-Windows way were everything is unpredictable. First of all one in three boots fails, because systemd messes up the order of the nfs-mounts. OSS now has some weirdness as well, where it sometimes just doesn&amp;rsquo;t work and restarting the computer makes it work again. Shutting down the system actually never works, because on shutting down, it again messes up the order of nfs unmounts and never manages to stop OSS (the things actually &lt;em&gt;spawns jobs&lt;/em&gt; to stop other processes, see the irony?!). But the biggest issues is that after a random amount of minutes systemd or logind or whatever is responsible for logins just crashes, throwing me unto a console, which asks me to enter my root password or press Ctrl-D to continue and where my keyboard doesn&amp;rsquo;t work anymore (apparently that is handled by the same stuff). Wild button-pressing sometimes retuns me back to X, which then seems to just keep on working, with the exception of an ocasional flicker. And of course &amp;ndash; thanks to systemd &amp;ndash; there is nothing logged anywhere in any form that I can read&amp;hellip;
Really, most sysadmins I know warned me about the unreliability of systemd, but I didn&amp;rsquo;t expect it to be that bad. And all of it just to boot one second faster. The GNU/Linux desktop has really fallen far IMHO and I seriously doubt that the whole concept of making everything more integrated and removing modularity and other core unix concepts will help the Free Software movement in the end. Where we win people with some eye-candy and a faster boot, we will alienate more because the software becomes unstable, unreliable and unpredictable. &lt;strong&gt;Rebooting should never be the fix to a problem!&lt;/strong&gt; [/rant]&lt;/p&gt;
&lt;p&gt;Ok, back to topic, do you know a GNU/Linux Distro that adheres to keep-it-simple philosophy, does not use Poettering-Ware and has a somewhat recent Xorg?&lt;/p&gt;
&lt;p&gt;I thought about switching back to Debian, but they seem to be going the Poettering-road as well, as &lt;a href=&#34;http://people.debian.org/~stapelberg/2013/05/27/systemd-survey-results.html&#34;&gt;recent polls&lt;/a&gt; indicate. &lt;a href=&#34;http://www.dracolinux.org/&#34;&gt;Draco GNU/Linux&lt;/a&gt; was my first idea, since they use OSSv4 as default and lots of BSD-stuff, but the Xorg available is quite old, and the projects future is a little unkown&amp;hellip; Slackware was my next idea, but it doesn&amp;rsquo;t even include my default window manager (&amp;ldquo;awesome&amp;rdquo;).
What are your thoughts on this? Any suggestions?&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Autumn Leaves</title>
      <link>https://hannes.hauswedell.net/post/2013/05/25/autumn-leaves/</link>
      <pubDate>Sat, 25 May 2013 14:41:06 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/05/25/autumn-leaves/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/05/autumn_leaves1.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/05/autumn_leaves1-1024x576.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;This is my current wallpaper on my desktop. Not a winter picture, but autumn is ok, too. I took the picture in Brandenburg in fall of 2011. Had I had more time, I might have taken some better ones, because the light was really great. I would really have liked to make one without the »Hochstand« (high seat?). But actually I was quite in a hurry, because there were other people walking in the forest, and the picture was taken just when the person in front of me was concealed by a tree.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/05/autumn_leaves1.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/05/autumn_leaves1-1024x576.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;This is my current wallpaper on my desktop. Not a winter picture, but autumn is ok, too. I took the picture in Brandenburg in fall of 2011. Had I had more time, I might have taken some better ones, because the light was really great. I would really have liked to make one without the »Hochstand« (high seat?). But actually I was quite in a hurry, because there were other people walking in the forest, and the picture was taken just when the person in front of me was concealed by a tree.&lt;/p&gt;
&lt;p&gt;The only editing done on the picture is manual contrast/gamma correction and transformation to black-and-white with a green filter. I might post a tutorial on the digikam workflow involved with making this picture, if you are interested in that, let me know.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Free commenting disabled</title>
      <link>https://hannes.hauswedell.net/post/2013/05/21/free-commenting-disabled/</link>
      <pubDate>Tue, 21 May 2013 16:57:08 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/05/21/free-commenting-disabled/</guid>
      <description>&lt;p&gt;Since I have had more and more spam coming through the filters and annoying me no end, I decided to restrict commenting to registered users (which are only FSFE fellows). I regret to do this, but the ratio of spam to content is 5,245 to 22 (do the math yourself) and I don&amp;rsquo;t want to spend what time I have for the blog with removing spam. I hope to change it in the future again, once a better anti-spam solution has been found.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Since I have had more and more spam coming through the filters and annoying me no end, I decided to restrict commenting to registered users (which are only FSFE fellows). I regret to do this, but the ratio of spam to content is 5,245 to 22 (do the math yourself) and I don&amp;rsquo;t want to spend what time I have for the blog with removing spam. I hope to change it in the future again, once a better anti-spam solution has been found.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Winter in Berlin</title>
      <link>https://hannes.hauswedell.net/post/2013/05/09/winter-in-berlin/</link>
      <pubDate>Thu, 09 May 2013 19:21:46 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/05/09/winter-in-berlin/</guid>
      <description>&lt;p&gt;While spring and early summer are claiming Berlin now and most folks are out enjoying the change, I thought I&amp;rsquo;d post a late winter picture. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/05/pure_hate.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/05/pure_hate-177x300.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;People who know me, know that I am more of a winter person, so I usually have pictures of winter or fall around when the sun shines too bright outside. This picture was taken about two months ago in Pankow, Berlin. It is an HDR rendering made of three individual shots using Luminance HDR and the Mantiuk06 algorithm. Color and Contrast were corrected with digikam.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;While spring and early summer are claiming Berlin now and most folks are out enjoying the change, I thought I&amp;rsquo;d post a late winter picture. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/05/pure_hate.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/05/pure_hate-177x300.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;People who know me, know that I am more of a winter person, so I usually have pictures of winter or fall around when the sun shines too bright outside. This picture was taken about two months ago in Pankow, Berlin. It is an HDR rendering made of three individual shots using Luminance HDR and the Mantiuk06 algorithm. Color and Contrast were corrected with digikam.&lt;/p&gt;
&lt;p&gt;I like the way the different elements in the picture contrast each other&amp;hellip; the classical architecture and the graffiti; the coziness of the christmas-like tree and the cold wind&amp;hellip; it somehow doesn&amp;rsquo;t want to fit together and still does.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>HowTo: Dual-Boot Ubuntu [arm] and CM10.1 on the TF700t</title>
      <link>https://hannes.hauswedell.net/post/2013/04/20/howto-dual-boot-ubuntu-arm-and-cm10-1-on-the-tf700t/</link>
      <pubDate>Sat, 20 Apr 2013 18:48:32 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/04/20/howto-dual-boot-ubuntu-arm-and-cm10-1-on-the-tf700t/</guid>
      <description>&lt;p&gt;I thought I&amp;rsquo;d cover how I got to my current dual-boot on my Transformer. The main difference to other setups is, that my Transformer&amp;rsquo;s data partition is encrypted, which makes some steps more difficult.&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-goal&#34;&gt;The Goal&lt;/h2&gt;
&lt;p&gt;After following these instructions you will have a regular dual-boot on the transformer, like on any notebook or desktop, i.e. when booting the device you get to select which OS to start. The Android experience is in no way diminished, everything works as before. The Ubuntu experience is just like you would have on a notebook, with RAM being the only limiting factor and some rough edges. Wifi and (proprietary) 3d- and video-acceleration work. Unity works, although I use awesome wm, as everywhere else.
The rough edges are missing suspend support, some rendering glitches here and there, no VTs&amp;hellip; for more info, see the &lt;a href=&#34;http://forum.xda-developers.com/showthread.php?t=2014759&#34;&gt;XDA-thread of the port&lt;/a&gt;. This is also the place, in case anything described here doesn&amp;rsquo;t work.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I thought I&amp;rsquo;d cover how I got to my current dual-boot on my Transformer. The main difference to other setups is, that my Transformer&amp;rsquo;s data partition is encrypted, which makes some steps more difficult.&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-goal&#34;&gt;The Goal&lt;/h2&gt;
&lt;p&gt;After following these instructions you will have a regular dual-boot on the transformer, like on any notebook or desktop, i.e. when booting the device you get to select which OS to start. The Android experience is in no way diminished, everything works as before. The Ubuntu experience is just like you would have on a notebook, with RAM being the only limiting factor and some rough edges. Wifi and (proprietary) 3d- and video-acceleration work. Unity works, although I use awesome wm, as everywhere else.
The rough edges are missing suspend support, some rendering glitches here and there, no VTs&amp;hellip; for more info, see the &lt;a href=&#34;http://forum.xda-developers.com/showthread.php?t=2014759&#34;&gt;XDA-thread of the port&lt;/a&gt;. This is also the place, in case anything described here doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;h2 id=&#34;preperation&#34;&gt;Preperation&lt;/h2&gt;
&lt;p&gt;You should know what I am talking about in the following. If not you should probably get to know your device better, before doing this.&lt;/p&gt;
&lt;p&gt;What you need:
· Unlocked Transformer TF700t, with CyanogenMod 10.x, stock Android 4.1.x or CleanRom 4.1.x [yes, CM-Versions of Android 4.2 work, others don&amp;rsquo;t]
·· if the transformer is not yet encrypted, do this now (through Settings-&amp;gt;Security)
· one dedicated µSD-Card with at least 10GB. I would recommend at least class 10, better UHS1 to get decent performance, as Ubuntu will reside on this. You can get the latter for 22€ these days&amp;hellip; [&amp;ldquo;SD1&amp;rdquo;]
· a second µSD-Card with 1GiB free space [&amp;ldquo;SD2&amp;rdquo;]
· a µSD to SD-Converter (you get these free with µSDs usually)&lt;/p&gt;
&lt;p&gt;Get the following files and put them on SD2
· &lt;a href=&#34;http://goo.im/devs/rabits/tf700/linux-install-0.8.3.zip&#34;&gt;Kernel/Bootloader&lt;/a&gt;
· &lt;a href=&#34;http://goo.im/devs/rabits/tf700/linux-install-0.8.3.zip&#34;&gt;Ubuntu RootFS&lt;/a&gt;
· A current &lt;a href=&#34;http://get.cm/?device=tf700t&#34;&gt;CM-Nightly&lt;/a&gt; without the boot-blob inside (just open the zip and remove the boot-blob)&lt;/p&gt;
&lt;h2 id=&#34;action&#34;&gt;Action&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Make backups of your data. Just in case.&lt;/li&gt;
&lt;li&gt;Put SD2 into the µSD-Slot of the transformer and SD1 into the converter and into the SD-Slot of the transformer.&lt;/li&gt;
&lt;li&gt;Reboot the transformer into Recovery and select the &amp;ldquo;linux-install-*.zip&amp;rdquo; as Update&lt;/li&gt;
&lt;li&gt;Follow the on-screen instructions, selecting the Dock-SD-Card (SD1) as target&lt;/li&gt;
&lt;li&gt;After you are done, reboot into Ubuntu, see if it works.&lt;/li&gt;
&lt;li&gt;Reboot again, into CM, see that it doesn&amp;rsquo;t work (loading and loading).&lt;/li&gt;
&lt;li&gt;Reboot into Recovery again, install the prepared CM-update (without the boot-blob, or you will overwrite the loader!)&lt;/li&gt;
&lt;li&gt;Reboot into CM, and see if it works (will still take longer to load on first load)&lt;/li&gt;
&lt;li&gt;Switch the SD-Cards to have the Dock&amp;rsquo;s reader free again.&lt;/li&gt;
&lt;li&gt;be happy&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;open-ends&#34;&gt;Open Ends&lt;/h2&gt;
&lt;p&gt;As mentioned, there are still some issues, the main one for me being, that I have not yet successfully decrypted the android data partition from Ubuntu, which I would like to share as home directory. But altogether I am quite happy to have a proper OS, whenever I need to do serious things :) Here&amp;rsquo;s a screenshot:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/04/screen.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/04/screen-300x187.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Emergency Exit</title>
      <link>https://hannes.hauswedell.net/post/2013/04/11/emergency-exit/</link>
      <pubDate>Thu, 11 Apr 2013 20:49:06 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/04/11/emergency-exit/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/04/emergency_exit.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/04/emergency_exit-300x225.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the picture that is used in the header and which inspired the title of the blog. The picture was taken with my transformer pad through the window of a bus, in Northern Ireland, last fall. I ran it through some filters of the android image program, not much was done on the computer. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;I kind of like the sound of »emergency exit«, and it fits with the picture. You are stuck in a place that isn&amp;rsquo;t  good for you &amp;ndash; but things aren&amp;rsquo;t hopeless, there is a way out. Can be understood as a allegory on our society in general or the Software world or whatever the viewer might see in it.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;a href=&#34;https://hannes.hauswedell.net/post/2013/04/emergency_exit.jpg&#34;&gt;&lt;img src=&#34;https://hannes.hauswedell.net/post/2013/04/emergency_exit-300x225.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the picture that is used in the header and which inspired the title of the blog. The picture was taken with my transformer pad through the window of a bus, in Northern Ireland, last fall. I ran it through some filters of the android image program, not much was done on the computer. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;I kind of like the sound of »emergency exit«, and it fits with the picture. You are stuck in a place that isn&amp;rsquo;t  good for you &amp;ndash; but things aren&amp;rsquo;t hopeless, there is a way out. Can be understood as a allegory on our society in general or the Software world or whatever the viewer might see in it.&lt;/p&gt;
&lt;p&gt;Then again the picture has a more gloomy touch to it, the sky that is inscribed with &amp;ldquo;EMERGENCY EXIT&amp;rdquo; (or at least parts of the words) and symbolising salvation is distant and unreal, the viewer remains in darkness and the surrounding world as well. Both, the vignetting effect applied to the picture and the fact that there is glass between the viewer and the scene create a separateness that hints at the possibility that you might actually not reach the emergency exit in time.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Blog Overhaul</title>
      <link>https://hannes.hauswedell.net/post/2013/03/28/blog-overhaul/</link>
      <pubDate>Thu, 28 Mar 2013 19:30:34 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/03/28/blog-overhaul/</guid>
      <description>&lt;p&gt;Dear readers,&lt;/p&gt;
&lt;p&gt;I have changed the look and feel on my blog a little. It is more streamlined now, and it will contain pictures and notes on photography as well.&lt;!-- more --&gt;
I will mostly write about technical details of the the picture taking and editing process, but the pictures themself might be interesting for not-technical users as well :)&lt;/p&gt;
&lt;p&gt;Hopefully some people who know more about digital photography will find their way to this blog and leave helpful comments, so I can improvemy skills!&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Dear readers,&lt;/p&gt;
&lt;p&gt;I have changed the look and feel on my blog a little. It is more streamlined now, and it will contain pictures and notes on photography as well.&lt;!-- more --&gt;
I will mostly write about technical details of the the picture taking and editing process, but the pictures themself might be interesting for not-technical users as well :)&lt;/p&gt;
&lt;p&gt;Hopefully some people who know more about digital photography will find their way to this blog and leave helpful comments, so I can improvemy skills!&lt;/p&gt;
&lt;p&gt;I will write more on the choice of title and title picture in another post&amp;hellip;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Tracking memory usage Revisited</title>
      <link>https://hannes.hauswedell.net/post/2013/03/08/tracking-memory-usage-revisited/</link>
      <pubDate>Fri, 08 Mar 2013 13:36:45 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2013/03/08/tracking-memory-usage-revisited/</guid>
      <description>&lt;p&gt;I posted an article on tracking memory usage a while ago. Unfortunately it doesn&amp;rsquo;t work for a lot of cases, i.e. when programs are statically linked, or are written in a way where they don&amp;rsquo;t go through the dynamic linker, e.g. programs written in Java. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;I now actually pgrep the child processes of the invoked command and sum up all the processes&amp;rsquo; resident set memory, as found in /proc, repeatedly, preserving the max. The temporal resolution of this of course depends on the interval at which you measure, but especially on commands executing over a long time this seem to be be very close to VmHWM. I currently check every 300ms.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I posted an article on tracking memory usage a while ago. Unfortunately it doesn&amp;rsquo;t work for a lot of cases, i.e. when programs are statically linked, or are written in a way where they don&amp;rsquo;t go through the dynamic linker, e.g. programs written in Java. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;I now actually pgrep the child processes of the invoked command and sum up all the processes&amp;rsquo; resident set memory, as found in /proc, repeatedly, preserving the max. The temporal resolution of this of course depends on the interval at which you measure, but especially on commands executing over a long time this seem to be be very close to VmHWM. I currently check every 300ms.&lt;/p&gt;
&lt;p&gt;You can find the script here &lt;a href=&#34;https://hannes.hauswedell.net/post/2013/03/wrapper_new_sh.txt&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Missing (Free) Android Apps - II - E-Mail</title>
      <link>https://hannes.hauswedell.net/post/2012/12/26/missing-free-android-apps-ii-e-mail/</link>
      <pubDate>Wed, 26 Dec 2012 22:11:46 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/12/26/missing-free-android-apps-ii-e-mail/</guid>
      <description>&lt;p&gt;This is a pretty serious one: there are no proper E-Mail apps for Android tablets. &lt;!-- more --&gt; Yes, I know there is K9, but K9 is only good for phones. Seeing that the K9 people also develop the proprietary (and for-money) Kaitan Mail, which is for tablet and high-resolution phones, I have little hope of seeing K9 being upgraded any time soon to being usable on tablets.&lt;/p&gt;
&lt;p&gt;The only alternative I have seen so far is the stock Jelly-Bean(and after) Mail program, which looks decent on my screen and which I use right now. But it also lacks so many crucial features, that I am not happy with it at all. Just to name a few:&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;This is a pretty serious one: there are no proper E-Mail apps for Android tablets. &lt;!-- more --&gt; Yes, I know there is K9, but K9 is only good for phones. Seeing that the K9 people also develop the proprietary (and for-money) Kaitan Mail, which is for tablet and high-resolution phones, I have little hope of seeing K9 being upgraded any time soon to being usable on tablets.&lt;/p&gt;
&lt;p&gt;The only alternative I have seen so far is the stock Jelly-Bean(and after) Mail program, which looks decent on my screen and which I use right now. But it also lacks so many crucial features, that I am not happy with it at all. Just to name a few:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;editable and top-placable quotations&lt;/li&gt;
&lt;li&gt;identities (you won&amp;rsquo;t believe, I actually set up the same email account multiple times to get different sender-addresses &amp;ndash; and I had to cheat the program to be able to do it&amp;hellip;)&lt;/li&gt;
&lt;li&gt;gnupg&lt;/li&gt;
&lt;li&gt;a white-on-black theme
&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My transformer also shipped with an E-Mail program that was a little better than stock Android (e.g. it had support for showing things in a threaded view), but it was proprietary. Then again it looked very much like a fork of the stock E-Mail app, maybe one should investigate if the proprietary fork was legitimate.&lt;/p&gt;
&lt;p&gt;Anyway, the overall situation is kind of dissapointing. I mean, I really have lowered my expectations of Android, but emailing really is the most basic functionality a &amp;ldquo;mobile device&amp;rdquo; should provide&amp;hellip;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Hacking encryption into Android</title>
      <link>https://hannes.hauswedell.net/post/2012/12/04/hacking-encryption-into-android/</link>
      <pubDate>Tue, 04 Dec 2012 10:52:51 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/12/04/hacking-encryption-into-android/</guid>
      <description>&lt;p&gt;Next weekend we are going to have a small hackathon in Berlin to port/fix/implement disk encryption on various Android devices. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;Android has full disk encryption since 4.0, but it only works when using regular filesystems, e.g. ext. If you have a device that doesn&amp;rsquo;t offer proper block devices, because the hardware doesn&amp;rsquo;t do wear-leveling et cetera, you will probably have YAFFS2 as a file system or something similar that does this on software side. Unfortunately this prevents standard encryption (luks, dm-crypt&amp;hellip;) from working. But there is some outdated code floating around that is supposed to implement this, which we will try to update and integrate with current CyanogenMod. More details on the issue can be found &lt;a href=&#34;http://code.google.com/p/cyanogenmod/issues/detail?id=6685&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;http://code.google.com/p/freexperia/issues/detail?id=658&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://code.google.com/p/cyanogenmod/issues/detail?id=5678&#34;&gt;here&lt;/a&gt; (in parts).&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Next weekend we are going to have a small hackathon in Berlin to port/fix/implement disk encryption on various Android devices. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;Android has full disk encryption since 4.0, but it only works when using regular filesystems, e.g. ext. If you have a device that doesn&amp;rsquo;t offer proper block devices, because the hardware doesn&amp;rsquo;t do wear-leveling et cetera, you will probably have YAFFS2 as a file system or something similar that does this on software side. Unfortunately this prevents standard encryption (luks, dm-crypt&amp;hellip;) from working. But there is some outdated code floating around that is supposed to implement this, which we will try to update and integrate with current CyanogenMod. More details on the issue can be found &lt;a href=&#34;http://code.google.com/p/cyanogenmod/issues/detail?id=6685&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;http://code.google.com/p/freexperia/issues/detail?id=658&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://code.google.com/p/cyanogenmod/issues/detail?id=5678&#34;&gt;here&lt;/a&gt; (in parts).&lt;/p&gt;
&lt;p&gt;Since many phones with hardware keyboards (Xperia Pro, Xperia Mini Pro) are affected, and a lot of hackers have those, maybe you are one of those and want to help! Or maybe you just want to help, which would also really be appreciated. Actually anyone with Android, Java and/or C(++) skills is really welcome!&lt;/p&gt;
&lt;p&gt;The hackathon facts:
· 2012.12.08 11:00 ↔ 2012.12.09 18:00
· graciously hosted by &lt;a href=&#34;http://in-berlin.de&#34;&gt;IN-Berlin e.V.&lt;/a&gt; (&lt;a href=&#34;http://osm.org/go/0MZvv6ctT--&#34;&gt;OpenStreetMap&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;We will have a limited amount of sponsored Club Mate. Other drinks are available for inexpensive purchase. Food will have to find its way to us by delivery. Bring your own phone, bring your own laptop. Hope to see you there!&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Tracking memory usage</title>
      <link>https://hannes.hauswedell.net/post/2012/11/29/tracking-memory-usage/</link>
      <pubDate>Thu, 29 Nov 2012 10:33:30 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/11/29/tracking-memory-usage/</guid>
      <description>&lt;p&gt;&amp;hellip; or why using Linux can be a pain, when you come from the BSD-world. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;On BSD (and MacOSX and probable other UNIXes), if you want to track a program&amp;rsquo;s memory usage, you can simply issue the following in a CSHELL
&lt;code&gt;set time= ( 0 &amp;quot;%D KB avg / %K KB total / %M KB max&amp;quot; )&lt;/code&gt;
or just use &lt;a href=&#34;http://www.freebsd.org/cgi/man.cgi?query=time&#34;&gt;/usr/bin/time&amp;rsquo;s l-parameter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On GNU/Linux on the other hand, rusage as defined by POSIX is not completely implemented, so you cannot do this. A workaround is preloading /lib/libmemusage.so which plugs into your program&amp;rsquo;s memory allocation, keeps track of stuff and prints funky statistics in the end.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&amp;hellip; or why using Linux can be a pain, when you come from the BSD-world. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;On BSD (and MacOSX and probable other UNIXes), if you want to track a program&amp;rsquo;s memory usage, you can simply issue the following in a CSHELL
&lt;code&gt;set time= ( 0 &amp;quot;%D KB avg / %K KB total / %M KB max&amp;quot; )&lt;/code&gt;
or just use &lt;a href=&#34;http://www.freebsd.org/cgi/man.cgi?query=time&#34;&gt;/usr/bin/time&amp;rsquo;s l-parameter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On GNU/Linux on the other hand, rusage as defined by POSIX is not completely implemented, so you cannot do this. A workaround is preloading /lib/libmemusage.so which plugs into your program&amp;rsquo;s memory allocation, keeps track of stuff and prints funky statistics in the end.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s of course better than nothing, but it does create extra overhead, and especially the huge amount of colored (sic!) output that is added to your program&amp;rsquo;s stderr really comes in unhandy if you are working on a benchmarking infrastructure and have program pipelines, where you want stdout and stderr preserved.&lt;/p&gt;
&lt;p&gt;Thankfully I found a &lt;a href=&#34;https://github.com/caseywdunn/agalma/blob/master/src/memusage.c&#34;&gt;different approach&lt;/a&gt;, that also hooks into the program by preloading a library, but not interfering with all the memory allocations. It uses /proc-fs on Linux to also get the maximum resident set memory of a process just before it terminates and prints this.&lt;/p&gt;
&lt;p&gt;I changed it to print to the fourth file descriptor instead of stderr, so the output can be processed seperately. And I made output more easily parsable.&lt;/p&gt;
&lt;p&gt;Then I wrote a wrapper script that you can pass your command call, and it will execute it (preserving stdout and stderr) and print the total run-time and the maximum resident set memory usage of your process (or a sub-process spawned by it) to FD4.&lt;/p&gt;
&lt;p&gt;Here are the files:
· &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/11/mymemusage.c&#34;&gt;mymemusage.c&lt;/a&gt;
· &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/11/wrapper_sh.txt&#34;&gt;wrapper.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I might adapt it to detect, if it is running on *BSD and then do the easy way (right now this will only work on Linux).&lt;/p&gt;
&lt;p&gt;The only situation where this doesn&amp;rsquo;t work, is where your process spawns multiple processes in parallel and you want the maximum memory usage of the group. Then again, I think there is no solution for this that doesn&amp;rsquo;t involve polling /proc regularly for your process groups current memory usage and summing that up&amp;hellip; Luckily parallelization is done mostly by threads nowadays.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Missing (Free) Android Apps - I - Office</title>
      <link>https://hannes.hauswedell.net/post/2012/11/06/missing-free-android-apps-i-office/</link>
      <pubDate>Tue, 06 Nov 2012 15:04:11 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/11/06/missing-free-android-apps-i-office/</guid>
      <description>&lt;p&gt;Ok, so you know that I am using Android, and that I am not too happy with the situation. Ultimately Android is a JAVA-based operating system for phones, so maybe I shouldn&amp;rsquo;t be surprised that trying to replace a FreeBSD (or proper GNU/Linux) laptop with it, will cause some grief. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;But, than Android does have some cool things (which I might elaborate on in another post), and the availibility just forces us as political Free Software users to take the OS seriously and care about its users.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Ok, so you know that I am using Android, and that I am not too happy with the situation. Ultimately Android is a JAVA-based operating system for phones, so maybe I shouldn&amp;rsquo;t be surprised that trying to replace a FreeBSD (or proper GNU/Linux) laptop with it, will cause some grief. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;But, than Android does have some cool things (which I might elaborate on in another post), and the availibility just forces us as political Free Software users to take the OS seriously and care about its users.&lt;/p&gt;
&lt;p&gt;So whats preventing me from be as productive on my device, as I want to be? Since I am not rooted and still running ASUS-Android 4.1.1 I will not talk about platform problems, like keyboard integration, but only apps. Maybe you know of some apps that could help, or see some Apps that you could help out with testing or hacking, who knows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Part 1 of this series is on Word-processing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, I don&amp;rsquo;t digg Office-apps in general, because I prefer tex, but especially in my current ultra-mobile use case, where I often need to take some formatted notes, or hand the Transformer to someone else, I need a working office app. My device came with Polaris Office preinstalled, which is proprietary and only creates docx files which totally rules it out.&lt;/p&gt;
&lt;p&gt;I looked around for a while, but I really did not find a working free replacement. LibreOffice seems to have someone &lt;a href=&#34;http://people.gnome.org/~michael/blog/2012-07-03-libreoffice-android.html&#34;&gt;working on it&lt;/a&gt;, but judging from my previous experiencewith OOo it is probably such a memory hog that I doubt it will work nicely. But maybe I am too skeptic.&lt;/p&gt;
&lt;p&gt;Then there is &lt;a href=&#34;http://blogs.kde.org/2012/06/13/more-calligra-active-android&#34;&gt;Calligra Active&lt;/a&gt;, the mobile port of former KOffice, which would probably be right for my usecase and looks like it is way more portable than LibreOffice, for which they are developing a completely new interface&amp;hellip;
BUT unfortunately the developer builds of Calligra Active crash on my Transformer. Have any of you tried them, yet? Is there some way this development could be spead up? I have the feeling some projects would be a lot further, if they had half the (wo)man-power other big projects have&amp;hellip;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>ASUS Transformer Pad Infinity</title>
      <link>https://hannes.hauswedell.net/post/2012/10/31/asus-transformer-pad-infinity/</link>
      <pubDate>Wed, 31 Oct 2012 11:54:46 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/10/31/asus-transformer-pad-infinity/</guid>
      <description>&lt;p&gt;I have this tablet since two or three months now and I must say, I pleasently surprised with the hardware. People who know me, know that I don&amp;rsquo;t say stuff like that often.&lt;!-- more --&gt;
My taste in hardware just doesn&amp;rsquo;t align with the mainstream, I guess. I want hardware keyboards, I need high resolution displays, I like metal bodies and battery time is important. I don&amp;rsquo;t care about weight, style issues or fancy accesories, like pink fur covers or stuff like that.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have this tablet since two or three months now and I must say, I pleasently surprised with the hardware. People who know me, know that I don&amp;rsquo;t say stuff like that often.&lt;!-- more --&gt;
My taste in hardware just doesn&amp;rsquo;t align with the mainstream, I guess. I want hardware keyboards, I need high resolution displays, I like metal bodies and battery time is important. I don&amp;rsquo;t care about weight, style issues or fancy accesories, like pink fur covers or stuff like that.&lt;/p&gt;
&lt;p&gt;I am not going go into details about the hardware, since you can look that up anywhere and there are lots of reviews available. Let&amp;rsquo;s just say, it has a great screen and long battery life. The only thing they could improve is giving the keyboard backlights, that would help working in the dark!&lt;/p&gt;
&lt;p&gt;The issues I do have with the device are all related to software, I will go into that in a seperate post&amp;hellip;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Long time no see</title>
      <link>https://hannes.hauswedell.net/post/2012/10/31/long-time-no-see/</link>
      <pubDate>Wed, 31 Oct 2012 11:40:32 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/10/31/long-time-no-see/</guid>
      <description>&lt;p&gt;Hi everyone, ok so there haven&amp;rsquo;t been posts in while, because I was incredibly busy, but I do plan on finishing the line of posts concerning my audio setup. I also have a post in line regarding my (possibly irrelevant) thoughts on KDE and I have a few things to say about Android which I have been using a lot lately, so stay tuned.&lt;/p&gt;
&lt;p&gt;The spam issue is getting kind of out-of-hand (over 1000 spam comments VS a handful of real ones), so if your comments don&amp;rsquo;t appear immediately don&amp;rsquo;t get angry. If in doubt of being regarded as a robot, just write me an email and I will whitelist you!&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Hi everyone, ok so there haven&amp;rsquo;t been posts in while, because I was incredibly busy, but I do plan on finishing the line of posts concerning my audio setup. I also have a post in line regarding my (possibly irrelevant) thoughts on KDE and I have a few things to say about Android which I have been using a lot lately, so stay tuned.&lt;/p&gt;
&lt;p&gt;The spam issue is getting kind of out-of-hand (over 1000 spam comments VS a handful of real ones), so if your comments don&amp;rsquo;t appear immediately don&amp;rsquo;t get angry. If in doubt of being regarded as a robot, just write me an email and I will whitelist you!&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>A versatile, open and future-proof audio setup [ part 2 ] Storage</title>
      <link>https://hannes.hauswedell.net/post/2012/06/14/a-versatile-open-and-future-proof-audio-setup-part-2-storage/</link>
      <pubDate>Thu, 14 Jun 2012 13:22:09 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/06/14/a-versatile-open-and-future-proof-audio-setup-part-2-storage/</guid>
      <description>&lt;p&gt;This post covers storage and organisation of the files.&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2 id=&#34;general-layout&#34;&gt;General Layout&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;MUSICDIR
  │
  ├── FILES
  │    ├── _flac
  │    ├── _flac_vorb
  │    ├── _other
  │    └── _vorb
  │
  ├── LINKS
  │    ├── best
  │    ├── smallest
  │    └── vorb
  │
  └── meta
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, the obvious stuff:
· &lt;code&gt;MUSICDIR&lt;/code&gt; is where you keep your music.
· &lt;code&gt;FILES&lt;/code&gt; is a sub directory that contains your actual files.
· &lt;code&gt;LINKS&lt;/code&gt; contains links to files from &lt;code&gt;FILES&lt;/code&gt;, based on certain criteria.
· &lt;code&gt;meta&lt;/code&gt; contains maintenance scripts and other stuff that is not music.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;This post covers storage and organisation of the files.&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2 id=&#34;general-layout&#34;&gt;General Layout&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;MUSICDIR
  │
  ├── FILES
  │    ├── _flac
  │    ├── _flac_vorb
  │    ├── _other
  │    └── _vorb
  │
  ├── LINKS
  │    ├── best
  │    ├── smallest
  │    └── vorb
  │
  └── meta
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, the obvious stuff:
· &lt;code&gt;MUSICDIR&lt;/code&gt; is where you keep your music.
· &lt;code&gt;FILES&lt;/code&gt; is a sub directory that contains your actual files.
· &lt;code&gt;LINKS&lt;/code&gt; contains links to files from &lt;code&gt;FILES&lt;/code&gt;, based on certain criteria.
· &lt;code&gt;meta&lt;/code&gt; contains maintenance scripts and other stuff that is not music.&lt;/p&gt;
&lt;h2 id=&#34;files&#34;&gt;Files&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;FILES&lt;/code&gt; contains four subdirectories. &lt;code&gt;_flac&lt;/code&gt; contains my music in the &lt;a href=&#34;http://flac.sourceforge.net&#34;&gt;FLAC-format&lt;/a&gt;. FLAC is a lossless audio codec, for more information click on the link. To be honest, I am not sure if I can hear the difference between FLAC and &lt;a href=&#34;http://www.vorbis.com&#34;&gt;Ogg Vorbis&lt;/a&gt; at high bitrates, but that&amp;rsquo;s not the point. I don&amp;rsquo;t want to worry about quality and I want to be able to convert formats, if a better one appears, which is only feasible for lossless audio (you should never convert between lossy formats as it just increases lossiness).&lt;/p&gt;
&lt;p&gt;Now while I am slowly reripping my music collection to FLAC, there is also some music where I only have the lossy versions on my hard-disk (e.g. broken or lost CDs…). These files go to &lt;code&gt;_vorb&lt;/code&gt; if they are in Ogg Vorbis, or to &lt;code&gt;_other&lt;/code&gt; if they are MP3, MPC or some other weird format. The &lt;code&gt;_flac_vorb&lt;/code&gt; folder is special, it contains all the music I have as FLAC, but converted to low quality Ogg Vorbis (Quality 2.5). This is, because in some situations FLAC is not handy, e.g. when your bandwidth is limited or your storage is limited&amp;hellip; the details will be explained later. A Script that converts your FLAC to Vorbis while preserving the file system hierarchy and Tags is available &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/06/update_flac_vorb.sh_.txt&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note that it is important that beneath the codec-directories you have the same hierarchy, i.e. if you organize your music by genre, you should do so for all codecs. Any other way of sorting is also good, but don&amp;rsquo;t have all your files just flying around on the topmost level. Actually the scripts do not allow any files on the topmost level, just directories. In case you were wondering, this is how I currently file my music beneath the aforementioned levels, although it is completely unimportant for the setup:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.../genre/artist/year - albumtitle/artist - tracknumber - tracktitle.ext
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;p&gt;The folders in &lt;code&gt;LINKS&lt;/code&gt; are based on certain criteria. Since there is some redundancy in my files (songs both available as FLAC and Vorbis), I want to remove that. Also when actually playing music, of course I don&amp;rsquo;t want to worry about which format it is in, I want two CDs by the same artist to appear in the same folder, even if they are in different formats. So I wrote a little &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/06/update_LINKS.sh_.txt&#34;&gt;script&lt;/a&gt; that &amp;ldquo;joins&amp;rdquo; the folders from &lt;code&gt;FILES&lt;/code&gt; by creating lots of symlinks in &lt;code&gt;LINKS&lt;/code&gt;. It currently creates three &amp;ldquo;joins&amp;rdquo;:
· &lt;code&gt;best&lt;/code&gt; : contains the highest quality version of a song. This folder is the folder you want to index with computers on the local network (or just your desktop)
· &lt;code&gt;smallest&lt;/code&gt; : contains the smallest file of each song. This folder is the folder you want to index from computers that access the music from remote locations. It is also the directory you will want to sync to your portable audio player, your phone, whatever&amp;hellip;
· &lt;code&gt;vorbis&lt;/code&gt; : contains just the vorbis files (original and flac-converted ones). I am not using this yet, but I want to serve this with OwnCloud, so I can listen to the music with html5 from other places. It might also be useful, if you want to stream through icecast or so.&lt;/p&gt;
&lt;p&gt;Note that these are really many links if your music collection is big. I don&amp;rsquo;t know if that&amp;rsquo;s an issue on certain filesystems (I use ZFS, so I know it doesn&amp;rsquo;t matter).&lt;/p&gt;
&lt;h2 id=&#34;serving-the-files&#34;&gt;Serving the files&lt;/h2&gt;
&lt;p&gt;Ok, now you have the music organized. You can think about how to serve it. I have it on a server, and can access it from different locations. I think that&amp;rsquo;s a good idea, but you can do all the stuff explained here on your regular computer as well.&lt;/p&gt;
&lt;h2 id=&#34;known-issues&#34;&gt;Known Issues&lt;/h2&gt;
&lt;p&gt;· The scripts currently don&amp;rsquo;t do any cleanup, which is not optimal. I will fix that, as soon as I get time. When it&amp;rsquo;s fixed, it should be feasible to have the scripts run by cron.
· When you change something in the hierarchy (e.g. split a genre folder up into two, want to delete an artist,…) you have to do this in all the folders in &lt;code&gt;FILES&lt;/code&gt; which may be annoying (&lt;code&gt;LINKS&lt;/code&gt; will be updated automatically, though).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;stay tuned for the next post about portable audio!&lt;/em&gt;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>A versatile, open and future-proof audio setup [ part 1 ] Overview</title>
      <link>https://hannes.hauswedell.net/post/2012/06/06/a-versatile-open-and-future-proof-audio-setup-part-1-overview/</link>
      <pubDate>Wed, 06 Jun 2012 12:55:41 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/06/06/a-versatile-open-and-future-proof-audio-setup-part-1-overview/</guid>
      <description>&lt;p&gt;Here are the general components of the setup, as well as planned components. Fear not, most of everything that follows does not imply this setup and is generally usable. You don&amp;rsquo;t even need a server for the most part. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server&lt;/strong&gt;
· acts as storage for local and remote access
· handles maintenance jobs
· plays music directly, remote controlled [planned]
· runs FreeBSD and ZFS
· more details in separate article&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Here are the general components of the setup, as well as planned components. Fear not, most of everything that follows does not imply this setup and is generally usable. You don&amp;rsquo;t even need a server for the most part. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server&lt;/strong&gt;
· acts as storage for local and remote access
· handles maintenance jobs
· plays music directly, remote controlled [planned]
· runs FreeBSD and ZFS
· more details in separate article&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regular Clients&lt;/strong&gt;
· some Laptops and Desktops
· running GNU/Linux and FreeBSD
· access files through NFS (+OpenVPN)
· arbitrary player software&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Portable Audio Player&lt;/strong&gt;
· Sandisk SansaClip+
· multiple µSD-Cards
· more details (esp. on syncing) in separate article&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Android Clients [planned]&lt;/strong&gt;
· one or multiple Android clients
· access files through NFS or WebDAV
· or µSD-Cards (see above)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Universal Access [planned]&lt;/strong&gt;
· based on OwnCloud&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>A versatile, open and future-proof audio setup [ part 0 ]</title>
      <link>https://hannes.hauswedell.net/post/2012/06/04/a-versatile-open-and-future-proof-audio-setup-part-0/</link>
      <pubDate>Mon, 04 Jun 2012 11:13:23 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/06/04/a-versatile-open-and-future-proof-audio-setup-part-0/</guid>
      <description>&lt;p&gt;Since it might be useful to some other people I want to document my audio setup in a few blog posts. By audio setup I mean the storage, organization and playback of my music collection. It covers the following: file systems, file formats, network access, choice of portable hardware, my own maintenance software (conversion, synchronization etc) and briefly other software (operating systems, playback software). &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;The overall features of the system, as I will describe later:&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Since it might be useful to some other people I want to document my audio setup in a few blog posts. By audio setup I mean the storage, organization and playback of my music collection. It covers the following: file systems, file formats, network access, choice of portable hardware, my own maintenance software (conversion, synchronization etc) and briefly other software (operating systems, playback software). &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;The overall features of the system, as I will describe later:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fully compatible and based on Free Software codecs&lt;/li&gt;
&lt;li&gt;uses Free Software in all parts, except playback on portable&lt;/li&gt;
&lt;li&gt;inexpensive hardware, especially the portable part&lt;/li&gt;
&lt;li&gt;scalable to very large music collections, expandable to growing music collections&lt;/li&gt;
&lt;li&gt;easily adaptable to different or new situations (e.g. individual parts of the systems may be used independently)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The system works, but is not completely finished, i.e. some maintenance operations have yet to be added or tuned for performance or convenience, but I think it will be useful nevertheless. If you are skilled in bourne syntax, you might spot some rough edges or have ideas for the TODOs. If so, please let me know.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>PDFReaders 2.0 - Your help is needed!</title>
      <link>https://hannes.hauswedell.net/post/2012/05/21/pdfreaders-2-0-your-help-is-needed/</link>
      <pubDate>Mon, 21 May 2012 13:41:13 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/05/21/pdfreaders-2-0-your-help-is-needed/</guid>
      <description>&lt;p&gt;Hi everyone,&lt;/p&gt;
&lt;p&gt;we are currently preparing a major update to PDFReaders.org, adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a more appealing and cleaner &amp;ldquo;home&amp;rdquo;-page, with &lt;strong&gt;one recommendation&lt;/strong&gt; for the auto-detected platform&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free pdf reader recommendations for mobile platforms&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free pdf browser plugin recommmendations&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BUT, we need some help with gathering/verifying information, deciding what to recommend&amp;hellip;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Please have a look at the current &lt;a href=&#34;https://wiki.fsfe.org/PDFreaders/todo2012/Overview-Page&#34;&gt;Reader-Overview&lt;/a&gt; and the TODOs there.&lt;/p&gt;
&lt;p&gt;Please tell us&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;if you know any other Free pdf readers that we haven&amp;rsquo;t listed, yet (for any plaform, but especially OSX and iOS)&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Hi everyone,&lt;/p&gt;
&lt;p&gt;we are currently preparing a major update to PDFReaders.org, adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a more appealing and cleaner &amp;ldquo;home&amp;rdquo;-page, with &lt;strong&gt;one recommendation&lt;/strong&gt; for the auto-detected platform&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free pdf reader recommendations for mobile platforms&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free pdf browser plugin recommmendations&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BUT, we need some help with gathering/verifying information, deciding what to recommend&amp;hellip;&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Please have a look at the current &lt;a href=&#34;https://wiki.fsfe.org/PDFreaders/todo2012/Overview-Page&#34;&gt;Reader-Overview&lt;/a&gt; and the TODOs there.&lt;/p&gt;
&lt;p&gt;Please tell us&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;if you know any other Free pdf readers that we haven&amp;rsquo;t listed, yet (for any plaform, but especially OSX and iOS)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;which Android reader you would recommend&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;any other ideas you might have!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can reach us via &lt;a href=&#34;mailto:feedback(@)pdfreaders(.)org&#34;&gt;mail&lt;/a&gt; or comment directly in the &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/05/21/pdfreaders-2-0-your-help-is-needed/&#34;&gt;blog&lt;/a&gt;. If you have an account at the &lt;a href=&#34;https://wiki.fsfe.org/&#34;&gt;fellowship-wiki&lt;/a&gt; you can commit changes to the overview directly.&lt;/p&gt;
&lt;p&gt;Thanks for your help!&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Improving E-Mail Privacy</title>
      <link>https://hannes.hauswedell.net/post/2012/05/12/improving-e-mail-privacy/</link>
      <pubDate>Sat, 12 May 2012 19:07:37 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/05/12/improving-e-mail-privacy/</guid>
      <description>&lt;p&gt;I have recently decided to use PGP / GnuPG to sign and encrypt emails, and I also recently switched from KMail (after using it for ~10 years) to Thunderbird [the why of the latter is a longer story I might tell some other time].&lt;/p&gt;
&lt;p&gt;So, after not caring about email privacy for pretty long, I now got it all setup, although the setup on my laptop produces faulty inline PGP once in a while, where it doesn&amp;rsquo;t even recognize signed content itself&amp;hellip;&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have recently decided to use PGP / GnuPG to sign and encrypt emails, and I also recently switched from KMail (after using it for ~10 years) to Thunderbird [the why of the latter is a longer story I might tell some other time].&lt;/p&gt;
&lt;p&gt;So, after not caring about email privacy for pretty long, I now got it all setup, although the setup on my laptop produces faulty inline PGP once in a while, where it doesn&amp;rsquo;t even recognize signed content itself&amp;hellip;&lt;/p&gt;
&lt;p&gt;Anyway, what I want to discuss today is the email header. As you all know, it contains all sorts of information, even your IP-Address &amp;ndash; if you have a nasty provider. I kind of had the intuition that Thunderbird and Enigmail would reduce this info, or at least not add to it, but apparently that is not true.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;Stuff you normally transmit with every (signed) E-Mail:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1) Thunderbird user agent&lt;/strong&gt; I was kind of confused by it, as I thought this information should go into the &amp;ldquo;X-Mailer&amp;rdquo; info, but obviously Mozilla has their own way, as you can see below. And it contains quite a bit of information, beside the mail client: My operating system, my windowing system, my cpu-architecture, even the Gecko-revision (what has that got to do with anything?).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:10.0.3) Gecko/20120407 Thunderbird/10.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2) Enigmail user agent&lt;/strong&gt; Enigmail has its own client field, where it tells the world that it is installed on my system, and what version. Since Enigmail is specific to Thunderbird, this also tells people I am using Thunderbird (even if we get around 1) ).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; X-Enigmail-Version: 1.4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3) GnuPG Identifier&lt;/strong&gt; Then, inside the PGP-Signature, GnuPG informs everyone of its version and my operating system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; Version: GnuPG v2.0.19 (FreeBSD)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4) Enigmail advertising&lt;/strong&gt; In case people hadn&amp;rsquo;t noticed from 2) or the combination of 1) and 3), here comes Enigmail again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you might ask yourself why I worry about this information. Well first of all, it fulfills no real purpose. The receiving party doesn&amp;rsquo;t act on this information and it doesn&amp;rsquo;t need this information, as E-Mail is pretty standardized. &lt;strong&gt;This alone should be reason enough not to transmit the information.&lt;/strong&gt; But here are some real scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If an attacker knows the applications you are using and even their versions, it might make it easier for him to send you prepared code that acts on certain known vulnerabilities of these application versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you use more than one computer, people can identify which computer you wrote your E-Mail from based on different CPU-architectures, operating systems or application versions. This is less of an issue than the IP, but can still be used against you in different situations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn&amp;rsquo;t find any place that describes how to easily fix this, so I gathered the solutions from different web-sites and man-pages&amp;hellip; to fix all of the above, go to &lt;em&gt;Edit-&amp;gt;Preferences-&amp;gt;Advanced-&amp;gt;General-&amp;gt;Config Editor&lt;/em&gt; and set these variables (they fix the above problems in the exact order):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;general.useragent.override=&amp;quot;&amp;quot;
extensions.enigmail.addHeaders=false
extensions.enigmail.agentAdditionalParam=&amp;quot;--no-emit-version&amp;quot;
extensions.enigmail.useDefaultComment=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first two variables have to be created(string and bool), as they are non-default and there is no gui-way to set them. And yes the value for the last one is &amp;rsquo;true&#39;.&lt;/p&gt;
&lt;p&gt;Hope this is usefull to some of you and saves you some googling or scroogling ;).&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>my awesome (wm) config</title>
      <link>https://hannes.hauswedell.net/post/2012/05/05/my-awesome-wm-config/</link>
      <pubDate>Sat, 05 May 2012 12:57:40 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/05/05/my-awesome-wm-config/</guid>
      <description>&lt;p&gt;Since quite a few people have been asking me for my awesome config, I thought I&amp;rsquo;d upload it.&lt;/p&gt;
&lt;p&gt;For those of you who don&amp;rsquo;t know awesome, &lt;a href=&#34;http://awesome.naquadah.org/&#34;&gt;check it out&lt;/a&gt;, it&amp;rsquo;s awesome! SCNR &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;Main differences from the default are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;remove all panels and stuff, because they are ugly&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;load xfce4-panel instead, because it&amp;rsquo;s light, but provides stuff like mpd-controls &amp;amp;c&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;create 12 tags (virtual desktops)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bind certain type of applications to certain desktops&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Since quite a few people have been asking me for my awesome config, I thought I&amp;rsquo;d upload it.&lt;/p&gt;
&lt;p&gt;For those of you who don&amp;rsquo;t know awesome, &lt;a href=&#34;http://awesome.naquadah.org/&#34;&gt;check it out&lt;/a&gt;, it&amp;rsquo;s awesome! SCNR &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;Main differences from the default are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;remove all panels and stuff, because they are ugly&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;load xfce4-panel instead, because it&amp;rsquo;s light, but provides stuff like mpd-controls &amp;amp;c&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;create 12 tags (virtual desktops)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bind certain type of applications to certain desktops&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;map Meta to ALt instead of Winkey, because my main kbd doesn&amp;rsquo;t have a winkey&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;map the tags to F* instead of the number keys, so I get tags with Alt+F* (original unix style)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use cairo-compmgr where available (unfortunately not on FreeBSD) and pre-start some other stuff (e.g. launchy for running things)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thats basically it. I have thought about using shifty for dynamic tagging, but haven&amp;rsquo;t gotten around to trying it, yet.&lt;/p&gt;
&lt;p&gt;Here it is: &lt;a href=&#34;https://hannes.hauswedell.net/post/2012/05/rc.lua_.txt&#34;&gt;rc.lua&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(in case you consider that bit of code as (c)-able I hereby release into CC0 / public domain)&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>An inside view on the Great Chinese Firewall</title>
      <link>https://hannes.hauswedell.net/post/2012/04/20/an-inside-view-on-the-great-chinese-firewall/</link>
      <pubDate>Fri, 20 Apr 2012 14:08:33 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/04/20/an-inside-view-on-the-great-chinese-firewall/</guid>
      <description>&lt;p&gt;As I am currently located in China, I thought I&amp;rsquo;d give all of you some technical infos on the current censorship techniques employed here. My experience differs a little from what &lt;a href=&#34;http://en.wikipedia.org/wiki/Internet_censorship_in_the_People%27s_Republic_of_China#Current_methods&#34;&gt;Wikipedia tells&lt;/a&gt; us. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What you see as a user:&lt;/strong&gt;
youtube.com, facebook.com, twitter.com are all not reachable. Google.com is on and off, usually redirects to google.com.hk (which is still the less censored version of google.cn). Google.de is however available. A nice site that lets you test which web-sites are unavailable is &lt;a href=&#34;http://www.greatfirewallofchina.org/&#34;&gt;http://www.greatfirewallofchina.org&lt;/a&gt;, from my experience it is reliable.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;As I am currently located in China, I thought I&amp;rsquo;d give all of you some technical infos on the current censorship techniques employed here. My experience differs a little from what &lt;a href=&#34;http://en.wikipedia.org/wiki/Internet_censorship_in_the_People%27s_Republic_of_China#Current_methods&#34;&gt;Wikipedia tells&lt;/a&gt; us. &lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What you see as a user:&lt;/strong&gt;
youtube.com, facebook.com, twitter.com are all not reachable. Google.com is on and off, usually redirects to google.com.hk (which is still the less censored version of google.cn). Google.de is however available. A nice site that lets you test which web-sites are unavailable is &lt;a href=&#34;http://www.greatfirewallofchina.org/&#34;&gt;http://www.greatfirewallofchina.org&lt;/a&gt;, from my experience it is reliable.&lt;/p&gt;
&lt;p&gt;Now funny enough all things political that I checked are available, be it critical (western) newspaper sites, blogs et cetera. Even Wikipedia is available. All sites that I checked, especially Wikipedia and Google.de do offer SSL (valid!) and so looking at &lt;a href=&#34;https://en.wikipedia.org/wiki/Tiananmen_Square_protests_of_1989&#34;&gt;https://en.wikipedia.org/wiki/Tiananmen_Square_protests_of_1989&lt;/a&gt; is possible (note that some sources claim that the western propaganda on this event is at least &lt;a href=&#34;http://www.telegraph.co.uk/news/worldnews/wikileaks/8555142/Wikileaks-no-bloodshed-inside-Tiananmen-Square-cables-claim.html&#34;&gt;partly wrong&lt;/a&gt;, so don&amp;rsquo;t take this as defending the WP-article). Note also that I did not try without SSL, because I was told, that that would be detected and can get your internet service cut.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Whats going on under the hood:&lt;/strong&gt;
Like I said, I did not experiment too much with entering sensitive terms in search engines, but regarding the web-site blocking I can say that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the DNS-Servers here resolve certain adresses to other IPs (obvious one). Strangely enough first neblock-owner checks reveal these IPs to be outside of China, even EU&amp;hellip; will investigate this further.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dns-requests to foreign (probably non-whitelisted) DNS-servers are either all rerouted (based on port or deep packet inspection), or filtered and manipulated in case the requested host matches a blacklist or an expression (based on deep packet inspection). So just setting a different DNS-Server is no good, even when they are not widely known (contrary to what WP says)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;traffic to the real IPs of the sites is blocked, so if you happen to know where twitter.com is, it still doesn&amp;rsquo;t get you there. This is probably achieved by resetting the TCP connection. Note that this happens early on, a traceroute to twiiter only goes one hop before dissappearing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I currently go online trough SSH port forwarding, tunneling and proxies, will update that to proper VPN, as soon as I get the time. Anything encrypted really works, no issues with ssh and https on regular ports. OpenVPN also works&amp;hellip;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>FSFE Affiliate Userscript v0.3 released.</title>
      <link>https://hannes.hauswedell.net/post/2012/04/05/fsfe-affiliate-userscript-v0-3-released/</link>
      <pubDate>Thu, 05 Apr 2012 09:08:38 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/04/05/fsfe-affiliate-userscript-v0-3-released/</guid>
      <description>&lt;p&gt;Thanks to Hugo, for finding a bug in the version 0.2 with non-[.de|com] domains. Should be fixed now. Get the new version on my blog, as usual.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Thanks to Hugo, for finding a bug in the version 0.2 with non-[.de|com] domains. Should be fixed now. Get the new version on my blog, as usual.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>FSFE Affiliate Userscript v0.2 released.</title>
      <link>https://hannes.hauswedell.net/post/2012/03/29/fsfe-affiliate-userscript-v0-2-released/</link>
      <pubDate>Thu, 29 Mar 2012 19:17:30 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/03/29/fsfe-affiliate-userscript-v0-2-released/</guid>
      <description>&lt;p&gt;I decided to rewrite the script.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s new:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;only one 5-line function from another script is used, the rest is original code under CC0 / Public Domain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Amazon code is cleaner, should produce less false-positive replacements (in theory ;) )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for Libri.de / Bookzilla.de is added. Any and all links to Libri are replaced with links to Bookzilla. Actions on Libri.de itself are also &amp;ldquo;transferred&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded>&lt;p&gt;I decided to rewrite the script.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s new:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;only one 5-line function from another script is used, the rest is original code under CC0 / Public Domain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Amazon code is cleaner, should produce less false-positive replacements (in theory ;) )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for Libri.de / Bookzilla.de is added. Any and all links to Libri are replaced with links to Bookzilla. Actions on Libri.de itself are also &amp;ldquo;transferred&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
    </item>
    
    <item>
      <title>FSFE-Affiliate Userscript now available</title>
      <link>https://hannes.hauswedell.net/post/2012/03/29/fsfe-affiliate-userscript-now-available/</link>
      <pubDate>Thu, 29 Mar 2012 11:56:26 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/03/29/fsfe-affiliate-userscript-now-available/</guid>
      <description>&lt;p&gt;I have uploaded a userscript that you can use to support FSFE when buying at Amazon. Automatic support for redirecting from libri.de to bookzilla.de is planned, aswell as any other affiliate programs FSFE might take part in.&lt;/p&gt;
&lt;p&gt;In contrast to the AffiliateFox-Plugin, the userscript is compatible with non-Mozilla browsers. But it works on those, too, in case you prefer to install something where you can see the source, before installing it ;)&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have uploaded a userscript that you can use to support FSFE when buying at Amazon. Automatic support for redirecting from libri.de to bookzilla.de is planned, aswell as any other affiliate programs FSFE might take part in.&lt;/p&gt;
&lt;p&gt;In contrast to the AffiliateFox-Plugin, the userscript is compatible with non-Mozilla browsers. But it works on those, too, in case you prefer to install something where you can see the source, before installing it ;)&lt;/p&gt;
&lt;p&gt;For more information see &lt;a href=&#34;post/userscripts/&#34;&gt;post/userscripts/&lt;/a&gt;&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Blog and Micro-Blogs now working!</title>
      <link>https://hannes.hauswedell.net/post/2012/03/28/blog-and-micro-blogs-now-working/</link>
      <pubDate>Wed, 28 Mar 2012 15:11:06 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/03/28/blog-and-micro-blogs-now-working/</guid>
      <description>&lt;p&gt;After the last test post, I am now convinced that the blog and the micro-blogs work. You can visit this site regularly or follow me on &lt;a href=&#34;http://identi.ca/h2&#34;&gt;identi.ca&lt;/a&gt; or &lt;a href=&#34;http://twitter.com/__h2__&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;After the last test post, I am now convinced that the blog and the micro-blogs work. You can visit this site regularly or follow me on &lt;a href=&#34;http://identi.ca/h2&#34;&gt;identi.ca&lt;/a&gt; or &lt;a href=&#34;http://twitter.com/__h2__&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
</content:encoded>
    </item>
    
    <item>
      <title>Should we call Free Software releases &#34;products&#34;?</title>
      <link>https://hannes.hauswedell.net/post/2012/03/28/should-we-call-free-software-releases-products/</link>
      <pubDate>Wed, 28 Mar 2012 14:46:28 +0000</pubDate>
      
      <guid>https://hannes.hauswedell.net/post/2012/03/28/should-we-call-free-software-releases-products/</guid>
      <description>&lt;p&gt;I have posted a lengthy answer on Bernhard&amp;rsquo;s blog[1], why I don&amp;rsquo;t think &amp;ldquo;product&amp;rdquo; is a suitable term. What are your thoughts on this? Reply here or on Bernhards&amp;rsquo; blog!&lt;/p&gt;
&lt;p&gt;[1] &lt;a href=&#34;http://blogs.fsfe.org/bernhard/2012/03/lets-end-all-free-software-projects-quickly/&#34;&gt;http://blogs.fsfe.org/bernhard/2012/03/lets-end-all-free-software-projects-quickly/&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;I have posted a lengthy answer on Bernhard&amp;rsquo;s blog[1], why I don&amp;rsquo;t think &amp;ldquo;product&amp;rdquo; is a suitable term. What are your thoughts on this? Reply here or on Bernhards&amp;rsquo; blog!&lt;/p&gt;
&lt;p&gt;[1] &lt;a href=&#34;http://blogs.fsfe.org/bernhard/2012/03/lets-end-all-free-software-projects-quickly/&#34;&gt;http://blogs.fsfe.org/bernhard/2012/03/lets-end-all-free-software-projects-quickly/&lt;/a&gt;&lt;/p&gt;
</content:encoded>
    </item>
    
  </channel>
</rss>
