<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Malvin Gattinger - Posts</title>
    <link href="https://malv.in/feed.xml" rel="self" />
    <link href="https://malv.in" />
    <id>https://malv.in/feed.xml</id>
    <author>
        <name>Malvin Gattinger</name>
        
        <email>blog@malv.in</email>
        
    </author>
    <updated>2024-12-09T00:00:00Z</updated>
    <entry>
    <title>Updating Dependencies in a Lean (+ Mathlib) Project</title>
    <link href="https://malv.in/posts/2024-12-09-howto-update-lean-dependencies.html" />
    <id>https://malv.in/posts/2024-12-09-howto-update-lean-dependencies.html</id>
    <published>2024-12-09T00:00:00Z</published>
    <updated>2024-12-09T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Whenever a new <a href="https://lean-lang.org/">Lean</a> version comes
out — or whenever I want to use something only recently added
to <a href="https://leanprover-community.github.io/">mathlib</a> — then
I need to update the dependencies of my project.</p>
<p>This is something I have to do every few weeks and each time it was basically trial and error.
But today also someone else asked me how this is done, so this time I documented it.</p>
<p>Concretely, I wrote this note here while upgrading my
project <a href="https://github.com/m4lvin/lean4-pdl">lean4-pdl</a>
from Lean 4.13 to 4.14, released on 2 December 2024.</p>
<p>Disclaimer: I am not an expert on any of this stuff, and this is probably not the best advice you can find.
Please contact me if something mentioned here is wrong or not recommended, I’ll be happy to update the post!</p>
<h2 id="background">Background</h2>
<h3 id="where-are-dependencies-defined">Where are dependencies defined?</h3>
<p>Dependencies of a Lean project are managed by three files:</p>
<ul>
<li><p><code>lean-toolchain</code> is very short and specifies which version of Lean itself we want.
In my case, before the update it consisted of:</p>
<pre><code>leanprover/lean4:v4.13.0</code></pre></li>
<li><p><code>lakefile.lean</code></p>
<p>This file is listing the dependencies.
In my case, the only dependency is mathlib.
Without comments it looks like this:</p>
<pre class="lean"><code>import Lake
open Lake DSL

package «pdl»

require mathlib from git
  &quot;https://github.com/leanprover-community/mathlib4.git&quot;@&quot;v4.13.0&quot;

@[default_target]
lean_lib «Pdl»

lean_lib «Bml»</code></pre>
<p>I think the newer way of doing things is to use a <code>lakefile.toml</code> file instead of a <code>lakefile.lean</code>.
I’ll make that switch some other day.</p></li>
<li><p><code>lake-manifest.json</code> is <em>automatically</em> generated from the other two files.
Do not edit it manually.
The manifest actually pins down fully specified versions by referring to a git commit of mathlib.
This ensures reproducibility: someone downloading the project later can compile it without guessing versions of dependencies.
You can also notice that the manifest contains a lot more dependencies besides mathlib — in my case 9 repositories!
This is because mathlib itself depends on those things:
<code>plausible</code>, <code>LeanSearchClient</code>, <code>import-graph</code>, <code>ProofWidgets4</code>, <code>aesop</code>, <code>quote4</code>, <code>batteries</code> and <code>lean4-cli</code>.</p></li>
</ul>
<p>All three files should be tracked by git.</p>
<h3 id="cant-i-do-this-without-terminal-voodoo">Can’t I do this without terminal voodoo?</h3>
<p>Officially, yes, I guess?
In VS codium, we can click on the <span class="math display">∀</span> logo and then under “Project actions…” click on “Update dependency”.
But for me this does not (always) seem to work.
In particular it sometimes took very long because it started compiling Mathlib instead of downloading cache files.
It also did not seem to update the manifest file, even though I guess it should do that.</p>
<h3 id="the-second-naive-way-lake-update">The second naive way: <code>lake update</code></h3>
<p>It seems one should be able to run <code>lake update</code> and be done, but in practice this has hurt me a few times.
In particular as far as I understand, <code>lake update</code> updates everything (Lean, mathlib, other dependencies) to the latest versions.
I like to have a bit more control and stick to the stable version of Lean instead of jumping to release candidates.
Hence, see the next section.</p>
<h3 id="safety-measures">Safety measures</h3>
<p>Above you can see that my <code>lakefile.lean</code> does not just say “I want mathlib” but says “I want a mathlib that works with Lean version v4.13.0”.
This is possible because in the mathlib4 repository there is <em>tag</em> for it.
See <a href="https://github.com/leanprover-community/mathlib4/tags" class="uri">https://github.com/leanprover-community/mathlib4/tags</a> for all available tags.</p>
<h2 id="the-actual-update">The actual update</h2>
<p>Now here is the actual update procedure.</p>
<ol start="0" type="1">
<li><p>Close VS codium and make sure <code>git status</code> is clean.</p></li>
<li><p>Change the content of the file <code>lean-toolchain</code> to refer to the new version:</p>
<pre><code>leanprover/lean4:v4.14.0</code></pre></li>
<li><p>In the file <code>lakefile.lean</code>, change <code>v4.13.0</code> to <code>v4.14.0</code>.</p></li>
<li><p>Delete the old manifest and all built files:</p>
<p><code>rm -rf lake-manifest.json .lake</code></p>
<p>Deleting <code>.lake</code> here is a bit radical and does mean that the next step will take even longer
But for some previous updates this was the easiest way to fix things.</p></li>
<li><p>Run <code>lake update -R</code>.</p>
<p>This will take a long time and output many things, including this crucial line:</p>
<pre><code>info: pdl: no previous manifest, creating one from scratch</code></pre>
<p>And indeed, at that moment a new <code>lake-manifest.json</code> is generated.</p></li>
<li><p>Now check that the project still compiles and run <code>lake build</code>.</p>
<p>For example, I got <code>error: no such file or directory</code> because I had <code>import Running Mathlib.Order.BoundedOrder</code> in a file.
A <a href="https://github.com/search?q=repo%3Aleanprover-community%2Fmathlib4%20Mathlib.Order.BoundedOrder&amp;type=code">search in mathlib</a>
shows that apparently this file no longer exists, so I changed the import to
<code>Mathlib.Order.BoundedOrder.Basic</code>.</p>
<p>Also plenty of warnings came up, but they are usually easy to fix:</p>
<ul>
<li><p><code>The `unfold_let` tactic is deprecated. Please use `unfold` instead.</code></p></li>
<li><p><code>`List.mem_join` has been deprecated, use `List.mem_flatten` instead</code></p></li>
</ul></li>
<li><p>Once everything compiles, make a commit!</p>
<p>I usually do that as soon as there are no more errors, but before fixing all the warnings.</p></li>
</ol>
<p>To sum it up, for my project you can see all the changes needed for the update in the diff for
the commit <a href="https://github.com/m4lvin/lean4-pdl/commit/c7a2dd0a272a71660dbd7f7bbe858edc31668ee5">c7a2dd0a272a71660dbd7f7bbe858edc31668ee5</a>.</p>
<h2 id="simple-method-without-pinning">Simple Method without Pinning</h2>
<p>If you do not care which Lean version to use, but just want the latest, then the instructions
on <a href="https://leanprover-community.github.io/install/project.html#updating-mathlib-in-your-project">this page</a>
under the heading “Updating Mathlib in your project” provide a two step method:</p>
<ol type="1">
<li><p>Overwrite the <code>lean-toolchain</code> in your project with the one from mathlib.</p></li>
<li><p>Run <code>lake update</code>.</p></li>
</ol>
<p>After this, check if all your files compile, for example with <code>lake build</code>.
The page also suggests to run <code>lake exe mk_all</code> for which I could not find documentation but which seems to regenerate the top-level files (in my case <code>Pdl.lean</code> and <code>Bml.lean</code>).</p>]]></summary>
</entry>
<entry>
    <title>Alexandru's Birthday Puzzle</title>
    <link href="https://malv.in/posts/2022-01-15-alexandru-birthday-puzzle.html" />
    <id>https://malv.in/posts/2022-01-15-alexandru-birthday-puzzle.html</id>
    <published>2022-01-15T00:00:00Z</published>
    <updated>2022-01-15T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Malvin: What a great idea to have a workshop on the birthday of Alexandru. But I must confess that I do not know how old he gets.</p>
