<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Malte Gerken</title><link href="https://www.maltegerken.de/" rel="alternate"/><link href="https://www.maltegerken.de/feeds/all.atom.xml" rel="self"/><id>https://www.maltegerken.de/</id><updated>2025-03-12T16:09:36+01:00</updated><subtitle>Some notes on random stuff</subtitle><entry><title>Show current traffic in the XFCE panel</title><link href="https://www.maltegerken.de/blog/2024/08/show-current-traffic-in-the-xfce-panel/" rel="alternate"/><published>2024-08-21T07:50:35+02:00</published><updated>2025-03-10T08:17:20+01:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2024-08-21:/blog/2024/08/show-current-traffic-in-the-xfce-panel/</id><summary type="html">&lt;p&gt;The XFCE panel has some monitoring plugins one can enable, but theese are
always displaying a graph, not the current value. I was looking for something
which will display the network traffic in a compact form, which was not
available. As it is possible to apply css to the generic …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The XFCE panel has some monitoring plugins one can enable, but theese are
always displaying a graph, not the current value. I was looking for something
which will display the network traffic in a compact form, which was not
available. As it is possible to apply css to the generic monitor texts, I came
up with the following script which will display the traffic of the default
device.&lt;/p&gt;
&lt;p&gt;This looks something like this (updated March 2025 to properly support multiple
default routes):&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image showing some sample traffic data" src="https://www.maltegerken.de/images/xfce-traffic.png"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;ip&lt;span class="w"&gt; &lt;/span&gt;route&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/dev/ {print $5}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n1&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/xfce-genmon-traffic/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="nv"&gt;rx2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/sys/class/net/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/statistics/rx_bytes&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;tx2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/sys/class/net/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEVICE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/statistics/tx_bytes&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;dt2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$EPOCHREALTIME&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/timestamp&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rx1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rx_bytes&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;tx1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tx_bytes&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;dt1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/timestamp&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dt2&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$dt1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(&lt;/span&gt;&lt;span class="nv"&gt;$rx2&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$rx1&lt;/span&gt;&lt;span class="s2"&gt;) / &lt;/span&gt;&lt;span class="nv"&gt;$dt&lt;/span&gt;&lt;span class="s2"&gt; * 8&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bc&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(&lt;/span&gt;&lt;span class="nv"&gt;$tx2&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$tx1&lt;/span&gt;&lt;span class="s2"&gt;) / &lt;/span&gt;&lt;span class="nv"&gt;$dt&lt;/span&gt;&lt;span class="s2"&gt; * 8&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bc&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rxk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;txk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rxm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;txm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rxk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; k&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;txk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; k&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$rxm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rxt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rxm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; M&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$txm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;txm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; M&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$rxg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rxt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rxg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; G&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$txg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;txg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; G&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;- k&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;- k&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;rxk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;txk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;txt&amp;gt;&amp;lt;tt&amp;gt;&amp;lt;span size=&amp;#39;75%&amp;#39; line_height=&amp;#39;0.9&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; In: &amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$rxk&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%6s&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;rxt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;bit/s&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;           &amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Out: &amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$txk&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%6s&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;txt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;bit/s&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;           &amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/tt&amp;gt;&amp;lt;/txt&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;tool&amp;gt;&amp;lt;/tool&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;css&amp;gt;.genmon_value { padding-left: 10px; padding-right: 7px}&amp;lt;/css&amp;gt;&amp;quot;&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$rx2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rx_bytes&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$tx2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tx_bytes&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dt2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RUNP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/timestamp&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first version simply used a &lt;code&gt;sleep&lt;/code&gt;, but this will make the whole panel
unresponsive. It is important that the scripts exits quickly, thus the solution
with the temporary files. They should end up on a tmpfs, so nothing is saved to
a disk.&lt;/p&gt;
&lt;p&gt;If there is less than 2kbit/s of traffic, it will display a blank value.
Prefixes range from k to G by default.&lt;/p&gt;</content><category term="linux"/></entry><entry><title>Creating PDF forms with LaTeX</title><link href="https://www.maltegerken.de/blog/2021/07/creating-pdf-forms-with-latex/" rel="alternate"/><published>2021-07-11T16:25:43+02:00</published><updated>2023-09-01T09:37:53+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2021-07-11:/blog/2021/07/creating-pdf-forms-with-latex/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Update 2023&lt;/strong&gt;: While this all works in principle, I encountered too many PDF
viewers where some form elements where doing unexpected things. The current
approach is to only print visual form elements and make the form fillable with
some PDF authoring software.&lt;/p&gt;
&lt;p&gt;A few weeks ago I thought it would …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Update 2023&lt;/strong&gt;: While this all works in principle, I encountered too many PDF
viewers where some form elements where doing unexpected things. The current
approach is to only print visual form elements and make the form fillable with
some PDF authoring software.&lt;/p&gt;
&lt;p&gt;A few weeks ago I thought it would be a good idea to change a form such that it
would be fillable on a computer. I started the task using LibreOffice, as other
people not so familiar with computers are also editing the form occasionally. It
became clear very quickly that working with fillable form elements in
LibreOffice is a huge pain in the ass, so I switched to LaTeX to give it a try.
Unsurprisingly that gave the desired results in the end, but I learned a few
things one has to take into account if creating forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Forms using &lt;code&gt;hyperref&lt;/code&gt; work quite well, but some customization might be
  required. You need a &lt;code&gt;Form&lt;/code&gt; environment, but that can contain the whole
  document.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;hyperref&lt;/code&gt; documentation on forms is very limited, to figure out the
  available &lt;code&gt;borderstyle&lt;/code&gt; options I had to look into the PDF specifications&lt;sup id="fnref:pdfspecs"&gt;&lt;a class="footnote-ref" href="#fn:pdfspecs"&gt;1&lt;/a&gt;&lt;/sup&gt;.
  &lt;code&gt;hyperref&lt;/code&gt; essentially creates the form elements and passes the options directly
  into the PDF.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;One should not assume that all PDF viewers support forms, which means that
  lines under the field should not be a part of the form field. The first
  version I distributed used &lt;code&gt;borderstyle=U&lt;/code&gt;&lt;sup id="fnref:borderstyle"&gt;&lt;a class="footnote-ref" href="#fn:borderstyle"&gt;2&lt;/a&gt;&lt;/sup&gt; for most text entries, so when
  people printed it to fill it out the lines under the fields went missing. This
  is obviously not so nice. The same problem applies to checkboxes, in this case
  without &lt;code&gt;borderstyle&lt;/code&gt; changes, the boxes just vanished. Apparently a lot of
  smartphone previews which can print do not support forms and I underestimated
  the amount of people who have used them.&lt;/p&gt;
&lt;p&gt;Long story short: Make sure that the form looks fine without any support for
PDF forms in the viewer, which means never to use borders and draw lines
under/around the fields yourself. Some advanced hacking is required to do that
for checkboxes and radios.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All inputs must have a unique name, otherwise some PDF viewers might not
  display the second input. Evince just displays everything, but you should at
  least check with Adobe Reader.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Some example customizations&lt;/h2&gt;