<p>Hans: I also do not know.</p>
<p>Sonja: Of course I know. But instead of just telling you his age, let me give you a puzzle. In fact, on the day of the workshop Alexandru will have an age that is a product of two prime numbers.</p>
<p>Malvin: Oh, nice, an age that can be used for Cryptography!</p>
<p>Hans: But probably the numbers are too low - I guess he must be between 40 and 90?</p>
<p>Sonja: Correct. Let me now tell each of you one of the prime numbers. Malvin will get a prime number between 1 and 10, and Hans will get a prime number between 10 and 20.</p>
<p>[ Sonja secretly tells Malvin and Hans a number. ]</p>
<p>Hans: I do not know the age and I do not know whether you know it.</p>
<p>Malvin: Aha! I did not know it before, but now I know it!</p>
<p>Hans: Oh, good, now I also know it!</p>
<p>Sonja: Great, and because all our readers are perfect logicians, they will also know it now.</p>
<p>Malvin and Hans: Happy Birthday Alexandru!</p>
<hr />
<p>Written for the occasion of Alexandru Baltag’s birthday workshop.
For information about the workshop and many other birthday wishes, see <a href="https://tinyurl.com/thebaltagworkshop" class="uri">https://tinyurl.com/thebaltagworkshop</a> (spoiler alert!).</p>
<hr />
<p>The puzzle above can be solved using <a href="https://w4eg.de/malvin/illc/smcdelweb">SMCDEL</a> as follows.</p>
<pre><code>-- Alexandru&#39;s Birthday Puzzle in SMCDEL

VARS 2,3,5,7,     -- first prime
     11,13,17,19  -- second prime

LAW  AND (
  -- exactly one of each list must be true:
  ONEOF (2, 3, 5, 7),
  ONEOF (11, 13, 17, 19),
  -- manually exclude products below 40 and above 90:
  ~2,
  (3 -&gt; (~11 &amp; ~13)),
  (5 -&gt; ~19),
  (7 -&gt; ~13 &amp; ~17 &amp; ~19)
  )

OBS  hans:   11, 13, 17, 19
     malvin: 2, 3, 5, 7

-- list all states
WHERE?
  Top

-- list all states where the dialogue is true
WHERE?
  -- Hans: I do not know the age:
  ~ (AND ( hans knows whether 2, hans knows whether 3, hans knows whether 5) )
  &amp;
  -- ... and I do not know whether you know it:
  ~ (hans knows whether AND (malvin knows whether 11, malvin knows whether 13, malvin knows whether 17))
  &amp;
  -- Malvin: Aha! I did not know it before ...
  ~ AND (malvin knows whether 11, malvin knows whether 13, malvin knows whether 17)
  &amp;
  -- ... but now I know it!
  &lt; ! ~ (AND (hans knows whether 2, hans knows whether 3, hans knows whether 5) )
      &amp; ~ (hans knows whether (AND ( malvin knows whether 11, malvin knows whether 13, malvin knows whether 17 )))
  &gt;
    (AND ( malvin knows whether 11, malvin knows whether 13, malvin knows whether 17))</code></pre>]]></summary>
</entry>
<entry>
    <title>Cyclists in Kaštela — a true story</title>
    <link href="https://malv.in/posts/2021-12-29-cyclists-in-kastela.html" />
    <id>https://malv.in/posts/2021-12-29-cyclists-in-kastela.html</id>
    <published>2021-12-29T00:00:00Z</published>
    <updated>2021-12-29T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Once upon a time there was a small house in Kaštela, in the south of Croatia.
Kaštela is a quiet place most of the year, but crowded with tourists in summer.
Also this small house was full of tourists on this evening.
But it was not a hotel or anything similar.</p>
<p>The person who used to live here and still owned the place, had left more than a year ago:
Frane, in his late 20s, had embarked on a cycling trip around the world.
Instead of selling or renting out his house, he donated it to the cycling community.
He left the door unlocked, published the address and GPS coordinates on <a href="https://www.warmshowers.org/">warmshowers.org</a> and wrote: “Welcome to my home, I am not there, make yourself comfortable.”
And so we did.</p>
<p>On this evening in July 2016, after 136 km and a flat tire, I opened the door at the end of a backstreet.
I was greeted by the smell of food and the sounds of conversation and a guitar.
In the middle of the living room stood four touring bikes, next to which I placed my own.</p>
<p>Someone had taped a big sheet on the wall with instructions “How to survive in Kaštela”.
There were recommendations where one could buy camping gas and what was the cheapest prepaid SIM for Croatia.
A hand-drawn map of the surroundings included multiple cafes and bars and their wifi passwords, the library, a bakery and a supermarket.
It also showed the free water taps and showers at the beach, because while the house still had electricity, the water had been turned off.</p>
<p>Dinner was ready, and six people sat down at the kitchen table.
Two cyclists from South Korea had taken a plane to Paris and were on their way home — one of them was carrying an electric guitar.
A cyclist from France was going in the opposite direction, but already staying here for a week and complaining about how comfortable it was.
Another cyclist from Croatia was making a small tour along the coast.
His route coincided with mine (Ljubljana to Athens) and we continued together on the next day.
Finally, an exception was made to also grant asylum to a VW bus traveller from Germany.</p>
<p>It was a great evening.</p>
<hr />
<p>Note: I wrote this originally for a yearbook of <a href="https://www.svcover.nl/">Cover</a>, the study association for AI and Computer Science in Groningen.
They asked for a made-up or hard-to-believe story and I went for hard-to-believe.
Everything in this story is true.
Frane’s house probably hosted hundreds of cyclists.
See <a href="https://w4eg.de/malvin/2016-summertour/" class="uri">https://w4eg.de/malvin/2016-summertour/</a> for my whole trip.</p>]]></summary>
</entry>
<entry>
    <title>Rendering Elm to static HTML with Selenium</title>
    <link href="https://malv.in/posts/2020-07-04-rendering-elm-to-static-html-with-selenium.html" />
    <id>https://malv.in/posts/2020-07-04-rendering-elm-to-static-html-with-selenium.html</id>
    <published>2020-07-04T00:00:00Z</published>
    <updated>2020-07-04T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Suppose you have a <a href="https://malv.in/publications.html">simple page</a> on a website with part of its content generated by an Elm program.