&lt;p&gt;I have added some commands to my custom document class, but it should be easy
to adjust them. The borders for the form elements are made using tikz, so you
have to load it.&lt;/p&gt;
&lt;p&gt;First some default options are defined, which make sure that the border is not
displayed using zero width borders. For the radio symbol see the hyperref
documentation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;\renewcommand*&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\DefaultOptionsofRadio&lt;/span&gt;&lt;span class="nb"&gt;}{&lt;/span&gt;print,radio, radiosymbol=6, width=&lt;span class="k"&gt;\baselineskip&lt;/span&gt;, bordercolor=&lt;span class="nb"&gt;{&lt;/span&gt;black&lt;span class="nb"&gt;}&lt;/span&gt;, borderwidth=0pt&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\renewcommand*&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\DefaultOptionsofText&lt;/span&gt;&lt;span class="nb"&gt;}{&lt;/span&gt;print,bordercolor=&lt;span class="nb"&gt;{&lt;/span&gt;black&lt;span class="nb"&gt;}&lt;/span&gt;, backgroundcolor=white, borderwidth=0pt&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;TextFields&lt;/h3&gt;
&lt;p&gt;The fields itself are displayed either without any label at all (you must still
provide a unique name) or with a label under the input field. All input fields
are underlined to make them visible in printed forms. Multiline fields are
displayed with a border.&lt;/p&gt;
&lt;p&gt;Two commands are provided: &lt;code&gt;\field&lt;/code&gt; and &lt;code&gt;\fieldinline&lt;/code&gt;, which both take
name/label and width as arguments, e.g. &lt;code&gt;\field{Your Name}{6cm}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As the layout command is customized, it has to distinguish between the different
style (with label, without label, multiline). This is done by checking the width
of the label or the height of the field.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;\renewcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\LayoutTextField&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;[2]&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="c"&gt;% label, field&lt;/span&gt;
&lt;span class="k"&gt;\setbox&lt;/span&gt;0=&lt;span class="k"&gt;\hbox&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;#1&lt;span class="k"&gt;\unskip&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="k"&gt;\ifdim\wd&lt;/span&gt;0=0pt
&lt;span class="k"&gt;\setbox&lt;/span&gt;1=&lt;span class="k"&gt;\hbox&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;#2&lt;span class="k"&gt;\unskip&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="k"&gt;\ifdim\ht&lt;/span&gt;1&amp;gt;3ex
&lt;span class="c"&gt;% Multiline&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;[every node/.style=&lt;span class="nb"&gt;{&lt;/span&gt;inner sep=0,outer sep=0&lt;span class="nb"&gt;}&lt;/span&gt;]
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west]&lt;/span&gt; (TextFieldNode) at (0cm,0cm) &lt;span class="nb"&gt;{&lt;/span&gt;#2&lt;span class="nb"&gt;}&lt;/span&gt;;
  &lt;span class="k"&gt;\draw&lt;/span&gt; [thick] (current bounding box.south west) rectangle (current bounding box.north east);
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;
&lt;span class="k"&gt;\else&lt;/span&gt;
&lt;span class="c"&gt;% Inline field, lowered a little bit to be better integrated into the text&lt;/span&gt;
&lt;span class="k"&gt;\raisebox&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;-3.2pt&lt;span class="nb"&gt;}{&lt;/span&gt;&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;[every node/.style=&lt;span class="nb"&gt;{&lt;/span&gt;inner sep=0,outer sep=0&lt;span class="nb"&gt;}&lt;/span&gt;]
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west]&lt;/span&gt; (TextFieldNode) at (0cm,0cm) &lt;span class="nb"&gt;{&lt;/span&gt;#2&lt;span class="nb"&gt;}&lt;/span&gt;;
  &lt;span class="k"&gt;\draw&lt;/span&gt;&lt;span class="na"&gt;[thick]&lt;/span&gt; ([yshift=-0.3ex]TextFieldNode.south west) -- ([yshift=-0.3ex]TextFieldNode.south east);
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}}&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;
&lt;span class="k"&gt;\fi&lt;/span&gt;
&lt;span class="k"&gt;\else&lt;/span&gt;
&lt;span class="c"&gt;% Field with label below it&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;[every node/.style=&lt;span class="nb"&gt;{&lt;/span&gt;inner sep=0,outer sep=0&lt;span class="nb"&gt;}&lt;/span&gt;]
    &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west]&lt;/span&gt; (TextFieldNode) at (0cm,2ex) &lt;span class="nb"&gt;{&lt;/span&gt;#2&lt;span class="nb"&gt;}&lt;/span&gt;;
    &lt;span class="k"&gt;\draw&lt;/span&gt;&lt;span class="na"&gt;[thick]&lt;/span&gt; ([yshift=-0.3ex]TextFieldNode.south west) -- ([yshift=-0.3ex]TextFieldNode.south east);
    &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west,font=\footnotesize]&lt;/span&gt; at (0cm,-0.9ex) &lt;span class="nb"&gt;{&lt;/span&gt;#1&lt;span class="nb"&gt;}&lt;/span&gt;;
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;
&lt;span class="k"&gt;\fi&lt;/span&gt;
&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\newcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\field&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;[2]&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\TextField&lt;/span&gt;&lt;span class="na"&gt;[width=#2]&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;#1&lt;span class="nb"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;\newcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\fieldinline&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;[2]&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\TextField&lt;/span&gt;&lt;span class="na"&gt;[width=#2,name=#1]&lt;/span&gt;&lt;span class="nb"&gt;{}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Radio fields&lt;/h3&gt;
&lt;p&gt;For radio elements this is a little bit more complicated. In theory you can just use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;\ChoiceMenu&lt;/span&gt;&lt;span class="na"&gt;[radio=true,name=Yourname]&lt;/span&gt;&lt;span class="nb"&gt;{}{&lt;/span&gt;Yes,No&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and two checkboxes with labels will be displayed side by side. The problem
arises if the viewer does not support form fields, as the checkboxes will
disappear, leaving only the labels.&lt;/p&gt;
&lt;p&gt;The solution is to build the form yourself by placing a checkbox without a
border inside a box drawn by tikz. To make things interesting some PDF viewers
(e.g. Evince) do not display things behind a form element, so to retain the
borders you must make sure that the form element is not over any lines.&lt;/p&gt;
&lt;p&gt;I only required some Yes/No options in the form, so that is what is implemented
below. &lt;code&gt;\yesnoticks{fieldname}&lt;/code&gt; displays the tick boxes and the labels, with
&lt;code&gt;\yesno{Text}{fieldname}&lt;/code&gt; the explanation for the ticks is displayed on the left
with the ticks and the right in an uniform way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;\newcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\radiosize&lt;/span&gt;&lt;span class="nb"&gt;}{&lt;/span&gt;0.33cm&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\newcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\yesnoticks&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;[1]&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;
&lt;span class="k"&gt;\raisebox&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;-3.2pt&lt;span class="nb"&gt;}{&lt;/span&gt;&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}&lt;/span&gt;[every node/.style=&lt;span class="nb"&gt;{&lt;/span&gt;inner sep=0,outer sep=0&lt;span class="nb"&gt;}&lt;/span&gt;]
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west,style={inner sep=2px}]&lt;/span&gt; (FieldYes) at (0cm,0cm) &lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\ChoiceMenu&lt;/span&gt;&lt;span class="na"&gt;[radio=true,name=#1,width=\radiosize,height=\radiosize]&lt;/span&gt;&lt;span class="nb"&gt;{}{&lt;/span&gt;=Yes&lt;span class="nb"&gt;}}&lt;/span&gt;;
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west]&lt;/span&gt; (LabelYes) at ([xshift=0.7ex]FieldYes.east) &lt;span class="nb"&gt;{&lt;/span&gt;Yes&lt;span class="nb"&gt;}&lt;/span&gt;;
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west,style={inner sep=2px}]&lt;/span&gt; (FieldNo) at ([xshift=1ex]LabelYes.east) &lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\ChoiceMenu&lt;/span&gt;&lt;span class="na"&gt;[radio=true,name=#1,width=\radiosize,height=\radiosize]&lt;/span&gt;&lt;span class="nb"&gt;{}{&lt;/span&gt;=No&lt;span class="nb"&gt;}}&lt;/span&gt;;
  &lt;span class="k"&gt;\node&lt;/span&gt;&lt;span class="na"&gt;[anchor=west]&lt;/span&gt; (LabelNo) at ([xshift=0.7ex]FieldNo.east) &lt;span class="nb"&gt;{&lt;/span&gt;No&lt;span class="nb"&gt;}&lt;/span&gt;;
  &lt;span class="k"&gt;\draw&lt;/span&gt; [thick] ([xshift=-(&lt;span class="k"&gt;\radiosize&lt;/span&gt;+0.15cm),yshift=-(&lt;span class="k"&gt;\radiosize&lt;/span&gt;+0.15cm)]FieldYes.north east) rectangle (FieldYes.north east);
  &lt;span class="k"&gt;\draw&lt;/span&gt; [thick] ([xshift=-(&lt;span class="k"&gt;\radiosize&lt;/span&gt;+0.15cm),yshift=-(&lt;span class="k"&gt;\radiosize&lt;/span&gt;+0.15cm)]FieldNo.north east) rectangle (FieldNo.north east);
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;tikzpicture&lt;span class="nb"&gt;}}&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;
&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\newcommand&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\yesno&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;[2]&lt;span class="nb"&gt;{&lt;/span&gt;&lt;span class="k"&gt;\pbox&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;0.8&lt;span class="k"&gt;\textwidth&lt;/span&gt;&lt;span class="nb"&gt;}{&lt;/span&gt;&lt;span class="k"&gt;\setstretch&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;1&lt;span class="nb"&gt;}&lt;/span&gt;#1&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="k"&gt;\hfill\yesnoticks&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;#2&lt;span class="nb"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;Using these customizations one can build a form using&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;Form&lt;span class="nb"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;\field&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;name&lt;span class="nb"&gt;}{&lt;/span&gt;0.3&lt;span class="k"&gt;\linewidth&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="k"&gt;\hfill\field&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;phone&lt;span class="nb"&gt;}{&lt;/span&gt;0.3&lt;span class="k"&gt;\linewidth&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="k"&gt;\hfill\field&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;address&lt;span class="nb"&gt;}{&lt;/span&gt;0.3&lt;span class="k"&gt;\linewidth&lt;/span&gt;&lt;span class="nb"&gt;}&lt;/span&gt;&lt;span class="c"&gt;%&lt;/span&gt;

    I would like to bring some &lt;span class="k"&gt;\fieldinline&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;things&lt;span class="nb"&gt;}{&lt;/span&gt;4cm&lt;span class="nb"&gt;}&lt;/span&gt; to the party.

    &lt;span class="k"&gt;\yesno&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;I like Pets&lt;span class="nb"&gt;}{&lt;/span&gt;pets&lt;span class="nb"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;\yesno&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;This is a very long sentence to show what happens if it does not fit in one line.&lt;span class="nb"&gt;}{&lt;/span&gt;lines&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;Form&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will result in (all fields fillable in the viewer)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Sample document" src="https://www.maltegerken.de/images/latex_forms.png"&gt;&lt;/p&gt;
&lt;p&gt;(download &lt;a href="https://www.maltegerken.de/code/latex_forms.tex"&gt;source code&lt;/a&gt;, &lt;a href="https://www.maltegerken.de/code/latex_forms.pdf"&gt;resulting PDF&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;See also / references&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://texwelt.de/fragen/7850/wie-passe-ich-den-stil-von-formularfeldern-an-insbesondere-das-setzen-des-labels-unter-das-feld-und-rahmen-bei-textfeldern"&gt;https://texwelt.de/fragen/7850/wie-passe-ich-den-stil-von-formularfeldern-an-insbesondere-das-setzen-des-labels-unter-das-feld-und-rahmen-bei-textfeldern&lt;/a&gt; (in german)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://texwelt.de/fragen/7946/wie-setzt-man-die-breite-von-textfield-und-einer-linie-mit-tikz-layout-synchron-und-mit-fill"&gt;https://texwelt.de/fragen/7946/wie-setzt-man-die-breite-von-textfield-und-einer-linie-mit-tikz-layout-synchron-und-mit-fill&lt;/a&gt; (in german)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:pdfspecs"&gt;
&lt;p&gt;You can buy them from ISO or download them from Adobe for free, just
Google 'pdf specification'.&amp;#160;&lt;a class="footnote-backref" href="#fnref:pdfspecs" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:borderstyle"&gt;
&lt;p&gt;This should be an underlined element, which was impossible to
create in LibreOffice. Maybe the reason was the missing support in some viewers.&amp;#160;&lt;a class="footnote-backref" href="#fnref:borderstyle" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="latex"/></entry><entry><title>Collection of useful links for LaTeX</title><link href="https://www.maltegerken.de/blog/2020/11/collection-of-useful-links-for-latex/" rel="alternate"/><published>2020-11-30T11:14:21+01:00</published><updated>2022-10-11T10:30:49+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2020-11-30:/blog/2020/11/collection-of-useful-links-for-latex/</id><content type="html">&lt;p&gt;As I sometimes come around some useful links which just go missing again I will collect them here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://esc-now.de/_/latex-individuelle-kopf--und-fusszeilen-update/?lang=en"&gt;Kopf- und Fußzeilen mit scrartcl&lt;/a&gt; (in German)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://alexwlchan.net/2017/10/latex-underlines/"&gt;LaTeX underlines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://texblog.org/2011/04/04/make-page-margins-visible/"&gt;Show page frames, to debug margins etc.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://texfaq.org/"&gt;LaTeX FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tex.stackexchange.com/questions/25249/how-do-i-use-a-particular-font-for-a-small-section-of-text-in-my-document"&gt;Switching fonts for some sections only&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;to be continued...&lt;/p&gt;</content><category term="latex"/></entry><entry><title>Homeautomation using Home Assistant</title><link href="https://www.maltegerken.de/blog/2020/10/homeautomation-using-home-assistant/" rel="alternate"/><published>2020-10-16T19:14:16+02:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2020-10-16:/blog/2020/10/homeautomation-using-home-assistant/</id><summary type="html">&lt;p&gt;Early in the summer we had the idea to change the lights on our back porch from
various switches inside the garage to something one could control without going
anywhere. As I had an old RaspberryPi lying around I ordered a small relay
board and installed &lt;a href="https://www.domoticz.com/"&gt;domoticz&lt;/a&gt; to switch the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Early in the summer we had the idea to change the lights on our back porch from
various switches inside the garage to something one could control without going
anywhere. As I had an old RaspberryPi lying around I ordered a small relay
board and installed &lt;a href="https://www.domoticz.com/"&gt;domoticz&lt;/a&gt; to switch the GPIOs.&lt;/p&gt;
&lt;p&gt;There were a few downsides:
The system is unintuitive with a not so nice interface, the documentation is
not the best and I do not know C++. There is also the problem that I had to
maintain another operating system and the fact that one should not power off a
linux system by disconnecting the power. That poses a problem as one would
switch off the power for the whole garden when working on the wiring.&lt;/p&gt;
&lt;h3&gt;Switching to Home Assistant&lt;/h3&gt;
&lt;p&gt;I found a much better solution with ESP32 based boards in combination with
&lt;a href="https://www.home-assistant.io/"&gt;Home Assistant&lt;/a&gt; (using the &lt;a href="https://www.home-assistant.io/docs/installation/raspberry-pi/"&gt;virtualenv
install&lt;/a&gt;), which
is running on the local RaspberryPi based homeserver. The ESP microcontroller
are now running with &lt;a href="https://esphome.io/"&gt;ESPHome&lt;/a&gt; and are connected directly
through the ESPHome API to Home Assistant.&lt;/p&gt;
&lt;p&gt;After that turned out to be working quite nicely I added two other smart lights
which are using an ESP8266 internally and a Sonoff Basic Relais to control
another light in the garden. The only problem was that you always needed your
smartphone to turn the lights on. It was usually fine in the summer on the porch,
but in the winter when one is just doing some short things in the garden it is
problematic. I thought about repurposing a switch with an ESP8266 for that task,
but in the end I decided to substitute a time switch we had next to our front
door with a Sonoff S20. I flashed ESPHome and used homeassistant to do the timed
switches while the button on the S20 is now used to switch some garden lights.&lt;/p&gt;
&lt;h3&gt;Remote 433 MHz sensors&lt;/h3&gt;
&lt;p&gt;I have also a MQTT broker which is solely used to add 433 MHz based remote
temperature senders to Home Assistant, as these have been around the house for
quite a long time already. This is done with a Realtek DVB-T USB Stick in
combination with &lt;a href="https://github.com/merbanan/rtl_433"&gt;rtl_433&lt;/a&gt; and a bridging
script which can be found
&lt;a href="https://github.com/merbanan/rtl_433/blob/master/examples/rtl_433_mqtt_hass.py"&gt;here&lt;/a&gt;.
The additional script is only needed to add autodiscovery for Home Assistant,
as &lt;code&gt;rtl_433&lt;/code&gt; can publish the values directly to MQTT.&lt;/p&gt;
&lt;p&gt;Collecting data from the remote sensors is done via&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rtl_433&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;433&lt;/span&gt;.92M&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;433&lt;/span&gt;.66M&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;433&lt;/span&gt;.88M&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;868&lt;/span&gt;.33M&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;si&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;newmodel&lt;span class="w"&gt; &lt;/span&gt;-F&lt;span class="w"&gt; &lt;/span&gt;mqtt://mqqt.server.local:1883,user&lt;span class="o"&gt;=&lt;/span&gt;username,pass&lt;span class="o"&gt;=&lt;/span&gt;password&lt;span class="w"&gt; &lt;/span&gt;-F&lt;span class="w"&gt; &lt;/span&gt;kv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note the specified protocols, you most likely have to adjust them. Limiting the
protocols was quite important, as otherwise even tire pressure sensors from
passing cars were added to Home Assistant. As I am also using sensors operating
at 868 MHz I have to use an 17cm antenna, otherwise the reception is very bad.
I am therefore also cycling the used frequencies every 2 minutes (most sensors
transmit the signal once every minute.)&lt;/p&gt;
&lt;p&gt;As there are 5 sensors in total I used the
&lt;a href="https://www.home-assistant.io/integrations/min_max/"&gt;Min/Max&lt;/a&gt; integration from
Home Assistant to generate a single value for the outside temperature. As
usually some of the sensors are in direct sunlight this value is just the
lowest reported. I then generate a 24 hour average using a custom
&lt;a href="https://github.com/Limych/ha-average"&gt;ha-average&lt;/a&gt; component to remove the
daily cycle.&lt;/p&gt;
&lt;h3&gt;Power meter&lt;/h3&gt;
&lt;p&gt;There is now also a ESP8266 based sensor to monitor the power meter.
The power meter provided by the local grid operator has three different
communication interfaces utilizing infrared LEDs. There is an info interface
which provides the total energy in kWh via the SML protocol, but the power
meter does not provide the current power (if yours does provide the power,
there is a nice firmware by Michael Rüttgers available &lt;a href="https://github.com/mruettgers/SMLReader"&gt;on
Github&lt;/a&gt; to process the output and
publish the information via MQTT). A bidirectional interface is sealed and
requires additional commands via an IR LED.&lt;/p&gt;
&lt;p&gt;Luckily there is another interface where the IR LED simply emits 10000
pulses/kWh. I used a BPW 40 phototransistor to register the pulses which are
emitted and count them via the ESPHome pulse counter. See
&lt;a href="https://esphome.io/cookbook/power_meter.html"&gt;here&lt;/a&gt; for details, wiring as for
the SML reader.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Show MPRIS music credits in the XFCE Panel</title><link href="https://www.maltegerken.de/blog/2020/10/show-mpris-music-credits-in-the-xfce-panel/" rel="alternate"/><published>2020-10-02T08:24:26+02:00</published><updated>2025-03-12T16:09:36+01:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2020-10-02:/blog/2020/10/show-mpris-music-credits-in-the-xfce-panel/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Update 2024&lt;/strong&gt;: I updated the script to the version actually in use, with some
minor improvements and some added features.&lt;/p&gt;
&lt;p&gt;I usually listen to music while working and every once in a while I ask
myself what the current track might be. I could switch to my music player or …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Update 2024&lt;/strong&gt;: I updated the script to the version actually in use, with some
minor improvements and some added features.&lt;/p&gt;
&lt;p&gt;I usually listen to music while working and every once in a while I ask
myself what the current track might be. I could switch to my music player or
have a look in the sound control plugin of the XFCE panel, but that involves
clicking or moving the focus. I was looking for a way to just display the current
tracks artist und title in the panel, but there was no indicator for that.&lt;/p&gt;
&lt;p&gt;I came up with a small script which is called periodically by the &lt;a href="https://docs.xfce.org/panel-plugins/xfce4-genmon-plugin"&gt;Generic
Monitor plugin&lt;/a&gt;. The
script has a dependency on &lt;a href="https://github.com/altdesktop/playerctl"&gt;playerctl&lt;/a&gt;
which is used to get the current metadata from players which have a MPRIS D-Bus
interface. The script will display the current title and artist if
something is playing and pad the output with spaces to the left. This is done to
prevent the indicator in the middle of the screen to move around to much when
the length of the information changes. As I do not use a monospaced font there
is some difference none the less, but it is negligible.&lt;/p&gt;
&lt;p&gt;The script is as following, it makes it also possible to click on the panel
item to pause or unpause the current player:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;player&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;playerctl&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{{playerName}} {{status}}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Playing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f1&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;playpausecmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;playerctl play-pause&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$player&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;playerctl&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$player&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;metadata&lt;span class="w"&gt; &lt;/span&gt;title&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;playerctl&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$player&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;metadata&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;artist&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;playerctl&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$player&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;metadata&lt;span class="w"&gt; &lt;/span&gt;artist&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;album&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;playerctl&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$player&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;metadata&lt;span class="w"&gt; &lt;/span&gt;album&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$artist&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;artist&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;47&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;tool&amp;gt;%s\n%s\n%s&amp;lt;/tool&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$artist&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$album&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/&amp;amp;/&amp;amp;amp;/&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;txt&amp;gt;%50s&amp;lt;/txt&amp;gt;\n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$text&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/&amp;amp;/&amp;amp;amp;/&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;txtclick&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$playpausecmd&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/txtclick&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;css&amp;gt;.genmon_value { padding-left: 5px; padding-right: 5px}&amp;lt;/css&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is some inconsistency with the &lt;code&gt;playerctl metadata artist&lt;/code&gt; command, as
this will display the first available artist. If the current player does not
provide one it will look at the next player. The radio streams I tested only had
the &lt;code&gt;icy-title&lt;/code&gt; tag set, so the script will check if the active player actually
provides the &lt;code&gt;artist&lt;/code&gt; value before extracting it. This works also for Chrome,
so e.g. YouTube videos will also be displayed with the uploader and the title.&lt;/p&gt;
&lt;p&gt;For me it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image showing a sample track in the panel" src="https://www.maltegerken.de/images/mpris-monitor.png"&gt;&lt;/p&gt;</content><category term="linux"/></entry><entry><title>Various useful PDF manipulation commands</title><link href="https://www.maltegerken.de/blog/2020/02/various-useful-pdf-manipulation-commands/" rel="alternate"/><published>2020-02-20T11:56:12+01:00</published><updated>2023-12-19T21:01:57+01:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2020-02-20:/blog/2020/02/various-useful-pdf-manipulation-commands/</id><summary type="html">&lt;h3&gt;Merging and rotating PDFs&lt;/h3&gt;
&lt;p&gt;Merging PDFs can be easily done with &lt;code&gt;pdftk&lt;/code&gt;. You can also use this tool to select
only specific pages from your document or rotate pages. This is my go-to tool if I
don't have to manipulate pages beyond rotation.&lt;/p&gt;
&lt;p&gt;To &lt;strong&gt;concatenate all PDFs&lt;/strong&gt; in the working …&lt;/p&gt;</summary><content type="html">&lt;h3&gt;Merging and rotating PDFs&lt;/h3&gt;
&lt;p&gt;Merging PDFs can be easily done with &lt;code&gt;pdftk&lt;/code&gt;. You can also use this tool to select
only specific pages from your document or rotate pages. This is my go-to tool if I
don't have to manipulate pages beyond rotation.&lt;/p&gt;
&lt;p&gt;To &lt;strong&gt;concatenate all PDFs&lt;/strong&gt; in the working directory use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdftk&lt;span class="w"&gt; &lt;/span&gt;*.pdf&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;filename.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To &lt;strong&gt;select only pages&lt;/strong&gt; 1-3 and 5 from one document use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdftk&lt;span class="w"&gt; &lt;/span&gt;input.pdf&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;-3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;filename.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This even works with pages from multiple input files&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdftk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;input1.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;other_file.pdf&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;A1&lt;span class="w"&gt; &lt;/span&gt;A2&lt;span class="w"&gt; &lt;/span&gt;B7&lt;span class="w"&gt; &lt;/span&gt;B3&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;filename.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Rotation can be done with the &lt;code&gt;rotate&lt;/code&gt; subcommand, to rotate page 4 by 180 degrees use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdftk&lt;span class="w"&gt; &lt;/span&gt;input.pdf&lt;span class="w"&gt; &lt;/span&gt;rotate&lt;span class="w"&gt; &lt;/span&gt;4south&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;output.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is also possible to combine everything&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdftk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;input1.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;other_file.pdf&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;A1left&lt;span class="w"&gt; &lt;/span&gt;B1left&lt;span class="w"&gt; &lt;/span&gt;B2right&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;filename.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See also the &lt;a href="https://linux.die.net/man/1/pdftk"&gt;manpage for details&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Printing in special arrangements&lt;/h3&gt;
&lt;p&gt;Assuming you have a PDF and want to print that as a brochure or you want to
print one A5 page two times on an A4 page. A useful tool for that is &lt;code&gt;pdfjam&lt;/code&gt;,
which you might already have installed. At least in Archlinux it is included in
the &lt;code&gt;texlive-core&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Brochure or Book printing&lt;/strong&gt; of a document&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdfbook&lt;span class="w"&gt; &lt;/span&gt;input.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also set the output format using &lt;code&gt;pdfbook2&lt;/code&gt; (which should be available
using TeX Live) with &lt;code&gt;pdfbook2 --paper=a5paper input.pdf&lt;/code&gt; to some paper format
known to LaTex. Use the &lt;code&gt;--short-edge&lt;/code&gt; option if you need short edge double
sided printing (See also &lt;code&gt;pdfbook2 --help&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Print &lt;strong&gt;single page A5 document two times on A4&lt;/strong&gt; sheet&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdfjam&lt;span class="w"&gt; &lt;/span&gt;--nup&lt;span class="w"&gt; &lt;/span&gt;2x1&lt;span class="w"&gt; &lt;/span&gt;--landscape&lt;span class="w"&gt; &lt;/span&gt;--outfile&lt;span class="w"&gt; &lt;/span&gt;out.pdf&lt;span class="w"&gt; &lt;/span&gt;input.pdf&lt;span class="w"&gt; &lt;/span&gt;input.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This can also be done as a script which handles input file rotation correctly&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/zsh&lt;/span&gt;

&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;outfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$infile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Input file required!&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Output file required!&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;pdfinfo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$infile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Pages&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[0-9]\+&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;One single page documents!&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="nv"&gt;wdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;dims&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(@f)&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;pdfinfo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$infile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Page size&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[0-9]\+\.[0-9]\+&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;landscape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;bc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$dims&lt;/span&gt;&lt;span class="s2"&gt;[1] &amp;gt;= &lt;/span&gt;&lt;span class="nv"&gt;$dims&lt;/span&gt;&lt;span class="s2"&gt;[2]&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$landscape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-eq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;pdfjam&lt;span class="w"&gt; &lt;/span&gt;--angle&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--fitpaper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--rotateoversize&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;--outfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/rot.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$infile&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$infile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/rot.pdf
&lt;span class="k"&gt;fi&lt;/span&gt;

pdfjam&lt;span class="w"&gt; &lt;/span&gt;--nup&lt;span class="w"&gt; &lt;/span&gt;2x1&lt;span class="w"&gt; &lt;/span&gt;--landscape&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;--outfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/out.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/rot.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/rot.pdf

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$landscape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-eq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;pdfjam&lt;span class="w"&gt; &lt;/span&gt;--angle&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;270&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--fitpaper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--rotateoversize&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--quiet&lt;span class="w"&gt; &lt;/span&gt;--outfile&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/out.pdf
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;/out.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$outfile&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$wdir&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which can be used easily like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./a5-to-double-a4&lt;span class="w"&gt; &lt;/span&gt;input.pdf&lt;span class="w"&gt; &lt;/span&gt;out.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the script above some rotation commands are also used: &lt;code&gt;pdf90&lt;/code&gt; and &lt;code&gt;pdf270&lt;/code&gt;&lt;/p&gt;</content><category term="linux"/></entry><entry><title>Some notes on using digiKam as a photo manager</title><link href="https://www.maltegerken.de/blog/2017/03/some-notes-on-using-digikam-as-a-photo-manager/" rel="alternate"/><published>2017-03-08T18:15:01+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-03-08:/blog/2017/03/some-notes-on-using-digikam-as-a-photo-manager/</id><summary type="html">&lt;p&gt;Digikam is a very powerful and complex software to manage photos. I was using
shotwell previously for quite some time, but it's capabilities are limited.
Wherever you go, digiKam is recommended instead.&lt;/p&gt;
&lt;p&gt;The best things in digiKam so far are hierarchical tags
and automatic face detection. But on the other …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Digikam is a very powerful and complex software to manage photos. I was using
shotwell previously for quite some time, but it's capabilities are limited.
Wherever you go, digiKam is recommended instead.&lt;/p&gt;
&lt;p&gt;The best things in digiKam so far are hierarchical tags
and automatic face detection. But on the other hand: why is it not possible to
simply export the images and remove metadata or resize during that process?
You even have to use the 'external Storage exporter'-Plugin, which is
not included in digiKam, but lives in the kipi-Plugins.&lt;/p&gt;
&lt;p&gt;If you use oldstyle harddrives to store your photos make sure to save the digiKam
database on some fast SSD storage. The performance improvements are worth it.&lt;/p&gt;
&lt;p&gt;In the first version of this post I had some trouble with digiKam crashes, but
I haven't encountered any in the last years.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Automatically adding a transparent background with ImageMagick</title><link href="https://www.maltegerken.de/blog/2017/01/automatically-adding-a-transparent-background-with-imagemagick/" rel="alternate"/><published>2017-01-18T20:33:47+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-18:/blog/2017/01/automatically-adding-a-transparent-background-with-imagemagick/</id><summary type="html">&lt;p&gt;Yesterday I had to convert some JPEG images with a white background into a PNG with a transparent background. While it is possible to do this by just replacing white with transparent, this also replaces white in other parts of the image where this is not intended. So the better …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Yesterday I had to convert some JPEG images with a white background into a PNG with a transparent background. While it is possible to do this by just replacing white with transparent, this also replaces white in other parts of the image where this is not intended. So the better way is to select all the white regions connected to a certain point, using a fuzzy matcher to avoid leaving fragments. This worked as intended:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;convert&lt;span class="w"&gt; &lt;/span&gt;infile.jpg&lt;span class="w"&gt; &lt;/span&gt;-fill&lt;span class="w"&gt; &lt;/span&gt;transparent&lt;span class="w"&gt; &lt;/span&gt;-fuzz&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;-floodfill&lt;span class="w"&gt; &lt;/span&gt;+0+0&lt;span class="w"&gt; &lt;/span&gt;white&lt;span class="w"&gt; &lt;/span&gt;outfile.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From various posts on the ImageMagick forum and Stackoverflow.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Download files using Python 3</title><link href="https://www.maltegerken.de/blog/2017/01/download-files-using-python-3/" rel="alternate"/><published>2017-01-18T20:33:47+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-18:/blog/2017/01/download-files-using-python-3/</id><content type="html">&lt;p&gt;To download files accessible over HTTP(S) where you are generating their URLs with Python 3, saving can be done with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlretrieve&lt;/span&gt;
&lt;span class="n"&gt;urlretrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;local_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="python"/></entry><entry><title>Commonly needed OpenSSL commands</title><link href="https://www.maltegerken.de/blog/2017/01/commonly-needed-openssl-commands/" rel="alternate"/><published>2017-01-06T16:39:57+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-06:/blog/2017/01/commonly-needed-openssl-commands/</id><content type="html">&lt;p&gt;Very handy list of needed commands:
&lt;a href="https://www.sslshopper.com/article-most-common-openssl-commands.html"&gt;https://www.sslshopper.com/article-most-common-openssl-commands.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is especially useful if you hve to check details of a certificate, but
also to check which certificate is serverd on non HTTP protocols.&lt;/p&gt;</content><category term="linux"/></entry><entry><title>How to test a mail server from the command line</title><link href="https://www.maltegerken.de/blog/2017/01/how-to-test-a-mail-server-from-the-command-line/" rel="alternate"/><published>2017-01-06T16:39:57+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-06:/blog/2017/01/how-to-test-a-mail-server-from-the-command-line/</id><summary type="html">&lt;p&gt;As I am currently setting up a new mail server, I had to test the new server
manually (As of now, the DNS records are not changed, so mail clients are
problematic).&lt;/p&gt;
&lt;p&gt;If you want to test plain text ports like standard postfix, go simply with
&lt;code&gt;telnet localhost 25&lt;/code&gt;. If …&lt;/p&gt;</summary><content type="html">&lt;p&gt;As I am currently setting up a new mail server, I had to test the new server
manually (As of now, the DNS records are not changed, so mail clients are
problematic).&lt;/p&gt;
&lt;p&gt;If you want to test plain text ports like standard postfix, go simply with
&lt;code&gt;telnet localhost 25&lt;/code&gt;. If you try this remotely from home (on the public
interface), you will be kicked out by the server, because usually IP-ranges
from ISPs for dynamic allocations are blocked. So use this directly on your
server or from another server. Common things like &lt;code&gt;helo&lt;/code&gt; and &lt;code&gt;ehlo&lt;/code&gt; might work,
but 'sending' mail without authentication should fail, even for adresses the
server is responsible for.&lt;/p&gt;
&lt;p&gt;The other part is the SMTP submission, which should be on port 587 for
STARTSSL. This service is used by the mail client to send mails, therefore it
is usually required to use encryption (test this with telnet and check if auth
is allowed). Doing encryption with telnet is not possible, so use openssl for
STARTTLS in this case:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;s_client&lt;span class="w"&gt; &lt;/span&gt;-starttls&lt;span class="w"&gt; &lt;/span&gt;smtp&lt;span class="w"&gt; &lt;/span&gt;-crlf&lt;span class="w"&gt; &lt;/span&gt;-connect&lt;span class="w"&gt; &lt;/span&gt;your.mail.host:587
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After that usage is as with the telnet client on port 25, but for sending mail
you must authenticate yourself. For plain auth, use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;auth plain [user/pass string]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;with the user and password string generated with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;perl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;MMIME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Base64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;print encode_base64(&amp;quot;\000user\@mdomain.com\000password&amp;quot;);&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that @ has to be escaped and the &lt;code&gt;\000&lt;/code&gt; must remain in place.&lt;/p&gt;
&lt;p&gt;See for example this Microsoft site for possible SMTP commands:
&lt;a href="https://technet.microsoft.com/en-us/library/aa996114(v=exchg.65).aspx"&gt;https://technet.microsoft.com/en-us/library/aa996114(v=exchg.65).aspx&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wiki.zimbra.com/wiki/Simple_Troubleshooting_For_SMTP_Via_Telnet_And_Openssl"&gt;https://wiki.zimbra.com/wiki/Simple_Troubleshooting_For_SMTP_Via_Telnet_And_Openssl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="linux"/></entry><entry><title>Migrate a VM from VirtualBox to libvirt</title><link href="https://www.maltegerken.de/blog/2017/01/migrate-a-vm-from-virtualbox-to-libvirt/" rel="alternate"/><published>2017-01-02T15:51:29+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-02:/blog/2017/01/migrate-a-vm-from-virtualbox-to-libvirt/</id><summary type="html">&lt;p&gt;Assuming you are using KVM as the libvirt backend:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Find location of harddrive in filesystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release and remove harddrive from VirtualBox (has not worked without this step)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert to raw image with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;VBoxManage&lt;span class="w"&gt; &lt;/span&gt;clonehd&lt;span class="w"&gt; &lt;/span&gt;--format&lt;span class="w"&gt; &lt;/span&gt;RAW&lt;span class="w"&gt; &lt;/span&gt;vboximage.vdi&lt;span class="w"&gt; &lt;/span&gt;rawimage.raw
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert to qcow2 image with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;qemu-img&lt;span class="w"&gt; &lt;/span&gt;convert&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;raw&lt;span class="w"&gt; &lt;/span&gt;rawimage …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;Assuming you are using KVM as the libvirt backend:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Find location of harddrive in filesystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Release and remove harddrive from VirtualBox (has not worked without this step)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert to raw image with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;VBoxManage&lt;span class="w"&gt; &lt;/span&gt;clonehd&lt;span class="w"&gt; &lt;/span&gt;--format&lt;span class="w"&gt; &lt;/span&gt;RAW&lt;span class="w"&gt; &lt;/span&gt;vboximage.vdi&lt;span class="w"&gt; &lt;/span&gt;rawimage.raw
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert to qcow2 image with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;qemu-img&lt;span class="w"&gt; &lt;/span&gt;convert&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;raw&lt;span class="w"&gt; &lt;/span&gt;rawimage.raw&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;qcow2&lt;span class="w"&gt; &lt;/span&gt;image.qcow2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy image file as root to &lt;code&gt;/data/libvirt/images&lt;/code&gt; (Adapt for your system)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new virtual machine with &lt;code&gt;virt-manager&lt;/code&gt; and select the image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If it should be connected to physical network: Change Network source to shared device name and select &lt;code&gt;br0&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start machine, maybe it is necessary to update the device name in &lt;code&gt;/etc/network/interfaces&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=""&gt;https://seravo.fi/2012/migrating-from-virtualbox-to-virt-manager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="linux"/></entry><entry><title>A new beginning</title><link href="https://www.maltegerken.de/blog/2017/01/a-new-beginning/" rel="alternate"/><published>2017-01-02T14:57:11+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-02:/blog/2017/01/a-new-beginning/</id><content type="html">&lt;p&gt;It has been a while since the last time I published something on this page. So I made some changes, from german to english, new layout and more as a notebook than a blog. We will see if this blog survives this time.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Debugging with IPython shell</title><link href="https://www.maltegerken.de/blog/2017/01/debugging-with-ipython-shell/" rel="alternate"/><published>2017-01-02T14:57:11+01:00</published><updated>2021-07-11T19:08:51+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2017-01-02:/blog/2017/01/debugging-with-ipython-shell/</id><content type="html">&lt;p&gt;Debugging in Python is very easy with IPython, you don't need pdb or so, just do a simple&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;IPython&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;embed&lt;/span&gt;

&lt;span class="c1"&gt;#Inside some functions&lt;/span&gt;
&lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's all.&lt;/p&gt;
&lt;h3&gt;Reference&lt;/h3&gt;
&lt;p&gt;See &lt;a href=""&gt;https://ipython.org/ipython-doc/3/api/generated/IPython.terminal.embed.html#IPython.terminal.embed.embed&lt;/a&gt;&lt;/p&gt;</content><category term="python"/></entry><entry><title>Munin plugin für Vodafone LTE Datenverbrauch</title><link href="https://www.maltegerken.de/blog/2013/08/munin-plugin-fur-vodafone-lte-datenverbrauch/" rel="alternate"/><published>2013-08-23T16:06:00+02:00</published><updated>2013-08-23T16:06:00+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2013-08-23:/blog/2013/08/munin-plugin-fur-vodafone-lte-datenverbrauch/</id><summary type="html">&lt;p&gt;Wir haben bei uns zuhause seit geraumer Zeit einen Internetzugang über LTE von Vodafone. Zum einen sei gesagt, dass dieser Zugang der bislang stabilste ist, den wir hatten. Auch die Geschwindigkeit ist sehr gut. Was jedoch fehlt, ist eine Übersicht über den Datenverbrauch direkt im Router. Auch kann der Router …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Wir haben bei uns zuhause seit geraumer Zeit einen Internetzugang über LTE von Vodafone. Zum einen sei gesagt, dass dieser Zugang der bislang stabilste ist, den wir hatten. Auch die Geschwindigkeit ist sehr gut. Was jedoch fehlt, ist eine Übersicht über den Datenverbrauch direkt im Router. Auch kann der Router kein SNMP, was natürlich schade ist.&lt;/p&gt;
&lt;p&gt;Deswegen habe ich eine Plugin für Munin geschrieben, womit der Verbrauch getrackt werden kann. Selbstverstädlich cached das Plugin die Werte, da auch die Website nicht live ist, somit kann man die Server von Vodafone entlasten, wenn man nicht alle 5 Minuten den Verbrauch abfragt. Das Plugin steht unter der MIT Lizenz und ist in Python geschrieben.&lt;/p&gt;
&lt;p&gt;Sollte also jemand, der auch einen LTE-Zugang von Vodafone besitzt, die Entwicklung seines Datenverbrauchs verfolgen wollen, kann er das Plugin gerne nutzen.&lt;/p&gt;
&lt;p&gt;Projektseite: &lt;a href="https://git.maltegerken.de/malte.gerken/munin-vodafone-traffic"&gt;Gitlab Seite zum Plugin&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Update 15. September 2013&lt;/h3&gt;
&lt;p&gt;Das Plugin läuft nun auch mit der neuen Seite von Vodafone.&lt;/p&gt;
&lt;h3&gt;Update 14. Juli 2014&lt;/h3&gt;
&lt;p&gt;Es existiert jetzt eine Minimalversion des Skriptes, welche nicht mehr auf Munin aufsetzt, sondern einen Graphen mittels GNUPlot erstellt.&lt;/p&gt;
&lt;p&gt;Projektseite: &lt;a href="https://git.maltegerken.de/malte.gerken/simple-vodafone-traffic-logger"&gt;Neue Minimalversion&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ich habe aktuell nur noch diese Version im Einsatz, die alte wird zur Zeit auch nicht gepflegt.&lt;/p&gt;
&lt;h3&gt;Update 2017&lt;/h3&gt;
&lt;p&gt;Mangels Internetanschluss von Vodafone benutze ich das Script nicht mehr selber, daher wird es auch nicht länger geupdated.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Evince und Zugriffsrechte</title><link href="https://www.maltegerken.de/blog/2013/05/evince-und-zugriffsrechte/" rel="alternate"/><published>2013-05-31T13:12:00+02:00</published><updated>2013-05-31T13:12:00+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2013-05-31:/blog/2013/05/evince-und-zugriffsrechte/</id><summary type="html">&lt;p&gt;Evince ist der Dokumentenbetrachter aus der Gnome-Suite, welcher unter anderen PDF-Dateien darstellen kann. Zumindest nutze ich ihn nur dafür. Momentan habe ich jedoch ein Problem mit der "Save a Copy" Funktion von Evince, da dieser die geöffnete Datei nur unter neuem Namen abspeichert, jedoch Zugriffsrechte nicht ändert (z.B. mittels …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Evince ist der Dokumentenbetrachter aus der Gnome-Suite, welcher unter anderen PDF-Dateien darstellen kann. Zumindest nutze ich ihn nur dafür. Momentan habe ich jedoch ein Problem mit der "Save a Copy" Funktion von Evince, da dieser die geöffnete Datei nur unter neuem Namen abspeichert, jedoch Zugriffsrechte nicht ändert (z.B. mittels gesetztem umask). Ich öffne meine PDF meist direkt aus Firefox heraus und dieser speichert sie dann temporär unter &lt;code&gt;/tmp&lt;/code&gt; mit den Rechten 400, also nur ein Leserecht für den Besitzer, ab.&lt;/p&gt;
&lt;p&gt;Probleme gibt es nun zum Beispiel, wenn man eine aktualisierte version unter dem gleichen Namen speichern möchte. Da Evince nun versucht die Datei zu ändern, gibt es natürlich eine Fehlermeldung. Man kann natürlich die Datei erst löschen und dann speichern, aber das ist nur wieder ein Umweg. Als alternative kann man mit einem Einzeiler in der Shell die Rechte aller PDF-Dateien anpassen (z.B. auf 600):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*.pdf&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chmod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="linux"/><category term="linux"/><category term="opensource"/></entry><entry><title>APT-Repository aufsetzen</title><link href="https://www.maltegerken.de/blog/2012/07/apt-repository-aufsetzen/" rel="alternate"/><published>2012-07-17T13:10:00+02:00</published><updated>2012-07-17T13:10:00+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2012-07-17:/blog/2012/07/apt-repository-aufsetzen/</id><summary type="html">&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Für ein eigenes APT-Repository gibt es mehrere Gründe. Ich hatte den Anreiz, da ich ein Metapaket erstellt habe, mit welchem ich auf jedem neu aufgesetztem Computer immer die selben Pakete installieren kann. Um das Metapaket bereitstellen zu können, und bei einer Änderung der zu installierenden Pakete wenig aufwand zu …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Für ein eigenes APT-Repository gibt es mehrere Gründe. Ich hatte den Anreiz, da ich ein Metapaket erstellt habe, mit welchem ich auf jedem neu aufgesetztem Computer immer die selben Pakete installieren kann. Um das Metapaket bereitstellen zu können, und bei einer Änderung der zu installierenden Pakete wenig aufwand zu haben, habe ich dieses in ein eigenes Repository gepackt. Ist leichter als es sich anhört:) Als das Repository "fertig" war, habe ich es gleich erweitert, da ich Probleme mit den Paketquellen von Owncloud habe. Ich habe also deren Quelle gespiegelt und die .deb-Pakete übernommen (Und das ganze gleich mit einem Skript automatisiert).&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2&gt;Umsetzung&lt;/h2&gt;
&lt;p&gt;Für eine Paketquelle braucht man zunächst mal einen PGP-Schlüssel, um diese signieren zu können. Es sei noch anzumerken, dass ich einen recht einfachen Weg gegangen bin, der dafür leicht umzusetzen ist. Dafür werden alle Pakete unterhalb des Root-Ordner (hier /path/to/repo) des Repos platziert, eine Aufteilung in Unterordner ist kein Problem. Nun wird das folgende Script ausgeführt, es erstellt die benötigten Release und Package Dateien und signiert die Releasedatei. Das Script sollte somit unter dem Benutzer ausgeführt werden, unter welchem auch das PGP-Zertifikat erstellt worden ist. Eine etwas detailliertere Beschriebung findet man bei &lt;a href="http://michael.stapelberg.de/Artikel/Debian_Repository"&gt;Michael Stapelberg&lt;/a&gt;, wo ich auch die meisten Teile hergenommen habe.&lt;/p&gt;
&lt;p&gt;Script &lt;code&gt;update_aptrepo.sh&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;make_apt_archive&lt;span class="o"&gt;(){&lt;/span&gt;
&lt;span class="c1"&gt;# alte Dateien löschen&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;Release
rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;Release.gpg
rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;Packages
rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;Packages.gz

&lt;span class="c1"&gt;# Packages erzeugen, jeweils mit und ohne gzip&lt;/span&gt;
apt-ftparchive&lt;span class="w"&gt; &lt;/span&gt;packages&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Packages
gzip&lt;span class="w"&gt; &lt;/span&gt;-9&lt;span class="w"&gt; &lt;/span&gt;Packages
apt-ftparchive&lt;span class="w"&gt; &lt;/span&gt;packages&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Packages

&lt;span class="c1"&gt;# Release Datei erzeugen&lt;/span&gt;
apt-ftparchive&lt;span class="w"&gt; &lt;/span&gt;release&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Release

&lt;span class="c1"&gt;# Signieren&lt;/span&gt;
gpg&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;Release.gpg&lt;span class="w"&gt; &lt;/span&gt;-ba&lt;span class="w"&gt; &lt;/span&gt;Release
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/path/to/archiv
make_apt_archive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Es ist nun ein leichtes, mehrere Repositories in Unterordner des Webroots zu erzeugen, indem zum Beispiel einfach ein&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd /path/to/otherarchiv
make_apt_archive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An das Script angehängt wird.&lt;/p&gt;
&lt;p&gt;Anschließend wird der Ordner mit dem Repo über einen Webserver freigegeben, so dass der erste Ordner über&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;http://repo.example.com/archiv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;und der zweite über&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;http://repo.example.com/otherarchiv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;zu erreichen ist. Die Paketquelle kann dann hinzugefügt werden, die entsprechende Zeile für die &lt;code&gt;sources.list&lt;/code&gt; lautet dann&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;deb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://repo.example.com/archiv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wenn man nun versucht, Pakete aus dieser Paketquelle zu installieren, wird die Paketverwaltung meckern, da sie die Authentizität der Paketquelle nicht überprüfen kann. Dies liegt daran, dass wir APT noch mit dem PGP-Public-Key bekannt machen müssen. Angenommen, der Publickey ist unter der Datei PublicKey gespeichert, so lautet der Befehl&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;apt-key add PublicKey
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Dann sollte die Paketquelle ordnungsgemäß funktionieren.&lt;/p&gt;
&lt;p&gt;Wer doch lieber ein etwas komplexeres Setting möchte, sollte sich den Artikel von &lt;a href="http://www.pro-linux.de/artikel/2/1459/apt-repositorium-erstellen-variante-1-apt-ftparchive.html"&gt;Pro-Linux&lt;/a&gt; einmal durchlesen.&lt;/p&gt;
&lt;h2&gt;Quellen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://michael.stapelberg.de/Artikel/Debian_Repository"&gt;http://michael.stapelberg.de/Artikel/Debian_Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pro-linux.de/artikel/2/1459/apt-repositorium-erstellen-variante-1-apt-ftparchive.html"&gt;http://www.pro-linux.de/artikel/2/1459/apt-repositorium-erstellen-variante-1-apt-ftparchive.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="linux"/><category term="linux"/><category term="opensource"/></entry><entry><title>Unison</title><link href="https://www.maltegerken.de/blog/2012/07/unison/" rel="alternate"/><published>2012-07-14T14:44:00+02:00</published><updated>2012-07-14T14:44:00+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2012-07-14:/blog/2012/07/unison/</id><summary type="html">&lt;p&gt;Dieser Artikel soll einen Überblick über mein aktuelles Unison-Setting liefern und allgemein die Konfiguration und Inbetriebnahme von Unison behandeln. Aber Schritt für Schritt.&lt;/p&gt;
&lt;h2&gt;Was ist Unison?&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;Unison&lt;/a&gt; ist ein freies Programm, mit dem man Ordner synchronisieren kann. Dabei können die Ordner auf dem selben Rechner sein, per Samba-Freigabe eingebunden sein …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Dieser Artikel soll einen Überblick über mein aktuelles Unison-Setting liefern und allgemein die Konfiguration und Inbetriebnahme von Unison behandeln. Aber Schritt für Schritt.&lt;/p&gt;
&lt;h2&gt;Was ist Unison?&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;Unison&lt;/a&gt; ist ein freies Programm, mit dem man Ordner synchronisieren kann. Dabei können die Ordner auf dem selben Rechner sein, per Samba-Freigabe eingebunden sein, oder einfach über SSH erreichbar sein. Außerdem besteht die Möglichkeit, einen Unison-Dienst zu starten, welcher auf einem festgelegten Port lauscht und darüber synchronisiert. Unison ist für UNIX-artige Systeme sowie Windows verfügbar.&lt;/p&gt;
&lt;h2&gt;Installation und Konfiguration&lt;/h2&gt;
&lt;p&gt;Unison wird über das Paket &lt;code&gt;unison&lt;/code&gt; bzw. &lt;code&gt;unison-gtk&lt;/code&gt; installiert, danach ist die graphische Oberfläche über den Befehl &lt;code&gt;unison&lt;/code&gt; verfügbar. Um zwei lokale Ordner synchron zu halten, ist nun nur noch Unison zu konfigurieren. Dies geschieht über die Graphische Oberfläche, sämtliche Schritte sollten selbsterklärend sein. Für den rein lokalen Abgleich ist nur &lt;code&gt;unison-gtk&lt;/code&gt; erforderlich. Interessanter ist für die meisten jedoch die Synchronisierung über das Netzwerk.&lt;!-- more --&gt;&lt;/p&gt;
&lt;p&gt;Ich gehe hier davon aus, dass ein Rechner als Server dient und alle anderen Clients sind, welche mit dem Server synchronisieren. Auf dem Server wird das Paket &lt;code&gt;unison&lt;/code&gt; sowie ein SSH-Server benötigt, sodass die Clients sich über SSH auf den Server verbinden können und dort den Server starten können. Es ist also nicht notwendig, dass Unison dauerhaft läuft. Auf den Clients muss man man das Paket &lt;code&gt;unison-gtk&lt;/code&gt; installieren, es sollte zudem ein SSH-Client installiert sein. Es ist darauf zu achten, dass die Synchronisierung nur funktioniert, wenn auf jedem Rechner die gleiche Version von Unison installiert ist. Nun ist auf jedem Client ein SSH-Zertifikat zu erzeugen und der Public-Key dem Server bekannt zu machen (z.B. mit &lt;code&gt;ssh-copy-id&lt;/code&gt;). Anschließend kann in Unison sehr einfach ein neues Profil angelegt werden, um die Synchronisierung zu starten, die kann beim ersten Mal je nach Datenmenge etwas dauern.&lt;/p&gt;
&lt;p&gt;Etwas knifflig sind Windows-Clients, da es für diese keinen wirklich tollen SSH-Client gibt. Laut &lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html#ssh-win"&gt;Unison Handbuch&lt;/a&gt; soll man Cygwin installieren, und dann den 'normalen' OpenSSH-Client nutzen, aber wer will schon eine ganze UNIX-Umgebung haben? Es geht also auch anders, und zwar mit plink und pagent, dies sind zwei Programme aus dem Putty-Umfeld, diese sind &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html"&gt;hier runterladbar&lt;/a&gt;. Zum erstellen eines Keys wird zudem noch PuttyGen benötigt. Wie das alles genau funktioniert, kann ich mittlerweile nicht mehr wirklich nachvollziehen, aber Google zeigt einem sehr brauchbare Ergebnisse an.&lt;/p&gt;
&lt;h2&gt;Meine Umgebung&lt;/h2&gt;
&lt;p&gt;Ich habe den Unison Server auf meinem RaspberryPi laufen, dieser stellt einen Teil der Daten auch per Samba-Freigabe zur Verfügung. Mit dem Server synchronisiere ich meinen Laptop, auf welchem Ubuntu 11.10 läuft sowie meinen Desktoprechner mit u.a. Windows XP. Diesen benötige ich hin und wieder für Arbeiten für die Uni, da bestimmte Programme nur für Windows verfügbar sind und eine virtuelle Maschine zu unpraktisch ist. Dieses Setting hat zudem den Vorteil, dass man bei komplexeren Arbeiten beide Computer gleichzeitig nutzen kann und die Daten mit wenigen Klicks synchron gehalten werden können. Da der RaspberryPi eh immer an ist, muss ich nicht noch vorher einen weiteren PC starten, dass war bis vor kurzem anders (Da gab es den ja noch nicht).&lt;/p&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;http://www.cis.upenn.edu/~bcpierce/unison/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wiki.ubuntuusers.de/Unison"&gt;http://wiki.ubuntuusers.de/Unison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="linux"/><category term="linux"/><category term="windows"/><category term="opensource"/></entry><entry><title>Mailman installieren</title><link href="https://www.maltegerken.de/blog/2012/05/mailman-installieren/" rel="alternate"/><published>2012-05-19T15:00:00+02:00</published><updated>2012-05-19T15:00:00+02:00</updated><author><name>Malte Gerken</name></author><id>tag:www.maltegerken.de,2012-05-19:/blog/2012/05/mailman-installieren/</id><summary type="html">&lt;p&gt;So, mal eine kleine Anleitung, wie man Mailman installieren kann, 
unter anderem für mich als Gedächtnisstütze:) Aber erstmal:&lt;/p&gt;
&lt;h2&gt;Was ist eigentlich Mailman?&lt;/h2&gt;
&lt;p&gt;Mailman ist ein Listenserver, welcher einem Mailinglisten 
bereitstellt. Das ist zum Beispiel nützlich, wenn man in einer 
größeren Gruppe kommunizieren will, kann zum Beispiel auch als eine 
Art …&lt;/p&gt;</summary><content type="html">&lt;p&gt;So, mal eine kleine Anleitung, wie man Mailman installieren kann, 
unter anderem für mich als Gedächtnisstütze:) Aber erstmal:&lt;/p&gt;
&lt;h2&gt;Was ist eigentlich Mailman?&lt;/h2&gt;
&lt;p&gt;Mailman ist ein Listenserver, welcher einem Mailinglisten 
bereitstellt. Das ist zum Beispiel nützlich, wenn man in einer 
größeren Gruppe kommunizieren will, kann zum Beispiel auch als eine 
Art Newsletter herhalten. Benutzer melden sich an einer Mailingliste 
an und erhalten dann die Mails, welche an diese Liste gehen. Man 
kann detailliert einstellen, wer an die Liste eine Mail schreiben 
darf und ob Anhänge erlaubt sind und noch vieles mehr. Man kann das 
ganze also auch als Forum betrachten, nur dass man neue Beiträge 
direkt in seinem Mailclient lesen kann.&lt;/p&gt;
&lt;h2&gt;Was wird für Mailman benötigt?&lt;/h2&gt;
&lt;p&gt;Um Mailman installieren zu können, sollte man ein paar Dinge haben:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Einen Server, auf dem man Root-Rechte hat&lt;/li&gt;
&lt;li&gt;Eine IP-Adresse, welche statisch ist (keine Wählverbindung!)&lt;/li&gt;
&lt;li&gt;Einen installierten und konfigurierten MTA (z.B. Postfix)&lt;/li&gt;
&lt;li&gt;Eine Domain, zu der man auch Subdomains aufschalten kann Dann kann es auch schon los gehen :) &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Die Installation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;HINWEIS: Das ist eher was für erfahrene Linuxer, die Wissen was 
sie tun und sich auch helfen können, wenn mal was nicht mehr geht!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ich zeige die Installation und auch die Konfiguration für Ubuntu 
10.04 Server Edition mit Postfix als MTA, es funtioniert aber auch 
mit anderen MTAs! Es ist lediglich folgendes Paket zu installieren:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mailman
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Danach müssen noch die Berechtigungen geprüft und berichtigt werden, 
ein Aufruf von &lt;code&gt;check_perms&lt;/code&gt; hilft hier weiter. Um die gefundenen 
Fehler zu korrigieren, das Script noch einmal mit dem Parameter &lt;code&gt;-f&lt;/code&gt; 
aufrufen, so oft, bis keine Änderung bei der Ausgabe mehr 
stattfindet oder halt nichts mehr gefunden wird. Eventuell ist dann 
noch etwas Handarbeit nötig, das Script scheitert anscheinend 
manchmal an Symlinks.&lt;/p&gt;
&lt;h2&gt;Die Konfiguration&lt;/h2&gt;
&lt;p&gt;Ein bisschen tricky, da man doch verhältnismäßig wenig verschiedene 
Anleitungen im Netz findet, also muss man ein wenig schauen, 
probieren und hoffen ;) Zuerst machen wir mal ein Backup von 
&lt;code&gt;/etc/postfix&lt;/code&gt;, man weiß ja nie, und Backups sind immer gut. Dann 
machen wir uns an die eigentliche Konfiguration:&lt;/p&gt;
&lt;h3&gt;Mailman&lt;/h3&gt;
&lt;p&gt;Zuerst Mailman, in der Datei &lt;code&gt;/etc/mailman/mm_cfg.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Die Sprache&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_SERVER_LANGUAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;en&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# Der MTA&lt;/span&gt;
&lt;span class="n"&gt;MTA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Postfix&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;#-------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Default domain for email addresses of newly created MLs&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_EMAIL_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;lists.example.de&amp;#39;&lt;/span&gt;
&lt;span class="c1"&gt;#-------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Default host for web interface of newly created MLs&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_URL_HOST&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;lists.example.de&amp;#39;&lt;/span&gt;
&lt;span class="c1"&gt;#-------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# Required when setting any of its arguments.&lt;/span&gt;
&lt;span class="n"&gt;add_virtualhost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_URL_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_EMAIL_HOST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;POSTFIX_STYLE_VIRTUAL_DOMAINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lists.example.de&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Der Listenverwalter&lt;/span&gt;
&lt;span class="n"&gt;DEB_LISTMASTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;postmaster@example.de&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ich gehe hier davon aus, dass Mailman auf einer eigenen Subdomain 
installiert wird (lists.*). Ein besonderer Augenmerk sollte auf der 
Zeile mit dem MTA liegen: Auch wenn im "Handbuch" von Mailman steht, 
dass für Postfix MTA=none gesetzt werden soll, hat dies bei mir 
nicht funktioniert, so geht es, allerdings mit Anführungszeichen! 
Nun legen wir unsere Verwaltungsliste an, sie heißt Mailman:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;newlist mailman
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Es werden dann ein paar Daten abgefragt, wie die Mail-Adresse des 
Listenverwalters. Soviel zu Mailman bisher, jetzt machen wir ihn mit 
Postfix bekannt.&lt;/p&gt;
&lt;h3&gt;Postfix&lt;/h3&gt;
&lt;p&gt;Als erstes editieren (gegebenenfalls anlegen) wir die Datei 
&lt;code&gt;/etc/postfix/transport&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lists.example.de    mailman:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An die main.cf fügen wir folgendes an, bzw. erweitern bestehende Einträge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# Mailman
relay_domains = lists.example.de
relay_recipient_maps = hash:/var/lib/mailman/data/virtual-mailman
transport_maps = hash:/etc/postfix/transport
mailman_destination_recipient_limit = 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nun folgt noch eine Änderung in der &lt;code&gt;master.cf&lt;/code&gt;, hier sind folgende 
zwei Zeilen einzufügen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hier sollte darauf geachtet werden, dass diese zwei Zeilen schon da 
sein können, das war bei mir der Fall, ich weis allerdings nicht 
warum.&lt;/p&gt;
&lt;h3&gt;Abschlussarbeiten&lt;/h3&gt;
&lt;p&gt;Zuerst werden Standard-Einstellungen für die erste Liste geladen, 
und ein Passwort zum erstellen neuer Listen angelegt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;config_list&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;/var/lib/mailman/data/sitelist.cfg&lt;span class="w"&gt; &lt;/span&gt;mailman
mmsitepass
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;und dann alle Änderungen übernehmen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;postmap&lt;span class="w"&gt; &lt;/span&gt;transport
/usr/lib/mailman/bin/genaliases
/etc/init.d/postfix&lt;span class="w"&gt; &lt;/span&gt;reload
/etc/init.d/mailman&lt;span class="w"&gt; &lt;/span&gt;start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Jetzt sollte Mailman starten, ohne dass es Probleme gibt, wenn das 
nicht der Fall ist, steht in der Fehlermeldung recht gut, woran es 
hapert. Wichtig ist hier auch, die Maillogs zu checken und Postfix 
zu testen, wer schickt sich nicht gerne viele nette Mails;) Jetzt 
ist man quasi schon fertig, aber das ganze ist noch etwas Benutzer 
unfreundlich, denn momentan kann man sich nur mit Mails an mailman 
in Listen eintragen usw. Auch fehlt ein Admininterface... Also wird 
noch schnell weiterkonfiguriert:&lt;/p&gt;
&lt;h3&gt;Apache&lt;/h3&gt;
&lt;p&gt;Mailman liefert bereits eine Apache Konfigurationsdatei mit, diese 
muss nur noch aktiviert werden:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ln&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/etc/mailman/apache.conf&lt;span class="w"&gt; &lt;/span&gt;/etc/apache2/sites-available/mailman
a2ensite&lt;span class="w"&gt; &lt;/span&gt;mailman
/etc/init.d/apache2&lt;span class="w"&gt; &lt;/span&gt;force-reload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Soweit, so leicht... Wenn gewünscht können in 
&lt;code&gt;/etc/mailman/apache.conf&lt;/code&gt; noch Änderungen vorgenommen werden, aber 
dann daran denken, dass diese erst bei einem Reload des Webservers 
berücksichtigt werden. Und das wars auch schon:)&lt;/p&gt;
&lt;h2&gt;Quellen und weitere Infos&lt;/h2&gt;
&lt;p&gt;Auch ich hab meine Infos ja woher, und zwar unter anderem hier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.ubuntu.com/community/Mailman"&gt;https://help.ubuntu.com/community/Mailman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gaiaes.com/content/configuring-mailman-ubuntu-postfix"&gt;http://gaiaes.com/content/configuring-mailman-ubuntu-postfix&lt;/a&gt; Hier kann man auch weitere Informationen erhalten, wenn man das Setting etwas verändern will.&lt;/li&gt;
&lt;/ul&gt;</content><category term="linux"/><category term="linux"/><category term="mail"/><category term="opensource"/></entry></feed>