To also make (the initial view of) the content available to users or simple web crawlers who do not run JavaScript, it can be useful to generate a static HTML copy.
This can also help to prevent flickering when the website loads.</p>
<p>Previously I used <del><a href="https://github.com/eeue56/elm-static-html">elm-static-html</a></del> <a href="https://github.com/ThinkAlexandria/elm-static-html">static-html-from-elm</a> for this, but in combination with <code>Html.Styled</code> from <a href="https://github.com/rtfeldman/elm-css">elm-css</a> the output was not exactly the same as when running the Elm code in a browser and there were encoding problems.
Hence, why not use a browser to generate the static HTML?</p>
<p>We can do this using Selenium.</p>
<p>First, we make an HTML file which works in your local browser, say <code>render.html</code>:
See also the Elm guide about <a href="https://guide.elm-lang.org/interop/#embedding-in-html">Embedding in HTML</a>.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;!doctype</span> html<span class="dt">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">html</span><span class="ot"> lang</span><span class="op">=</span><span class="st">&quot;en&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;</span><span class="kw">head</span><span class="dt">&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">meta</span><span class="ot"> charset</span><span class="op">=</span><span class="st">&quot;UTF-8&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">script</span><span class="ot"> src</span><span class="op">=</span><span class="st">&quot;MyElmProject.min.js&quot;</span><span class="dt">&gt;&lt;/</span><span class="kw">script</span><span class="dt">&gt;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;/</span><span class="kw">head</span><span class="dt">&gt;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;</span><span class="kw">body</span><span class="dt">&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> id</span><span class="op">=</span><span class="st">&quot;MyApp&quot;</span><span class="dt">&gt;&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">script</span><span class="dt">&gt;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    Elm<span class="op">.</span><span class="at">Main</span><span class="op">.</span><span class="fu">init</span>({</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">node</span><span class="op">:</span> <span class="bu">document</span><span class="op">.</span><span class="fu">getElementById</span>(<span class="st">&quot;MyApp&quot;</span>)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    })<span class="op">;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">script</span><span class="dt">&gt;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;/</span><span class="kw">body</span><span class="dt">&gt;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">html</span><span class="dt">&gt;</span></span></code></pre></div>
<p>Second, we use <a href="https://www.selenium.dev/">Selenium</a> to control a “headless”, i.e. invisible, Chrome to open the HTML file, run the Elm script and print out the innerHTML.
For example, save the following as <code>static-via-selenium.py</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> os <span class="im">import</span> getcwd</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> selenium <span class="im">import</span> webdriver</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>options <span class="op">=</span> webdriver.ChromeOptions()</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>options.headless <span class="op">=</span> <span class="va">True</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>driver <span class="op">=</span> webdriver.Chrome(options<span class="op">=</span>options)</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>url <span class="op">=</span> <span class="st">&quot;file://&quot;</span> <span class="op">+</span> getcwd() <span class="op">+</span> <span class="st">&quot;/render.html&quot;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>driver.get(url)</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>divContent <span class="op">=</span> driver.find_element_by_id(<span class="st">&#39;MyApp&#39;</span>).get_attribute(<span class="st">&#39;innerHTML&#39;</span>)</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>driver.quit()</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(divContent)</span></code></pre></div>
<p>Finally, the following <code>Makefile</code> will build the <code>.js</code>, <code>.min.js</code> and <code>.static.html</code> files.
For <code>.min.js</code> we follow the <a href="https://guide.elm-lang.org/optimization/asset_size.html">Elm guide about minification</a>.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dv">all:</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dv">MyApp.js:</span><span class="dt"> src/*.elm</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="er">    </span>elm make --optimize --output=<span class="ch">$@</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="dv">MyApp.min.js:</span><span class="dt"> MyApp.js</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="er">    </span>uglifyjs <span class="ch">$&lt;</span> --compress \</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&#39;pure_funcs</span><span class="ch">=</span><span class="st">&quot;F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9&quot;,pure_getters,keep_fargs=false,unsafe_comps,unsafe&#39; </span><span class="ch">\</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="st">        | uglifyjs --mangle --output=</span><span class="ch">$@</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="dv">MyApp.static.html:</span><span class="dt"> render.html MyApp.min.js</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="er">        </span>python3 static-via-selenium.py &gt; <span class="ch">$@</span></span></code></pre></div>
<p>You can now use the content of <code>MyApp.static.html</code> as a static replacement by putting it inside the <code>&lt;div id="MyApp"&gt;&lt;/div&gt;</code> in <code>index.html</code>.
We leave it as an exercise for the reader to also automate this last step.</p>]]></summary>
</entry>
<entry>
    <title>Five Hints for Modern LaTeX</title>
    <link href="https://malv.in/posts/2019-04-30-five-hints-for-modern-latex.html" />
    <id>https://malv.in/posts/2019-04-30-five-hints-for-modern-latex.html</id>
    <published>2019-04-30T00:00:00Z</published>
    <updated>2019-04-30T00:00:00Z</updated>
    <summary type="html"><![CDATA[<ol type="1">
<li><p>Install the <code>cm-super</code> package and put <code>\usepackage{etex,microtype}</code> in your preamble.</p></li>
<li><p>Enable clickable links with <code>\usepackage{hyperref}</code> and use <code>\autoref{thm:foo}</code>.</p></li>
<li><p>Write <code>\emph{this}</code>, not <code>{\em this}</code>. Similarly, use <code>\textbf{this}</code>, not <code>{\bf this}</code>.</p></li>
<li><p>For displayed formulas, use <code>\[ ... \]</code>, not <code>$$ ... $$</code>.</p></li>
<li><p>Use <a href="https://www.ctan.org/pkg/chktex"><code>chktex</code></a>, ideally integrated into your editor.</p></li>
</ol>
<p>And for a lot more, see <a href="https://www.ctan.org/pkg/l2tabu-english" class="uri">https://www.ctan.org/pkg/l2tabu-english</a>.</p>]]></summary>
</entry>
<entry>
    <title>If you want me to read your email ...</title>
    <link href="https://malv.in/posts/2019-03-10-if-you-want-me-to-read-your-email.html" />
    <id>https://malv.in/posts/2019-03-10-if-you-want-me-to-read-your-email.html</id>
    <published>2019-03-10T00:00:00Z</published>
    <updated>2019-03-10T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p><em>… please read this.</em></p>
<p>I really like email.
It is one of the few federated communication systems that is used by most internet users.</p>
<p>However, there are two kinds of problems with email recently.
First, structurally: email has been almost centralized by the biggest advertisement company, spam is still a huge problem, and running an email server on your own is quite tedious.
Second, and the topic of this post: individual emails are often full of nonsense that should not be there.
Additionally, people seem to be getting lazier and lazier before hitting the send button.</p>
<p>Here comes a wish list how I like my email, sorted by the amount of effort I ask from you.</p>
<h2 id="no-html.">No HTML.</h2>
<p>Just use plain text for your email.
I care about its content, not whether you want me to read it in olive Comic Sans on a beige background.
Moreover, HTML emails are a security disaster.</p>
<h2 id="correct-spelling.">Correct spelling.</h2>
<p>Use a spellchecker and ensure that you write names correctly.
I will also make an effort to spell your name correctly in my reply.
If you really find something hard to spell or type, copy-paste it.
But note that HTML formatting might make it obvious that you copied something from somewhere else — another reason not to use it.</p>
<h2 id="no-advertisements.">No advertisements.</h2>
<p>I don’t care which typewriter, smartphone, tablet, mail client, operating system, anti-virus software or coffee brand you use.
Hence you do not have to finish your email with a signature advertising it.
Often these signatures are added automatically, so you might not even know that you are sending around advertisements.
Moreover, such signatures are sometimes a sign that your anti-virus is doing a
<a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle attack</a>
against you.</p>
<h2 id="dont-spy-on-me.">Don’t spy on me.</h2>
<p>An email should be self-contained and not “call home” each time I open it.
When my email program tells me it had to block remote content, I will no longer read your email with an open mind.
Also, please just forget about the “receipt confirmation” feature.
If you should know that I read your email, I will tell you.</p>
<p>This goes together with the previous comment, because automatic crapware signatures tend to include remote content.
Why should your anti-virus company get a notification each time I read your email?</p>
<h2 id="use-a-decent-provider.">Use a decent provider.</h2>
<p>The saying “If you are not paying, you are the product” is very true for email.
Where are your emails stored and what is the business model of the company storing them?
Should I be careful what I write because it will be used to <del>optimize advertisements</del> manipulate you?</p>
<p>Depending on the context in which you are contacting me, please use the right account.
Say, if you are a student and your university provides an address for you, please use it:
j.kees@university.tld makes a much better impression than kittenlover98@aol.com.</p>
<h2 id="encrypt.">Encrypt.</h2>
<p>Finally, if you really want me to be happy when I get your email, please use PGP.
Mare sure to also <em>sign</em> your email and make <a href="https://keys.openpgp.org/">your public key available</a>.</p>
<p><br /></p>
<p><em>Thank you.</em></p>]]></summary>
</entry>
<entry>
    <title>Symbolically finding Cheryl's Birthday with SMCDEL</title>
    <link href="https://malv.in/posts/2019-03-01-symbolically-finding-cheryls-birthday-with-SMCDEL.html" />
    <id>https://malv.in/posts/2019-03-01-symbolically-finding-cheryls-birthday-with-SMCDEL.html</id>
    <published>2019-03-01T00:00:00Z</published>
    <updated>2019-03-01T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>This is a follow-up to my previous post
<em><a href="https://malv.in/posts/2015-04-20-finding-cheryls-birthday-with-DEMO.html">Finding Cheryl’s Birthday with DEMO</a></em>
in which I solved the famous puzzle about
<a href="https://en.wikipedia.org/wiki/Cheryl%27s_Birthday">Cheryl’s Birthday</a>
using DEMO, an explicit model checker for
<a href="https://seop.illc.uva.nl/entries/dynamic-epistemic/">Dynamic Epistemic Logic</a> (DEL).</p>
<p>Since <a href="https://github.com/jrclogic/SMCDEL/commit/1505d9e26528ca35d708870a818f70419792b16d">this commit</a>
the famous puzzle is also one of the examples included in <a href="https://github.com/jrclogic/SMCDEL">SMCDEL</a>, a symbolic model checker for DEL.
Here I will explain the basics usage of SMCDEL and highlight the differences between explicit and symbolic model checking.</p>
<p>Like DEMO, also SMCDEL is meant to be used as a Haskell module.
There is also a command-line and a <a href="https://w4eg.de/malvin/illc/smcdelweb/">web interface</a> which are easier to use, but as of now they provide less functionality.
It would be a hassle to encode Cheryl’s Birthday in the format needed by those interfaces, so here we will use Haskell directly.</p>
<p>We start by importing a Haskell library for lists and two modules from SMCDEL: the language and the symbolic methods for S5.
The latter choice makes sense because the puzzle is only about knowledge, not belief.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">SMCDEL.Examples.Cheryl</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">SMCDEL.Language</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">SMCDEL.Symbolic.S5</span></span></code></pre></div>
<p>Before doing anything with SMCDEL we define the set of all possibilities, i.e. all birthdays.
This is exactly the same as in the DEMO version, but for readability we also introduce a type alias.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Possibility</span> <span class="ot">=</span> (<span class="dt">Int</span>, <span class="dt">String</span>)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">possibilities ::</span> [<span class="dt">Possibility</span>]</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>possibilities <span class="ot">=</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  [ (<span class="dv">15</span>,<span class="st">&quot;May&quot;</span>), (<span class="dv">16</span>,<span class="st">&quot;May&quot;</span>), (<span class="dv">19</span>,<span class="st">&quot;May&quot;</span>)</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">17</span>,<span class="st">&quot;June&quot;</span>), (<span class="dv">18</span>,<span class="st">&quot;June&quot;</span>)</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">14</span>,<span class="st">&quot;July&quot;</span>), (<span class="dv">16</span>,<span class="st">&quot;July&quot;</span>)</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">14</span>,<span class="st">&quot;August&quot;</span>), (<span class="dv">15</span>,<span class="st">&quot;August&quot;</span>), (<span class="dv">17</span>,<span class="st">&quot;August&quot;</span>) ]</span></code></pre></div>
<p>Recall that DEMO offers many different atomic propositions like <code>P Int</code>, <code>Q Int</code>, <code>R Int</code> and <code>Info a</code>.
Especially the <code>Info a</code> propositions are a very convenient and powerful tool.
Unfortunately, such nominal propositions are not available in SMCDEL.
The language in SMCDEL provides only one set of atomic propositions given by <code>P Int</code>.
This restriction is due to the encoding with
<a href="https://en.wikipedia.org/wiki/Binary_decision_diagram">Binary Decision Diagrams</a>.</p>
<p>Still, also without <code>Info a</code> propositions we can make our life easy:
we define abbreviations in Haskell so that we can write formulas more easily.
For example, we fix that <code>P 17</code> means “The day of Cheryl’s birthday is 17.”
and that <code>P 8</code> means “The month of Cheryl’s birthday is August.”</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">dayIs ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Prp</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>dayIs <span class="ot">=</span> <span class="dt">P</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">monthIs ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Prp</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>monthIs <span class="st">&quot;May&quot;</span>    <span class="ot">=</span> <span class="dt">P</span> <span class="dv">5</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>monthIs <span class="st">&quot;June&quot;</span>   <span class="ot">=</span> <span class="dt">P</span> <span class="dv">6</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>monthIs <span class="st">&quot;July&quot;</span>   <span class="ot">=</span> <span class="dt">P</span> <span class="dv">7</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>monthIs <span class="st">&quot;August&quot;</span> <span class="ot">=</span> <span class="dt">P</span> <span class="dv">8</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>monthIs _        <span class="ot">=</span> <span class="fu">undefined</span></span></code></pre></div>
<p>We then combine our atomic propositions to form more complex formulas.
For example, the command <code>thisPos (15,"August")</code> will give us the conjunction <code>Conj [PrpF (P 15), PrpF (P 8)]</code> saying that Cheryl’s birthday is the 15th of August.
The second formula <code>knWhich i</code> says that agent <span class="math inline"><em>i</em></span> <em>knows</em> Cheryl’s birthday.
This the same as <code>knowsBday</code> in the <code>DEMO</code> version and also here we define it as a big disjunction.
This is not optimal, but given the small model size in this puzzle, it does not hurt.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">thisPos ::</span> <span class="dt">Possibility</span> <span class="ot">-&gt;</span> <span class="dt">Form</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>thisPos (d,m) <span class="ot">=</span> <span class="dt">Conj</span> <span class="op">$</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">PrpF</span> (dayIs d)   <span class="op">:</span> [ <span class="dt">Neg</span> (<span class="dt">PrpF</span> <span class="op">$</span> dayIs d&#39;)   <span class="op">|</span> d&#39; <span class="ot">&lt;-</span> nub (<span class="fu">map</span> <span class="fu">fst</span> possibilities) \\ [d] ]) <span class="op">++</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">PrpF</span> (monthIs m) <span class="op">:</span> [ <span class="dt">Neg</span> (<span class="dt">PrpF</span> <span class="op">$</span> monthIs m&#39;) <span class="op">|</span> m&#39; <span class="ot">&lt;-</span> nub (<span class="fu">map</span> <span class="fu">snd</span> possibilities) \\ [m] ])</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ot">knWhich ::</span> <span class="dt">Agent</span> <span class="ot">-&gt;</span> <span class="dt">Form</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>knWhich i <span class="ot">=</span> <span class="dt">Disj</span> [ <span class="dt">K</span> i (thisPos pos) <span class="op">|</span> pos <span class="ot">&lt;-</span> possibilities ]</span></code></pre></div>
<p>Now, instead of an initial Kripke model, for SMCDEL we need a <em>knowledge structure</em> modelling the start of the puzzle.
A knowledge structure is the symbolic analogue of a Kripke model.
Recall that a Kripke model contains a set of worlds <span class="math inline"><em>w</em><sub>1</sub></span>, <span class="math inline"><em>w</em><sub>2</sub></span>, etc. and valuations like <span class="math inline"><em>p</em><sub>1</sub> : true</span>, <span class="math inline"><em>p</em><sub>2</sub> : false</span>, etc. for each world.
Instead of listing all this information explicitly, a knowledge structure contains a <em>summary</em> of the whole set of worlds.</p>
<p><strong>The main trick of symbolic model checking is to replace the explicit list of worlds with a boolean formula and then say:
My worlds are all boolean assignments satisfying this formula.</strong></p>
<p>Well, and there are some more ingredients.
First, there are many tricks to find and modify this boolean formula.
Second, instead of a <em>formula</em> we only need the boolean <em>function</em> it represents and this can be represented as a Binary Decision Diagram.</p>
<p>A knowledge structure now consists of three parts:</p>
<ul>
<li>a list of propositions called the vocabulary: <code>allprops</code>,</li>
<li>the aforementioned boolean formula: <code>statelaw</code>, and</li>
<li>for each agent a list which propositions that agent observes: <code>obs</code>.</li>
</ul>
<p>Let us compare this again to a Kripke model.
The vocabulary and state law together replace the set of worlds and the valuation function.
The observational variables replace the accessibility relation.</p>
<p>(Maybe you are now wondering whether a knowledge structure is just a different way to write down a Kripke model.
The answer is yes.
Think of knowledge structures as a data structure to store Kripke models.)</p>
<p>Enough theory, here is the initial knowledge structure for Cheryl’s Birthday puzzle:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">start ::</span> <span class="dt">KnowStruct</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>start <span class="ot">=</span> <span class="dt">KnS</span> allprops statelaw obs <span class="kw">where</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  allprops <span class="ot">=</span> <span class="fu">sort</span> <span class="op">$</span> nub <span class="op">$</span> <span class="fu">map</span> (dayIs <span class="op">.</span> <span class="fu">fst</span>) possibilities <span class="op">++</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>                          <span class="fu">map</span> (monthIs <span class="op">.</span> <span class="fu">snd</span>) possibilities</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  statelaw <span class="ot">=</span> boolBddOf <span class="op">$</span> <span class="dt">Conj</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    [ <span class="dt">Disj</span> (<span class="fu">map</span> thisPos possibilities)</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    , <span class="dt">Conj</span> [ <span class="dt">Neg</span> <span class="op">$</span> <span class="dt">Conj</span> [thisPos p1, thisPos p2]</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>           <span class="op">|</span> p1 <span class="ot">&lt;-</span> possibilities, p2 <span class="ot">&lt;-</span> possibilities, p1 <span class="op">/=</span> p2 ] ]</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  obs <span class="ot">=</span> [ (<span class="st">&quot;Albert&quot;</span> , nub <span class="op">$</span> <span class="fu">map</span> (monthIs <span class="op">.</span> <span class="fu">snd</span>) possibilities)</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>        , (<span class="st">&quot;Bernard&quot;</span>, nub <span class="op">$</span> <span class="fu">map</span> (dayIs   <span class="op">.</span> <span class="fu">fst</span>) possibilities) ]</span></code></pre></div>
<p>It is easy to check that <code>allprobs</code> is the list <code>map P [5,6,7,8,14,15,16,17,18,19]</code>.
The formula <code>statelaw</code> essentially says “The birthday must be one of the <code>possibilities</code>, but it cannot be two different ones at the same time.”
To encode the knowledge of the agents, we let Albert observe all atomic propositions about the day and Bernard those about the month.
An equivalent and sometimes more intuitive way to read observational variables is this: an agent observes a variable iff the agent <em>knows whether</em> that variable is true.</p>
<p>Now we will update the <del>model</del> structure with public announcements, given by the dialogue in the puzzle.
The announced formulas are exactly the same as in the DEMO implementation, with small syntax adaptations.
Instead of the <code>upd_pa</code> function in DEMO we now use the <code>update</code> function in SMCDEL.
In fact, <code>update</code> is <a href="https://wiki.haskell.org/Polymorphism">polymorphic</a> such that it also accepts action models or transformers, but here it is given a formula and will thus execute a public announcement.</p>
<p>First Albert says: “I don’t know when Cheryl’s birthday is and I know that Bernard does not know.”
To model this we update with the following conjunction:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>round1 <span class="ot">=</span> update start (<span class="dt">Conj</span> [ <span class="dt">Neg</span> <span class="op">$</span> knWhich <span class="st">&quot;Albert&quot;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>                            , <span class="dt">K</span> <span class="st">&quot;Albert&quot;</span> <span class="op">$</span> <span class="dt">Neg</span> (knWhich <span class="st">&quot;Bernard&quot;</span>)])</span></code></pre></div>
<p>Then Bernard says: “Now I know when Cheryl’s birthday is.”</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>round2 <span class="ot">=</span> update round1 (knWhich <span class="st">&quot;Bernard&quot;</span>)</span></code></pre></div>
<p>Finally, Albert says: “Now I also know when Cheryl’s birthday is.”</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>round3 <span class="ot">=</span> update round2 (knWhich <span class="st">&quot;Albert&quot;</span>)</span></code></pre></div>
<p>We can now get the solution by asking for the remaining states:</p>
<pre><code>$ stack ghci src/SMCDEL/Examples/Cheryl.hs
λ&gt; statesOf round3
[[P 7,P 16]]</code></pre>
<p>To get the solution in a more readable form, we can write a little helper function:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">cherylsBirthday ::</span> <span class="dt">String</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>cherylsBirthday <span class="ot">=</span> m <span class="op">++</span> <span class="st">&quot; &quot;</span> <span class="op">++</span> <span class="fu">show</span> d <span class="op">++</span> <span class="st">&quot;th&quot;</span> <span class="kw">where</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  [(d,m)] <span class="ot">=</span> <span class="fu">filter</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    (\(d&#39;,m&#39;) <span class="ot">-&gt;</span> [monthIs m&#39;, dayIs d&#39;] <span class="ot">`elem`</span> statesOf round3)</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    possibilities</span></code></pre></div>
<p>Spoiler alert!</p>
<pre><code>λ&gt; cherylsBirthday
&quot;July 16th&quot;</code></pre>
<p>If you want to learn more about the internals of SMCDEL,
please have a look at the <a href="https://github.com/jrclogic/SMCDEL/">source code and documentation</a>
or <a href="https://malv.in/phdthesis/">my PhD thesis</a>.
The first chapter also describes the basics of Dynamic Epistemic Logic.</p>]]></summary>
</entry>
<entry>
    <title>Self-hosting the WiFi Connectivity Check for Android</title>
    <link href="https://malv.in/posts/2018-11-08-self-hosting-the-wifi-connectivity-check-for-android.html" />
    <id>https://malv.in/posts/2018-11-08-self-hosting-the-wifi-connectivity-check-for-android.html</id>
    <published>2018-11-08T00:00:00Z</published>
    <updated>2018-11-08T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Android is made by Google, but at least as of 2018 it is still possible to use
it without Google services. Reasons to do so include privacy and independence.
Of course it would be better to switch to another platform completely, but a
<a href="https://puri.sm/products/librem-5/">privacy focussed free software phone</a>
or an
<a href="https://postmarketos.org/">alternative operating system</a>
for Android hardware are not there yet.</p>
<p>One of the “Android calling home” functions that is tricky to disable or remove,
is the check for internet connectivity after joining a WiFi network.</p>
<p>Every Android device requests <code>https://connectivitycheck.gstatic.com/generate_204</code>
after connecting to a wireless network.
This page hosted by google is empty and returns a 204 status code.
Most <a href="https://en.wikipedia.org/wiki/Captive_portal">captive portals</a>
use status code 200 to serve a page or 203 to redirect somewhere,
hence this works as a simple check whether the device is behind a portal.</p>
<p>I now wanted to keep my Fairphone 2 from connecting to this server.
Setting the checked URL to some nonsense would disable the check, but then
Android would claim that it has no internet connection all the time, showing a
dreaded exclamation mark icon.</p>
<p>But which server should I use instead?</p>
<p>As I am running multiple webservers for my own and friends’ websites, the way
to go was to set up a link that generates 204 results myself.</p>
<p>To create the correct response I made a simple file <code>204.php</code> as follows.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">http_response_code</span>(<span class="dv">204</span>)<span class="ot">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="cf">exit</span>()<span class="ot">;</span></span></code></pre></div>
<p>Alternatively, if PHP is not available, one can also add a simple redirect to
the websever configuration, in my case Apache:</p>
<pre><code>&lt;VirtualHost *:80&gt;
    ...
    RedirectMatch 204 (.*)/204$
    ...
&lt;/VirtualHost&gt;</code></pre>
<p>Then, in a root terminal on the phone I entered the following two commands,
from <em>pat_512</em> in the Fairphone Forum (see links below).</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">settings</span> put global captive_portal_http_url <span class="st">&quot;http://198.51.100.24/204&quot;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">settings</span> put global captive_portal_https_url <span class="st">&quot;https://example.com/204.php&quot;</span></span></code></pre></div>
<p>In fact, this could also be used to track a device, recording on the server
when it was in which wifi, or rather when it had which public IP address.
Setting the URL differently on different devices could then be used to
distinguish their requests.</p>
<hr />
<p><strong>Related Links</strong></p>
<ul>
<li><a href="https://forum.fairphone.com/t/using-lineageos-on-the-fp2/28848/157">Post by <em>pat_512</em> in the Fairphone Forum</a></li>
<li><a href="https://android.stackexchange.com/questions/186993/captive-portal-parameters">Discussion of captive portal parameters on android.stackexchange.com</a></li>
</ul>]]></summary>
</entry>
<entry>
    <title>The ILLC Course Title Generator</title>
    <link href="https://malv.in/posts/2016-06-17-illc-course-title-generator.html" />
    <id>https://malv.in/posts/2016-06-17-illc-course-title-generator.html</id>
    <published>2016-06-17T00:00:00Z</published>
    <updated>2016-06-17T00:00:00Z</updated>
    <summary type="html"><![CDATA[<iframe src="https://w4eg.de/malvin/illc/coursetitle.php">
</iframe>]]></summary>
</entry>
<entry>
    <title>Finding Cheryl's Birthday with DEMO</title>
    <link href="https://malv.in/posts/2015-04-20-finding-cheryls-birthday-with-DEMO.html" />
    <id>https://malv.in/posts/2015-04-20-finding-cheryls-birthday-with-DEMO.html</id>
    <published>2015-04-20T00:00:00Z</published>
    <updated>2015-04-20T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>This report shows how to solve the famous riddle from Singapore
(see <a href="http://www.nytimes.com/2015/04/15/science/a-math-problem-from-singapore-goes-viral-when-is-cheryls-birthday.html">New York Times</a>)
with epistemic model checking.
We use <code>DEMO_S5</code> from
<a href="https://web.archive.org/web/20160803170251/http://homepages.cwi.nl/~jve/software/demo_s5/" class="uri">https://web.archive.org/web/20160803170251/http://homepages.cwi.nl/~jve/software/demo_s5/</a> and a modified version
of <code>KRIPKEVIS</code> from <a href="https://w4eg.de/malvin/illc/kripkevis" class="uri">https://w4eg.de/malvin/illc/kripkevis</a>.</p>
<p>You can also download <a href="https://w4eg.de/malvin/illc/cheryl/CHERYL.pdf">a PDF version of this report</a>
and <a href="https://w4eg.de/malvin/illc/cheryl/CHERYL.zip">the source files</a>.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">CHERYL</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Function</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">DEMO_S5</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">KRIPKEVIS</span></span></code></pre></div>
<p>We first define the set of all possibilities:</p>
<pre class=".haskell"><code>allpos :: [(Int, String)]
allpos = [ (15,&quot;May&quot;), (16,&quot;May&quot;), (19,&quot;May&quot;), (17,&quot;June&quot;), (18,&quot;June&quot;),
  (14,&quot;July&quot;), (16,&quot;July&quot;), (14,&quot;August&quot;), (15,&quot;August&quot;), (17,&quot;August&quot;) ]</code></pre>
<p>This forms the set of worlds in our initial model. Moreover, also the
set of actual worlds is the full set, hence <code>allpos</code> occurs twice in the
definition below. The two elements of <code>rels</code> define the epistemic
relations of Albert and Bernard. Instead of listing explicitly which
possibilities they can distinguish we use haskell functions to say that
they confuse the same day and the same month, respectively.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">initCheryl ::</span> <span class="dt">EpistM</span> (<span class="dt">Int</span>,<span class="dt">String</span>)</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>initCheryl <span class="ot">=</span> <span class="dt">Mo</span> allpos [a,b] [] rels allpos <span class="kw">where</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  rels <span class="ot">=</span> [ ( a, groupBy ((<span class="op">==</span>) <span class="ot">`on`</span> <span class="fu">snd</span>) allpos )</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>         , ( b, groupBy ((<span class="op">==</span>) <span class="ot">`on`</span> <span class="fu">fst</span>) (sortBy (<span class="fu">compare</span> <span class="ot">`on`</span> <span class="fu">fst</span>) allpos) ) ]</span></code></pre></div>
<p>This is the initial model with all possibilities:</p>
<p><img src="https://w4eg.de/malvin/illc/cheryl/initCheryl.svg" /></p>
<p>The formula saying that <span class="math inline"><em>i</em></span> knows Cheryl’s birthday is defined as the
disjunction over all statements of the form “Agent i knows that the
birthday is s”:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">knowsBday ::</span> <span class="dt">Agent</span> <span class="ot">-&gt;</span> <span class="dt">Form</span> (<span class="dt">Int</span>, [<span class="dt">Char</span>])</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>knowsBday i <span class="ot">=</span> <span class="dt">Disj</span> [ <span class="dt">Kn</span> i (<span class="dt">Info</span> s) <span class="op">|</span> s <span class="ot">&lt;-</span> allpos ]</span></code></pre></div>
<p>Now we update the model three times, using the function <code>upd_pa</code> for
public announcements. First with Albert: I don’t know when Cheryl’s
birthday is and I know that Bernard does not know.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>model2 <span class="ot">=</span> upd_pa initCheryl (<span class="dt">Conj</span> [<span class="dt">Ng</span> <span class="op">$</span> knowsBday a, <span class="dt">Kn</span> a <span class="op">$</span> <span class="dt">Ng</span> (knowsBday b)])</span></code></pre></div>
<p><img src="https://w4eg.de/malvin/illc/cheryl/model2.svg" /></p>
<p>The second announcement by Bernard: “Now I know when Cheryl’s birthday
is.”</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>model3 <span class="ot">=</span> upd_pa model2 (knowsBday b)</span></code></pre></div>
<p><img src="https://w4eg.de/malvin/illc/cheryl/model3.svg" /></p>
<p>Finally, Albert says: “Now I also know when Cheryl’s birthday is.”</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>model4 <span class="ot">=</span> upd_pa model3 (knowsBday a)</span></code></pre></div>
<p><img src="https://w4eg.de/malvin/illc/cheryl/model4.svg" /></p>
<p>Lastly, this helper function uses <code>texModel</code> from <code>KRIPKEVIS</code> to
generate the drawings:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">myTexModel ::</span> <span class="dt">EpistM</span> (<span class="dt">Int</span>,<span class="dt">String</span>) <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>myTexModel (<span class="dt">Mo</span> states _ _ rels pointed) fn <span class="ot">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  texModel showState showAgent showVal <span class="st">&quot;&quot;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">VisModel</span> states rels [(s,<span class="dv">0</span>)<span class="op">|</span>s<span class="ot">&lt;-</span>states] pointed) fn</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>    showState (n,string) <span class="ot">=</span> (<span class="fu">show</span> n) <span class="op">++</span> string</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    showAgent i          <span class="ot">=</span> <span class="kw">if</span> i<span class="op">==</span>a <span class="kw">then</span> <span class="st">&quot;Albert&quot;</span> <span class="kw">else</span> <span class="st">&quot;Bernard&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    showVal _            <span class="ot">=</span> <span class="st">&quot;&quot;</span></span></code></pre></div>]]></summary>
</entry>

</feed>
