<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Blog | dr. Sybren</title>
    <link>https://stuvel.eu/post/</link>
      <atom:link href="https://stuvel.eu/post/index.xml" rel="self" type="application/rss+xml" />
    <description>Blog</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-gb</language><copyright>© 2000-2026 Sybren A. Stüvel</copyright>
    <image>
      <url>https://stuvel.eu/img/logo.png</url>
      <title>Blog</title>
      <link>https://stuvel.eu/post/</link>
    </image>
    
    <item>
      <title>Dynamic DNS tool for TransIP</title>
      <link>https://stuvel.eu/post/2026-01-02-transip-dynamicdns/</link>
      <pubDate>Fri, 02 Jan 2026 16:13:03 +0100</pubDate>
      <guid>https://stuvel.eu/post/2026-01-02-transip-dynamicdns/</guid>
      <description>&lt;p&gt;My domains, like &lt;code&gt;stuvel.eu&lt;/code&gt; and &lt;code&gt;stüvel.eu&lt;/code&gt;, are hosted by TransIP. I&amp;rsquo;m in the
process of moving all my websites to some hardware at home, and my ISP contract
does not give me a fixed IP-adress. And since I didn&amp;rsquo;t like the solutions I
found online, I made my own.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/transip-dyndns&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TransIP DynDNS&lt;/a&gt; is a tool that periodically checks its own public IP
address, and if it changed, uses the TransIP API to update DNS records. That
way, these records are always pointing to the right address, ensuring my
websites remain reachable.&lt;/p&gt;
&lt;h3 id=&#34;example-configuration&#34;&gt;Example Configuration&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;general:
  IPv4: true
  IPv6: false   # Unfortunately my current ISP doesn&#39;t offer IPv6 yet.
  watch-period: 5m
account:
  username: TRANSIP_USERNAME
  private-key: /path/to/transip-dyndns.pem  # Private key obtained from TransIP.
records:
  # Expanded notation:
  - domain: example.com
    entry: my-home
    type: A

  # Collapsed notation:
  - { domain: &amp;quot;example.com&amp;quot;, entry: &amp;quot;my-home&amp;quot;, type: A }

  # By not specifying the type, both A and AAAA records will be updated.
  # This also depends on whether IPv4/IPv6 are disabled above.
  - { domain: &amp;quot;example.com&amp;quot;, entry: &amp;quot;my-home&amp;quot; }

  # Types other than A or AAAA need an explicit &#39;content field.
  # {{.IPv4}} and {{.IPv6}} will be replaced with the current IP address.
  - { domain: &amp;quot;example.com&amp;quot;, entry: &amp;quot;my-home&amp;quot;, type: TXT,
      content: &amp;quot;v=spf1 ip4:{{.IPv4}} ip6:{{.IPv6}} include:thirdpartydomain.com -all&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s more information in 
&lt;a href=&#34;https://gitlab.com/dr.sybren/transip-dyndns#transip-dynamic-dns-updater&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the README file&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;thanks&#34;&gt;Thanks&lt;/h3&gt;
&lt;p&gt;Many thanks to 
&lt;a href=&#34;https://github.com/jlentink/go-transip-dyndns&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;J Lentink&lt;/a&gt; for
making a similar tool, and releasing it under the MIT license. It helped me to
build this tool, which is a bit simpler to use. Mine has a smaller config, is
therefore easier to update, and it performs less API calls.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA project has been archived</title>
      <link>https://stuvel.eu/post/2025-04-16-python-rsa-archived/</link>
      <pubDate>Wed, 16 Apr 2025 10:42:06 +0200</pubDate>
      <guid>https://stuvel.eu/post/2025-04-16-python-rsa-archived/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m one of the original authors and the maintainer of 
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA&lt;/a&gt;.
Unfortunately I don&amp;rsquo;t have the time and brain space left to properly maintain
Python-RSA. As you can see from the lack of activity on the open issues, and the
lack of commits, that has been the case for a while now.&lt;/p&gt;
&lt;p&gt;As Python-RSA is included as a dependency in quite a few high-profile projects,
I don&amp;rsquo;t feel comfortable handing over the project to someone else. It&amp;rsquo;s just too
big of a risk.&lt;/p&gt;
&lt;p&gt;Thanks for having used this little library for so long, and in so many projects.
I truely didn&amp;rsquo;t expect that when I started working on it. Also big thanks to all
the people helping out and improving the project.&lt;/p&gt;
&lt;p&gt;There are improvements that haven&amp;rsquo;t made it into a new release. As I said, I
don&amp;rsquo;t have the time and the brain space to really investigate and oversee the
security impact of all those changes. It&amp;rsquo;s not a decision I&amp;rsquo;ve made lightly.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s it. If you want to keep the project alive, please fork it. Give it the
love it deserves, investigate those yet-unreleased improvements, and have a
project that&amp;rsquo;s then already better than how I left this one.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blender Conference 2024</title>
      <link>https://stuvel.eu/post/2024-10-27-blender-conference-2024/</link>
      <pubDate>Sun, 27 Oct 2024 22:43:38 +0100</pubDate>
      <guid>https://stuvel.eu/post/2024-10-27-blender-conference-2024/</guid>
      <description>&lt;p&gt;Blender Conference 2024 was amazing again, as always. Our talk &lt;strong&gt;A New Animation
System - Progress Report&lt;/strong&gt; was also received very well.&lt;/p&gt;
&lt;h2 id=&#34;presentation&#34;&gt;Presentation&lt;/h2&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/N7micU0YyOw&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&#34;slides&#34;&gt;Slides&lt;/h2&gt;
&lt;iframe src=&#39;https://stuvel.eu/files/bconf2024/&#39; style=&#39;width: 100%; height: 30em&#39;&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>Blender Conference 2023</title>
      <link>https://stuvel.eu/post/2023-10-29-blender-conference-2023/</link>
      <pubDate>Sun, 27 Oct 2024 21:43:38 +0100</pubDate>
      <guid>https://stuvel.eu/post/2023-10-29-blender-conference-2023/</guid>
      <description>&lt;p&gt;This blog post I wrote after the 2024 conference, just so that the slides are
available here as well.&lt;/p&gt;
&lt;h2 id=&#34;a-new-animation-system&#34;&gt;A New Animation System&lt;/h2&gt;
&lt;p&gt;Animation &amp;amp; Rigging module presentation about the plans for a new animation system.&lt;/p&gt;
&lt;h3 id=&#34;video&#34;&gt;Video&lt;/h3&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/689qsElGb_U&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3 id=&#34;slides&#34;&gt;Slides&lt;/h3&gt;
&lt;iframe src=&#39;https://stuvel.eu/files/bconf2023/animrig/&#39; style=&#39;width: 100%; height: 30em&#39;&gt;&lt;/iframe&gt;
&lt;h2 id=&#34;flamenco-v33-hands-on-class&#34;&gt;Flamenco v3.3 hands-on class&lt;/h2&gt;
&lt;p&gt;Hands-on class about installing &amp;amp; using the Flamenco render farm.&lt;/p&gt;
&lt;h3 id=&#34;video-1&#34;&gt;Video&lt;/h3&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/Zktl91BfEY0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3 id=&#34;slides-1&#34;&gt;Slides&lt;/h3&gt;
&lt;iframe src=&#39;https://stuvel.eu/files/bconf2023/flamenco/&#39; style=&#39;width: 100%; height: 30em&#39;&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>New Website Section: Electronics</title>
      <link>https://stuvel.eu/post/2024-01-10-new-section-electronics/</link>
      <pubDate>Wed, 10 Jan 2024 22:11:29 +0100</pubDate>
      <guid>https://stuvel.eu/post/2024-01-10-new-section-electronics/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve just added a new section to this website: &lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/electronics/&#34;&gt;Electronics&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Sometimes I just want to share my electronics projects. Even though I design
them in a web-based tool (EasyEDA), and that also has a sharing feature, I want
to have my own projects on my own website. That way I own the data, and also I
can write an article, combine some things together, and make it overall a better
place for my purpose.&lt;/p&gt;
&lt;p&gt;Go check out my first published project:

&lt;a href=&#34;https://stuvel.eu/electronics/2022-03-bicycle-lights/&#34;&gt;Bicycle Lights&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>webp presets</title>
      <link>https://stuvel.eu/post/2023-10-20-webp-presets/</link>
      <pubDate>Fri, 20 Oct 2023 13:01:11 +0200</pubDate>
      <guid>https://stuvel.eu/post/2023-10-20-webp-presets/</guid>
      <description>&lt;p&gt;When exporting WebP images from Gimp, there is a selector for the &amp;ldquo;Source Type&amp;rdquo;.
I&amp;rsquo;ve always wondered what these options mean, and today I found the info.&lt;/p&gt;
&lt;figure id=&#34;figure-gimp-exporter-options-for-webp-images&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2023-10-20-webp-presets/gimp-export-box_huf2c09d149ce8cb424c34353eca0f3d35_11444_2000x2000_fit_q90_h2_lanczos_2.webp&#34; data-caption=&#34;GIMP exporter options for WebP images&#34;&gt;
  &lt;img data-src=&#34;https://stuvel.eu/post/2023-10-20-webp-presets/gimp-export-box_huf2c09d149ce8cb424c34353eca0f3d35_11444_2000x2000_fit_q90_h2_lanczos_2.webp&#34; class=&#34;lazyload&#34; alt=&#34;Screenshot of GIMP, showing its exporter options for WebP images&#34; width=&#34;309&#34; height=&#34;319&#34;&gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    GIMP exporter options for WebP images
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Apparently the only place where this is available is in the actual source code
of the webp encoder. Fortunately Jon Jensen dove in there and wrote about it on

&lt;a href=&#34;https://www.endpointdev.com/blog/2022/02/webp-heif-avif-jpegxl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;their blog&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Picture:&lt;/strong&gt; digital picture, like portrait, inner shot&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Photo:&lt;/strong&gt; outdoor photograph, with natural lighting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drawing:&lt;/strong&gt; hand or line drawing, with high-contrast details&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Icon:&lt;/strong&gt; small-sized colorful images&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text:&lt;/strong&gt; text-like&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course it&amp;rsquo;s all still very subjective. What is &amp;ldquo;small-sized&amp;rdquo;? What if I take
a digital photograph inside of a coffee cup? In any case this is the official
explanation, and for now I&amp;rsquo;m happy I have at least &lt;em&gt;something&lt;/em&gt; to go on.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Compose Key on Windows</title>
      <link>https://stuvel.eu/post/2023-07-31-compose-key-on-windows/</link>
      <pubDate>Mon, 31 Jul 2023 11:39:39 +0200</pubDate>
      <guid>https://stuvel.eu/post/2023-07-31-compose-key-on-windows/</guid>
      <description>&lt;p&gt;My last name is Stüvel, and it causes 
&lt;a href=&#34;https://stuvel.eu/post/2016-02-04-my-name-in-the-modern-world/&#34;&gt;all kinds of issues on various
systems&lt;/a&gt;. Since in the Netherlands people typically use a keyboard
with US layout, there is no &lt;code&gt;ü&lt;/code&gt; key. So &lt;strong&gt;how do I type my name?&lt;/strong&gt;
Compose key to the rescue.&lt;/p&gt;
&lt;p&gt;On Linux I type the &lt;code&gt;ü&lt;/code&gt; by using the &lt;strong&gt;Compose key&lt;/strong&gt;. Since modern keyboards
don&amp;rsquo;t have such a key, I&amp;rsquo;ve configured my right-hand Alt key to become Compose.
To type &lt;code&gt;ü&lt;/code&gt;, I press &lt;code&gt;Compose&lt;/code&gt;, &lt;code&gt;&amp;quot;&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;. One after the other, I don&amp;rsquo;t have to
keep three keys pressed at the same time.&lt;/p&gt;
&lt;p&gt;I can hear you think: isn&amp;rsquo;t what US International layout is for? Yes, and no.
With that layout I can shave off a key, and type &lt;code&gt;&amp;quot;&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt; instead. However,
every time I want to have just single or double quotes, I have to type &lt;code&gt;&amp;quot;&lt;/code&gt;,
&lt;code&gt;&amp;lt;space&amp;gt;&lt;/code&gt;, doubling the number of keys necessary. As a software developer, this
is unacceptable to me, because I have to type these quotes so often.&lt;/p&gt;
&lt;p&gt;Additionally, the Compose key &lt;strong&gt;expands far beyond accented Latin characters&lt;/strong&gt;:&lt;/p&gt;
&lt;style inline&gt;
  table {
    font-size: 90%;
  }
  td code {
    font-size: 1.2em;
  }
  div.mechanical {
    display: flex;
  }

  div.mechanical table {
    width: 50%;
  }
&lt;/style&gt;
&lt;div class=&#39;mechanical&#39;&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Compose Sequence&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;&lt;/code&gt;, &lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ü&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;½&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;€&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Compose Sequence&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;♥&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;o&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;©&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;⁰&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Now, most Linux systems have built-in support for the Compose key, but Windows
does not. Fortunately I recently found 
&lt;a href=&#34;https://github.com/SamHocevar/wincompose&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WinCompose&lt;/a&gt;, which fills in
that gap pretty well. It&amp;rsquo;ll now get installed by default on any of my Windows
machines!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer v1.5 released</title>
      <link>https://stuvel.eu/post/2023-04-16-flatterer-v1.5/</link>
      <pubDate>Sun, 16 Apr 2023 00:16:38 +0200</pubDate>
      <guid>https://stuvel.eu/post/2023-04-16-flatterer-v1.5/</guid>
      <description>&lt;p&gt;Flatterer v1.5 has just been released! It adds new operators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Extrude Finger&lt;/strong&gt;: easily create finger connections between laser-cut parts.
Select some edges and click &lt;em&gt;Extrude Fingers&lt;/em&gt; to extrude them in just the right
direction, using the material thickness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Separate Mesh into Faces&lt;/strong&gt;: split up the mesh  into separate objects for
each side.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Align to Local Axis&lt;/strong&gt;: rotate the mesh to align it with the object&amp;rsquo;s local
axes, then counter-rotate the object so that everything stays in place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/p&gt;
&lt;p&gt;For the full list of features check 
&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Gitea Pull Requests</title>
      <link>https://stuvel.eu/post/2023-02-17-gitea-pull-requests-and-fish/</link>
      <pubDate>Fri, 17 Feb 2023 15:35:05 +0100</pubDate>
      <guid>https://stuvel.eu/post/2023-02-17-gitea-pull-requests-and-fish/</guid>
      <description>&lt;p&gt;Since 
&lt;a href=&#34;https://code.blender.org/2023/02/new-blender-development-infrastructure/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender moved to Gitea&lt;/a&gt; I&amp;rsquo;ve struggled a bit with the pull requests workflow. Getting contributors&amp;rsquo; changes onto my machine wasn&amp;rsquo;t as simple as I wanted it to be. So, I wrote a little shell script to make my life easier.&lt;/p&gt;
&lt;p&gt;The functions below I store in &lt;code&gt;~/.config/fish/conf.d/aliases.fish&lt;/code&gt;. Once they&amp;rsquo;re installed, I have these commands at my, well…, command:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2024-04-03:&lt;/strong&gt; I&amp;rsquo;ve started to track those scripts at 
&lt;a href=&#34;https://projects.blender.org/dr.sybren/.profile/src/branch/main/shell-functions/pull-requests.fish&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;my projects.blender.org profile space&lt;/a&gt;. Go there to get the latest versions.&lt;/p&gt;
&lt;h3 id=&#34;pr-number--o-owner--r-repo&#34;&gt;&lt;code&gt;pr NUMBER [-o owner] [-r repo]&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;I can just type &lt;code&gt;pr NUMBER&lt;/code&gt; to get a Blender pull request, for example &lt;code&gt;pr 104512&lt;/code&gt;. It will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a branch named &lt;code&gt;PR/104512/author-branch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If that branch already existed, it gets removed before creating a brand new one.&lt;/li&gt;
&lt;li&gt;Pull in the changes from the PR.&lt;/li&gt;
&lt;li&gt;The options &lt;code&gt;-o&lt;/code&gt; and &lt;code&gt;-r&lt;/code&gt; are optional, and both default to &lt;code&gt;blender&lt;/code&gt;. I use this for Flamenco pull requests, for example, like &lt;code&gt;pr -o studio -r flamenco 12345&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The branch is named like this so that I can easily find it back later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2023-03-06:&lt;/strong&gt; addition of the &lt;code&gt;-o&lt;/code&gt; and &lt;code&gt;-r&lt;/code&gt; options.&lt;/p&gt;
&lt;h3 id=&#34;prprune&#34;&gt;&lt;code&gt;prprune&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This removes all the branches named &lt;code&gt;PR/...&lt;/code&gt;. I use it to periodically clean things up.&lt;/p&gt;
&lt;h3 id=&#34;the-code&#34;&gt;The code&lt;/h3&gt;
&lt;p&gt;Store this snippet in &lt;code&gt;~/.config/fish/conf.d/aliases.fish&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function pr -d &amp;quot;Pull in a Blender pull request&amp;quot;
    # Set defaults
    set _flag_owner blender
    set _flag_repo blender

    argparse &#39;o/owner=&#39; &#39;r/repo=&#39; -- $argv
    or return 48

    set PRNUM $argv[1]

    set JSON &amp;quot;pr-$PRNUM.json&amp;quot;
    set URL &amp;quot;https://projects.blender.org/api/v1/repos/{$_flag_owner}/{$_flag_repo}/pulls/$PRNUM&amp;quot;
    curl -s -o$JSON $URL
    or return 49

    set PR_STATUS (jq -r .state &amp;lt;$JSON)
    if [ (jq -r .merged &amp;lt;$JSON) = &amp;quot;true&amp;quot; ]
        printf &amp;quot;\033[92mPR is already merged, check $URL\033[0m\n&amp;quot;
        echo &amp;quot;Merged at:&amp;quot; (jq -r .merged_at &amp;lt;$JSON)
        echo &amp;quot;Merged by:&amp;quot; (jq -r .merged_by.full_name &amp;lt;$JSON)
        return 51
    end
    if [ (jq -r .state &amp;lt;$JSON) = &amp;quot;closed&amp;quot; ]
        printf &amp;quot;\033[91mPR is closed, check $URL\033[0m\n&amp;quot;
        return 50
    end

    set PR_NUM (jq -r .number &amp;lt;$JSON)
    set PR_TITLE (jq -r .title &amp;lt;$JSON)
    printf &amp;quot;\033[95mPulling #$PR_NUM: $PR_TITLE\033[0m\n&amp;quot;

    set PR_REPO (jq -r .head.repo.full_name &amp;lt;$JSON)   # &amp;quot;ChrisLend/blender&amp;quot;
    set PR_AUTHOR (jq -r .head.repo.owner.username &amp;lt;$JSON)   # &amp;quot;ChrisLend&amp;quot;
    set PR_BRANCH (jq -r .head.ref &amp;lt;$JSON) # &amp;quot;vertical_scrolling_offscreen&amp;quot;
    set LOCAL_BRANCH &amp;quot;PR/$PRNUM/$PR_AUTHOR-$PR_BRANCH&amp;quot;

    printf &amp;quot;\033[90mIncoming branch: $PR_REPO\033[0m\n&amp;quot;
    printf &amp;quot;\033[90mLocal branch   : $LOCAL_BRANCH\033[0m\n&amp;quot;

    rm -f $JSON

    set CURBRANCH (git branch --show-current 2&amp;gt;/dev/null)
    if test &amp;quot;$CURBRANCH&amp;quot; != &amp;quot;main&amp;quot;;
        git checkout main
    end
    if git branch | grep -q $LOCAL_BRANCH;
        printf &amp;quot;\033[95mBranch $LOCAL_BRANCH exists, going to refresh it\033[0m\n&amp;quot;
        git branch -D $LOCAL_BRANCH
    else
        printf &amp;quot;\033[96mBranch $LOCAL_BRANCH does not exist\033[0m\n&amp;quot;
    end

    git checkout -b $LOCAL_BRANCH main; or return 47
    git pull --ff --commit https://projects.blender.org/$PR_REPO $PR_BRANCH; or return 48

    printf &amp;quot;\033[95mBranch $LOCAL_BRANCH is ready for use\033[0m\n&amp;quot;
    printf &amp;quot;\033[94mPulled #$PR_NUM: $PR_TITLE\033[0m\n&amp;quot;
end

function prprune -d &amp;quot;Delete all PR/* branches&amp;quot;
    set BRANCHES (string trim (git branch | grep &#39;^  PR/&#39;))
    if test -z &amp;quot;$BRANCHES&amp;quot;;
        echo &amp;quot;No PR branches to prune&amp;quot;
        return 0
    end
    git branch -D $BRANCHES
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that I wrote similar code for Phabricator in my 
&lt;a href=&#34;https://stuvel.eu/post/2021-10-14-fish-and-gits/&#34;&gt;Fish and Gits&lt;/a&gt; post, which also shows more of my Git config.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Gitea Easy Linking</title>
      <link>https://stuvel.eu/post/2023-02-09-gitea-clipboard-buttons/</link>
      <pubDate>Thu, 09 Feb 2023 14:59:33 +0100</pubDate>
      <guid>https://stuvel.eu/post/2023-02-09-gitea-clipboard-buttons/</guid>
      <description>&lt;p&gt;Since this week, Blender development has moved from Phabricator to

&lt;a href=&#34;https://projects.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Gitea on projects.blender.org&lt;/a&gt;. Even though much of the workflow has
changed, I still have the need to reference issues, pull requests, and commits
from other places, like chats, forum discussions, my work log, etc.&lt;/p&gt;
&lt;p&gt;Just 
&lt;a href=&#34;https://stuvel.eu/post/2020-11-19-greasemonkey-phabricator-link-copy/&#34;&gt;like I did for Phabricator&lt;/a&gt;, I created a little &lt;em&gt;GreaseMonkey&lt;/em&gt;
script to add some useful buttons to the Gitea interface.&lt;/p&gt;
&lt;p&gt;First download the Greasemonkey add-on for your browser (for 
&lt;a href=&#34;https://www.greasespot.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Firefox&lt;/a&gt; or

&lt;a href=&#34;https://www.tampermonkey.net&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Chrome/Chromium-based browsers&lt;/a&gt;), then add the script:&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://projects.blender.org/dr.sybren/.profile/raw/branch/main/webbrowser-scripts/gitea-document-links.js&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Get the Script&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Then visit 
&lt;a href=&#34;https://projects.blender.org/blender/blender/issues/104435&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;an issue page&lt;/a&gt;. You should see buttons next to the issue
title: &amp;ldquo;MD&amp;rdquo;, &amp;ldquo;TXT&amp;rdquo;, and &amp;ldquo;Wiki&amp;rdquo;. Which ones appear depends on whether you&amp;rsquo;re
looking at an issue/PR or a commit.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer v1.4 released</title>
      <link>https://stuvel.eu/post/2023-01-07-flatterer-v1.4/</link>
      <pubDate>Sat, 07 Jan 2023 16:35:33 +0100</pubDate>
      <guid>https://stuvel.eu/post/2023-01-07-flatterer-v1.4/</guid>
      <description>&lt;p&gt;Flatterer v1.4 has just been released! It adds support for &lt;strong&gt;engraving edges&lt;/strong&gt;
and comes with an improved GUI.&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/p&gt;
&lt;p&gt;Of course the add-on automatically applies &lt;em&gt;kerf compensation&lt;/em&gt;, so there is no
need to manually move edges around. For the full list of features check

&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer v1.3 released</title>
      <link>https://stuvel.eu/post/2022-12-31-flatterer-v1.3/</link>
      <pubDate>Sat, 31 Dec 2022 12:05:40 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-12-31-flatterer-v1.3/</guid>
      <description>&lt;p&gt;Flatterer v1.3 has just been released! It adds the export of &lt;strong&gt;multi-page SVG&lt;/strong&gt;
files, where each page represents a slab of cuttable material. Each page is also
seen as an &lt;em&gt;Inkscape layer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Tools that don&amp;rsquo;t support pages, like LightBurn, will see them as groups instead,
still keeping it simple to select one such group and cut out only those before
putting on a new plate of material on the cutting bed.&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/p&gt;
&lt;p&gt;Of course the add-on automatically applies &lt;em&gt;kerf compensation&lt;/em&gt;, so there is no
need to manually move edges around. For the full list of features check

&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Keychron Function Keys on Linux</title>
      <link>https://stuvel.eu/post/2022-12-09-keychron-f-keys-on-linux/</link>
      <pubDate>Fri, 09 Dec 2022 11:31:26 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-12-09-keychron-f-keys-on-linux/</guid>
      <description>&lt;p&gt;Recently I bought a Keychron K5 SE keyboard (with clicky blue optical switches,
thank you for asking). When I started using it on an Ubuntu Linux machine, it
worked great except one thing: &lt;strong&gt;the F1-F12 function keys did not work well&lt;/strong&gt;.
As with so many laptops and other keyboards, they defaulted to their &amp;ldquo;special&amp;rdquo;
meaning, controlling brightness, volume, that kind of thing. The real issue,
though, is that &lt;strong&gt;fn + F-key did not work&lt;/strong&gt; either.&lt;/p&gt;
&lt;p&gt;This is due to the Linux kernel recognising the keyboard as an Apple keyboard
clone. Fortunately it&amp;rsquo;s easy to revert that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;echo 0 | sudo tee /sys/module/hid_apple/parameters/fnmode
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command should immediately make F-keys register as normal function keys, so
F5 actually works as F5. Try pressing it to reload this article!&lt;/p&gt;
&lt;p&gt;This fix works immediately, but doesn&amp;rsquo;t survive reboots. To &lt;strong&gt;make the fix
permanent&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;echo &amp;quot;options hid_apple fnmode=0&amp;quot; | sudo tee /etc/modprobe.d/hid_apple.conf
sudo update-initramfs -c -k all  # To make sure it&#39;s loaded early enough.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was put on this path by 
&lt;a href=&#34;https://hkdb.medium.com/keychron-function-keys-on-linux-2026fe8ae2e0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jeremy Cheng&amp;rsquo;s article on the same topic&lt;/a&gt;.
Only a minor change was needed (putting &lt;code&gt;0&lt;/code&gt; there instead of the &lt;code&gt;2&lt;/code&gt; he uses).
And I needed to add the &lt;code&gt;update-initramfs&lt;/code&gt; command for my Ubuntu install. Thanks
Jeremy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning to Draw</title>
      <link>https://stuvel.eu/post/2022-12-04-learning-to-draw/</link>
      <pubDate>Sun, 04 Dec 2022 13:01:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-12-04-learning-to-draw/</guid>
      <description>&lt;p&gt;To get more into the fundamentals of animation, I&amp;rsquo;m learning how to draw! Bought
an Apple Pencil 2 to draw on my iPad, and I like it a lot. For now I keep things
simple, with a (simulated) pencil and black-and-white drawings. Drawing bugs
also makes it a nicer experience, because when I mess up the proportions, it
still looks like a bug.&lt;/p&gt;
&lt;p&gt;I share my drawings on Mastodon, at 
&lt;a href=&#34;https://fosstodon.org/@sybren&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://fosstodon.org/@sybren&lt;/a&gt;. There&amp;rsquo;s also
an 
&lt;a href=&#34;https://fosstodon.org/users/sybren.rss&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSS feed of my Mastodon posts&lt;/a&gt; if you&amp;rsquo;d rather use that.&lt;/p&gt;
&lt;p&gt;On a somewhat unrelated note, I just wrote an article 
&lt;a href=&#34;https://stuvel.eu/articles/gps-waypoint-deduplication/&#34;&gt;GPS Waypoint
Deduplication&lt;/a&gt;. It&amp;rsquo;s about how I deduplicated my Osmand favourites with
a bit of Python code. And of course I had to seize this opportunity to use my
new drawing skills for a little flow diagram of the process :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blender Conference 2022</title>
      <link>https://stuvel.eu/post/2022-11-07-blender-conference/</link>
      <pubDate>Mon, 07 Nov 2022 16:00:10 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-11-07-blender-conference/</guid>
      <description>&lt;p&gt;Finally, after three years, there was another Blender Conference! With 700+
participants it was bigger than ever, and of course the energy was amazing.
There were so many talks, and many of them high quality. The image above is not
me, btw ;-)&lt;/p&gt;
&lt;p&gt;For me the highlight was the Character Animation workshop that we did just
before the conference, and having most of the Animation &amp;amp; Rigging module there
in the flesh &amp;ndash; some others joined for the conference itself. Being together and
working on big new ideas really worked well for the energy &amp;amp; enthousiasm in the
team. So much passion!&lt;/p&gt;
&lt;p&gt;This year I had two talks:&lt;/p&gt;
&lt;h2 id=&#34;the-future-of-character-animation--rigging&#34;&gt;The Future of Character Animation &amp;amp; Rigging&lt;/h2&gt;
&lt;p&gt;The aim of this presentation was not just to talk about the workshop &amp;amp; its
outcomes, but also to solicit feedback on the presented ideas from a wider
audience.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/msOjFC03JRY&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&#34;distributed-rendering-with-flamenco-v3&#34;&gt;Distributed rendering with Flamenco v3&lt;/h2&gt;
&lt;p&gt;
&lt;a href=&#34;https://flamenco.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Flamenco v3&lt;/a&gt; has been released just over a month
ago! Aimed at simplicity and interactivity, the render management software used
by Blender Studio is now considered to be featured and stable enough that anyone
can use it in their production. In this talk Sybren will show how to get it
working for various situations, from simple use at home to the setup used by
Blender Studio for their current production.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/shIDWVSTGe4&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;And the slides:&lt;/p&gt;
&lt;iframe src=&#39;bconf22-flamenco-3&#39; style=&#39;width: 100%; height: 25em&#39;&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 4.9 released</title>
      <link>https://stuvel.eu/post/2022-07-20-python-rsa-4.9-released/</link>
      <pubDate>Wed, 20 Jul 2022 12:32:23 +0200</pubDate>
      <guid>https://stuvel.eu/post/2022-07-20-python-rsa-4.9-released/</guid>
      <description>&lt;p&gt;The final release of &lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA v4.9&lt;/a&gt;&lt;/strong&gt; can be obtained from 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa/4.9&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python
Package Index&lt;/a&gt;, or just installed with
&lt;code&gt;pip install --upgrade rsa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This release contains improvements by Arie Bovenberg, Michał Górny,
&lt;code&gt;myheroyuki&lt;/code&gt;, and myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove debug logging from &lt;code&gt;rsa/key.py&lt;/code&gt;
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/194&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#194&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Remove overlapping slots in &lt;code&gt;PrivateKey&lt;/code&gt; and &lt;code&gt;PublicKey&lt;/code&gt;.
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/189&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#189&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Do not include CHANGELOG/LICENSE/README.md in wheel
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/191&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#191&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Fixed Key Generation Unittest: Public and Private keys are assigned the wrong way around
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/188&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#188&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More information on the 
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA&lt;/a&gt; page.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Touch pad dimmer with ESP32 &amp; ESPHome</title>
      <link>https://stuvel.eu/post/2022-06-05-esphome-touch-dimmer/</link>
      <pubDate>Sun, 05 Jun 2022 22:59:14 +0200</pubDate>
      <guid>https://stuvel.eu/post/2022-06-05-esphome-touch-dimmer/</guid>
      <description>&lt;p&gt;Recently I&amp;rsquo;ve been toying a lot with 
&lt;a href=&#34;https://esphome.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ESPHome&lt;/a&gt; in
combination with 
&lt;a href=&#34;https://www.home-assistant.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Home Assistant&lt;/a&gt;. In this post
I&amp;rsquo;ll show how I made a &lt;strong&gt;touch-pad LED dimmer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;My goal was to have touch control over one or more LED strips. My requirements
for the system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;single tap should toggle&lt;/strong&gt; the LED strip. This toggling should use the
default transition. In other words, if the the dimming behaviour needs
different transitions, this shouldn&amp;rsquo;t interfere with the normal toggles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Holding&lt;/strong&gt; the touch pad should &lt;strong&gt;smoothly increase or decrease the
brightness&lt;/strong&gt; the LED strip. This stops when the LED is either fully on or
fully off.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Releasing and then holding&lt;/strong&gt; the touch pad should &lt;strong&gt;change the direction&lt;/strong&gt;,
i.e. if the light was getting dimmer, release &amp;amp; hold should start making it
brighter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From a coding standpoint, I had two more wishes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To add another touch pad + LED strip, it should require as little code copying
as possible.&lt;/li&gt;
&lt;li&gt;The amount of &lt;code&gt;lambda&lt;/code&gt; in the YAML file should be kept to a minimum.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;This is what I came up with. The ingredients you need to make it work in the
&lt;code&gt;YAML&lt;/code&gt; file are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;light&lt;/code&gt; with its &lt;code&gt;output&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;binary_sensor&lt;/code&gt; for the touch pad&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;esp32_touch:&lt;/code&gt; section to enable touch support&lt;/li&gt;
&lt;li&gt;And finally the &lt;code&gt;touch_dimmer.zip&lt;/code&gt; file you can download at the bottom of this post.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is a minimal example YAML file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;esphome:
  name: name-of-your-device

# Add a light and its output:
output:
  - platform: ledc
    id: the_output
    pin: GPIO17

light:
  - platform: monochromatic
    id: the_light
    output: the_output
    name: The LED

# Add a binary touch sensor:
esp32_touch:

binary_sensor:
  - platform: esp32_touch
    id: the_touch_sensor
    pin: GPIO13
    threshold: 550

# Add the touch dimmer itself:
touch_dimmer:
  - id: the_touch_dimmer
    light_id: the_light
    touch_id: the_touch_sensor

# The touch dimming code needs the ESPHome scripting
# component. If your YAML file has no scripts yet,
# just add this dummy.
script:
  - id: dummy
    mode: single
    then:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, download 
&lt;a href=&#34;touch_dimmer.zip&#34;&gt;touch_dimmer.zip&lt;/a&gt; and extract it next to
your YAML file. This should give you this directory structure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-plain&#34;&gt;your_project.yaml
touch_dimmer_example.yaml
custom_components/touch_dimmer/__init__.py
custom_components/touch_dimmer/touch_dimmer.h
&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;touch_dimmer.zip&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Download touch_dimmer.zip&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Last updated for ESPHome version 2025.10.1.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ESP32, BLE, and the fix of the advertisement issues</title>
      <link>https://stuvel.eu/post/2022-05-01-esp32-ble-advertisement-fixed/</link>
      <pubDate>Sun, 01 May 2022 12:48:55 +0200</pubDate>
      <guid>https://stuvel.eu/post/2022-05-01-esp32-ble-advertisement-fixed/</guid>
      <description>&lt;p&gt;After following a 
&lt;a href=&#34;https://randomnerdtutorials.com/esp32-ble-server-client/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ESP32 + Bluetooth Low Energy (BLE) tutorial&lt;/a&gt;, my phone
would only connect once to the ESP32. After it disconnected it wouldn&amp;rsquo;t
reconnect. This is how I fixed it.&lt;/p&gt;
&lt;p&gt;After a lot of tinkering I found out one thing I didn&amp;rsquo;t find in any of the
tutorials I browsed through: &lt;strong&gt;after a BLE client connects, the BLE server will
stop advertising&lt;/strong&gt;. As a result, &lt;em&gt;nRF Connect&lt;/em&gt; (the app I use to test on my phone)
wouldn&amp;rsquo;t reconnect.&lt;/p&gt;
&lt;p&gt;I solved it by restarting the advertising in the &lt;code&gt;onConnect&lt;/code&gt; callback function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class BLEServerCB : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer, esp_ble_gatts_cb_param_t *param) override {
    BLEDevice::startAdvertising();
  }
} bleServerCB;

void setup() {
  BLEDevice::init(DEVICE_NAME);
  BLEServer *bleServer = BLEDevice::createServer();
  bleServer-&amp;gt;setCallbacks(&amp;amp;bleServerCB);
  // ... the rest of the setup.
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will keep your ESP32 announcing its presence to the world, regardless of
who connected in the past. Might not be what you want, but it sure helped me
test things.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer v1.2 released</title>
      <link>https://stuvel.eu/post/2022-04-06-flatterer-v1.2/</link>
      <pubDate>Wed, 06 Apr 2022 22:12:03 +0200</pubDate>
      <guid>https://stuvel.eu/post/2022-04-06-flatterer-v1.2/</guid>
      <description>&lt;p&gt;Flatterer v1.2 has just been released! It gives you the ability to &lt;strong&gt;export wire
edges&lt;/strong&gt; and &lt;strong&gt;include a table of shape dimensions&lt;/strong&gt;. Furthermore, it exports to
layers compatible with Inkscape, and uses a slightly thicker outline for better
visibility in larger projects.&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/p&gt;
&lt;p&gt;Of course the add-on automatically applies &lt;em&gt;kerf compensation&lt;/em&gt;, so there is no
need to manually move edges around. For the full list of features check

&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer v1.1 released</title>
      <link>https://stuvel.eu/post/2022-02-09-flatterer-v1.1/</link>
      <pubDate>Sun, 09 Jan 2022 15:06:01 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-02-09-flatterer-v1.1/</guid>
      <description>&lt;p&gt;Flatterer v1.1 has just been released! It gives you &lt;strong&gt;more control over the
shape packing options&lt;/strong&gt;. In the past weeks I&amp;rsquo;ve already had a project for which
the default options didn&amp;rsquo;t quite work well enough, so I decided to expose a few
options to give you more control over it.&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Sorting&lt;/dt&gt;
&lt;dd&gt;The packing algorithm tries to fit each shape as well as possible. It does this basically shape by shape, and thus the order in which the shapes are packed has an impact on the result. This option allows you to choose this sorting. The choices are:&lt;/dd&gt;
&lt;/dl&gt;
&lt;ul&gt;
&lt;li&gt;Do not sort. &lt;em&gt;Not sure what the use is, but you never know.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Sort by descending area.&lt;/li&gt;
&lt;li&gt;Sort by descending perimeter. &lt;em&gt;This was the old hard-coded behaviour, and still is the default.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Sort by difference of rectangle sides.&lt;/li&gt;
&lt;li&gt;Sort by shortest side.&lt;/li&gt;
&lt;li&gt;Sort by longest side.&lt;/li&gt;
&lt;li&gt;Sort by ration between sides.&lt;/li&gt;
&lt;/ul&gt;
&lt;dl&gt;
&lt;dt&gt;Rotation&lt;/dt&gt;
&lt;dd&gt;The packing algorithm can rotate each shape by 90° to see if that works better. If you don&amp;rsquo;t want this, you can now turn it off.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/p&gt;
&lt;p&gt;Of course the add-on automatically applies &lt;em&gt;kerf compensation&lt;/em&gt;, so there is no
need to manually move edges around. For the full list of features check

&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flatterer: a new Blender add-on</title>
      <link>https://stuvel.eu/post/2022-01-09-flatterer-v1/</link>
      <pubDate>Sun, 09 Jan 2022 15:06:01 +0100</pubDate>
      <guid>https://stuvel.eu/post/2022-01-09-flatterer-v1/</guid>
      <description>&lt;p&gt;I bought a laser cutter, and of course I want to use Blender to make cuttable
designs. So, I made my own add-on called Flatterer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flatterer turns a 3D model in Blender into a set of shapes suitable for laser
cutting.  It&amp;rsquo;s aimed at easily exporting boxes, enclosures, and other
made-for-laser-cutting designs to SVG.&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/flatterer/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Check Out Flatterer&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Of course the add-on automatically applies &lt;em&gt;kerf compensation&lt;/em&gt;, so there is no
need to manually move edges around. For the full list of features check

&lt;a href=&#34;https://stuvel.eu/software/flatterer/&#34;&gt;the Flatterer software page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Class D Amplifier Prototype</title>
      <link>https://stuvel.eu/post/2021-12-10-class-d-amplifier/</link>
      <pubDate>Fri, 10 Dec 2021 13:43:44 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-12-10-class-d-amplifier/</guid>
      <description>&lt;p&gt;The amplifier we use for the TV is getting old, and an annoying 50 Hz hum is
finding its way to the speakers. So, of course, I decided to make my own
amplifier. I&amp;rsquo;ve

&lt;a href=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/&#34;&gt;done that before&lt;/a&gt;,
with a class B design, and this time I wanted to do something different.&lt;/p&gt;





  
  











&lt;figure id=&#34;figure-the-class-d-simple-amp&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2021-12-10-class-d-amplifier/featured_hu4110f0c1314d3e1b9c16cb13989e1697_157292_2000x2000_fit_q90_lanczos.jpg&#34; data-caption=&#34;The Class D Simple Amp&#34;&gt;


  &lt;img data-src=&#34;https://stuvel.eu/post/2021-12-10-class-d-amplifier/featured_hu4110f0c1314d3e1b9c16cb13989e1697_157292_2000x2000_fit_q90_lanczos.jpg&#34; class=&#34;lazyload&#34; alt=&#34;&#34; width=&#34;800&#34; height=&#34;556&#34;&gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    The Class D Simple Amp
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;This amplifier is a &lt;strong&gt;Class D design&lt;/strong&gt;, which means that it transforms the audio
signal into a high-speed (200 kHz) digital signal. It then amplifies that
digital signal; because of the digital nature, the amplifier MOSFETs will be
either fully on or fully off. Since either no current is flowing (100% off) or
the MOSFET has practically no resistance (100% on), there is very little heat
produced, making the design energy-efficient.&lt;/p&gt;





  
  











&lt;figure id=&#34;figure-circuit-diagram-of-the-class-d-simple-amp&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2021-12-10-class-d-amplifier/simple-amp-class-d-schematic_hud21671bcd84f9b30415438a4d2629ae6_168532_2000x2000_fit_lanczos_3.png&#34; data-caption=&#34;Circuit diagram of the Class D Simple Amp&#34;&gt;


  &lt;img data-src=&#34;https://stuvel.eu/post/2021-12-10-class-d-amplifier/simple-amp-class-d-schematic_hud21671bcd84f9b30415438a4d2629ae6_168532_2000x2000_fit_lanczos_3.png&#34; class=&#34;lazyload&#34; alt=&#34;&#34; width=&#34;1169&#34; height=&#34;827&#34;&gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    Circuit diagram of the Class D Simple Amp
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;This is just a &lt;strong&gt;prototype that outputs mono audio&lt;/strong&gt;. It&amp;rsquo;s there for me to
learn about its behaviour (it&amp;rsquo;s different on a PCB compared to the earlier
breadboard prototype I made) before I copy-paste the components to the final 2.1
(stereo + subwoofer) version.&lt;/p&gt;
&lt;p&gt;Above you see the circuit diagram. I&amp;rsquo;ve &lt;strong&gt;shared the design&lt;/strong&gt; under the GPL
license, including the PCB layout, on

&lt;a href=&#34;https://oshwlab.com/dr.Sybren/simple-amp-class-d-v1&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open Source Hardware Lab&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 4.8 released</title>
      <link>https://stuvel.eu/post/2021-11-24-python-rsa-4-8-released/</link>
      <pubDate>Wed, 24 Nov 2021 11:14:56 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-11-24-python-rsa-4-8-released/</guid>
      <description>&lt;p&gt;The final release of &lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA v4.8&lt;/a&gt;&lt;/strong&gt; can be obtained from 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa/4.8&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python
Package Index&lt;/a&gt;, or just installed with
&lt;code&gt;pip install --upgrade rsa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This release contains improvements by Ram Rachum, Andrey Semakin, Hubert Kario,
Kian Meng Ang, and myself of course:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Switch to 
&lt;a href=&#34;https://python-poetry.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Poetry&lt;/a&gt; for dependency and release management.&lt;/li&gt;
&lt;li&gt;Compatibility with Python 3.10.&lt;/li&gt;
&lt;li&gt;Chain exceptions using &lt;code&gt;raise new_exception from old_exception&lt;/code&gt;
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/157&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#157&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Added marker file for PEP 561. This will allow type checking tools in dependent projects
to use type annotations from Python-RSA
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/136&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#136&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Use the Chinese Remainder Theorem when decrypting with a private key. This
makes decryption 2-4x faster
(
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/163&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#163&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More information on the 
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA&lt;/a&gt; page.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Light Intensity Tool</title>
      <link>https://stuvel.eu/post/2021-11-14-light-intensity-tool/</link>
      <pubDate>Sun, 14 Nov 2021 13:26:26 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-11-14-light-intensity-tool/</guid>
      <description>&lt;p&gt;For my electronics projects I often have the need to &lt;strong&gt;take the linear position
of a potentiometer, and translate it to an exponential value&lt;/strong&gt; I can use to PWM
some LEDs. I had some Python scripts scattered around to do this, but figured it
was more convenient to have a web-based tool instead. So, here it is!&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://stuvel.eu/software/light/&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Go To The Tool&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The tool takes the number of bits you can use to PWM the LEDs, and the number of
steps you want in the lookup table. It&amp;rsquo;ll then generate some C code that&amp;rsquo;ll give
you that lookup table.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fish &amp; Gits</title>
      <link>https://stuvel.eu/post/2021-10-14-fish-and-gits/</link>
      <pubDate>Thu, 14 Oct 2021 15:59:20 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-10-14-fish-and-gits/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been using the 
&lt;a href=&#34;https://fishshell.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Fish shell&lt;/a&gt; for a while, and it&amp;rsquo;s
really gotten to the point where I miss it when I can&amp;rsquo;t use it :)&lt;/p&gt;
&lt;p&gt;To share with folks, here are some of my Fish configurations and Git configs
that make my life as a Blender developer easier.&lt;/p&gt;
&lt;p&gt;This post was made possible by the 
&lt;a href=&#34;https://fund.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Development Fund&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;fish-config&#34;&gt;Fish Config&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Update 2024-04-03:&lt;/strong&gt; I&amp;rsquo;ve started to track the pull request related functions 
&lt;a href=&#34;https://projects.blender.org/dr.sybren/.profile/src/branch/main/shell-functions/pull-requests.fish&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;my projects.blender.org profile space&lt;/a&gt;. Go there to get the latest versions.&lt;/p&gt;
&lt;p&gt;These I store in &lt;code&gt;~/.config/fish/conf.d/aliases.fish&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set BLENDER_BUILD_ROOT  /home/sybren/workspace/blender-git
set FLAMENCO_ROOT /home/sybren/workspace/blender/flamenco-3

function cdf -d &amp;quot;CD to Flamenco directory&amp;quot;
    cd $FLAMENCO_ROOT
end

function cdlibs -d &amp;quot;CD to Blender libs directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/lib
end

function cddeps -d &amp;quot;CD to Blender deps directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/build_deps/deps
end

function cdbuild -d &amp;quot;CD to Blender release build directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/build_linux
end

function cddebug -d &amp;quot;CD to Blender debug build directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/build_debug
end

function cdsrc -d &amp;quot;CD to Blender source directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/blender
end

function cdtracker -d &amp;quot;CD to Blender bug tracker directory&amp;quot;
    cd $BLENDER_BUILD_ROOT/tracker
end

function cddocs -d &amp;quot;CD to Blender developer docs and activate the venv&amp;quot;
    cd $BLENDER_BUILD_ROOT/developer-docs
    . ./.venv/bin/activate.fish
end

function cdmanual -d &amp;quot;CD to Blender manual and activate the venv&amp;quot;
    cd $BLENDER_BUILD_ROOT/manual
    . ./.venv/bin/activate.fish
end

function _makebranch -a BRANCH
    cdsrc; or return 1
    printf &amp;quot;\033[95mChecking out branch \033[96m$BRANCH\033[0m\n&amp;quot;
    git co $BRANCH; or return 2
    printf &amp;quot;\033[95mPulling branch \033[96m$BRANCH\033[0m\n&amp;quot;
    git pull; or return 5
    printf &amp;quot;\033[95mmake update\033[0m\n&amp;quot;
    make update; or return 3
    printf &amp;quot;\033[95mBuilding Blender\033[0m\n&amp;quot;
    bb; or return 4
    printf &amp;quot;\033[95mBuilt $BRANCH\033[0m\n&amp;quot;
end

function mm -d &amp;quot;Make Main, update &amp;amp; build Blender main branch, release mode&amp;quot;
    _makebranch main
end

function mmb -d &amp;quot;Make Main, then run Blender&amp;quot;
    _makebranch main; and blender --open-last $argv
end

function mr -d &amp;quot;Make release branch&amp;quot;
    cdsrc
    set branch (git branch -r --list &#39;origin/blender-v*-release&#39; | sort -n | tail -n 1 | sed &#39;s+.*origin/++&#39;)
    printf &amp;quot;\033[95mSwitching to release branch\033[0m \033[96m$branch\033[0m\n&amp;quot;
    _makebranch $branch
end

function bb -d &amp;quot;Build Blender, release mode&amp;quot;
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_linux/ $argv; or return $status
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_linux/ install
end

function bbb -d &amp;quot;Build Blender and run with last file&amp;quot;
    bb &amp;amp;&amp;amp; blender --open-last $argv
end

function bbd -d &amp;quot;Build Blender, debug mode&amp;quot;
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_debug/ $argv; or return $status
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_debug/ install
end

function bbbd -d &amp;quot;Build Blender in Debug mode and run with last file&amp;quot;
    bbd &amp;amp;&amp;amp; blenderdebug --open-last $argv
end

function bbt -d &amp;quot;Build Blender, Clang-Tidy mode&amp;quot;
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_tidy/ $argv
end

function bbr -d &amp;quot;Build Blender, release branch&amp;quot;
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_release/ $argv
end

function cdb
    set BLENDVER (blender --version | grep &#39;^Blender&#39; | cut -d&#39; &#39; -f2 | sed &#39;s/\\([0-9]\\+\\.[0-9]\\+\\).*/\\1/&#39;)
    echo &amp;quot;Blender version: $BLENDVER&amp;quot;
    cd ~/.config/blender/$BLENDVER
end

function git_rebase_onto_main
    read -P &amp;quot;Rebase onto main? ENTER for yes, CTRL+C for no.&amp;quot;; or begin
        printf &amp;quot;\033[94mNot rebasing, the work is done.\033[0m\n&amp;quot;
        return
    end
    git rebase main; and git submodule foreach git pull --rebase origin main
end

function svnadd -a SUBDIR -d &amp;quot;Add new files and remove deleted files&amp;quot;
  # This is the Fish way of doing `SVN_STATUS=$(&amp;lt;svn status $SUBDIR)`
  begin; set -l IFS; set SVN_STATUS (svn status $SUBDIR); end

  echo &amp;quot;$SVN_STATUS&amp;quot; | grep &#39;^\? &#39; | sed &#39;s/^.//&#39; | xargs --no-run-if-empty -n 1 svn add
  echo &amp;quot;$SVN_STATUS&amp;quot; | grep &#39;^\! &#39; | sed &#39;s/^.//&#39; | xargs --no-run-if-empty -n 1 svn rm
end

function pr -d &amp;quot;Pull in a Blender pull request&amp;quot;
    # Set defaults
    set _flag_owner blender
    set _flag_repo blender

    argparse &#39;o/owner=&#39; &#39;r/repo=&#39; -- $argv
    or return 48

    # Check for -r owner/repo notation:
    set _flag_combined (echo &amp;quot;$_flag_repo&amp;quot; | string split /)
    set _num_combined (count $_flag_combined)
    if [ $_num_combined -gt 1 ]
        set _flag_owner $_flag_combined[1]
        set _flag_repo $_flag_combined[2]
    end

    set PRNUM $argv[1]

    set JSON &amp;quot;pr-$PRNUM.json&amp;quot;
    set URL &amp;quot;https://projects.blender.org/api/v1/repos/$_flag_owner/$_flag_repo/pulls/$PRNUM&amp;quot;
    if ! curl --fail --no-progress-meter -o$JSON $URL
        printf &amp;quot;\033[91mError fetching $URL\033[0m\n&amp;quot;
        return 49
    end

    # Sanity check we can read the result
    if ! jq &amp;lt;$JSON &amp;gt;/dev/null
        printf &amp;quot;\033[91mCannot parse JSON at $JSON\033[0m\n&amp;quot; &amp;gt;&amp;amp;2
        return 50
    end

    set PR_STATUS (jq -r .state &amp;lt;$JSON)
    if [ (jq -r .merged &amp;lt;$JSON) = &amp;quot;true&amp;quot; ]
        printf &amp;quot;\033[92mPR is already merged, check $URL\033[0m\n&amp;quot;
        echo &amp;quot;Merged at:&amp;quot; (jq -r .merged_at &amp;lt;$JSON)
        echo &amp;quot;Merged by:&amp;quot; (jq -r .merged_by.full_name &amp;lt;$JSON)
        return 51
    end
    if [ (jq -r .state &amp;lt;$JSON) = &amp;quot;closed&amp;quot; ]
        printf &amp;quot;\033[91mPR is closed, check $URL\033[0m\n&amp;quot;
        return 50
    end

    set PR_NUM (jq -r .number &amp;lt;$JSON)
    set PR_TITLE (jq -r .title &amp;lt;$JSON)
    printf &amp;quot;\033[95mPulling #$PR_NUM: $PR_TITLE\033[0m\n&amp;quot;

    set PR_REPO (jq -r .head.repo.full_name &amp;lt;$JSON)   # &amp;quot;ChrisLend/blender&amp;quot;
    set PR_AUTHOR (jq -r .head.repo.owner.username &amp;lt;$JSON)   # &amp;quot;ChrisLend&amp;quot;
    set PR_BRANCH (jq -r .head.ref &amp;lt;$JSON) # &amp;quot;vertical_scrolling_offscreen&amp;quot;
    set PR_BASE_BRANCH (jq -r .base.ref &amp;lt;$JSON) # &amp;quot;main&amp;quot; or &amp;quot;blender-v3.5-release&amp;quot;
    set LOCAL_BRANCH &amp;quot;PR/$PRNUM/$PR_AUTHOR-$PR_BRANCH&amp;quot;

    printf &amp;quot;\033[90mIncoming branch: $PR_REPO\033[0m\n&amp;quot;
    printf &amp;quot;\033[90mBase  branch   : $PR_BASE_BRANCH\033[0m\n&amp;quot;
    printf &amp;quot;\033[90mLocal branch   : $LOCAL_BRANCH\033[0m\n&amp;quot;

    rm -f $JSON

    set CURBRANCH (git branch --show-current 2&amp;gt;/dev/null)
    if test &amp;quot;$CURBRANCH&amp;quot; != &amp;quot;$PR_BASE_BRANCH&amp;quot;;
        git checkout $PR_BASE_BRANCH
    end
    if git branch | grep -q $LOCAL_BRANCH;
        printf &amp;quot;\033[95mBranch $LOCAL_BRANCH exists, going to refresh it\033[0m\n&amp;quot;
        git branch -D $LOCAL_BRANCH
    else
        printf &amp;quot;\033[96mBranch $LOCAL_BRANCH does not exist\033[0m\n&amp;quot;
    end

    git checkout -b $LOCAL_BRANCH $PR_BASE_BRANCH; or return 47
    git pull --no-rebase --ff --no-edit --commit https://projects.blender.org/$PR_REPO $PR_BRANCH; or return 48

    printf &amp;quot;\033[95mBranch $LOCAL_BRANCH is ready for use\033[0m\n&amp;quot;
    printf &amp;quot;\033[94mPulled #$PR_NUM: $PR_TITLE\033[0m\n&amp;quot;
end

function prprune -d &amp;quot;Delete all PR/* branches&amp;quot;
    set BRANCHES (string trim (git branch | grep &#39;^  PR/&#39;))
    if test -z &amp;quot;$BRANCHES&amp;quot;;
        echo &amp;quot;No PR branches to prune&amp;quot;
        return 0
    end
    git branch -D $BRANCHES
end

function ffmp4 -a FNAME -d &amp;quot;Use FFmpeg to convert MKV to MP4&amp;quot;
    set OUTNAME (string replace -i .mkv .mp4 &amp;quot;$FNAME&amp;quot;)
    if test &amp;quot;$FNAME&amp;quot; = &amp;quot;$OUTNAME&amp;quot;;
        set OUTNAME (string replace -i -- .mov .mp4 &amp;quot;$FNAME&amp;quot;)
    end
    if test &amp;quot;$FNAME&amp;quot; = &amp;quot;$OUTNAME&amp;quot;;
        set OUTNAME (string replace -i -- .webm .mp4 &amp;quot;$FNAME&amp;quot;)
    end
    if test &amp;quot;$FNAME&amp;quot; = &amp;quot;$OUTNAME&amp;quot;;
        set OUTNAME (string replace -i -- .mp4 -recoded.mp4 &amp;quot;$FNAME&amp;quot;)
    end
    if test &amp;quot;$FNAME&amp;quot; = &amp;quot;$OUTNAME&amp;quot;;
        echo &amp;quot;Input must end in .mkv, .mp4, .webm, or .mov&amp;quot;
        return 1
    end

    ffmpeg -i &amp;quot;$FNAME&amp;quot; -c:v h264 -crf 23 -c:a aac -b:a 192k &amp;quot;$OUTNAME&amp;quot;
    or return $status

    dolphin --select &amp;quot;$OUTNAME&amp;quot; &amp;amp; disown
end

alias l=&#39;ls -F --color=auto&#39;
alias ll=&#39;l -lh&#39;
alias df=&#39;df -h&#39;
alias du=&#39;du -h&#39;
alias grep=&#39;grep --color&#39;
alias qtc=&#39;qtcreator -client&#39;
alias sqlite=&#39;sqlite3&#39;
alias docker-logfile=&#39;docker inspect --format=&amp;quot;{{.LogPath}}&amp;quot;&#39;
alias json_pp=&amp;quot;python3 -c &#39;import json, sys; print(json.dumps(json.load(sys.stdin), sort_keys=True, indent=4))&#39;&amp;quot;
alias trimlong=&amp;quot;sed &#39;s/\(.\{120\}\).*/\1…/&#39;&amp;quot;
alias ffprobe-json=&amp;quot;ffprobe -v error -hide_banner -print_format json -show_streams -show_format&amp;quot;
alias dot2png=&amp;quot;dot -Tpng -O&amp;quot;
alias abccat=&amp;quot;abcls -a -m -l -r -t&amp;quot;
alias cdp=&amp;quot;cd (pwd -P)&amp;quot;
alias bcode=&amp;quot;code $BLENDER_BUILD_ROOT/blender.code-workspace&amp;quot;
alias dcode=&amp;quot;cddocs; code .&amp;quot;
alias wg=&#39;wget --content-disposition&#39;

alias rbi=&amp;quot;git rebase --interactive&amp;quot;
alias rbc=&amp;quot;git rebase --continue&amp;quot;
alias rba=&amp;quot;git rebase --abort&amp;quot;
alias gg=&amp;quot;git gui&amp;quot;
alias gga=&amp;quot;git gui citool --amend&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;git-config&#34;&gt;Git Config&lt;/h3&gt;
&lt;p&gt;My Git configuration (&lt;code&gt;~/.gitconfig&lt;/code&gt;) also has some nice aliases &amp;amp; other options:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[color]
    ui = auto
[pull]
    rebase = true
[push]
    default = simple
[alias]
    co = &amp;quot;checkout&amp;quot;
    cp = &amp;quot;cherry-pick&amp;quot;
    ff = &amp;quot;merge --ff-only&amp;quot;
    mt = &amp;quot;mergetool&amp;quot;
    up = &amp;quot;checkout @~1&amp;quot;
    st = &amp;quot;status --ignore-submodules=none&amp;quot;
    car = &amp;quot;commit --amend --reset-author&amp;quot;
    rbi = &amp;quot;rebase -i&amp;quot;
    rbc = &amp;quot;rebase --continue&amp;quot;
    rba = &amp;quot;rebase --abort&amp;quot;
    tpush = &amp;quot;!git push &amp;amp;&amp;amp; git push --tags&amp;quot;
    out = &amp;quot;log @{u}.. --pretty=oneline&amp;quot;
    head = &amp;quot;show HEAD&amp;quot;
    unstash = &amp;quot;stash pop&amp;quot;
    authors = &amp;quot;!f() { git log --since &#39;now - 1 year&#39; \&amp;quot;$@\&amp;quot; | grep ^Author | sed &#39;s/Author: //&#39; | sed &#39;s/&amp;lt;.*&amp;gt;//&#39; | sort -f | uniq -ci | sort -nr | nl -s &#39;&#39; | sort -nr; } ; f&amp;quot;
    glog = &amp;quot;log --all --graph --abbrev-commit --decorate --date=short --format=format:&#39;%C(bold blue)%h%C(reset) %C(green)(%ad)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(dim magenta)%d%C(reset)&#39;&amp;quot;
    onelog = &amp;quot;log --abbrev-commit --decorate --date=short --format=format:&#39;%C(bold blue)%h%C(reset) %C(green)(%ad)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(dim magenta)%d%C(reset)&#39;&amp;quot;
    ver = &amp;quot;log --oneline -n 1 --no-abbrev&amp;quot;
[diff]
    tool = kdiff3
    guitool = kdiff3
[merge]
    tool = kdiff3
    guitool = kdiff3
  	renamelimit = 4096
[core]
    excludesfile = /home/sybren/.configfiles/gitignore_global
[gui]
    gcwarning = false
    encoding = utf-8
[rerere]
  	enabled = true
[gc]
  	rerereUnresolved = 365
  	rerereResolved = 365
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v7 released</title>
      <link>https://stuvel.eu/post/2021-09-19-beatstripper-for-beatsaber-1.17/</link>
      <pubDate>Sun, 19 Sep 2021 10:55:57 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-09-19-beatstripper-for-beatsaber-1.17/</guid>
      <description>&lt;p&gt;This release of 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt; is
compatible with Beat Saber version 1.17. Furthermore, it now &lt;strong&gt;auto-capitalises
the player names in the party mode name picker&lt;/strong&gt; (the one you see after you finish
a map).&lt;/p&gt;
&lt;p&gt;BeatStripper strips down party mode scores to just each player&amp;rsquo;s highest score.
It can also merge Solo scores into the Party leaderboards.&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://gitlab.com/dr.sybren/beatstripper/-/releases&#39; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;btn btn-primary px-5 py-3&#34;&gt;Get BeatStripper&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Spherical Panoramas Explained</title>
      <link>https://stuvel.eu/post/2021-08-29-spherical-panoramas/</link>
      <pubDate>Sun, 29 Aug 2021 12:48:25 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-08-29-spherical-panoramas/</guid>
      <description>&lt;p&gt;Want to create beautiful spherical panoramas? Check out the new article I wrote on the subject: 
&lt;a href=&#34;https://stuvel.eu/articles/spherical-panoramas/&#34;&gt;&lt;strong&gt;Spherical Panoramas&lt;/strong&gt;&lt;/a&gt;. It covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The required hardware.&lt;/li&gt;
&lt;li&gt;How to shoot the photos.&lt;/li&gt;
&lt;li&gt;Editing the photos.&lt;/li&gt;
&lt;li&gt;Using Hugin to stitch them together &amp;amp; do HDR-merging.&lt;/li&gt;
&lt;li&gt;Viewing your result.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What are you waiting for? Go and 
&lt;a href=&#34;https://stuvel.eu/articles/spherical-panoramas/&#34;&gt;read the article&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Skyfill v1.5 released</title>
      <link>https://stuvel.eu/post/2021-07-25-skyfill-v1-5-released/</link>
      <pubDate>Sun, 25 Jul 2021 15:42:23 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-07-25-skyfill-v1-5-released/</guid>
      <description>&lt;p&gt;Version v1.5 of 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt; has been released. The most important improvement is the addition of a &lt;strong&gt;mirror ball mode&lt;/strong&gt;. The mirror ball reflects the ground, resulting in a mini planet version of the panorama hanging in the sky. To see what it looks like, &lt;strong&gt;check 
&lt;a href=&#34;https://stuvelfoto.nl/panorama/tulpen-rood-geel-120m-mirrorball/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;these tulip fields&lt;/a&gt;&lt;/strong&gt; and be sure to look up.&lt;/p&gt;
&lt;p&gt;Apart from the mirror ball, &lt;strong&gt;performance has been improved&lt;/strong&gt;, so even normal Sky-filling will be faster.&lt;/p&gt;
&lt;p class=&#39;call-to-action&#39;&gt;
  &lt;a href=&#39;https://gitlab.com/dr.sybren/skyfill/-/releases&#39;  class=&#34;btn btn-primary px-5 py-3&#34;&gt;Get Skyfill&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;You can grab your copy at 
&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Gitlab&lt;/a&gt;, and read how to use the mirror ball feature in 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;the documentation&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Most drones (UAVs) cannot look straight up to photograph the sky above them. As
a result, spherical panoramas made with drones tend to have a gap in the sky.
Some drones, like my DJI Mavic 2, can fill in this gap automatically while
generating a preview. However, when I stitch the photos myself to get a better
quality output, there is still that sky gap. I got fed up with having to choose
between a nice sky or a nice overall image, so I did what developers do and made
my own software: 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Code in MarkDown</title>
      <link>https://stuvel.eu/post/2021-07-11-code-in-markdown/</link>
      <pubDate>Sun, 11 Jul 2021 12:15:07 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-07-11-code-in-markdown/</guid>
      <description>&lt;p&gt;Many systems like Discord, Matrix, Blender Chat, Stack Exchange, Discourse, Slack, etc. use MarkDown for their markup. In short, this allows you to share snippets of code with each other. The thing that makes this worth writing about, is that &lt;strong&gt;natural text should behave differently from code&lt;/strong&gt;. Natural text can be rewrapped to comfortably match the device you&amp;rsquo;re reading it on. With code, however, this should not be done, as it makes it horrible to read.&lt;/p&gt;
&lt;div class=&#34;alert alert-note&#34;&gt;
  &lt;div&gt;
    Whatever you do, &lt;strong&gt;do not post a screenshot of your code&lt;/strong&gt;. It may look like the simple solution, but it&amp;rsquo;s only simple &lt;em&gt;for you&lt;/em&gt;. It&amp;rsquo;s impossible to copy-paste code from a screenshot into a text editor, so if someone wants to help you out by adjusting your code for you, you&amp;rsquo;ve now forced them into typing it all by hand.
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The solution is that you have to mark blocks of code with &lt;strong&gt;triple backticks&lt;/strong&gt;. On many keyboards this is one of the left-most keys, left of the 1, under the Escape key. This is what it looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```
def function():
    print(&#34;This is just some code&#34;)
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;def function():
    print(&amp;quot;This is just some code&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;If you want to get syntax highlighting as well, be sure to type the language name directly after the opening backticks, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```python
def function():
    print(&#34;This is just some code&#34;)
```
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def function():
    print(&amp;quot;This is just some code&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not always supported by all MarkDown systems, though. For example,
Phabricator, Blender&amp;rsquo;s previous bug tracker, used &lt;code&gt;lang=python&lt;/code&gt; as marker,
instead of just &lt;code&gt;python&lt;/code&gt;. 
&lt;a href=&#34;https://projects.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Gitea, Blender&amp;rsquo;s current bug tracker&lt;/a&gt;
&lt;strong&gt;works just fine&lt;/strong&gt; with the &lt;code&gt;python&lt;/code&gt; marker, and also supports &lt;code&gt;cpp&lt;/code&gt; for C++,
&lt;code&gt;diff&lt;/code&gt; for diffs, and many more.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v6.0 released</title>
      <link>https://stuvel.eu/post/2021-05-08-beatstripper-for-beatsaber-1.15/</link>
      <pubDate>Sat, 08 May 2021 23:10:15 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-05-08-beatstripper-for-beatsaber-1.15/</guid>
      <description>&lt;p&gt;This release of 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt; is
compatible with the newly released Beat Saber 1.15, the three-year celebratory
release. Congratulations BeatSaber!&lt;/p&gt;
&lt;p&gt;The compatibility check with newer versions of Beat Saber became much smarter.
The file&amp;rsquo;s contents are now checked, and not just the version number. This makes
BeatStripper forward compatible with new versions, until they actually change
what&amp;rsquo;s saved in the files. Previously they bumped the version number but kept
the contents the same, which was a bit annoying. Now BeatStripper is compatible
with the future!&lt;/p&gt;
&lt;p&gt;BeatStripper strips down party mode scores to just each player&amp;rsquo;s highest score.
It can also merge Solo scores into the Party leaderboards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adding support for ATmega328PB to AVR-GCC and AVRDude</title>
      <link>https://stuvel.eu/post/2021-04-27-atmega328pb-on-gcc/</link>
      <pubDate>Tue, 27 Apr 2021 12:14:12 +0200</pubDate>
      <guid>https://stuvel.eu/post/2021-04-27-atmega328pb-on-gcc/</guid>
      <description>&lt;div class=&#34;alert alert-note&#34;&gt;
  &lt;div&gt;
    &lt;strong&gt;Update (2025-05-15):&lt;/strong&gt; Nowadays I would recommend 
&lt;a href=&#34;https://platformio.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PlatformIO&lt;/a&gt; when
writing software for the ATmega328PB microcontroller. It has built-in support
for the PB variant, and has worked like a charm in my latest project.
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href=&#34;https://blog.zakkemble.net/avr-gcc-builds/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AVR-GCC 10&lt;/a&gt; only has partial support for the
ATmega328PB microcontroller. For some reason, it does have a &amp;ldquo;device spec&amp;rdquo; file
but misses other essential files. In this post I&amp;rsquo;ll explain how to rectify
that.&lt;/p&gt;
&lt;p&gt;Note that the ATmega328PB was introduced in 2016, and GCC 10.3 was released in
2021. Not sure why GCC does have support for the ATmega328P but not its improved
(and 5 years old already) brother ATmega328PB.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m developing most of my microcontroller code on Windows, but with some
GNU-style tools (like Git-Bash), hence the mixture of forward and backward
slashes in paths. All of this should be independent of which platform you
actually develop on, though.&lt;/p&gt;
&lt;p&gt;Update 2021-05-04: This approach also works for the ATmega168PB microcontroller.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Update 2021-05-09:&lt;/strong&gt; I zipped the files together into

&lt;a href=&#34;https://stuvel.eu/files/atmega-168pb-328pb-for-avr-gcc-10.1.0.zip&#34;&gt;atmega-168pb-328pb-for-avr-gcc-10.1.0.zip&lt;/a&gt;.
Extract that to the root of your GCC install. After that, you only need to edit
&lt;code&gt;avr\include\avr\io.h&lt;/code&gt; as 
&lt;a href=&#34;#2-patching-ioh&#34;&gt;described below in the 2nd step&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# From the C:\avr-gcc-10.1.0-x64-windows directory:
$ find -name &#39;*328p*&#39;
./avr/include/avr/iom328p.h
./avr/lib/avr5/crtatmega328p.o
./avr/lib/avr5/libatmega328p.a
./lib/gcc/avr/10.1.0/device-specs/specs-atmega328p
./lib/gcc/avr/10.1.0/device-specs/specs-atmega328pb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, there are a bunch of files for the ATmega328&lt;strong&gt;P&lt;/strong&gt; that are
missing for the ATmega328&lt;strong&gt;PB&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;fixing-avr-gcc&#34;&gt;Fixing AVR-GCC&lt;/h2&gt;
&lt;p&gt;Fixing GCC requires two steps: copying some files, and patching a header file.&lt;/p&gt;
&lt;h3 id=&#34;1-copying-the-files&#34;&gt;1. Copying the files&lt;/h3&gt;
&lt;p&gt;You can get the files from the 
&lt;a href=&#34;http://packs.download.atmel.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ATmega DFP support pack&lt;/a&gt; from Microchip&amp;rsquo;s website, or from your install of Microchip Studio.&lt;/p&gt;
&lt;h4 id=&#34;from-the-atmega-dfp-support-pack&#34;&gt;From the ATmega DFP Support Pack&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Download the 
&lt;a href=&#34;http://packs.download.atmel.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ATmega DFP support pack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unzip the relevant files:
unzip -j Atmel.ATmega_DFP.x.y.zzz.atpack &lt;br&gt;
gcc/dev/atmega328pb/avr5/crtatmega328pb.o &lt;br&gt;
gcc/dev/atmega328pb/avr5/libatmega328pb.a &lt;br&gt;
include/avr/iom328pb.h&lt;/li&gt;
&lt;li&gt;Place the &lt;code&gt;.o&lt;/code&gt; and &lt;code&gt;.a&lt;/code&gt; files &lt;code&gt;C:\avr-gcc-10.1.0-x64-windows\avr\lib\avr5\&lt;/code&gt; (so next to their 328P counterparts).&lt;/li&gt;
&lt;li&gt;Place the &lt;code&gt;.h&lt;/code&gt; file in &lt;code&gt;C:\avr-gcc-10.1.0-x64-windows\avr\include\avr\&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Continue with the &amp;lsquo;Common Last Step&amp;rsquo; below&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;from-microchip-studio&#34;&gt;From Microchip Studio&lt;/h4&gt;
&lt;p&gt;Use this if you have Microchip Studio with the ATmega DFP support pack already installed.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find the DSP at &lt;code&gt;C:\Program Files\Microchip\xc8\vX.YY\dfp\xc8\avr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;From &lt;code&gt;lib\avr5&lt;/code&gt;, copy &lt;code&gt;crtatmega328pb.o&lt;/code&gt; and &lt;code&gt;libatmega328pb.a&lt;/code&gt; to &lt;code&gt;C:\avr-gcc-10.1.0-x64-windows\avr\lib\avr5\&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;include\avr\iom328pb.h&lt;/code&gt; to &lt;code&gt;C:\avr-gcc-10.1.0-x64-windows\avr\include\avr\&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Continue with the &amp;lsquo;Common Last Step&amp;rsquo; below&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;2-patching-ioh&#34;&gt;2. Patching io.h&lt;/h3&gt;
&lt;p&gt;Add the following to &lt;code&gt;C:\avr-gcc-10.1.0-x64-windows\avr\include\avr\io.h&lt;/code&gt; just underneath the part that handles the ATmega328P.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;#elif defined (__AVR_ATmega328PB__)
#  include &amp;lt;avr/iom328pb.h&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now be able to use &lt;code&gt;avr-gcc -mmcu=atmega328pb&lt;/code&gt; and &lt;code&gt;avr-g++ -mmcu=atmega328pb&lt;/code&gt;
to compile C and C++ sources for the ATmega328PB chip.&lt;/p&gt;
&lt;h2 id=&#34;fixing-avrdude&#34;&gt;Fixing AVRDude&lt;/h2&gt;
&lt;p&gt;To actually program the ATmega328PB with AVRDude, you need to update its
configuration &lt;code&gt;avrdude.conf&lt;/code&gt;. You can find the file in
&lt;code&gt;c:\avr-gcc-10.1.0-x64-windows\bin\avrdude.conf&lt;/code&gt; or in &lt;code&gt;/etc/avrdude.conf&lt;/code&gt; on
Linux.&lt;/p&gt;
&lt;p&gt;Add this below the ATmega328P definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-plain&#34;&gt;part parent &amp;quot;m328&amp;quot;
    id          = &amp;quot;m328pb&amp;quot;;
    desc        = &amp;quot;ATmega328PB&amp;quot;;
    signature   = 0x1e 0x95 0x16;

    ocdrev      = 1;
;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;setting-up-microchip-studio&#34;&gt;Setting up Microchip Studio&lt;/h2&gt;
&lt;p&gt;To configure Microchip Studio to use this new GCC, you have to add a &lt;em&gt;Toolchain
Flavour&lt;/em&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the project properties, &amp;ldquo;Advanced&amp;rdquo; tab, and there follow the
link to the preferences.&lt;/li&gt;
&lt;li&gt;Add a new flavour for both the &lt;em&gt;Atmel AVR 8-bit (C
Language)&lt;/em&gt; and &lt;em&gt;Atmel AVR 8-bit (CPP language)&lt;/em&gt; toolchains. Name it whatever you
want, and point it to the &lt;code&gt;bin&lt;/code&gt; directory of your GCC install.&lt;/li&gt;
&lt;li&gt;Press OK, and select the new toolchain flavour from the drop-down select box.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;credits&#34;&gt;Credits&lt;/h2&gt;
&lt;p&gt;This post was adapted from 
&lt;a href=&#34;https://gist.github.com/goncalor/51e1c8038cc058b4379552477255b4e1&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Gonçalo Ribeiro&amp;rsquo;s gist&lt;/a&gt;.
I decided to change some things around to match my own development environment.
Also having it as part of my blog makes it easier to find for whenever I need to
repeat this trick.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v5.0 released</title>
      <link>https://stuvel.eu/post/2021-03-09-beatstripper-for-beatsaber-1.14/</link>
      <pubDate>Fri, 19 Mar 2021 09:53:31 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-03-09-beatstripper-for-beatsaber-1.14/</guid>
      <description>&lt;p&gt;This release of 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt; is
compatible with the newly released Beat Saber 1.14 (new OST, yay!).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Show how many solo scores you improved since the last run. Requires running with the &lt;code&gt;-solo&lt;/code&gt; CLI option.&lt;/li&gt;
&lt;li&gt;Skip saving files when there was nothing for BeatStripper to do.&lt;/li&gt;
&lt;li&gt;Support file format 2.0.16, introduced by BeatSaber version 1.14.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BeatStripper strips down party mode scores to just each player&amp;rsquo;s highest score.
It can also merge Solo scores into the Party leaderboards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v4.2 for BeatSaber 1.13.4</title>
      <link>https://stuvel.eu/post/2021-03-09-beatstripper-for-beatsaber-1.13.4/</link>
      <pubDate>Tue, 09 Mar 2021 21:39:21 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-03-09-beatstripper-for-beatsaber-1.13.4/</guid>
      <description>&lt;p&gt;This release of 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt; is
compatible with the newly released Beat Saber 1.13.4.&lt;/p&gt;
&lt;p&gt;BeatStripper strips down party mode scores to just each player&amp;rsquo;s highest score.
It can also merge Solo scores into the Party leaderboards.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;There was an issue with this release, so I removed it from the releases page. Hold on, I&amp;rsquo;m working on a fix.&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;There was no issue with this release, just a misunderstanding. Version 4.2 is good to go!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatZipper v2.0 released</title>
      <link>https://stuvel.eu/post/2021-03-05-beatzipper-v2/</link>
      <pubDate>Fri, 05 Mar 2021 23:58:05 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-03-05-beatzipper-v2/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.beatsavior.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Beat Savior&lt;/a&gt; is a great site to download custom

&lt;a href=&#34;https://www.beatsaber.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Beat Saber&lt;/a&gt; maps, most of all because you can watch
a preview of the level on their website. This makes it really convenient to
browse, check, and download the maps.&lt;/p&gt;
&lt;p&gt;The biggest gripe I have is that after downloading you have to manually install
each map, by creating a directory and unzipping the downloaded file. Yes, there
are other ways, but this manual approach makes it possible for me to do this
while waiting for, say, some software I&amp;rsquo;m working on to compile.&lt;/p&gt;
&lt;p&gt;So, of course, I automated the process and created &lt;strong&gt;BeatZipper&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This version adds a nicer interface, and is simpler to use.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatzipper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Check the 
&lt;a href=&#34;https://stuvel.eu/software/beatzipper/&#34;&gt;BeatZipper&lt;/a&gt; page
for instructions on how to use it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v4.0 released</title>
      <link>https://stuvel.eu/post/2021-03-02-beatstripper-v4/</link>
      <pubDate>Tue, 02 Mar 2021 21:14:14 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-03-02-beatstripper-v4/</guid>
      <description>&lt;p&gt;This release of 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt; fixes an
issue with including &lt;strong&gt;Solo scores&lt;/strong&gt; in Beat Saber&amp;rsquo;s &lt;strong&gt;Party Mode&lt;/strong&gt;
leaderboards, and adds experimental support for &lt;strong&gt;Linux&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Some new commandline arguments have also been added, but they&amp;rsquo;re mostly useful
for me as a developer.&lt;/p&gt;
&lt;p&gt;Set up a shortcut that runs &lt;code&gt;beatstripper.exe -solo&lt;/code&gt;, run it, and it&amp;rsquo;ll copy
your solo scores into party mode.&lt;/p&gt;
&lt;p&gt;First time you run it you&amp;rsquo;ll have to give your name. This will get &amp;ldquo;(solo)&amp;rdquo;
appended to it, so typing the name &amp;ldquo;Sybren&amp;rdquo; will result in &amp;ldquo;Sybren (solo)&amp;rdquo; in
the Party Mode leaderboards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v3.0 released</title>
      <link>https://stuvel.eu/post/2021-02-17-beatstripper-v3/</link>
      <pubDate>Wed, 17 Feb 2021 21:06:04 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-02-17-beatstripper-v3/</guid>
      <description>&lt;p&gt;Include your &lt;strong&gt;Solo scores&lt;/strong&gt; in Beat Saber&amp;rsquo;s &lt;strong&gt;Party Mode&lt;/strong&gt; leaderboards.&lt;/p&gt;
&lt;p&gt;Have you ever wanted to know what score you got in Solo mode, while actually
playing in Party Mode? This version of

&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;Beat Stripper&lt;/a&gt;
adds an experimental feature that makes this possible.&lt;/p&gt;
&lt;p&gt;Set up a shortcut that runs &lt;code&gt;beatstripper.exe -solo&lt;/code&gt;, run it, and it&amp;rsquo;ll copy
your solo scores into party mode.&lt;/p&gt;
&lt;p&gt;First time you run it you&amp;rsquo;ll have to give your name. This will get &amp;ldquo;(solo)&amp;rdquo;
appended to it, so typing the name &amp;ldquo;Sybren&amp;rdquo; will result in &amp;ldquo;Sybren (solo)&amp;rdquo; in
the Party Mode leaderboards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatStripper v2.0 released</title>
      <link>https://stuvel.eu/post/2021-01-24-beatstripper/</link>
      <pubDate>Sun, 24 Jan 2021 14:56:16 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-01-24-beatstripper/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.beatsaber.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Beat Saber&lt;/a&gt; is a great party game, but I have one
gripe with the way it handles party high scores. It stores the last 10 high
scores of each song, regardless of who obtained those scores. So, I made a
little program to clean them up and only keep one high score per player.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatstripper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Read more about how to use it on 
&lt;a href=&#34;https://stuvel.eu/software/beatstripper/&#34;&gt;my BeatStripper page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to 
&lt;a href=&#34;https://mastodon.social/@fribbledom&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Muesli&lt;/a&gt; for pointing me to the

&lt;a href=&#34;https://github.com/charmbracelet/bubbletea&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;BubbleTea&lt;/a&gt; framework, which I used
to create the Text User Interface for BeatStripper.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>MyPy and Blender</title>
      <link>https://stuvel.eu/post/2021-01-15-mypy-and-blender/</link>
      <pubDate>Fri, 15 Jan 2021 16:24:18 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-01-15-mypy-and-blender/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;http://mypy-lang.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MyPy&lt;/a&gt; is a fantastic tool to do static checks of Python code. To make it
work well with 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt;, there are some tweaks to make to its
configuration.&lt;/p&gt;
&lt;p&gt;This is the config that I use. You can place it in a &lt;code&gt;pyproject.toml&lt;/code&gt; file, or
in &lt;code&gt;mypy.ini&lt;/code&gt;, whatever you wish.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[mypy]
python_version = 3.7
ignore_missing_imports = True
strict_optional = True
disallow_subclassing_any = False
disallow_any_generics = True
disallow_untyped_calls = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = true
warn_return_any = True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enforces that a typed function (so one that declares at least one parameter
or its return type) only calls into other typed functions. I&amp;rsquo;ve made mistakes in
the past where MyPy ignored an untyped function; the lack of errors made me
think incorrectly that the code was ok.&lt;/p&gt;
&lt;p&gt;The only thing that MyPy doesn&amp;rsquo;t like is the way Blender declares properties,
for example in operators and property groups. To work around this, use a &lt;code&gt;# type: ignore&lt;/code&gt; marker,
like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;from bpy.props import BoolProperty, PropertyGroup
class MyAddonSettings(PropertyGroup):
    enable_feature : BoolProperty(      # type: ignore
        name = &amp;quot;Enable The Feature&amp;quot;,
        description = &amp;quot;Turn on this amazing thing and be amazed&amp;quot;,
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all of this in place, you can run &lt;code&gt;mypy my_addon.py&lt;/code&gt; (for single-file
addons) or &lt;code&gt;mypy my_addon&lt;/code&gt; (where &lt;code&gt;my_addon&lt;/code&gt; is the directory containing the
Python sources).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 4.7 released!</title>
      <link>https://stuvel.eu/post/2021-01-10-python-rsa-4-7-released/</link>
      <pubDate>Sun, 10 Jan 2021 11:47:18 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-01-10-python-rsa-4-7-released/</guid>
      <description>&lt;p&gt;The final release of &lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA v4.7&lt;/a&gt;&lt;/strong&gt; can be obtained from 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa/4.7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python
Package Index&lt;/a&gt;, or just installed with
&lt;code&gt;pip install --upgrade rsa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This release contains improvements by hugovk, tomato42, and myself of course:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Declare &amp;amp; test support for Python 3.9.&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25658&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CVE-2020-25658&lt;/a&gt; - Bleichenbacher-style timing oracle in PKCS#1 v1.5 decryption code (Fixes 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/165&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#165&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Add padding length check as described by PKCS#1 v1.5 (Fixes 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/164&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#164&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Reuse of blinding factors to speed up blinding operations (Fixes 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/162&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#162&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More information on the 
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA&lt;/a&gt; page.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Locally re-pulling a Blender patch</title>
      <link>https://stuvel.eu/post/2021-01-08-arc-pull/</link>
      <pubDate>Fri, 08 Jan 2021 11:20:46 +0100</pubDate>
      <guid>https://stuvel.eu/post/2021-01-08-arc-pull/</guid>
      <description>&lt;p&gt;As core developer of 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; I often &lt;strong&gt;review
patches&lt;/strong&gt; from colleagues and other contributors. Getting that patch on my local
machine is as easy as typing &lt;code&gt;arc patch D1234&lt;/code&gt;, where &lt;code&gt;D1234&lt;/code&gt; is the patch
number. Once the author of the patch has updated it according to the feedback of
the reviewers, it&amp;rsquo;s not as trivial to &lt;strong&gt;update my local copy of the patch&lt;/strong&gt;,
though. This involves:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout master
git branch -D arcpatch-D1234
arc patch D1234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without deleting the branch, Arcanist will, instead of updating the existing
one, make a new branch for the patch.&lt;/p&gt;
&lt;p&gt;So, as usual, I wrote a little &lt;strong&gt;Fish shell script&lt;/strong&gt; to do this work for me.
Fish shell? Yeah. After I posted 
&lt;a href=&#34;https://stuvel.eu/post/2020-08-05-zsh-config/&#34;&gt;my ZSH configuration&lt;/a&gt;,
a friend of mine pointed me to the 
&lt;a href=&#34;https://fishshell.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Fish shell&lt;/a&gt;. It took
a bit of getting used to, but now I&amp;rsquo;m hooked, and I use it wherever I can. I
might write another blog post about that some time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE (2021-02-01)&lt;/strong&gt;: I&amp;rsquo;ve added optional rebasing on top of &lt;code&gt;master&lt;/code&gt; to the
commands. Just press ENTER to rebase, or Ctrl+C to skip that step and keep the
branch as-is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-fish&#34;&gt;function git_rebase_onto_master
    read -P &amp;quot;Rebase onto master? ENTER for yes, CTRL+C for no.&amp;quot;
    git rebase master &amp;amp;&amp;amp; git submodule foreach git pull --rebase origin master
end

function arcpull -d &amp;quot;Refresh and reapply the current patch from Phabricator&amp;quot;
    set BRANCH (git branch --show-current 2&amp;gt;/dev/null)
    if [ -z &amp;quot;$BRANCH&amp;quot; ];
        echo &amp;quot;Not on a Git repo&amp;quot;
        return 42
    end

    set PATCHNUM (string replace arcpatch-D &#39;&#39; $BRANCH)
    if [ $BRANCH = $PATCHNUM ];
        echo &amp;quot;Current branch $BRANCH is not an arcpatch branch&amp;quot; &amp;gt;&amp;amp;2
        return 47
    end
    echo &amp;quot;Current branch $BRANCH is for patch $PATCHNUM&amp;quot;

    git checkout master
    git branch -D $BRANCH
    arc patch D$PATCHNUM
    git_rebase_onto_master
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all I have to do is type &lt;code&gt;arcpull&lt;/code&gt; and it&amp;rsquo;ll figure out which patch the
current branch is for, and get a fresh copy for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: I&amp;rsquo;ve added another command to the script: &lt;code&gt;arcpatch D1234&lt;/code&gt;. This
nukes the &lt;code&gt;arcpatch-D1234&lt;/code&gt; branch if you have it, and re-fetches the patch. It&amp;rsquo;s
basically a version of the script above, except that it doesn&amp;rsquo;t take the
D-number from the current branch but from the CLI argument.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-fish&#34;&gt;function arcpatch -a PATCHNAME -d &amp;quot;Apply a patch from Phabricator&amp;quot;
    if test -z &amp;quot;$PATCHNAME&amp;quot;;
        echo &amp;quot;Usage: arcpatch D1234&amp;quot; &amp;gt;&amp;amp;2
        return 47
    end

    set BRANCH arcpatch-$PATCHNAME

    set CURBRANCH (git branch --show-current 2&amp;gt;/dev/null)
    if test &amp;quot;$CURBRANCH&amp;quot; != &amp;quot;master&amp;quot;;
        git checkout master
    end

    if git branch | grep -q $BRANCH;
        printf &amp;quot;\033[95mBranch $BRANCH exists, going to refresh it\033[0m\n&amp;quot;
        git branch -D $BRANCH
    else
        printf &amp;quot;\033[96mBranch $BRANCH does not exist\033[0m\n&amp;quot;
    end
    arc patch $PATCHNAME
    git_rebase_onto_master
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2&lt;/strong&gt;: another command to simply remove all &lt;code&gt;arcpatch-Dxxxx&lt;/code&gt; branches:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-fish&#34;&gt;function arcprune -d &amp;quot;Delete all arcpatch-Dxxxx branches&amp;quot;
    set BRANCHES (string trim (git branch | grep arcpatch-D))
    if test -z &amp;quot;$BRANCHES&amp;quot;;
        echo &amp;quot;No arc branches to prune&amp;quot;
        return 0
    end
    echo git branch -D $BRANCHES
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This post was made possible by the 
&lt;a href=&#34;https://fund.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Development Fund&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Toggle Blender&#39;s Build Options</title>
      <link>https://stuvel.eu/post/2020-12-07-enable-disable-stuff-blender/</link>
      <pubDate>Mon, 07 Dec 2020 13:11:51 +0100</pubDate>
      <guid>https://stuvel.eu/post/2020-12-07-enable-disable-stuff-blender/</guid>
      <description>&lt;p&gt;My work on 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; mostly involves the Animation &amp;amp;
Rigging module. For this, I can do without Cycles, USD, Alembic, Collada, and
some other modules. Disabling those modules allows me to &lt;strong&gt;build Blender faster&lt;/strong&gt;.
It would be even faster to disable everything you can disable, but that would
disable way too much. Also, it&amp;rsquo;s hard to change it back, because you can&amp;rsquo;t just
enable everything either.&lt;/p&gt;
&lt;p&gt;So, as usual, I wrote a little script to do this for me. Save the script below
to your build directory, and name it &lt;code&gt;enable-stuff.sh&lt;/code&gt;. Then create a symlink
&lt;code&gt;ln -s enable-stuff.sh disable-stuff.sh&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash

MY_BASE=$(basename &amp;quot;$0&amp;quot;)
MY_DIR=$(dirname $(readlink -f $0))

case $MY_BASE in
    enable-stuff.sh)
        WITH=ON
        ;;
    disable-stuff.sh)
        WITH=OFF
        ;;
    *)
        echo &amp;quot;Unknown name $MY_BASE&amp;quot; &amp;gt;&amp;amp;2
        exit 47
        ;;
esac

set -ex
cd $MY_DIR
cmake \
    -DWITH_ALEMBIC=${WITH} \
    -DWITH_OPENCOLLADA=${WITH} \
    -DWITH_USD=${WITH} \
    -DWITH_CODEC_AVI=${WITH} \
    -DWITH_CYCLES=${WITH} \
    -DWITH_LIBMV=${WITH} \
    -DWITH_MOD_FLUID=${WITH} \
    -DWITH_MOD_OCEANSIM=${WITH} \
    -DWITH_MOD_REMESH=${WITH} \
    .
nice -n 20 ninja -C $MY_DIR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I made a similar script for enabling and disabling tests, which only sets the
&lt;code&gt;WITH_GTESTS&lt;/code&gt; build option. I&amp;rsquo;ll leave that as an exercise for the reader.&lt;/p&gt;
&lt;p&gt;This post was made possible by the 
&lt;a href=&#34;https://fund.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Development Fund&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BeatZipper</title>
      <link>https://stuvel.eu/post/2020-12-05-beatzipper/</link>
      <pubDate>Sat, 05 Dec 2020 21:20:54 +0100</pubDate>
      <guid>https://stuvel.eu/post/2020-12-05-beatzipper/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.beatsavior.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Beat Savior&lt;/a&gt; is a great site to download custom

&lt;a href=&#34;https://www.beatsaber.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Beat Saber&lt;/a&gt; maps, most of all because you can watch
a preview of the level on their website. This makes it really convenient to
browse, check, and download the maps.&lt;/p&gt;
&lt;p&gt;The biggest gripe I have is that after downloading you have to manually install
each map, by creating a directory and unzipping the downloaded file. Yes, there
are other ways, but this manual approach makes it possible for me to do this
while waiting for, say, some software I&amp;rsquo;m working on to compile.&lt;/p&gt;
&lt;p&gt;So, of course, I automated the process and created &lt;strong&gt;BeatZipper&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;
&lt;a href=&#34;https://gitlab.com/dr.sybren/beatzipper/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download the latest release&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Check the 
&lt;a href=&#34;https://stuvel.eu/software/beatzipper/&#34;&gt;BeatZipper&lt;/a&gt; page
for instructions on how to use it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>PWM and Visual Brightness</title>
      <link>https://stuvel.eu/post/2020-12-02-pwm-and-visual-brightness/</link>
      <pubDate>Wed, 02 Dec 2020 11:58:34 +0100</pubDate>
      <guid>https://stuvel.eu/post/2020-12-02-pwm-and-visual-brightness/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I&amp;rsquo;ve made an 
&lt;a href=&#34;https://stuvel.eu/software/light/&#34;&gt;online version of the script&lt;/a&gt; too. So if you just want to get the values, go there &amp;amp; use it directly in your browser.&lt;/p&gt;
&lt;p&gt;For my microcontroller projects I often want to convert some linear value (like
a potentiometer position) into a light intensity. Since &lt;strong&gt;our eyes aren&amp;rsquo;t
linear&lt;/strong&gt;, this requires some math, and generally microcontrollers aren&amp;rsquo;t that
good in math.&lt;/p&gt;
&lt;p&gt;Our eyes roughly experience a doubling of the amount of light as a single
&amp;ldquo;step&amp;rdquo;. Double it again, and we perceive it as a similarly-sized step. This
means that, for our eyes to perceve the light becoming brighter linearly, it
actually needs do that exponentially.&lt;/p&gt;
&lt;figure id=&#34;figure-10-bit-power-levels-produced-by-my-script-the-linear-start-is-hard-to-see-but-it-helps-in-controlling-the-light&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2020-12-02-pwm-and-visual-brightness/graph-10bit_hu4f3c06b0be7e608c159ad117d30b7a71_9141_2000x2000_fit_lanczos_3.png&#34; data-caption=&#34;10-bit Power levels produced by my script. The linear start is hard to see, but it helps in controlling the light.&#34;&gt;
  &lt;img data-src=&#34;https://stuvel.eu/post/2020-12-02-pwm-and-visual-brightness/graph-10bit_hu4f3c06b0be7e608c159ad117d30b7a71_9141_2000x2000_fit_lanczos_3.png&#34; class=&#34;lazyload&#34; alt=&#34;Exponentially growing light power, with a little linear start&#34; width=&#34;739&#34; height=&#34;243&#34;&gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    10-bit Power levels produced by my script. The linear start is hard to see, but it helps in controlling the light.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My microcontrollers use either a 10-bit or 8-bit value to contol the brightness.
This provides a bit of a technical hurdle, because the exponential growth of the
light&amp;rsquo;s brightness actually starts out really slow. Converting that slow start
to a sequence of integers would produce a sequence like &lt;code&gt;0 0 0 1 1 2 3 5&lt;/code&gt;. Those
repeated numbers mean that whatever you use to control the light (like up/down
buttons) will appear to do nothing at first. To prevent this, my script will
simply &lt;strong&gt;start with linearly increasing numbers&lt;/strong&gt;, like &lt;code&gt;0 1 2 3 4 5&lt;/code&gt;, before moving
on to an &lt;strong&gt;exponential slope&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;using-the-script&#34;&gt;Using the script&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I&amp;rsquo;ve made an 
&lt;a href=&#34;https://stuvel.eu/software/light/&#34;&gt;online version of the script&lt;/a&gt; too. So if you just want to get the values, go there &amp;amp; use it directly in your browser.&lt;/p&gt;
&lt;p&gt;The script needs 
&lt;a href=&#34;https://www.python.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python&lt;/a&gt; to run. Download

&lt;a href=&#34;sybrens_light_intensity_script.py&#34;&gt;&lt;code&gt;sybrens_light_intensity_script.py&lt;/code&gt;&lt;/a&gt;, save it, edit it in a text editor
to adjust the parameters to your needs, and run it. It will output a few lines
of C code that can be used for microcontrollers.&lt;/p&gt;
&lt;h2 id=&#34;example-10-bit-output&#34;&gt;Example 10-bit output&lt;/h2&gt;
&lt;p&gt;This is what will be printed with the default settings of the script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10 bit intensity values&lt;/li&gt;
&lt;li&gt;30 steps in total&lt;/li&gt;
&lt;li&gt;6 linear steps to start with&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-cpp&#34;&gt;static const uint16_t light_map_10bit[] = {
    0, 1, 2, 3, 4, 5, 7, 9, 11, 14, 18, 22, 28, 35, 43, 54, 67, 83, 102,
    126, 156, 192, 237, 293, 361, 444, 548, 674, 831, 1023};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;example-8-bit-output&#34;&gt;Example 8-bit output&lt;/h2&gt;
&lt;p&gt;This is what will be printed with some modified settings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8 bit intensity values&lt;/li&gt;
&lt;li&gt;30 steps in total&lt;/li&gt;
&lt;li&gt;4 linear steps to start with&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-cpp&#34;&gt;static const uint8_t light_map_8bit[] = {
    0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 24, 29, 34, 40, 47, 54,
    64, 74, 87, 102, 118, 138, 161, 188, 219, 255};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;how-i-use-it&#34;&gt;How I use it&lt;/h2&gt;
&lt;p&gt;The values in the light map produced by my script are fed to a &lt;strong&gt;Pulse Width
Modulator&lt;/strong&gt;. These simply count up until their maximum (1023 for a 10-bit one)
and then restart at zero again. When they start counting, they turn on the
light, and when they go past a given value, they turn off the light again. The
higher the value, the longer the light stays on, and the brighter you see it.
This happens all thousands of times per second, so to our eyes the light is
stable, even though it&amp;rsquo;s actually rapidly blinking.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Phabricator Link Copy</title>
      <link>https://stuvel.eu/post/2020-11-19-greasemonkey-phabricator-link-copy/</link>
      <pubDate>Thu, 19 Nov 2020 14:03:58 +0100</pubDate>
      <guid>https://stuvel.eu/post/2020-11-19-greasemonkey-phabricator-link-copy/</guid>
      <description>&lt;p&gt;Blender developers use 
&lt;a href=&#34;https://developer.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Phabricator&lt;/a&gt; to track
tasks, bug reports, and patches. Often I need to create links to patch reviews,
bug reports, etc. I got tired of manually typing those, so I created a little

&lt;a href=&#34;https://www.greasespot.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Greasemonkey&lt;/a&gt; script.&lt;/p&gt;
&lt;p&gt;First download the 
&lt;a href=&#34;https://www.greasespot.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GreaseMonkey&lt;/a&gt; add-on for your browser, then add the
script. It should create two buttons in the top bar, &amp;ldquo;MD&amp;rdquo; and &amp;ldquo;WIKI&amp;rdquo;, for
respectively MarkDown and MediaWiki syntax.&lt;/p&gt;
&lt;p&gt;This is my 2nd GreaseMonkey script for Phabricator, the first one was to

&lt;a href=&#34;https://stuvel.eu/post/2020-09-29-greasemonkey-phabricator-list-count/&#34;&gt;count things in lists&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// ==UserScript==
// @name     Phabricator Document Link
// @version  1
// @include  https://developer.blender.org/*
// @grant    GM.setClipboard
// ==/UserScript==

function add_document_links() {
  let page_name = find_page_name();
  if (page_name === &amp;quot;&amp;quot;) return;

  let page_title = find_page_title();
  if (page_title === &amp;quot;&amp;quot;) return;

  add_button(&amp;quot;MD&amp;quot;, &amp;quot;[&amp;quot; + page_name + &amp;quot;: &amp;quot; + page_title + &amp;quot;](&amp;quot; + window.location + &amp;quot;)&amp;quot;);
  add_button(&amp;quot;MD (short)&amp;quot;, &amp;quot;[&amp;quot; + page_name + &amp;quot;](&amp;quot; + window.location + &amp;quot;)&amp;quot;);

  if (is_git_commit(page_name)) {
    let commit_id = window.location.pathname.substr(1, 14);
    add_button(&amp;quot;WIKI (long)&amp;quot;, &amp;quot;{{GitCommit|&amp;quot; + commit_id + &amp;quot;}}: &amp;quot; + page_title);
    add_button(&amp;quot;WIKI (short)&amp;quot;, &amp;quot;{{GitCommit|&amp;quot; + commit_id + &amp;quot;}}&amp;quot;);
  } else {
    add_button(&amp;quot;WIKI&amp;quot;, &amp;quot;{{Phab|&amp;quot; + page_name + &amp;quot;}}: &amp;quot; + page_title);
  }

  add_button(&amp;quot;TXT&amp;quot;, page_name + &amp;quot;: &amp;quot; + page_title);
}

function add_button(button_text, clipboard_text) {
  let button = document.createElement(&#39;button&#39;);
  button.textContent = button_text;
  button.className = &#39;button button-grey&#39;;
  button.setAttribute(&amp;quot;title&amp;quot;, clipboard_text);
  button.addEventListener(&#39;click&#39;, function() {
    console.log(&#39;Clipboard:&#39;, clipboard_text);
    GM.setClipboard(clipboard_text);
  });

  let button_parent_elt = find_button_parent_element();
  button_parent_elt.appendChild(button);
}

function find_button_parent_element() {
  let elements = document.getElementsByClassName(&#39;phabricator-main-menu-alerts&#39;);
  if (elements.length == 0) return undefined;
  return elements[0];
}

function find_page_name_element() {
  let page_name_elts = document.getElementsByClassName(&#39;phui-crumb-name&#39;);
  if (page_name_elts.length == 0) return undefined;
  return page_name_elts[page_name_elts.length-1];
}

function find_page_name() {
  let page_name_elt = find_page_name_element();
  if (!page_name_elt) return &amp;quot;&amp;quot;;
  return page_name_elt.textContent.trim();
}

function find_page_title() {
  let page_title_elts = document.getElementsByClassName(&#39;phui-header-header&#39;);
  if (page_title_elts.length == 0) return &amp;quot;&amp;quot;;
  let page_title = page_title_elts[0].textContent;
  return page_title.trim();
}

function is_git_commit(page_name) {
  return page_name.length == 12 &amp;amp;&amp;amp; /^[0-9A-Fa-f]{12}$/.test(page_name) &amp;amp;&amp;amp; window.location.pathname.startsWith(&amp;quot;/r&amp;quot;)
}

window.setTimeout(add_document_links, 100);
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Phabricator List Count</title>
      <link>https://stuvel.eu/post/2020-09-29-greasemonkey-phabricator-list-count/</link>
      <pubDate>Tue, 29 Sep 2020 11:39:11 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-09-29-greasemonkey-phabricator-list-count/</guid>
      <description>&lt;p&gt;Blender developers use 
&lt;a href=&#34;https://developer.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Phabricator&lt;/a&gt; to track
tasks, bug reports, and patches. Powerful as Phabricator is, when listing the
patches that are waiting to be reviewed, it doesn&amp;rsquo;t give you the total count.
Since we have to report those counts, I got tired of manually counting them and
created a little 
&lt;a href=&#34;https://www.greasespot.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Greasemonkey&lt;/a&gt; script.&lt;/p&gt;
&lt;p&gt;First download the 
&lt;a href=&#34;https://www.greasespot.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GreaseMonkey&lt;/a&gt; add-on for your browser, then add the
above script. Any list view should now show the number of items in that list. It
also copies the next/previous page buttons to the top of the list, for easy
access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I made another GM script, for 
&lt;a href=&#34;https://stuvel.eu/post/2020-11-19-greasemonkey-phabricator-link-copy/&#34;&gt;copying MarkDown and MediaWiki
compatible links from Phabricator&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;// ==UserScript==
// @name     Phabricator Table Counts
// @version  1
// @include  https://developer.blender.org/*
// ==/UserScript==

function count_table_rows() {
  let listviews = document.getElementsByClassName(&#39;phui-oi-list-view&#39;);
  if (listviews.length == 0) {
    return;
  }
  let listview = listviews[0];
  let p = document.createElement(&#39;p&#39;);
  p.textContent = listview.children.length + &amp;quot; elements in this list.&amp;quot;;

  let pagers = document.getElementsByClassName(&#39;application-search-pager&#39;);
  if (pagers.length &amp;gt; 0) {
    p.textContent += &#39; There are more pages: &#39;;

    let buttons = pagers[0].getElementsByClassName(&#39;button&#39;);
    for (i=0; i&amp;lt;buttons.length; i++) {
      let button = buttons.item(i);
      p.appendChild(button);
    }
  }

  listview.parentElement.insertBefore(p, listview);
}

window.setTimeout(count_table_rows, 500);
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Skyfill v1.2 released</title>
      <link>https://stuvel.eu/post/2020-09-13-skyfill-v1-2/</link>
      <pubDate>Sun, 13 Sep 2020 11:53:33 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-09-13-skyfill-v1-2/</guid>
      <description>&lt;p&gt;Version v1.2 of 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt; has been released. The most important
improvements are support for &lt;strong&gt;16-bit colour&lt;/strong&gt; and &lt;strong&gt;AdobeRGB&lt;/strong&gt;. You can

&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;download the release from Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The 16-bit colour support is automatic. Feed Skyfill a 16-bit image, and it&amp;rsquo;ll
output a 16-bit TIFF.&lt;/p&gt;
&lt;p&gt;The AdobeRGB support is preliminary. It&amp;rsquo;s &lt;em&gt;not&lt;/em&gt; auto-detected from the input
file, so you have to run Skyfill with &lt;code&gt;skyfill -adobergb myimage&lt;/code&gt;. The output
image also won&amp;rsquo;t declare it&amp;rsquo;s AdobeRGB, but it will be. If you know of any way
to read and write embedded colour space information in

&lt;a href=&#34;https://golang.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Go&lt;/a&gt;, please 
&lt;a href=&#34;https://stuvel.eu/contact&#34;&gt;let me know&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;These improvements were sponsored by 
&lt;a href=&#34;https://dfwskyview.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dan Rose&lt;/a&gt;.
Thanks, Dan!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Most drones (UAVs) cannot look straight up to photograph the sky above them. As
a result, spherical panoramas made with drones tend to have a gap in the sky.
Some drones, like my DJI Mavic 2, can fill in this gap automatically while
generating a preview. However, when I stitch the photos myself to get a better
quality output, there is still that sky gap. I got fed up with having to choose
between a nice sky or a nice overall image, so I did what developers do and made
my own software: 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skyfill allows you to do fill in the gap in the sky in high-resolution
images&lt;/strong&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Comments on Scripting for Artists</title>
      <link>https://stuvel.eu/post/2020-09-01-scripting-for-artists-comments/</link>
      <pubDate>Tue, 01 Sep 2020 10:49:07 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-09-01-scripting-for-artists-comments/</guid>
      <description>&lt;p&gt;During the Corona lockdown, I&amp;rsquo;ve been extending my Python training series

&lt;a href=&#34;https://cloud.blender.org/p/scripting-for-artists&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Scripting for Artists&lt;/a&gt; with a bunch of free chapters. This has been picked
up by 
&lt;a href=&#34;https://nicoz.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Nico Zevallos&lt;/a&gt;, who has written down 
&lt;a href=&#34;https://github.com/gnastacast/scripting_for_artists&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;notes from the series&lt;/a&gt; on
GitHub. Not only that, he also shares the blend files that he made based on the
series. Thanks for the work, Nico.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://github.com/gnastacast/scripting_for_artists&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Go to Nico&amp;rsquo;s GitHub project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Scripting for Artists training series is available on Blender Cloud, and I
made it as part of my work at Blender Institute, funded by Blender Cloud
subscribers.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Zwijnenbergerweg</title>
      <link>https://stuvel.eu/post/2020-08-13-zwijnenbergerweg-panorama/</link>
      <pubDate>Thu, 13 Aug 2020 23:47:57 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-08-13-zwijnenbergerweg-panorama/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/panorama/zwijnenbergerweg/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Check this panorama photo on stuvelfoto.nl&lt;/a&gt;
to see it in its full splendor. Drag in the photo to look around.&lt;/p&gt;
&lt;p&gt;This is a panorama that I made for the 
&lt;a href=&#34;https://cloud.blender.org/p/hdri/579edb97c379cf425405cebc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dutch Landscape Pack&lt;/a&gt; on the HDRI
section of Blender Cloud. Over there it&amp;rsquo;s also available as HDR image for
Blender Cloud subscribers.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My ZSH configuration</title>
      <link>https://stuvel.eu/post/2020-08-05-zsh-config/</link>
      <pubDate>Wed, 05 Aug 2020 12:21:13 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-08-05-zsh-config/</guid>
      <description>&lt;p&gt;A while (read: over 4 years) ago I moved from Bash to ZSH, and never looked
back. Initially I tried it out because Bash was getting quite slow with its tab
completion, and ZSH was considerably faster. After switching, I also noted that
ZSH is smarter in other areas. For example, when typing &lt;code&gt;chmod -x {tab}&lt;/code&gt;, it&amp;rsquo;ll
only auto-complete with files that are executable. When typing
&lt;code&gt;chmod -x file1 {tab}&lt;/code&gt; it will even skip &lt;code&gt;file1&lt;/code&gt; because you already used that
one.&lt;/p&gt;
&lt;p&gt;Another advantage is that you can paste some commands into the shell and it will
not execute them until you press Enter. Even when there are newlines in the
pasted text, ZSH won&amp;rsquo;t execute until you actually press the Enter key. This IMO
is good for security, but also helps to avoid errors when accidentally pasting
the wrong thing.&lt;/p&gt;
&lt;p&gt;To get things working juuuust right, I had to tweak some settings. Note that
this doesn&amp;rsquo;t list everything in my &lt;code&gt;~/.zshrc&lt;/code&gt;, just some parts that I think may
be of interest to others.&lt;/p&gt;
&lt;h2 id=&#34;auto-completion&#34;&gt;Auto-completion&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# The following lines were added by compinstall
zstyle :compinstall filename &#39;/home/sybren/.zshrc&#39;

autoload -Uz compinit
compinit
# End of lines added by compinstall

# Get Git/Mercurial/SVN info in the prompt (current branch, current action, etc.)
autoload -Uz vcs_info
zstyle &#39;:vcs_info:*&#39; enable hg git svn
# Display current HG action (like &#39;merging&#39;)
zstyle &#39;:vcs_info:hg*&#39; get-mq true
zstyle &#39;:vcs_info:*&#39;         formats &#39;%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b|%m%F{5}]%f&#39;
zstyle &#39;:vcs_info:hg*&#39; actionformats &#39;%F{5}(%f%s|%F{red}%a%F{5})%F{3}-%F{5}[%F{2}%b|%m%F{5}]%f&#39;

precmd () { vcs_info }
export PS1=&#39;
%F{2}%n@%m%f %F{3}%~%f ${vcs_info_msg_0_}%E
%# &#39;

# Custom completions
zstyle &amp;quot;:completion:*:*:abcecho:*&amp;quot; file-patterns &amp;quot;*.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:abcls:*&amp;quot; file-patterns &amp;quot;*.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:abcview:*&amp;quot; file-patterns &amp;quot;*.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:usdview:*&amp;quot; file-patterns &amp;quot;*.usd[ac] *.usd *.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:usdcat:*&amp;quot; file-patterns  &amp;quot;*.usd[ac] *.usd *.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:usdtree:*&amp;quot; file-patterns  &amp;quot;*.usd[ac] *.usd *.abc *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:blender:*&amp;quot; file-patterns &amp;quot;*.blend *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:blenderdebug:*&amp;quot; file-patterns &amp;quot;*.blend *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:dot2png:*&amp;quot; file-patterns &amp;quot;*.dot *(-/)&amp;quot;
zstyle &amp;quot;:completion:*:*:gaffer:*&amp;quot; file-patterns &amp;quot;*.gfr *(-/)&amp;quot;
zstyle &#39;:completion:*&#39; completer _complete
zstyle &#39;:completion:*&#39; matcher-list &#39;&#39; &#39;m:{[:lower:][:upper:]}={[:upper:][:lower:]}&#39; &#39;+l:|=* r:|=*&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last line is some magic that makes ZSH autocomplete using substrings instead
of prefixes. In other words, it has tab completion also on the middle of a
filename. This makes it possible to type &lt;code&gt;mplayer mjpeg{tab}&lt;/code&gt; and get &lt;code&gt;mplayer llama.mjpeg&lt;/code&gt; (this file was the only &lt;code&gt;.mjpeg&lt;/code&gt; file in the directory).&lt;/p&gt;
&lt;h2 id=&#34;key-bindings&#34;&gt;Key Bindings&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;bindkey -e
bindkey &amp;quot;^[[3~&amp;quot;  delete-char
bindkey &amp;quot;^[3;5~&amp;quot; delete-char
bindkey &amp;quot;^K&amp;quot; kill-line

# Ctrl left/right for word skipping
bindkey &#39;;5D&#39; backward-word
bindkey &#39;;5C&#39; forward-word

my-backward-delete-word() {
    local WORDCHARS=${WORDCHARS/\//}
    zle backward-delete-word
}
zle -N my-backward-delete-word
bindkey &#39;^W&#39; my-backward-delete-word
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last big is to make Ctrl+W erase only a word, and not the entire line.&lt;/p&gt;
&lt;h2 id=&#34;fuzzy-finder&#34;&gt;Fuzzy Finder&lt;/h2&gt;
&lt;p&gt;For searching through history I use 
&lt;a href=&#34;https://github.com/junegunn/fzf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Fuzzy Finder&lt;/a&gt;. It makes it much easier
to find previous commands, as it doesn&amp;rsquo;t require you to search for it exactly.
This means that you can just do &lt;code&gt;{Ctrl+R}code blender&lt;/code&gt; to find
&lt;code&gt;code ~/workspace/blender-git/blender.code-workspace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another very nice thing is that Enter only selects the command from history. You
then have the opportunity to edit it, before pressing Enter again to execute it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Build before Debug in VSCode</title>
      <link>https://stuvel.eu/post/2020-07-23-build-before-debug-in-vscode/</link>
      <pubDate>Thu, 23 Jul 2020 10:11:43 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-07-23-build-before-debug-in-vscode/</guid>
      <description>&lt;p&gt;For debugging 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; I have set up my IDE 
&lt;a href=&#34;https://code.visualstudio.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Visual
Studio Code&lt;/a&gt; such that it builds Blender
whenever I start the debugger. Before I did this, I would ofte forget to
manually build Blender, causing all kinds of confusion when the code didn&amp;rsquo;t
match up with the behaviour.&lt;/p&gt;
&lt;p&gt;Running a compiler before starting the debug sessions concerns a few files.
First we need a task in &lt;code&gt;.vscode/tasks.json&lt;/code&gt;. Here I added two tasks, one for a
release-mode build and one for a debug-mode build:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
    &amp;quot;version&amp;quot;: &amp;quot;2.0.0&amp;quot;,
    &amp;quot;tasks&amp;quot;: [
        {
            &amp;quot;label&amp;quot;: &amp;quot;Build Release&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;shell&amp;quot;,
            &amp;quot;command&amp;quot;: &amp;quot;nice -n 20 ninja -C /home/sybren/workspace/blender-git/build_linux/&amp;quot;,
            &amp;quot;problemMatcher&amp;quot;: [
                &amp;quot;$gcc&amp;quot;
            ]
        },
        {
            &amp;quot;label&amp;quot;: &amp;quot;Build Debug&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;shell&amp;quot;,
            &amp;quot;command&amp;quot;: &amp;quot;nice -n 20 ninja -C /home/sybren/workspace/blender-git/build_debug/&amp;quot;,
            &amp;quot;problemMatcher&amp;quot;: [
                &amp;quot;$gcc&amp;quot;
            ]
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to update &lt;code&gt;launch.json&lt;/code&gt; to run that task before starting Blender
itself. Note the &lt;code&gt;preLaunchTask&lt;/code&gt;, which is set to the &lt;code&gt;label&lt;/code&gt; of the task to
run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
    &amp;quot;version&amp;quot;: &amp;quot;0.2.0&amp;quot;,
    &amp;quot;configurations&amp;quot;: [
        {
            &amp;quot;name&amp;quot;: &amp;quot;Blender&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;cppdbg&amp;quot;,
            &amp;quot;request&amp;quot;: &amp;quot;launch&amp;quot;,
            &amp;quot;program&amp;quot;: &amp;quot;/home/sybren/workspace/blender-git/build_debug/bin/blender&amp;quot;,
            &amp;quot;args&amp;quot;: [],
            &amp;quot;stopAtEntry&amp;quot;: false,
            &amp;quot;cwd&amp;quot;: &amp;quot;/home/sybren/workspace/blender-git/blender&amp;quot;,
            &amp;quot;environment&amp;quot;: [],
            &amp;quot;externalConsole&amp;quot;: false,
            &amp;quot;MIMode&amp;quot;: &amp;quot;gdb&amp;quot;,
            &amp;quot;preLaunchTask&amp;quot;: &amp;quot;Build Debug&amp;quot;,
            &amp;quot;setupCommands&amp;quot;: [
                {
                    &amp;quot;description&amp;quot;: &amp;quot;Enable pretty-printing for gdb&amp;quot;,
                    &amp;quot;text&amp;quot;: &amp;quot;-enable-pretty-printing&amp;quot;,
                    &amp;quot;ignoreFailures&amp;quot;: true
                }
            ]
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s all there is to it. Now whenever I press F5, a new debug build is made,
and Blender starts, and debugging can begin.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simple Amplifier</title>
      <link>https://stuvel.eu/post/2020-07-06-simple-amplifier/</link>
      <pubDate>Mon, 06 Jul 2020 21:18:34 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-07-06-simple-amplifier/</guid>
      <description>




  
  











&lt;figure id=&#34;figure-the-simple-amp&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/featured_hu9a862d82914797b37d90af82dc28d48c_447240_2000x2000_fit_q90_lanczos.jpg&#34; data-caption=&#34;The Simple Amp&#34;&gt;


  &lt;img data-src=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/featured_hu9a862d82914797b37d90af82dc28d48c_447240_2000x2000_fit_q90_lanczos.jpg&#34; class=&#34;lazyload&#34; alt=&#34;&#34; width=&#34;1500&#34; height=&#34;855&#34;&gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    The Simple Amp
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;I built an amplifier! This little fella is going to replace the big old amp that
I use to hear my electric drumkit. I have made amplifiers before, but this one
is by far the best-sounding (and most powerful) one so far.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s made using only three transistors, two of which are the big boys you see in
the photo above. They come from an old amplifier that I got from a friend and
took apart for, well&amp;hellip; parts.&lt;/p&gt;





  
  











&lt;figure id=&#34;figure-circuit-diagram-of-the-simple-amp&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/simple-amp-schematic_hu190b0d115c5ce1d270add190df2754a4_110804_2000x2000_fit_lanczos_3.png&#34; data-caption=&#34;Circuit diagram of the Simple Amp&#34;&gt;


  &lt;img data-src=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/simple-amp-schematic_hu190b0d115c5ce1d270add190df2754a4_110804_2000x2000_fit_lanczos_3.png&#34; class=&#34;lazyload&#34; alt=&#34;&#34; width=&#34;1389&#34; height=&#34;835&#34;&gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    Circuit diagram of the Simple Amp
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;The schematic shows how everything fits together. Transistors Q2 and Q3 form a
push-pull configuration, and are biased by diodes D1 and D2. Transistor Q1
amplifies the signal; its bias is automatically corrected by the feedback
resistor R6.&lt;/p&gt;





  
  











&lt;figure id=&#34;figure-the-bottom-of-the-board-shows-the-tracks-and-smd-components&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/simple-amp-bottom_huc3c27fc948b91867730e2bd4bb0d0e97_500285_2000x2000_fit_q90_lanczos.jpg&#34; data-caption=&#34;The bottom of the board shows the tracks and SMD components&#34;&gt;


  &lt;img data-src=&#34;https://stuvel.eu/post/2020-07-06-simple-amplifier/simple-amp-bottom_huc3c27fc948b91867730e2bd4bb0d0e97_500285_2000x2000_fit_q90_lanczos.jpg&#34; class=&#34;lazyload&#34; alt=&#34;&#34; width=&#34;1500&#34; height=&#34;684&#34;&gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    The bottom of the board shows the tracks and SMD components
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;Since it&amp;rsquo;ll be sitting in the same spot connected to the same things, it just
has some solder connections. The audio inputs will get jack connectors, and the
speaker will just be soldered on.&lt;/p&gt;
&lt;p&gt;The PCB I made myself using UV exposure, etching with sodium persulfate, and
some drilling. One day I&amp;rsquo;ll make some videos about the entire process.&lt;/p&gt;
&lt;p&gt;I already have plans for the next amplifier, which will be stereo and have a
volume knob and some actual connectors :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Drone Panoramas Explained</title>
      <link>https://stuvel.eu/post/2020-06-29-drone-panoramas-explained/</link>
      <pubDate>Mon, 29 Jun 2020 19:19:03 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-29-drone-panoramas-explained/</guid>
      <description>&lt;p&gt;Sometimes people want to know how I create my 
&lt;a href=&#34;https://stuvelfoto.nl/panorama/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;spherical drone panoramas&lt;/a&gt;.
I though it would be a nice touch to just write it down, so that&amp;rsquo;s what I did.&lt;/p&gt;
&lt;p&gt;Check out my article on
&lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/articles/drone-panoramas/&#34;&gt;creating 360 degree spherical panoramas with a drone&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Miniature Planets</title>
      <link>https://stuvel.eu/post/2020-06-28-mini-planets/</link>
      <pubDate>Sun, 28 Jun 2020 14:46:44 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-28-mini-planets/</guid>
      <description>&lt;p&gt;For a long time I&amp;rsquo;ve been making miniature planets. Until now it was mostly for
fun, but finally I&amp;rsquo;ve added a section dedicated to them to my photo website!&lt;/p&gt;
&lt;p&gt;Take a look at my 
&lt;a href=&#34;https://stuvelfoto.nl/planeet/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;miniature planets gallery&lt;/a&gt;.
There are 6 planets now; expect the collection to grow :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Planned Changes to Blender&#39;s Alembic Exporter</title>
      <link>https://stuvel.eu/post/2020-06-22-changes-to-alembic-in-blender/</link>
      <pubDate>Mon, 22 Jun 2020 18:56:17 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-22-changes-to-alembic-in-blender/</guid>
      <description>&lt;p&gt;Recently I have been working on a new Alembic exporter, in such a way that both
Universal Scene Description (USD) and Alembic can be exported using the same
code base. This makes the export of Alembic and USD consistent, but does cause
some changes that I would like community feedback on.&lt;/p&gt;
&lt;p&gt;The actual blog post is not here, but at the 
&lt;a href=&#34;https://code.blender.org/2020/06/changes-to-the-alembic-exporter/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Developers Blog&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Scripting for Artists Chapter 2</title>
      <link>https://stuvel.eu/post/2020-06-18-scripting-for-artists-chapter-2/</link>
      <pubDate>Thu, 18 Jun 2020 20:24:51 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-18-scripting-for-artists-chapter-2/</guid>
      <description>&lt;p&gt;On 
&lt;a href=&#34;https://cloud.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Cloud&lt;/a&gt;, there are of course lots of
Blender tutorials. One of those has my face on it: 
&lt;a href=&#34;https://cloud.blender.org/p/scripting-for-artists/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Scripting for Artists&lt;/a&gt;.
It is a Python scripting series aimed at artists, and starts from the simplest of
beginnings (just copy-pasting stuff).&lt;/p&gt;
&lt;p&gt;As 
&lt;a href=&#34;https://www.blender.org/press/lockdown-openup-live-streams-tutorials-characters/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;relief during the COVID-19 worldwide quarantaine&lt;/a&gt;,
I got the opportunity to add a new chapter to this series. Even better: this new
chapter is completely free for everybody! The entire series is available on

&lt;a href=&#34;https://cloud.blender.org/p/scripting-for-artists/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Cloud&lt;/a&gt;, with the free chapter also available on

&lt;a href=&#34;https://www.youtube.com/watch?v=opZy2OJp8co&amp;amp;list=PLa1F2ddGya_8acrgoQr1fTeIuQtkSd6BW&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I got so many nice responses! It&amp;rsquo;s been an amazing journey, making these
tutorials from the comfort of my own kitchen, and then helping so many people
solving actual problems and making their lives more pleasant.&lt;/p&gt;
&lt;p&gt;Only available on YouTube are the 
&lt;a href=&#34;https://www.youtube.com/watch?v=Iupx9zP4boM&amp;amp;list=PLa1F2ddGya_8acrgoQr1fTeIuQtkSd6BW&amp;amp;index=8&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Live Scripting for Artists Q&amp;amp;A on Blender Everyday&lt;/a&gt; and my

&lt;a href=&#34;https://www.youtube.com/watch?v=hfYgCwC_4iE&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2017 Blender Cloud workshop&lt;/a&gt; on the subject.&lt;/p&gt;
&lt;h2 id=&#34;need-help&#34;&gt;Need Help?&lt;/h2&gt;
&lt;p&gt;If you want help with Python scripting in Blender, pop over to

&lt;a href=&#34;https://chat.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Chat&lt;/a&gt; and visit the &lt;code&gt;#python&lt;/code&gt; channel. There
you&amp;rsquo;ll find plenty of people who&amp;rsquo;re happy to help you out.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 4.5 &amp; 4.6 released!</title>
      <link>https://stuvel.eu/post/2020-06-18-python-rsa-4-6-released/</link>
      <pubDate>Thu, 18 Jun 2020 18:42:54 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-18-python-rsa-4-6-released/</guid>
      <description>&lt;p&gt;The final release of &lt;strong&gt;
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA v4.6&lt;/a&gt;&lt;/strong&gt; can be obtained from 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa/4.6&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python
Package Index&lt;/a&gt;, or just installed with
&lt;code&gt;pip install --upgrade rsa&lt;/code&gt;. Running that upgrade command on Python 2.7 will
automatically give you version 4.5, the last version to support Python 2.&lt;/p&gt;
&lt;p&gt;This release contains improvements by Alexey Sveshnikov, Jon Dufresne , Andrey
Semakin, Christian Heimes, Adelapie, and myself of course:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added support for Python 3.8.&lt;/li&gt;
&lt;li&gt;Dropped support for Python 2 and 3.4.&lt;/li&gt;
&lt;li&gt;Added type annotations to the source code. This will make Python-RSA easier to use in
your IDE, and allows better type checking.&lt;/li&gt;
&lt;li&gt;Added static type checking via 
&lt;a href=&#34;http://mypy-lang.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MyPy&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Fix 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/129&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#129&lt;/a&gt; Installing from source
gives UnicodeDecodeError.&lt;/li&gt;
&lt;li&gt;Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This is only
supported by Python 3.6+.&lt;/li&gt;
&lt;li&gt;Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out.&lt;/li&gt;
&lt;li&gt;Reject cyphertexts (when decrypting) and signatures (when verifying) that have
been modified by prepending zero bytes. This resolves 
&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-13757&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CVE-2020-13757&lt;/a&gt;.
Thanks Adelapie for 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/146&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pointing this out&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More information on the 
&lt;a href=&#34;https://stuvel.eu/software/rsa/&#34;&gt;Python-RSA&lt;/a&gt; page.&lt;/p&gt;
&lt;h2 id=&#34;what-about-versions-41---44&#34;&gt;What about versions 4.1 - 4.4?&lt;/h2&gt;
&lt;p&gt;Ok, so here is the whole story about where versions 4.1 - 4.4 disappeared to.&lt;/p&gt;
&lt;p&gt;After sitting on some smaller improvements for a while, in fairly rapid
succession I received two reports about security issues. The first one was
regarding the chosen &lt;em&gt;blinding factor&lt;/em&gt;. The second one was more serious; serious
enough to warrant a CVE: 
&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-13757&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CVE-2020-13757&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fortunately both issues were relatively easy to fix, so I rapidly released
&lt;strong&gt;version 4.1&lt;/strong&gt;. This was the first release to be built with

&lt;a href=&#34;https://poetry.eustace.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Poetry&lt;/a&gt; and with SHA3 support. As it turned out,
packages made with Poetry cannot be installed in a no-binaries environment, and
the same goes for the SHA3 support library needed on Python 3.5. So, out came
Python-RSA &lt;strong&gt;version 4.2&lt;/strong&gt; to resolve those issues.&lt;/p&gt;
&lt;p&gt;Version 4.1 was also the first to discontinue support for Python 2.7. This
version of Python has been marked end-of-life since the beginning of this year.
That deprecation didn&amp;rsquo;t go too smoothly, though; apparently the &lt;code&gt;setup.py&lt;/code&gt; code
missed a bit of metadata that declares that the package requires Python 3.5+, so
installations that were still using Python 2.7 were happily installing the new
Python-RSA version, and failing badly.&lt;/p&gt;
&lt;p&gt;To help the Python 2.7 users, I took Python-RSA 4.0 (the last one to support
2.7), cherry-picked the two security issues, and released it as Python-RSA
&lt;strong&gt;version 4.3&lt;/strong&gt;. After that I took version 4.2 and released that as &lt;strong&gt;version
4.4&lt;/strong&gt;, this time with the right &lt;code&gt;python_requires = &amp;quot;&amp;gt;=3.5&amp;quot;&lt;/code&gt; in place to make
sure Python 2.7 won&amp;rsquo;t try to use it.&lt;/p&gt;
&lt;p&gt;I tried to do it all too quickly, so I accidentally released version 4.4 without
that &lt;code&gt;python_requires&lt;/code&gt; stanza. So, still Python 2.7 installations tried to
upgrade and got broken, which is why I re-released version 4.3 as &lt;strong&gt;version
4.5&lt;/strong&gt; and re-released version 4.4 as &lt;strong&gt;version 4.6&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There you go. Now you know.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New Website</title>
      <link>https://stuvel.eu/post/2020-06-17-new-website/</link>
      <pubDate>Wed, 17 Jun 2020 17:59:35 +0200</pubDate>
      <guid>https://stuvel.eu/post/2020-06-17-new-website/</guid>
      <description>&lt;p&gt;Today I launched my new website, with a new look and underlying tech, but all
the old content. This makes my website faster, more modern, mobile-friendly, and
more secure. More importantly, it makes it easier for me to share more stuff, so
my blog will become more alive as well.&lt;/p&gt;
&lt;p&gt;My old website was made with 
&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt;. I still
feel that Django is a great framework, but it&amp;rsquo;s a bit overkill for my needs.
This new site is using 
&lt;a href=&#34;https://gohugo.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugo&lt;/a&gt;, a static site generator.&lt;/p&gt;
&lt;p&gt;Everything should still work. The URLs of pages have changed, but the old ones
should redirect to the new locations. If something is broken,
please 
&lt;a href=&#34;https://stuvel.eu/#contact&#34;&gt;let me know&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Slovenia &amp; Croatia spherical panorama pack in Blender Cloud</title>
      <link>https://stuvel.eu/post/2019-06-20-slovenia-croatia-spherical-panorama-pack-in-blender-cloud/</link>
      <pubDate>Thu, 20 Jun 2019 17:05:08 +0200</pubDate>
      <guid>https://stuvel.eu/post/2019-06-20-slovenia-croatia-spherical-panorama-pack-in-blender-cloud/</guid>
      <description>&lt;p&gt;Last year we went on holiday to Slovenia &amp;amp; Croatia (mentioned here in
chronological order of visiting) and made a set of 360°x180° panorama photos.
They are available as 
&lt;a href=&#34;https://cloud.blender.org/p/hdri/5d08ab52df8f84f2c147aaed&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;high dynamic range EXR files on Blender
Cloud&lt;/a&gt;. There are
multiple versions available, with resolutions up to approximately 135 megapixel.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Skyfill v1.1 released</title>
      <link>https://stuvel.eu/post/2019-05-06-skyfill-v1-1-released/</link>
      <pubDate>Mon, 06 May 2019 09:53:19 +0200</pubDate>
      <guid>https://stuvel.eu/post/2019-05-06-skyfill-v1-1-released/</guid>
      <description>&lt;p&gt;Version v1.1 of 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt; has been
released. The most important improvement is that it now also supports full-white
as fill colour for the sky. You can grab your copy at

&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most drones (UAVs) cannot look straight up to photograph the sky above them. As
a result, spherical panoramas made with drones tend to have a gap in the sky.
Some drones, like my DJI Mavic 2, can fill in this gap automatically while
generating a preview. However, when I stitch the photos myself to get a better
quality output, there is still that sky gap. I got fed up with having to choose
between a nice sky or a nice overall image, so I did what developers do and made
my own software: 
&lt;a href=&#34;https://stuvel.eu/software/skyfill/&#34;&gt;Skyfill&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skyfill allows you to do fill in the gap in the sky in high-resolution
images&lt;/strong&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Skyfill released!</title>
      <link>https://stuvel.eu/post/2019-03-17-skyfill-released/</link>
      <pubDate>Sun, 17 Mar 2019 13:44:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2019-03-17-skyfill-released/</guid>
      <description>&lt;p&gt;Most drones (UAVs) cannot look straight up to photograph the sky above them. As
a result, spherical panoramas made with drones tend to have a gap in the sky.
Some drones, like my DJI Mavic 2, can fill in this gap automatically while
generating a preview. However, when I stitch the photos myself to get a better
quality output, there is still that sky gap. I got fed up with having to choose
between a nice sky or a nice overall image, so I did what developers do and made
my own software: 
&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Skyfill&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skyfill allows you to do fill in the gap in the sky in high-resolution
images&lt;/strong&gt;.&lt;/p&gt;
&lt;figure id=&#34;figure-original-image-before-applying-skyfill&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2019-03-17-skyfill-released/skyfill-demo-source_hud2a3dd6e2d1bc63c3ea6e1af5c8037be_110052_2000x2000_fit_q90_lanczos.jpg&#34; data-caption=&#34;Original image, before applying Skyfill&#34;&gt;
  &lt;img data-src=&#34;https://stuvel.eu/post/2019-03-17-skyfill-released/skyfill-demo-source_hud2a3dd6e2d1bc63c3ea6e1af5c8037be_110052_2000x2000_fit_q90_lanczos.jpg&#34; class=&#34;lazyload&#34; alt=&#34;Before applying Skyfill&#34; width=&#34;1024&#34; height=&#34;512&#34;&gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Original image, before applying Skyfill
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure id=&#34;figure-skyfilled-image&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://stuvel.eu/post/2019-03-17-skyfill-released/skyfill-demo-skyfilled-blend-80_hub7ffeccd927a9d9404e51c0171ba5441_107307_2000x2000_fit_q90_lanczos.jpg&#34; data-caption=&#34;Skyfilled image&#34;&gt;
  &lt;img data-src=&#34;https://stuvel.eu/post/2019-03-17-skyfill-released/skyfill-demo-skyfilled-blend-80_hub7ffeccd927a9d9404e51c0171ba5441_107307_2000x2000_fit_q90_lanczos.jpg&#34; class=&#34;lazyload&#34; alt=&#34;After applying Skyfill&#34; width=&#34;1024&#34; height=&#34;512&#34;&gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Skyfilled image
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For more info see 
&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the project on Gitlab&lt;/a&gt;,
or just &lt;strong&gt;download 
&lt;a href=&#34;https://gitlab.com/dr.sybren/skyfill/-/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the software&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to 
&lt;a href=&#34;https://orkfotografie.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ork de Rooij&lt;/a&gt; for his help getting the
pixels right.&lt;/p&gt;
&lt;p&gt;I also put two new panoramas online on 
&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;stuvelfoto.nl&lt;/a&gt;,
both of course with the help of Skyfill:

&lt;a href=&#34;https://stuvelfoto.nl/panorama/finland/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Äkäslompolo in Finland&lt;/a&gt; and

&lt;a href=&#34;https://stuvelfoto.nl/panorama/ringweg-amsterdam/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ringweg Amsterdam&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>FFmpeg and DJI D-Log on the Mavic 2 Pro</title>
      <link>https://stuvel.eu/post/2019-01-21-ffmpeg-and-dji-d-log-on-the-mavic-2-pro/</link>
      <pubDate>Mon, 21 Jan 2019 13:43:53 +0100</pubDate>
      <guid>https://stuvel.eu/post/2019-01-21-ffmpeg-and-dji-d-log-on-the-mavic-2-pro/</guid>
      <description>&lt;p&gt;To properly see a video recorded with a DJI Mavic 2 Pro in D-log colours, it
needs conversion. This can be done with the 
&lt;a href=&#34;https://www.dji.com/fi/mavic-2/info#downloads&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cube file provided by
DJI&lt;/a&gt;. Such cube files contain the
lookup table (LUT) to turn the bland colours into proper ones when viewing with
a run-of-the-mill viewer like MPlayer, VLC, Windows Media Player, etc.&lt;/p&gt;
&lt;p&gt;Unfortunately, DJI&amp;rsquo;s cube file is incompatibe with FFmpeg. It should work with
this command, but doesn&amp;rsquo;t:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ffmpeg -i input_file.mp4 -c:v h264 -crf 21 \
    -vf lut3d=&#39;dlog-to-rec709.cube&#39; output_file.mp4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in an error &amp;ldquo;3D LUT is empty&amp;rdquo; from FFmpeg. &lt;strong&gt;Fortunately, this is
easily fixed&lt;/strong&gt;. Just open the .cube file in any text editor, and find the line
&lt;code&gt;LUT_3D_SIZE 33&lt;/code&gt;. There is a tab character between the &lt;code&gt;LUT_3D_SIZE&lt;/code&gt; and &lt;code&gt;33&lt;/code&gt;,
and even though this is fine according to 
&lt;a href=&#34;https://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/products/speedgrade/cc/pdfs/cube-lut-specification-1.0.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the
specifications&lt;/a&gt;,
FFmpeg doesn&amp;rsquo;t like it. Just replace it with a space, so change:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LUT_3D_SIZE&amp;lt;tab&amp;gt;33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LUT_3D_SIZE&amp;lt;space&amp;gt;33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file, and you&amp;rsquo;re done. The above ffmpeg command will now just work.&lt;/p&gt;
&lt;p&gt;Update: this incompatibility has been fixed in FFmpeg, and will be part of a
future release (current release is 4.1).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 4.0 released!</title>
      <link>https://stuvel.eu/post/2018-09-16-python-rsa-4-0-released/</link>
      <pubDate>Sun, 16 Sep 2018 14:23:59 +0200</pubDate>
      <guid>https://stuvel.eu/post/2018-09-16-python-rsa-4-0-released/</guid>
      <description>&lt;p&gt;After over two years of silence, Python-RSA 4.0 has been released! There are
many improvements and also backward-incompatible changes (hence the increase of
the major version number).&lt;/p&gt;
&lt;p&gt;Get it while it&amp;rsquo;s hot at

&lt;a href=&#34;https://pypi.python.org/pypi/rsa/4.0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python Package Index&lt;/a&gt;,
or just install with &lt;code&gt;pip install --upgrade rsa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This release contains improvements by adamantike, Alexandr, David Larlet, Fabio
Alessandro Locati, Florian Motlik, Hugo, Jon Banafato, Jon Dufresne, Joost
Rijneveld, Justin Simon, Michael Manganiello, yjqiang, and myself of course.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dropped support for Python 2.6 and 3.3.&lt;/li&gt;
&lt;li&gt;These modules were deprecated in version 3.4, and are now removed:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rsa.varblock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa.bigfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa._version133&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa._version200&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Removed CLI commands that use the VARBLOCK/bigfile format.&lt;/li&gt;
&lt;li&gt;Ensured that &lt;code&gt;PublicKey.save_pkcs1()&lt;/code&gt; and &lt;code&gt;PrivateKey.save_pkcs1()&lt;/code&gt; always
return bytes.&lt;/li&gt;
&lt;li&gt;Dropped support for Psyco.&lt;/li&gt;
&lt;li&gt;Miller-Rabin iterations determined by bitsize of key.

&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/58&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#58&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Added function &lt;code&gt;rsa.find_signature_hash()&lt;/code&gt; to return the name of the hashing
algorithm used to sign a message. &lt;code&gt;rsa.verify()&lt;/code&gt; now also returns that name,
instead of always returning &lt;code&gt;True&lt;/code&gt;.

&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/13&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#78&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add support for SHA-224 for PKCS1 signatures.

&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/pull/104&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;#104&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Transitioned from &lt;code&gt;requirements.txt&lt;/code&gt; to Pipenv for package management.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>All mail is mine</title>
      <link>https://stuvel.eu/post/2018-02-07-all-mail-is-mine/</link>
      <pubDate>Wed, 07 Feb 2018 11:23:59 +0100</pubDate>
      <guid>https://stuvel.eu/post/2018-02-07-all-mail-is-mine/</guid>
      <description>&lt;p&gt;While I&amp;rsquo;m doing web development I want to have an email server that ensures that
all mail will end up in my mailbox. To this end I set up Postfix with this rule
in &lt;code&gt;main.cf&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;header_checks = regexp:/etc/postfix/header_checks.regexp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;header_checks.regexp&lt;/code&gt; then contains:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/^To:/  REDIRECT sybren+keep-local@my.domain&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This results in all mail being sent via my SMTP server is delivered to my
mailbox, regardless of who it&amp;rsquo;s intended for.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python FlickrAPI 2.3 released</title>
      <link>https://stuvel.eu/post/2017-05-08-python-flickrapi-2-3-released/</link>
      <pubDate>Mon, 08 May 2017 13:11:14 +0200</pubDate>
      <guid>https://stuvel.eu/post/2017-05-08-python-flickrapi-2-3-released/</guid>
      <description>&lt;p&gt;A new version of the 
&lt;a href=&#34;http://stuvel.eu/flickrapi/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python FlickrAPI&lt;/a&gt; has been
released. You can download or upgrade it using &lt;code&gt;pip3 install -U flickrapi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Include README.md and CHANGELOG.md in the package data.&lt;/li&gt;
&lt;li&gt;Removed flickrapi/contrib.py, as a persistent connection is now managed (much
better) by requests (since

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/commit/cdeb6ffea26&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cdeb6ffea26&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Late-import module &lt;code&gt;webbrowser&lt;/code&gt;, only when needed (Thijs Triemstra)

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/pull/78&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Pull request #78 ]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Perform explicit commit after inserting auth token (Joshua Hunter)

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/pull/75&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Bug report #75 ]&lt;/a&gt;

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/pull/76&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Pull request #76 ]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Configured Tox &amp;amp; Travis to test on Python 3.6 as well.&lt;/li&gt;
&lt;li&gt;Timeout for API calls.

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/issues/27&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Feature Request #27 ]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Late-import SQLite3 to allow running on Heroku (and other systems).

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/issues/81&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Feature Request #81 ]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fixed using obsolete &lt;code&gt;func_name&lt;/code&gt; attribute.

&lt;a href=&#34;https://github.com/sybrenstuvel/flickrapi/issues/80&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[ Bug report #80 ]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Blender Conference 2016</title>
      <link>https://stuvel.eu/post/2016-10-31-blender-conference-2016/</link>
      <pubDate>Mon, 31 Oct 2016 16:01:22 +0100</pubDate>
      <guid>https://stuvel.eu/post/2016-10-31-blender-conference-2016/</guid>
      <description>&lt;p&gt;BConf 2016 was awesome, as ever. This is just a blog post to share

&lt;a href=&#34;https://stuvel.eu/files/bconf2016/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the slides&lt;/a&gt; of my workshop
&amp;ldquo;
&lt;a href=&#34;https://www.youtube.com/watch?v=mYrPqrFY7mA&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Develop add-ons like a pro&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;iframe src=&#39;https://stuvel.eu/files/bconf2016/&#39; style=&#39;width: 100%; height: 30em&#39;&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>I&#39;m a PhD &amp; work at Blender!</title>
      <link>https://stuvel.eu/post/2016-04-21-i-m-a-phd/</link>
      <pubDate>Thu, 21 Apr 2016 08:25:27 +0200</pubDate>
      <guid>https://stuvel.eu/post/2016-04-21-i-m-a-phd/</guid>
      <description>&lt;p&gt;Yesterday I obtained my PhD degree in Computer Science at the Universiteit
Utrecht, on the subject of the simulation of dense crowds. Of course my thesis

&lt;a href=&#34;https://stuvel.eu/files/publication/phd-thesis-sybren-stuvel.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dense Crowds of Virtual Humans&lt;/a&gt;
is available online!&lt;/p&gt;
&lt;p&gt;And, as of March 1st, I&amp;rsquo;m an employee of the

&lt;a href=&#34;https://blender.org/institute/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender Institute&lt;/a&gt;, I landed my dream job!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA 3.4 released</title>
      <link>https://stuvel.eu/post/2016-03-17-python-rsa-3-4-released/</link>
      <pubDate>Thu, 17 Mar 2016 13:53:50 +0100</pubDate>
      <guid>https://stuvel.eu/post/2016-03-17-python-rsa-3-4-released/</guid>
      <description>&lt;p&gt;Python-RSA 3.4 has been released! This is the first release from

&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GitHub&lt;/a&gt;, and contains a lot of
improvements by myself, 
&lt;a href=&#34;https://github.com/adamantike&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Michael Manganiello&lt;/a&gt;,
and 
&lt;a href=&#34;https://github.com/FiloSottile&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Filippo Valsorda&lt;/a&gt;, including the solution
for a side-channel vulnerability.&lt;/p&gt;
&lt;p&gt;Get it while it&amp;rsquo;s hot at

&lt;a href=&#34;https://pypi.python.org/pypi/rsa/3.4&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python Package Index&lt;/a&gt;, or just
install with &lt;code&gt;pip install --upgrade rsa&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moved development to Github: 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/sybrenstuvel/python-rsa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Solved side-channel vulnerability by implementing blinding, fixes #19&lt;/li&gt;
&lt;li&gt;Deprecated the VARBLOCK format and rsa.bigfile module due to security issues,
see 
&lt;a href=&#34;https://github.com/sybrenstuvel/python-rsa/issues/13&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/sybrenstuvel/python-rsa/issues/13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Integration with 
&lt;a href=&#34;https://travis-ci.org/sybrenstuvel/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Travis-CI&lt;/a&gt;,

&lt;a href=&#34;https://coveralls.io/github/sybrenstuvel/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Coveralls&lt;/a&gt; and

&lt;a href=&#34;https://codeclimate.com/github/sybrenstuvel/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Code Climate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Deprecated the old rsa._version133 and rsa._version200 submodules, they will
be completely removed in version 4.0.&lt;/li&gt;
&lt;li&gt;Add an &amp;rsquo;exponent&amp;rsquo; argument to key.newkeys()&lt;/li&gt;
&lt;li&gt;Switched from Solovay-Strassen to Miller-Rabin primality testing, to comply
with 
&lt;a href=&#34;http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;NIST FIPS 186-4&lt;/a&gt;
as probabilistic primality test (Appendix C, subsection C.3).&lt;/li&gt;
&lt;li&gt;Fixed various bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Version 3.4 is the last version in the 3.x range. Version 4.0 will drop the
following modules, as they are insecure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rsa._version133&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa._version200&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa.bigfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa.varblock&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those modules are marked as deprecated in version 3.4.&lt;/p&gt;
&lt;p&gt;Furthermore, in 4.0 the I/O functions will be streamlined to always work with
bytes on all supported versions of Python.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My name in the modern world</title>
      <link>https://stuvel.eu/post/2016-02-04-my-name-in-the-modern-world/</link>
      <pubDate>Thu, 04 Feb 2016 12:20:39 +0100</pubDate>
      <guid>https://stuvel.eu/post/2016-02-04-my-name-in-the-modern-world/</guid>
      <description>&lt;p&gt;My last name is a technical hurdle. At least, for many people. In this
high-tech, modern, globalized society, one would expect that a simple accented
character shouldn&amp;rsquo;t be an issue. After all, even &lt;strong&gt;a small child can write
Stüvel correctly with a stick in the mud&lt;/strong&gt;. So why is it such an issue in the
world of computers?&lt;/p&gt;
&lt;p&gt;To demonstrate the issue, here is a list of ways that I have seen my name appear:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;StÃ¼vel&lt;/li&gt;
&lt;li&gt;St??vel&lt;/li&gt;
&lt;li&gt;St�vel&lt;/li&gt;
&lt;li&gt;St++vel&lt;/li&gt;
&lt;li&gt;St&amp;amp;#252;vel&lt;/li&gt;
&lt;li&gt;St\xc3\xbcvel&lt;/li&gt;
&lt;li&gt;St vel&lt;/li&gt;
&lt;li&gt;St☐☐vel&lt;/li&gt;
&lt;li&gt;St³vel&lt;/li&gt;
&lt;li&gt;StĂźvel&lt;/li&gt;
&lt;li&gt;StÃ╝vel&lt;/li&gt;
&lt;li&gt;St? &amp;lt;Input Name=&lt;/li&gt;
&lt;li&gt;St~vel&lt;/li&gt;
&lt;li&gt;StÃ☐Ã¼vel&lt;/li&gt;
&lt;li&gt;StÃOvel&lt;/li&gt;
&lt;li&gt;St?üvel&lt;/li&gt;
&lt;li&gt;Stï¿½ï¿½vel&lt;/li&gt;
&lt;li&gt;St?vel&lt;/li&gt;
&lt;li&gt;&amp;ldquo;your last name contains illegal characters&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;your last name should contain at least one alphabet&amp;rdquo;, &amp;ldquo;only enter alphabetical characters&amp;rdquo;, etc.&lt;/li&gt;
&lt;li&gt;STÃœVE&lt;/li&gt;
&lt;li&gt;Stãœvel&lt;/li&gt;
&lt;li&gt;&amp;ldquo;you did not fill in a last name&amp;rdquo; and variants thereof&lt;/li&gt;
&lt;li&gt;St&lt;/li&gt;
&lt;li&gt;&amp;ldquo;your last name should contain only letters&amp;rdquo;&lt;/li&gt;
&lt;li&gt;St_f_»vel&lt;/li&gt;
&lt;li&gt;St√É¬ºvel&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The root cause? Often &lt;strong&gt;software is only tested with what the developers &amp;amp;
testers can easily type on their keyboard&lt;/strong&gt;. As a result, they use the characters
from the ASCII set, which happens to be the common dinominator between many
character encodings. If you want to ensure your system correctly handles
character data, test with non-ASCII characters. Go to Wikipedia, pick a
random article in a language you don&amp;rsquo;t know, and just copy-paste some text into
your application. Your system should be set up to handle this. Preferably by
using UTF-8, but as a worst-case it should at least let the user know
that non-ASCII characters aren&amp;rsquo;t supported.&lt;/p&gt;
&lt;p&gt;And please, don&amp;rsquo;t call those &amp;ldquo;illegal&amp;rdquo; or &amp;ldquo;special&amp;rdquo; characters. &lt;strong&gt;It&amp;rsquo;s not a
property of the characters, but a limitation of your system&lt;/strong&gt;. Those limitations
are usually simple to lift, as long as testing with non-ASCII characters is
part of the development process.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s move into the modern world, and accept the view that there are more names
than English ones. The best thing to read after this, one of my favourite
pages on the web, 
&lt;a href=&#34;https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Falsehoods Programmers Believe About Names&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New website &amp; Python-RSA 3.3</title>
      <link>https://stuvel.eu/post/2016-01-18-new-website-python-rsa-3-3/</link>
      <pubDate>Mon, 18 Jan 2016 21:29:40 +0100</pubDate>
      <guid>https://stuvel.eu/post/2016-01-18-new-website-python-rsa-3-3/</guid>
      <description>&lt;p&gt;You won&amp;rsquo;t notice it, but you&amp;rsquo;re now on my new website. The look is still the
same, but under the hood a lot has changed. This includes the blog being fixed
again, so that I can actually write new posts! Can you imagine, I didn&amp;rsquo;t blog a
single thing in 2015&amp;hellip;. well, that&amp;rsquo;ll change.&lt;/p&gt;
&lt;p&gt;Python-RSA 3.3 has been released! This release fixes a security leak, which was
filed under

&lt;a href=&#34;https://www.openwall.com/lists/oss-security/2016/01/05/3&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CVE-2016-1494&lt;/a&gt;. As
always, you can get the new version from the 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Package
Index&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python FlickrAPI 2.0 released</title>
      <link>https://stuvel.eu/post/2014-11-06-python-flickrapi-2-0-released/</link>
      <pubDate>Thu, 06 Nov 2014 17:55:41 +0100</pubDate>
      <guid>https://stuvel.eu/post/2014-11-06-python-flickrapi-2-0-released/</guid>
      <description>&lt;p&gt;Python FlickrAPI library version 2.0 has been released, and can be downloaded
from 
&lt;a href=&#34;https://pypi.org/project/flickrapi/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python Package Index&lt;/a&gt; with
more info at 
&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;my FlickrAPI page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The major change is that the &amp;ldquo;new&amp;rdquo; OAuth-based authentication is used. This
makes our Python FlickrAPI library a lot more future-proof.&lt;/p&gt;
&lt;p&gt;Thanks to Jim Easterbrook, Thai Nguyen, Nick Loadholtes and Bengt for their
contributions.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Panoramas: two terraces</title>
      <link>https://stuvel.eu/post/2014-08-21-panoramas-two-terraces/</link>
      <pubDate>Thu, 21 Aug 2014 21:13:08 +0200</pubDate>
      <guid>https://stuvel.eu/post/2014-08-21-panoramas-two-terraces/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: The panoramas are currently broken, I&amp;rsquo;ll get around to fix it
some time in the future.&lt;/p&gt;
&lt;p&gt;I just put two new 360/180 degree panoramas online, of places very well suited
for an exquisite dinner.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/panorama/slapic-terras&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://stuvelfoto.nl/media/pano/slapic-terras/thumbnail.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/panorama/slapic_terras&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Camping Slapić&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/panorama/haus_am_berg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://stuvelfoto.nl/media/pano/haus-am-berg_terras/thumbnail.jpg&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/panorama/haus_am_berg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hotel Haus am Berg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Moving from pwsafe to KeePass</title>
      <link>https://stuvel.eu/post/2014-07-30-moving-from-pwsafe-to-keepass/</link>
      <pubDate>Wed, 30 Jul 2014 11:01:38 +0200</pubDate>
      <guid>https://stuvel.eu/post/2014-07-30-moving-from-pwsafe-to-keepass/</guid>
      <description>&lt;p&gt;My favourite password management tool, pwsafe, is getting old. It&amp;rsquo;s no longer
part of Ubuntu and I&amp;rsquo;ve had to compile it myself for quite a while now. It&amp;rsquo;s
also not supported on Android, and shows other signs of aging. So, I moved to
KeePass. Exporting my database to CSV was simple, and to make the job of
importing it correctly into KeePass even easier, I wrote a simple Python script.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import csv

infile = open(&#39;passwords.csv&#39;, encoding=&#39;utf-8&#39;)
outfile = open(&#39;passwords-groupfixed.csv&#39;, &#39;w&#39;, encoding=&#39;utf-8&#39;, newline=&#39;&#39;)
incsv = csv.reader(infile, delimiter=&#39;\t&#39;)
outcsv = csv.writer(outfile)

for rowidx, row in enumerate(incsv):
    if rowidx == 0:
        # Skip comment row
        continue

    if rowidx == 1:
        outcsv.writerow([&#39;uuid&#39;, &#39;Title&#39;, &#39;User name&#39;, &#39;Password&#39;, &#39;Notes&#39;, &#39;URL&#39;])
        continue

    if len(row) != 6:
        raise SystemExit(&#39;Weird row: {}&#39;.format(row))

    uuid, group, name, login, passwd, notes = row
    if group:
        name = group + &#39;.&#39; + name

    url = &#39;&#39;
    if notes.startswith(&#39;http&#39;) or notes.startswith(&#39;www&#39;):
        url, notes = notes, url

    outcsv.writerow([uuid, name, login, passwd, notes, url])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script takes the pwsafe CSV and transforms it into a CSV file that can be
plugged into KeePass without any further configuration. Nice and easy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python FlickrAPI 1.4.4 released</title>
      <link>https://stuvel.eu/post/2014-06-18-python-flickrapi-1-4-4-released/</link>
      <pubDate>Wed, 18 Jun 2014 07:05:12 +0200</pubDate>
      <guid>https://stuvel.eu/post/2014-06-18-python-flickrapi-1-4-4-released/</guid>
      <description>&lt;p&gt;Python FlickrAPI library version 1.4.4 has been released, and can be downloaded
from

&lt;a href=&#34;https://pypi.python.org/pypi/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://pypi.python.org/pypi/flickrapi&lt;/a&gt;
with more info at 
&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stuvel.eu/flickrapi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changed default API URL to use HTTPS (Joseph Hui).&lt;/li&gt;
&lt;li&gt;PEP 8 compliance (Luar Roji).&lt;/li&gt;
&lt;li&gt;Replaced Distribute with Setuptools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the mean time, we have made more progress on the upcoming version 2.0. We
can always use more bug testers, bug fixers and documentation writers; check out

&lt;a href=&#34;https://bitbucket.org/sybren/flickrapi/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://bitbucket.org/sybren/flickrapi/&lt;/a&gt;
to get involved!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reloading your code in Blender</title>
      <link>https://stuvel.eu/post/2014-03-10-reloading-your-code-in-blender/</link>
      <pubDate>Mon, 10 Mar 2014 13:57:11 +0100</pubDate>
      <guid>https://stuvel.eu/post/2014-03-10-reloading-your-code-in-blender/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Things are considerably simpler. Just press F8 in Blender
2.79 or older, or press F3 and search for &amp;lsquo;Reload Scripts&amp;rsquo; in recent Blenders.&lt;/p&gt;
&lt;p&gt;Blender lets you script more or less everything. You can have your code inside
Blender (and the .blend file) itself, but I prefer to store it outside the
.blend file. This makes it easier to handle changes, and allows you to use any
editor you want. The downside is that reloading your code becomes a bit of a
hassle. This is a little snippet I wrote to reload my code in Blender with the
click of a button.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import bpy
import imp
import os.path
import sys

my_path = bpy.path.abspath(&#39;//&#39;)

if my_path not in sys.path:
    sys.path.insert(0, my_path)

def load_my_stuff():
    # This imports my main module and registers its contents.
    # Alter to suit your needs.
    import calc_distance
    calc_distance.register()

def reload_my_modules(base_path):
    &#39;&#39;&#39;Reloads all my modules.

    &amp;quot;my modules&amp;quot; are those that are stored in the same directory (or subdir)
    of this .blend file.
    &#39;&#39;&#39;

    base_path = os.path.normpath(base_path)  # normalize the path
    my_module = sys.modules[__name__]

    print(&#39;Reloading from %r&#39; % base_path)
    # Only allow reloading of pure-Python (i.e. not compiled) modules,
    # that have a __file__ and that are not this specific module.
    reloadable = (module for module in sys.modules.values()
                  if hasattr(module, &#39;__file__&#39;) and
                     module != my_module and
                     (module.__file__.endswith(&#39;.py&#39;) or
                      module.__file__.endswith(&#39;.pyc&#39;)))

    for module in reloadable:
        modpath = os.path.abspath(module.__file__)
        common = os.path.commonprefix([base_path, modpath])
        if os.path.commonprefix([base_path, modpath]).startswith(base_path):
            print(&#39;    Reloading %s from %s&#39; % (module, module.__file__))
            imp.reload(module)

    # re-register the reloaded classes.
    load_my_stuff()

class ReloadScriptsOperator(bpy.types.Operator):
    bl_idname = &#39;script.reload_my_scripts&#39;
    bl_label = &#39;Reload code&#39;
    bl_description = &#39;Reloads all distance code.&#39;

    def execute(self, context):
        my_path = bpy.path.abspath(&#39;//&#39;)
        if not my_path:
            self.report({&#39;ERROR&#39;}, &#39;Save the Blend file first, before reloading&#39;)
            return {&#39;CANCELLED&#39;}

        reload_my_modules(my_path)
        return {&#39;FINISHED&#39;}

print(80 * &#39;*&#39;)
print(&#39;Registering %s and the rest&#39; % __name__)
bpy.utils.register_module(__name__)

load_my_stuff()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code makes one assumption that&amp;rsquo;s important to know: it assumes that the
Python files you want to reload are in the same directory as your Blend file (or
subdirectory thereof). This means that you must &lt;strong&gt;save your Blend file&lt;/strong&gt; before
this works. If you store your code in a different directory, you&amp;rsquo;ll have to
modify the matching against &lt;code&gt;my_path&lt;/code&gt; to suit your needs.&lt;/p&gt;
&lt;p&gt;In order to have the &amp;ldquo;Reload code&amp;rdquo; button in the user interface somewhere, add
this line to your UI code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;layout.operator(&#39;script.reload_my_scripts&#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For completeness, here are the relevant parts of my custom UI panel:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class ReloadExamplePanel(bpy.types.Panel):
    bl_space_type = &#39;VIEW_3D&#39;
    bl_region_type = &#39;TOOLS&#39;
    bl_category = &amp;quot;Tools&amp;quot;
    bl_context = &amp;quot;objectmode&amp;quot;
    bl_label = &amp;quot;Reload button example&amp;quot;

    def draw(self, context):
        layout = self.layout
        layout.operator(&#39;script.reload_my_scripts&#39;)

        # Here I draw more stuff, but that&#39;s irrelevant if you don&#39;t have my code.

def register():
    print(&#39;Registering %s&#39; % __name__)
    bpy.utils.register_module(__name__)&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Counting pixels in Blender</title>
      <link>https://stuvel.eu/post/2014-02-28-counting-pixels-in-blender/</link>
      <pubDate>Fri, 28 Feb 2014 09:21:33 +0100</pubDate>
      <guid>https://stuvel.eu/post/2014-02-28-counting-pixels-in-blender/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: the image of the node setup has been lost.&lt;/p&gt;
&lt;p&gt;For my research, I&amp;rsquo;m using Blender to generate images. I wanted to know how
visible a certain object is in the final render (i.e. how many pixels it
occupies). For this there is the &amp;ldquo;object index&amp;rdquo; render pass (aka &amp;ldquo;IndexOB&amp;rdquo; in
the compositor). I&amp;rsquo;ve been struggling with it, since &lt;em&gt;it always outputs that the
index is 0&lt;/em&gt;, even though there are multiple objects in the scene.&lt;/p&gt;
&lt;p&gt;Well, with the help of mfoxdogg on the #blender IRC channel, we 
&lt;a href=&#34;https://wiki.blender.org/index.php/Doc:2.6/Manual/Composite_Nodes/Types/Convertor#ID_Mask_Node&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;found a
solution&lt;/a&gt;:
You need to set the index by hand, for every object you&amp;rsquo;re interested in. If you
go to the object properties (in the properties explorer), in the section
&amp;ldquo;Relations&amp;rdquo; there is a slider &amp;ldquo;Pass Index&amp;rdquo;. This is set to 0 by default, and you
can set it to any positive number you want. This is then reflected in the output
of the &amp;ldquo;IndexOB&amp;rdquo; render pass.&lt;/p&gt;
&lt;p&gt;So to solve my problem, I needed to count the pixels that a certain object
occupies in the image. For this I connected a viewer node to the &amp;ldquo;IndexOB&amp;rdquo; pass.
Once you&amp;rsquo;ve rendered, you can then access the pixel data using
&lt;code&gt;bpy.data.images[&#39;Viewer Node&#39;].pixels&lt;/code&gt;. It&amp;rsquo;s a one-dimensional array of floats,
in the RGBA format. This means that every pixel is represented as four
consecutive floats.&lt;/p&gt;
&lt;p&gt;The IndexOB data is stored in the RGB channels, and the alpha channel is set to
1.0. You could write some code to only inspect the R channel for its value and
count the ones that are equal to the object index you&amp;rsquo;re interested in. I chose
a more lazy approach of counting all RGBA values that are equal to the index,
then dividing by 3. For this you do need an object index larger than 1, as the
alpha channel is always set to 1 too. So here is the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import bpy

# I&#39;m interested in the object named &amp;quot;L&amp;quot;
ob_name = &#39;L&#39;

# Set the &amp;quot;pass index&amp;quot;
bpy.data.objects[ob_name].pass_index = 42

# Render the image
bpy.ops.render.render()

# Count all pixels that have value = 42. We count all R, G and B components
# separately, so divide by 3 to get the actual number of pixels
pixel_count = sum(1 for p in bpy.data.images[&#39;Viewer Node&#39;].pixels if p == 42) / 3
print(&#39;Pixel count for object %r : %i&#39; % (ob_name, pixel_count))
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA version 3.1.4 released </title>
      <link>https://stuvel.eu/post/2014-02-22-python-rsa-version-3-1-4-released/</link>
      <pubDate>Sat, 22 Feb 2014 10:55:39 +0100</pubDate>
      <guid>https://stuvel.eu/post/2014-02-22-python-rsa-version-3-1-4-released/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;It&amp;rsquo;s been a while since I&amp;rsquo;ve been working on my 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSA
library&lt;/a&gt;, and in the last weeks I&amp;rsquo;ve released a few new
minor versions. Here are the differences since my last blog post about it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed Python 3.x incompatibilities.&lt;/li&gt;
&lt;li&gt;Dropped support for Python 2.5.&lt;/li&gt;
&lt;li&gt;Added support for loading public keys from OpenSSL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rsa.pkcs1.verify()&lt;/code&gt; returns &lt;code&gt;True&lt;/code&gt; when successful (thanks Tim Heckman)&lt;/li&gt;
&lt;li&gt;First updated Distribute (thanks Jason R. Coombs), later replaced Distribute
with Setuptools.&lt;/li&gt;
&lt;li&gt;Fixed typo in &lt;code&gt;pyrsa-verify&lt;/code&gt; help message&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Comments via Disqus</title>
      <link>https://stuvel.eu/post/2014-01-20-comments-via-disqus/</link>
      <pubDate>Mon, 20 Jan 2014 19:47:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2014-01-20-comments-via-disqus/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: I&amp;rsquo;ve removed the ability to comment altogether.&lt;/p&gt;
&lt;p&gt;My blog has been targeted by spammers for years. The last months spam has been
on the rise, so I finally got fed up with it and replaced my home-grown comment
system with Disqus. Old comments are still there, new ones will be using Disqus
instead.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Installing Windows 8 with different product key</title>
      <link>https://stuvel.eu/post/2013-10-31-installing-windows-8-with-different-product-key/</link>
      <pubDate>Thu, 31 Oct 2013 10:32:43 +0100</pubDate>
      <guid>https://stuvel.eu/post/2013-10-31-installing-windows-8-with-different-product-key/</guid>
      <description>&lt;p&gt;New laptops often are shipped with the Windows product key stored in the
EFI/BIOS/whatever. The result is that you don&amp;rsquo;t get a product key prompt any
more. Great for reinstalls, as copying the key by hand is very error-prone.
However, when I wanted to install a fresh Win8 Pro version, the embedded &amp;ldquo;Home&amp;rdquo;
version key wasn&amp;rsquo;t accepted &lt;em&gt;and the installer did not ask for another key&lt;/em&gt;. It
was simply impossible to install Windows 8 Pro.&lt;/p&gt;
&lt;p&gt;This blog post will describe how I got it installed in the end.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get a USB stick that&amp;rsquo;s large enough - 4 GB or more should do it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transfer an ISO file of the Windows installation disk to the USB stick,
using 
&lt;a href=&#34;https://images2.store.microsoft.com/prod/clustera/framework/w7udt/1.0/en-us/Windows7-USB-DVD-tool.exe&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microsoft&amp;rsquo;s USB DVD tool&lt;/a&gt;.
Please note that this will erase any contents of your USB stick.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the USB stick, create a file &lt;code&gt;sources\PID.txt&lt;/code&gt; that contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[PID]
Value=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the &lt;code&gt;XXXX&lt;/code&gt;ses with your product key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy all files from the USB stick back to your harddisk.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reformat the stick as FAT32. Microsoft&amp;rsquo;s tool has formatted it as NTFS,
which is not supported as a boot device for newer laptops (i.e. the ones you
need this trick for in the first place).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy all files back from your harddisk to the USB stick.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Eject the USB stick. You need to do this cleanly (don&amp;rsquo;t just jank it out) to
ensure that all files were written to it. You don&amp;rsquo;t want to have to redo
your installation because it failed halfway, do you?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boot from the USB stick to install Windows. It will not prompt for the
product key, but use the one you specified in &lt;code&gt;sources\PID.txt&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Blender conference 2013</title>
      <link>https://stuvel.eu/post/2013-10-30-blender-conference-2013/</link>
      <pubDate>Wed, 30 Oct 2013 10:21:29 +0100</pubDate>
      <guid>https://stuvel.eu/post/2013-10-30-blender-conference-2013/</guid>
      <description>&lt;p&gt;Last weekend Amsterdam was visited by a great group of over 250

&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; professionals and enthousiast, for the
Blender Conference 2013. This year it was my pleasure to give a workshop about
my research, and how I use Blender to visualize my result.&lt;/p&gt;
&lt;p&gt;For the attendants (and other interested people), I&amp;rsquo;ve put my presentation, the
Blender file and accompanying SQLite database online:

&lt;a href=&#34;https://stuvel.eu/files/bcon_2013_sybren_workshop.7z&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stuvel.eu/files/bcon_2013_sybren_workshop.7z&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can still see the workshop online on Youtube. Tthe first 10 minutes is just
people leaving the previous workshop, and me setting up, though.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/Wt8WdSvaRms&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Lancering nieuwe website</title>
      <link>https://stuvel.eu/post/2013-09-01-lancering-nieuwe-website.nl/</link>
      <pubDate>Sun, 01 Sep 2013 12:33:32 +0200</pubDate>
      <guid>https://stuvel.eu/post/2013-09-01-lancering-nieuwe-website.nl/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm3.static.flickr.com/2892/9645619046_d6fe06e50b_b.jpg&#34; alt=&#34;Stüvel Foto&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Speciaal voor mijn fotografie is er vandaag een nieuwe website gelanceerd:

&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stuvelfoto.nl/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deze site is volledig gericht op fotografie: 
&lt;a href=&#34;https://stuvelfoto.nl/huwelijk&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;huwelijksreportages&lt;/a&gt;, 
&lt;a href=&#34;https://stuvelfoto.nl/portret&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;portretten&lt;/a&gt; en 
&lt;a href=&#34;https://stuvelfoto.nl/panorama&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;panorama&amp;rsquo;s&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Binnenkort zal ook stuvel.eu een verandering doorgaan, aangezien alle
fotografie-gerichte onderdelen nu een nieuw plekje op

&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stuvelfoto.nl/&lt;/a&gt; hebben.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Ik ben gestopt met trouwreportages. Portretten en panorama&amp;rsquo;s
maak ik des te meer.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ten reasons I don&#39;t like Visual Studio</title>
      <link>https://stuvel.eu/post/2013-08-26-ten-reasons-i-don-t-like-visual-studio/</link>
      <pubDate>Mon, 26 Aug 2013 13:38:25 +0200</pubDate>
      <guid>https://stuvel.eu/post/2013-08-26-ten-reasons-i-don-t-like-visual-studio/</guid>
      <description>&lt;p&gt;For my work I&amp;rsquo;m using Microsoft Visual Studio 2010 (VS) to write our C++ code.
There are so many things wrong with this IDE that I just had to write this post.
Here&amp;rsquo;s a list of why I think it&amp;rsquo;s crap:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The compiler requires certain environment variables, that are set by running
a batch file. The result is that it&amp;rsquo;s very hard to integrate the compiler
into another IDE such as Eclipse. Yes, it&amp;rsquo;s possible, but a very big hassle.
This effectively locks you into using their IDE, which makes its
shortcomings even more annoying.&lt;/li&gt;
&lt;li&gt;Code completion (&amp;ldquo;intellisense&amp;rdquo;) is often so slow that it&amp;rsquo;s often faster for
me to scroll through my sources and copy-and-paste a symbol myself.&lt;/li&gt;
&lt;li&gt;Code completion (&amp;ldquo;intellisense&amp;rdquo;) is dumb. It usually prefers some obscure
symbol that I&amp;rsquo;ve never used before, over the name of a local variable I
declared a few lines earlier. Compare this to PyCharm, where the first or
second suggested symbol is usually correct.&lt;/li&gt;
&lt;li&gt;There is no overview of the file you&amp;rsquo;re currently working in, like the
&amp;ldquo;outline&amp;rdquo; views offered by Eclipse and PyCharm.&lt;/li&gt;
&lt;li&gt;There is no way to show the location of the file you&amp;rsquo;re currently working on
in the Solution Explorer.&lt;/li&gt;
&lt;li&gt;No refactoring. At all. There is no easy way to rename a symbol, to extract
code into a new method, extract a variable, etc.&lt;/li&gt;
&lt;li&gt;When debugging a console application, the output is sent to a little window
I can&amp;rsquo;t resize, which closes immediately upon termination of the program.
WTF? All other IDEs I&amp;rsquo;ve used send the program&amp;rsquo;s output to a window inside
the IDE, so that you can actually inpect the output or read error messages,
after your program has stopped.&lt;/li&gt;
&lt;li&gt;The project property popup always reverts back to the current configuration
(you know, the &amp;ldquo;Debug&amp;rdquo;, &amp;ldquo;Release&amp;rdquo; etc. thingies), even though 99% of the
time I want the &amp;ldquo;All Configurations&amp;rdquo; configuration as I want most of the
project settings to be consistent between debug and release.&lt;/li&gt;
&lt;li&gt;Firefox, Chrome, Eclipse, PyCharm, all kind of environments where you&amp;rsquo;re
working with multiple documents in different tabs, you can use keyboard
shortcuts to go from one to the other (I prefer Ctrl+Page up/down). If you
want the same behaviour in VS, you need to 
&lt;a href=&#34;https://stackoverflow.com/questions/21027/changing-ctrltab-behavior-for-moving-between-document-in-visual-studio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;install an
extension&lt;/a&gt;
before you can set up your keybindings.&lt;/li&gt;
&lt;li&gt;VS doesn&amp;rsquo;t react to the forward/backward mouse buttons. Those are so handy
when you quickly have to change something (like add an #include statement)
and then go back to where you were before.&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Portretten in het park</title>
      <link>https://stuvel.eu/post/2013-07-31-portretten-in-het-park.nl/</link>
      <pubDate>Wed, 31 Jul 2013 21:11:16 +0200</pubDate>
      <guid>https://stuvel.eu/post/2013-07-31-portretten-in-het-park.nl/</guid>
      <description>&lt;p&gt;21 juli werden bij de Noorderparkbar liefdesliedjes gedraaid door Döske en
liefdesstoelen gepresenteerd door Marc. Een uitgelegen moment om wat intieme
portretten te maken.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/9403953780/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7376/9403953780_772cea7c7b_b.jpg&#34; alt=&#34;Tara&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/9401194669/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm4.static.flickr.com/3826/9401194669_385229038c_b.jpg&#34; alt=&#34;Tara&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Geschoten met m&amp;rsquo;n Hasselblad 500 C/M op Kodak Tri-X 400 film. Afgedrukt op
Ilford Multigrade papier met Ilford Warmtone ontwikkelaar.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sterkste man van Zaanstad 2013</title>
      <link>https://stuvel.eu/post/2013-07-18-sterkste-man-van-zaanstad-2013.nl/</link>
      <pubDate>Thu, 18 Jul 2013 21:34:10 +0200</pubDate>
      <guid>https://stuvel.eu/post/2013-07-18-sterkste-man-van-zaanstad-2013.nl/</guid>
      <description>&lt;p&gt;Afgelopen zaterdag waren we bij de Sterkste Man van Zaanstad, om onze vriend
Vlad aan te moedigen en natuurlijk om foto&amp;rsquo;s te maken. Het resultaat: Vlad is 1e
geworden, en wij hebben 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157634618988885&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;deze foto&amp;rsquo;s&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/9317692872/in/set-72157634618988885&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm4.static.flickr.com/3692/9317692872_3fc6e62d74_b.jpg&#34; alt=&#34;Vlad Buda&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/9278587784/in/set-72157634618988885&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm4.static.flickr.com/3743/9278587784_9ff5e8dda1_b.jpg&#34; alt=&#34;Frank, truck pulling&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/9278588410/in/set-72157634618988885&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm6.static.flickr.com/5329/9278588410_631000e19c_b.jpg&#34; alt=&#34;Vlad wins his first Sterkste Man competition!&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ga naar 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157634618988885&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;het overzicht van alle foto&amp;rsquo;s&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Orange &amp; Teal</title>
      <link>https://stuvel.eu/post/2013-06-29-orange-and-teal/</link>
      <pubDate>Sat, 29 Jun 2013 08:47:56 +0200</pubDate>
      <guid>https://stuvel.eu/post/2013-06-29-orange-and-teal/</guid>
      <description>&lt;p&gt;Check out this blog post on the typical look of the Hollywood blog buster
movies: 
&lt;a href=&#34;https://theabyssgazes.blogspot.nl/2010/03/teal-and-orange-hollywood-please-stop.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Teal and Orange - Hollywood, Please Stop the
Madness&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was linked by this post 
&lt;a href=&#34;https://www.redsharknews.com/post/item/843-colour-correction-overload&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Colour Correction
Overload?&lt;/a&gt;,
in which the author asks us whether colour grading is getting too much. I know I
found the Harry Potter films a bit too much in that area, and other movies too.
What do you think?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bl3nder in de Melkweg</title>
      <link>https://stuvel.eu/post/2012-12-30-bl3nder-in-de-melkweg.nl/</link>
      <pubDate>Sun, 30 Dec 2012 21:16:31 +0100</pubDate>
      <guid>https://stuvel.eu/post/2012-12-30-bl3nder-in-de-melkweg.nl/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://bl3nder.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bl3nder&lt;/a&gt; gaf gisteren een spetterend optreden in de
Melkweg in Amsterdam. Natuurlijk werden nummers van hun nieuwe album Gekkenhuis,
hun &amp;ldquo;gouwe ouwe&amp;rdquo; Leipe Shit Ouwe! en werden we getrakeerd op heerlijke funky en
jazzy jams.&lt;/p&gt;
&lt;p&gt;Als fotograaf kon ik gaan en staan waar ik wilde, en zelfs vanaf het podium
fotograferen. Hier onder vind je een paar foto&amp;rsquo;s, de rest staat 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8327494290/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;online op
Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8327493696/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8221/8327493696_1cf3364e41_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8326433965/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8363/8326433965_65a9049680_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8327492580/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8218/8327492580_e8a21f67a8_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8326434409/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8356/8326434409_0565e345bb_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8326435481/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8502/8326435481_5613c27ee5_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8326433293/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8362/8326433293_f4bd4941fc_b.jpg&#34; alt=&#34;Bl3nder in de Melkweg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deze en meer foto&amp;rsquo;s staan 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8327494290/in/set-72157632384085973/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;online op Flickr&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Start XBMC from remote</title>
      <link>https://stuvel.eu/post/2012-12-09-start-xbmc-from-remote/</link>
      <pubDate>Sun, 09 Dec 2012 02:35:37 +0100</pubDate>
      <guid>https://stuvel.eu/post/2012-12-09-start-xbmc-from-remote/</guid>
      <description>&lt;p&gt;The Android 
&lt;a href=&#34;https://play.google.com/store/apps/details?id=org.xbmc.android.remote&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;XBMC
Remote&lt;/a&gt;
app has a &amp;ldquo;Power on&amp;rdquo; button. This button sends a wake-on-lan (WOL) packet to the
XBMC server, so that it can wake up. However, my XBMC server runs all kinds of
server stuff, so I don&amp;rsquo;t want to let it sleep. Still, XBMC uses more than 10%
CPU power even when it&amp;rsquo;s in idle, so I don&amp;rsquo;t want it running all the time
either.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written a small Python script that executes a command every time it
receives a WOL packet. This is then used to start XBMC. Here is the Python
source code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# wol-trigger.py

import socket
import struct
import os
import sys
import subprocess

if &#39;SUDO_UID&#39; not in os.environ:
    raise SystemExit(&#39;Run with sudo&#39;)

# Try to parse these before spawning another process
uid = int(os.environ[&#39;SUDO_UID&#39;])
gid = int(os.environ[&#39;SUDO_GID&#39;])

# Let the user know what will happen
cmdargs = sys.argv[1:]
if cmdargs:
    print(&#39;Going to call:&#39;)
    print(&#39;    %s&#39; % &#39; &#39;.join(cmdargs))
    print(&#39;As UID=%i / GID=%i&#39; % (uid, gid))

# Open the port now we still have root rights.
port_nr = socket.getservbyname(&#39;discard&#39;, &#39;udp&#39;)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((&#39;255.255.255.255&#39;, port_nr))

# Drop root rights and become mortal again.
os.setgid(gid)
os.setuid(uid)

try:
    while True:
        packet = sock.recv(102)

        padding = struct.unpack(&#39;BBBBBB&#39;, packet[0:6])
        if padding != 6 * (255, ):
            hexpad = &#39;:&#39;.join(hex(b) for b in padding)
            print(&#39;Invalid WOL packet received: %s&#39; % hexpad)
            continue

        address = struct.unpack(&#39;BBBBBB&#39;, packet[6:12])
        mac = &#39;:&#39;.join(hex(a) for a in address)

        if cmdargs:
            print(&#39;Starting %s&#39; % (cmdargs, ))
            subprocess.call(cmdargs)
        else:
            print(&#39;Received WOL from %s&#39; % addr)
except KeyboardInterrupt:
    pass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a very minimalistic script, that doesn&amp;rsquo;t even check the MAC address in the
WOL packet. If you need it, it&amp;rsquo;s simple enough to add it in. You need to run it
with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo python wol-trigger.py xbmc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or with any other command or shell script you want to execute when you receive a
Wake-On-Lan magic packet. It needs to be run with sudo because the WOL port is
9, which is lower than 1024 and thus needs root rights to listen on. The command
to be executed will be running with the rights of the user running sudo, and
&lt;em&gt;not&lt;/em&gt; as root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sudo python wol-trigger.py id
Going to call:
    id
As UID=1000 / GID=1000
Starting [&#39;id&#39;]
uid=1000(sybren) gid=1000(sybren) groups=1000(sybren),0(root)&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script only works on Linux, but I&amp;rsquo;m sure it can be modified to work on other
systems too. That&amp;rsquo;s up to you, though ;-)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Vlad Buda</title>
      <link>https://stuvel.eu/post/2012-11-01-vlad-buda/</link>
      <pubDate>Thu, 01 Nov 2012 07:50:56 +0100</pubDate>
      <guid>https://stuvel.eu/post/2012-11-01-vlad-buda/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8143971405/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8330/8143971405_d60cb89da1.jpg&#34; alt=&#34;Vlad #10&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My friend Vlad trains at Raw Power Baarn. A few months ago I went to one of his
training sessions, and I was very impressed by not only their strength of body
but also of the mind. Vlad knows exactly what kind of signals his body sends,
which pain he can push through, and when to stop.&lt;/p&gt;
&lt;p&gt;Most of the photos I shot on Ilford Delta 3200. Back then I still used an old
light meter that turned out to be very inaccurate in dark situations, so
unfortunately the film was heavily underexposed. I&amp;rsquo;m quite happy with the result
I got, though, it came out much better than I expected (after I did a lot of
measurements and printed with the highest filtration for the most contrast).&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/8143971361/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8467/8143971361_008e5534cd.jpg&#34; alt=&#34;Vlad #1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The photo below is the only one I didn&amp;rsquo;t shoot on Ilford Delta 3200, but on
Kodak Tri-X 400:&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7982530908/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8032/7982530908_0722946e70.jpg&#34; alt=&#34;Face of Pain&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Vakantiefoto&#39;s</title>
      <link>https://stuvel.eu/post/2012-09-08-vakantiefotos/</link>
      <pubDate>Sat, 08 Sep 2012 15:21:24 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-09-08-vakantiefotos/</guid>
      <description>&lt;p&gt;Dit jaar zijn we weer naar Kroatië gegaan, en hebben we een heel aantal

&lt;a href=&#34;https://stuvel.eu/pano/zomer-2012/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;bol-panorama&amp;rsquo;s&lt;/a&gt; geschoten.
Daarnaast ook een hoop zwart-wit foto&amp;rsquo;s met mijn Hasselblad 500 C/M. Hier onder
vind je er alvast twee, de rest moet ik nog afdrukken en scannen.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7955646798/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8313/7955646798_bc817069a3.jpg&#34; alt=&#34;Drowned trees&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7955513308/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8034/7955513308_a34424b650.jpg&#34; alt=&#34;Old water wheel&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7957834864/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8307/7957834864_4474630191.jpg&#34; alt=&#34;Mysterious bottle&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7958463350/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8308/7958463350_104e2187e9.jpg&#34; alt=&#34;Early morning river&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>First photos with a Hasselblad</title>
      <link>https://stuvel.eu/post/2012-07-28-first-photos-with-a-hasselblad/</link>
      <pubDate>Sat, 28 Jul 2012 17:00:32 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-07-28-first-photos-with-a-hasselblad/</guid>
      <description>&lt;p&gt;These are the first photos I&amp;rsquo;ve taken with 
&lt;a href=&#34;https://stuvel.eu/blog/2012-07-24-hasselblad-500-c-m/&#34;&gt;my Hasselblad 500
C/M&lt;/a&gt;. I was actually planning of
shooting in black &amp;amp; white mostly, but since I had some unused colour film in my
fridge I thought it would be a good idea to practice with that. Turns out I
really like the result! The colours are vivid, but still look natural, and the
bokeh of the lens is simply terrific. I love this camera!&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7658567128/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7139/7658567128_285a440fda.jpg&#34; alt=&#34;Kitteh&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7662821944/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7107/7662821944_a2789fd587.jpg&#34; alt=&#34;Dinner in Amsterdam&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7658567944/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8427/7658567944_425760f8c4.jpg&#34; alt=&#34;Celebrating summer&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Trying out T-Max 400</title>
      <link>https://stuvel.eu/post/2012-07-27-trying-out-t-max-400/</link>
      <pubDate>Fri, 27 Jul 2012 11:13:02 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-07-27-trying-out-t-max-400/</guid>
      <description>&lt;p&gt;One of my favourite photographers, 
&lt;a href=&#34;https://www.stephanvanfleteren.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stephan
Vanfleteren&lt;/a&gt;, seems to shoot Kodak T-Max
400 film (the film is labeled Kodak 400TMY as you can see 
&lt;a href=&#34;https://www.stephanvanfleteren.com/gallery_portraits/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;in some of his
portraits&lt;/a&gt;). I wanted to
give the film a try too, so I met up with my friend and willing subject Matthijs
for a Sunday morning photoshoot in the park. Here is the first result.&lt;/p&gt;
&lt;figure id=&#34;figure-matthijs-4&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm9.static.flickr.com/8161/7655617774_a6216b97ec_b.jpg&#34; data-caption=&#34;Matthijs #4&#34;&gt;
  &lt;img src=&#34;https://farm9.static.flickr.com/8161/7655617774_a6216b97ec_b.jpg&#34; alt=&#34;Matthijs #4&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Matthijs #4
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure id=&#34;figure-matthijs-10&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm8.static.flickr.com/7117/7652719684_33a0ce5773_b.jpg&#34; data-caption=&#34;Matthijs #10&#34;&gt;
  &lt;img src=&#34;https://farm8.static.flickr.com/7117/7652719684_33a0ce5773_b.jpg&#34; alt=&#34;Matthijs #10&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Matthijs #10
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;How much can you say about a film after a single shoot? Well, I&amp;rsquo;m going to try
anyway. So far I like the details that are captured. It still feels a little too
&amp;ldquo;clean&amp;rdquo; for me, lacking a bit of punch or depth. That may have something to do
with my still-developing skills in the darkroom, though. So far it hasn&amp;rsquo;t won me
over &amp;ndash; Kodak Tri-X 400 will remain my favourite. For now - who knows what the
future brings!&lt;/p&gt;
&lt;figure id=&#34;figure-matthijs-12&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm9.static.flickr.com/8285/7867217612_55f4a02ca6_b.jpg&#34; data-caption=&#34;Matthijs #12&#34;&gt;
  &lt;img src=&#34;https://farm9.static.flickr.com/8285/7867217612_55f4a02ca6_b.jpg&#34; alt=&#34;Matthijs #12&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Matthijs #12
  &lt;/figcaption&gt;
&lt;/figure&gt;
</description>
    </item>
    
    <item>
      <title>Hasselblad 500 C/M</title>
      <link>https://stuvel.eu/post/2012-07-24-hasselblad-500-c-m/</link>
      <pubDate>Tue, 24 Jul 2012 19:22:55 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-07-24-hasselblad-500-c-m/</guid>
      <description>&lt;figure id=&#34;figure-my-hasselblad-500-cm&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm8.static.flickr.com/7256/7638854612_133487d0cd_b.jpg&#34; data-caption=&#34;My Hasselblad 500 C/M&#34;&gt;
  &lt;img src=&#34;https://farm8.static.flickr.com/7256/7638854612_133487d0cd_b.jpg&#34; alt=&#34;My Hasselblad 500 C/M&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    My Hasselblad 500 C/M
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have wanted a Hasselblad for years, and last Sunday I bought this Hasselblad
500 C/M, with 80mm f/2.8 Carl Zeiss Planar T* lens, waist-level finder and A12
film back. It&amp;rsquo;ll be a long wait for the first photos to come back from the lab!&lt;/p&gt;
&lt;figure id=&#34;figure-my-hasselblad-500-cm&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm9.static.flickr.com/8287/7638846378_0e38018fde_b.jpg&#34; data-caption=&#34;My Hasselblad 500 C/M&#34;&gt;
  &lt;img src=&#34;https://farm9.static.flickr.com/8287/7638846378_0e38018fde_b.jpg&#34; alt=&#34;My Hasselblad 500 C/M&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    My Hasselblad 500 C/M
  &lt;/figcaption&gt;
&lt;/figure&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA version 3.1.1 released</title>
      <link>https://stuvel.eu/post/2012-06-17-python-rsa-version-3-1-1-released/</link>
      <pubDate>Sun, 17 Jun 2012 10:11:58 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-06-17-python-rsa-version-3-1-1-released/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python-RSA version 3.1.1&lt;/a&gt; has been released. A lot of
things have been improved, thanks to Yesudeep Mangalapilly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Much, much faster&lt;/li&gt;
&lt;li&gt;Compatibility with Python 3.2&lt;/li&gt;
&lt;li&gt;Lot of bug fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python-RSA&lt;/a&gt; page for more information!&lt;/p&gt;
&lt;p&gt;Observant readers may have noticed that I snuck in a tiny minor release. Version
3.1.1 introduces full Python 3.2 compatibility for the key saving/loading stuff
as well, and fixes some doctests for Python 2.7. Nothing in the actual RSA
stuff was changed.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sheepies in Utrecht</title>
      <link>https://stuvel.eu/post/2012-05-01-sheepies-in-utrecht/</link>
      <pubDate>Tue, 01 May 2012 20:39:46 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-05-01-sheepies-in-utrecht/</guid>
      <description>&lt;p&gt;The campus of Utrecht University has a small field with sheep, and today I got up close and personal. One of the big sheep was even tame enough to let me stroke and pat it!&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7133187303/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7202/7133187303_512ccd3569_b.jpg&#34; alt=&#34;Schaapjes op de Uithof&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7133187243/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm9.static.flickr.com/8015/7133187243_4c1d6ce8be_b.jpg&#34; alt=&#34;Schaapjes op de Uithof&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6987103498/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7088/6987103498_74e66f3b69_b.jpg&#34; alt=&#34;Schaapjes op de Uithof&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6987103382/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7249/6987103382_f2791e89d3_b.jpg&#34; alt=&#34;Schaapjes op de Uithof&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Long romantic weekend in Paris</title>
      <link>https://stuvel.eu/post/2012-04-21-long-romantic-weekend-in-paris/</link>
      <pubDate>Sat, 21 Apr 2012 15:48:32 +0200</pubDate>
      <guid>https://stuvel.eu/post/2012-04-21-long-romantic-weekend-in-paris/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157629866954999/show/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7273/6953068538_b911813c90.jpg&#34; alt=&#34;Relaxing at the embankment of the Seine&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Marit and I had a long, very romantic weekend in Paris a few weeks ago.
Photo-wise all I took with me was my Chinon CS, two lenses (50mm f/1.7 and 28mm
f/2.8), and a roll of Kodak 400TX.&lt;/p&gt;
&lt;p&gt;Check 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157629866954999/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;all the photos on
Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6953068682/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7221/6953068682_ccd126188e_b.jpg&#34; alt=&#34;Marit at the Louvre&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7099138901/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm6.static.flickr.com/5444/7099138901_d6d79244cd_b.jpg&#34; alt=&#34;Live jazz on a bridge&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6953069286/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7088/6953069286_731a21432a_b.jpg&#34; alt=&#34;08-watermarked&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7099139297/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7123/7099139297_09fffa494c_b.jpg&#34; alt=&#34;The Seine early in the morning&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6953069198/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7073/6953069198_f9b57d771b_b.jpg&#34; alt=&#34;Marit at the Eiffel Tower&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7099139377/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm6.static.flickr.com/5341/7099139377_578713475d_b.jpg&#34; alt=&#34;Idyllic scene at the Eiffel Tower&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/7099139359/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm8.static.flickr.com/7261/7099139359_754cb20611_b.jpg&#34; alt=&#34;Bare feet at the Notre Dame&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>FlickrAPI and OAuth</title>
      <link>https://stuvel.eu/post/2012-02-24-flickrapi-and-oauth/</link>
      <pubDate>Fri, 24 Feb 2012 08:17:11 +0100</pubDate>
      <guid>https://stuvel.eu/post/2012-02-24-flickrapi-and-oauth/</guid>
      <description>&lt;p&gt;This summer Flickr will stop supporting their 
&lt;a href=&#34;https://www.flickr.com/services/api/misc.userauth.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;old authentication
system&lt;/a&gt; and move fully
to OAuth. I&amp;rsquo;ve gotten several questions about whether 
&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python
FlickrAPI&lt;/a&gt; will support that. No worries, it will.
If you want it fast, clone 
&lt;a href=&#34;https://bitbucket.org/sybren/flickrapi/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the
repository&lt;/a&gt;, implement OAuth (don&amp;rsquo;t
forget the unittests) and send me a pull request.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Joe McNally shows history of NG from 1992</title>
      <link>https://stuvel.eu/post/2012-01-05-joe-mcnally-shows-history-of-ng-from-1992/</link>
      <pubDate>Thu, 05 Jan 2012 14:05:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2012-01-05-joe-mcnally-shows-history-of-ng-from-1992/</guid>
      <description>&lt;p&gt;One of my photographic heroes, Joe McNally, wrote a 
&lt;a href=&#34;https://www.joemcnally.com/blog/2012/01/02/starting-off-looking-back/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;blog
post&lt;/a&gt;
looking back 20 years at National Geographic. He also has a video from back in
1992 about the process of National Geographic, from the photograph via editing,
more editing, and then finally to print. It&amp;rsquo;s very cool to look at, if not for
the story then at least for the hair.&lt;/p&gt;
&lt;p&gt;I find it striking how much Joe looks like what I feel is a typical NY
photographer back in the days. I would see him shoot alongside Peter Parker any
day.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://www.youtube.com/embed/VacqxeJ8AN8&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Play Framework</title>
      <link>https://stuvel.eu/post/2011-11-21-play-framework/</link>
      <pubDate>Mon, 21 Nov 2011 08:23:17 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-11-21-play-framework/</guid>
      <description>&lt;p&gt;At the start of my last project by 
&lt;a href=&#34;https://www.chess-ix.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Chess IX&lt;/a&gt; (I&amp;rsquo;m
leaving after working there for over 5 years) I looked at several Java web
frameworks. One of the frameworks was Wicked, which I 
&lt;a href=&#34;https://stuvel.eu/blog/162/my-experience-with-wicket&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;blogged
about&lt;/a&gt; earlier, but the
hands-down winner was the 
&lt;a href=&#34;https://www.playframework.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Play Framework&lt;/a&gt;. On
the surface it seemed to be designed much like my beloved

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt;, and now that we&amp;rsquo;ve arrived at the
final week of the project at my final week at Chess IX it seems like a good idea
to write about my findings.&lt;/p&gt;
&lt;h3 id=&#34;contents&#34;&gt;Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;#overview-of-play&#34;&gt;Overview of Play&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#the-http-cycle&#34;&gt;The HTTP cycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#controllers&#34;&gt;Controllers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#template-engine&#34;&gt;Template engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#translations&#34;&gt;Translations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#ajax-integration&#34;&gt;AJAX integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#database-layer&#34;&gt;Database layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#authentication-and-authorization&#34;&gt;Authentication and authorization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#dependency-management&#34;&gt;Dependency management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#unit-testing-and-cm-rc&#34;&gt;Unit testing and CM-RC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#spring-injection&#34;&gt;Spring injection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#other-front-end-tech&#34;&gt;Other front-end tech&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#the-verdict&#34;&gt;The verdict&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;overview-of-play&#34;&gt;Overview of Play&lt;/h3&gt;
&lt;p&gt;Play is a full application stack, from the incoming HTTP request all the way to
persistence, e-mails, scheduled jobs and dependency management. At the time of
writing, version 1.2.3 is the current version.&lt;/p&gt;
&lt;p&gt;The Play website already shows us 
&lt;a href=&#34;https://www.playframework.org/documentation/1.2.3/5things&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;5 cool things we can do with
Play&lt;/a&gt;, so I won&amp;rsquo;t
repeat them here. Go check them out, they&amp;rsquo;re cool.&lt;/p&gt;
&lt;h3 id=&#34;the-http-cycle&#34;&gt;The HTTP cycle&lt;/h3&gt;
&lt;p&gt;Play has a very clear notion of a HTTP request-response cycle:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTTP request for a certain URL comes in.&lt;/li&gt;
&lt;li&gt;The routing table is consulted to determine the controller method that&amp;rsquo;s to
be called. In our case this is a static Java method.&lt;/li&gt;
&lt;li&gt;The controller method is called with the parameters from the request&lt;/li&gt;
&lt;li&gt;The controller does its work, and results in a HTTP response.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By using a routing table, the URLs of the application are &lt;strong&gt;well defined&lt;/strong&gt;. This
has several advantages, for example bookmarkability of your pages.&lt;/p&gt;
&lt;p&gt;Play compiles and reloads your Java code on the fly. It can determine by itself
whether it should restart or not, and if it happens the restart is quite fast.&lt;/p&gt;
&lt;p&gt;Another important feature is that Play is &lt;strong&gt;stateless&lt;/strong&gt;. Anything that in other
frameworks would be stored in server-side state is stored in client-side cookies
(cryptographically signed to prevent tampering) or delegated to the database.&lt;/p&gt;
&lt;p&gt;The automatic reloading, combined with the routing table, result in a &lt;strong&gt;very
pleasant development flow&lt;/strong&gt;. You can just hit F5 and your page including your
code will be reloaded. This is quite different when using things like Tomcat or
JBoss and more traditional Java frameworks.&lt;/p&gt;
&lt;h3 id=&#34;controllers&#34;&gt;Controllers&lt;/h3&gt;
&lt;p&gt;The routing engine delegates a HTTP request to a controller method. This is a
static method in a subclass of &lt;code&gt;Controller&lt;/code&gt;. Here is one controller class with
two controller methods. The &lt;code&gt;certificateId&lt;/code&gt; parameter comes from the request,
for example when it ends in &lt;code&gt;?certificateId=123&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;package controllers.admin;

public class Certificates extends SecureCHController {

    public static void showCertificate(@Required Long certificateId) {
        Certificate cert = Certificate.findById(certificateId);
        render(cert);
    }

    public static void redirectDemo() {
        showHistory(123);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The controller class is dynamically altered in such a way that the
&lt;code&gt;showHistory(123)&lt;/code&gt; call results in a HTTP redirect to the URL that results in
the &lt;code&gt;showHistory&lt;/code&gt; call. The routing table is used to determine which URL the
browser should be sent to. The resulting property is that &lt;strong&gt;the URL always
reflects the displayed page&lt;/strong&gt;. This dynamic alteration is done for all &lt;code&gt;public static void&lt;/code&gt; methods, so if you want such a method but &lt;strong&gt;not&lt;/strong&gt; have it altered
that way, annotate it with &lt;code&gt;@Util&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Debugging your controllers is very easy. You don&amp;rsquo;t need to restart Play, you can
simply tell Eclipse to connect a debugger and you&amp;rsquo;re done. Now you can set
breakpoints, step through code, view/change variables, etc.&lt;/p&gt;
&lt;h4 id=&#34;updating-complex-objects&#34;&gt;Updating complex objects&lt;/h4&gt;
&lt;p&gt;Play has nice features for editing complex objects. Here is an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;// the model in models/User.java
@Entity
public class User extends Model {
    public String firstName;
    public String lastName;
    public Integer numberOfPets;
}

// the controller in controllers/Users.java
public class Users extends Controller {
    public static void edit(@Required Long id) {
        User user = User.findById(id);

        if (request.method.equals(&amp;quot;POST&amp;quot;)) {
            user.edit(&amp;quot;user&amp;quot;, params.all());
            user.validateAndSave();
        }

        render(user);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You would typically create a form like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;form action=&#39;@{edit(user.id)}&#39; method=&#39;POST&#39;&amp;gt;
    &amp;lt;input type=&#39;text&#39; name=&#39;user.firstName&#39; value=&#39;{user.firstName}&#39;&amp;gt;
    &amp;lt;input type=&#39;text&#39; name=&#39;user.lastName&#39; value=&#39;{user.lastName}&#39;&amp;gt;
    &amp;lt;input type=&#39;text&#39; name=&#39;user.numberOfPets&#39; value=&#39;{user.numberOfPets}&#39;&amp;gt;
    &amp;lt;button type=&#39;submit&#39;&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because in the posted data the names match the properties of the &lt;code&gt;User&lt;/code&gt; class,
the &lt;code&gt;user.edit(...)&lt;/code&gt; line updates the &lt;code&gt;user&lt;/code&gt; object just like you&amp;rsquo;d expect.&lt;/p&gt;
&lt;div class=&#34;warning&#34;&gt;
Be aware that the controller has no knowledge of the form that was posted. Someone could forge a POST request that contains more properties than the original form. If you&#39;re not careful, users could raise their own privileges.
&lt;p&gt;For example, if your User class has a &lt;code&gt;Boolean isAdmin&lt;/code&gt;, then a POST could
contain &lt;code&gt;user.isAdmin=true&lt;/code&gt;. Without any modification, a &lt;code&gt;user.edit(&amp;quot;user&amp;quot;, params.all())&lt;/code&gt; call will happily set that &lt;code&gt;isAdmin&lt;/code&gt; property.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&#34;template-engine&#34;&gt;Template engine&lt;/h3&gt;
&lt;p&gt;A lot of Java web frameworks are XML-centred. The reasoning behind it is that
it&amp;rsquo;s easy to validate the templates. This is of course true, but of limited use&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the validity of the templates doesn&amp;rsquo;t imply the validity of the produced HTML.
The nature of XML also makes it difficult to stick to the DRY principle, as
you&amp;rsquo;ll get constructions like below. This code tries to set &lt;code&gt;class=&amp;quot;secure&amp;quot;&lt;/code&gt; for
HTTPS links, and &lt;code&gt;class=&amp;quot;insecure&amp;quot;&lt;/code&gt; for other links:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;c:if test=&#39;href.startsWith(&amp;quot;https://&amp;quot;)&#39;&amp;gt;&amp;lt;a href=&amp;quot;&amp;lt;%= href %&amp;gt;&amp;quot; class=&amp;quot;secure&amp;quot;&amp;gt;&amp;lt;%= linkText %&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;c:/if&amp;gt;
&amp;lt;c:else&amp;gt;&amp;lt;a href=&amp;quot;&amp;lt;%= href %&amp;gt;&amp;quot; class=&amp;quot;insecure&amp;quot;&amp;gt;&amp;lt;%= linkText %&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/c:else&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Play uses Groovy as template language. With Groovy, the same concept would look
like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;a href=&amp;quot;${href}&amp;quot; class=&amp;quot;#{if not href.startsWith(&#39;https://&#39;)}in#{/}secure&amp;quot;&amp;gt;${linkText}&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Play you can also template anything that&amp;rsquo;s not an element, such as part of
a string or an HTML attribute. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;link rel=&#39;stylesheet&#39; href=&#39;{base_path}/style.css&#39; type=&#39;text/css&#39; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is impossible using Wicket without having to move the entire element to
your Java code.&lt;/p&gt;
&lt;p&gt;As you can see, you&amp;rsquo;re free to place your expressions right where you want them,
without having to bother making the mix of HTML and XML valid XML. This is very
important for modern sites, as &lt;strong&gt;HTML 5 is not XML&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Another upside is that you can use the same template engine for different
content: XML, CSV files, mixed HTML and plain text e-mails, etc. Note that this
also applies to JavaScript. With Wicket and other XML-based systems you cannot
do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;alert(&amp;quot;Page title: {page.title}&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Referring to the URL that will call a certain controller method is very easy:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;a href=&#39;@{controllers.SomeController.javaMethod()}&#39;&amp;gt;clickme&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;@@{...}&lt;/code&gt; instead of &lt;code&gt;@{...}&lt;/code&gt; to get absolute URLs, for example in e-mails.&lt;/p&gt;
&lt;h4 id=&#34;extending&#34;&gt;Extending&lt;/h4&gt;
&lt;p&gt;Templates can &amp;ldquo;extend&amp;rdquo; each other, in a somewhat object-oriented fashion. A
&amp;ldquo;parent&amp;rdquo; template can use a &lt;code&gt;#{doLayout /}&lt;/code&gt; statement, which will be replaced by
the contents of the &amp;ldquo;child&amp;rdquo; template. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;!-- master.html --&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;#{get &#39;title&#39; /} - My Super App&amp;lt;/title&amp;gt;
    &amp;lt;link type=&#39;text/css&#39; href=&#39;https://stuvel.eu/style.css&#39; rel=&#39;stylesheet&#39;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;some header&amp;lt;/header&amp;gt;
    #{doLayout /}
    &amp;lt;footer&amp;gt;some footer&amp;lt;/footer&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;!-- page.html --&amp;gt;
#{extends &#39;master.html&#39; /}
#{set title: &#39;This page&#39; /}

&amp;lt;article&amp;gt;The content of this page&amp;lt;/article&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s equally simple to create your own template tags. Just create a &lt;code&gt;tags&lt;/code&gt;
directory in the right spot, and place your tag files there. The tag files are
simply HTML (or whatever you want) and the filename will become the tag name.
Similar as &lt;code&gt;#{doLayout /}&lt;/code&gt; template tags have a &lt;code&gt;#{doBody /}&lt;/code&gt; that renders the
template tag&amp;rsquo;s body. Here is a silly example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;!-- tags/link.html --&amp;gt;
&amp;lt;a href=&#39;{_href}&#39;&amp;gt;#{doBody /}&amp;lt;/a&amp;gt;

&amp;lt;!-- usage in a template: --&amp;gt;
#{link href: &#39;https://stuvel.eu/&#39;}my website#{/link}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I do miss some features in the templating engine, though.

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt; has &amp;ldquo;blocks&amp;rdquo; which you define in a
&amp;ldquo;parent&amp;rdquo; template and can override in a &amp;ldquo;child&amp;rdquo; template. In the child you can
also include the block content of the parent, so it&amp;rsquo;s very easy to &lt;strong&gt;add&lt;/strong&gt;
something to the parent, rather than replacing the entire block. I didn&amp;rsquo;t see
this kind of flexibility in Play, but I must admit that I only looked at the
default templating engine; other engines are offered as plugins.&lt;/p&gt;
&lt;h4 id=&#34;groovy&#34;&gt;Groovy&lt;/h4&gt;
&lt;p&gt;Groovy has many language features that Java lacks. Of course with Java you can
do the same - it just takes more work. Here is a quick example in which we have
a list of people, where each person has some eye colour, and we want to have a
mapping from eye colour to the people with that eye colour. The script would
look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-groovy&#34;&gt;perEyeColour = people.groupBy { person -&amp;gt; person.eyeColour};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One could argue that grouping and sorting information is part of the
presentation logic (rather than doing this at the database layer). The powerful
way that Groovy can work with collections makes it a templating language that&amp;rsquo;s
pleasant to work with.&lt;/p&gt;
&lt;p&gt;For more information, check out the 
&lt;a href=&#34;http://groovy-lang.org/groovy-dev-kit.html#_working_with_collections&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Groovy collections
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;translations&#34;&gt;Translations&lt;/h3&gt;
&lt;p&gt;Play has a simple yet quite effective translation system. It reads the file
&lt;code&gt;messages&lt;/code&gt; for all translations, and &lt;code&gt;messages.nl&lt;/code&gt; if your browser tells the
server you want Dutch, or &lt;code&gt;messages.hr&lt;/code&gt; when you want Croatian (if you configure
your server to support those languages, of course). Whatever it cannot find in
these files it will take from the &lt;code&gt;messages&lt;/code&gt; file instead.&lt;/p&gt;
&lt;h3 id=&#34;ajax-integration&#34;&gt;AJAX integration&lt;/h3&gt;
&lt;p&gt;Play hasn&amp;rsquo;t got explicit AJAX support, but using AJAX is quite easy nonetheless.
Returning a JSON response that serializes some object is as simple as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;public static void someMethod(Long personId) {
    Person person = Person.findById(personId);
    renderJSON(person);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Accepting POSTed JSON is similarly easy. Replace &lt;code&gt;renderJSON&lt;/code&gt; with &lt;code&gt;renderXml&lt;/code&gt;
if you&amp;rsquo;d rather us XML.&lt;/p&gt;
&lt;p&gt;As for the client side you&amp;rsquo;re free to use whatever tooling you like, such as
jQuery.&lt;/p&gt;
&lt;h3 id=&#34;database-layer&#34;&gt;Database layer&lt;/h3&gt;
&lt;p&gt;Hibernate is used as the DB layer, but with a slight twist. By itself Hibernate
will persist all changes to a managed Java object, unless you explicitly prevent
it. In Play changes to the Java object are always never persisted to the DB,
unless you explicitly call &lt;code&gt;someObject.save()&lt;/code&gt;. In this case I feel that
&lt;strong&gt;explicit is better than implicit&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For simple queries Play created a simple language. Of course more powerful
queries are possible as well, and Play will detect from the syntax whether the
simple or more complex language is used. Here are some examples of the
&lt;code&gt;findBy(...)&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;@Entity
public class Profile extends Model {
    public User user;
    public String nickname;

    public static Profile findByNickname(String nick) {
        return find(&amp;quot;byNickname&amp;quot;, nick).first();
    }

    public static Profile findByUser(User user) {
        return find(&amp;quot;byUser&amp;quot;, user).first();
    }

    public static List&amp;lt;Profile&amp;gt; findActivatable() {

        String query = &amp;quot;select p from Profile p &amp;quot;
                + &amp;quot;where p.user is NULL &amp;quot;
                + &amp;quot;or p.user.activated = false&amp;quot;;

        return find(query).fetch();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The database interface is quite object oriented. Methods that we would
traditionally create a separate &lt;strong&gt;Database Access Object&lt;/strong&gt; (DAO) for, are simply
methods on the DB object itself. Static methods are used for queries on groups,
whereas non-statics are used for operations on single entities.&lt;/p&gt;
&lt;p&gt;What I do miss is per-page query logging. When Django is running in development
mode I can display the SQL statements and the time they took, right in the
template. This makes debugging your SQL a lot easier. Something like this is
also possible with Play of course, but requires you to go through a lot more
steps configuring Hibernate, and then the logging still shows up in your log
file, not on the page itself.&lt;/p&gt;
&lt;h4 id=&#34;property-simulation&#34;&gt;Property simulation&lt;/h4&gt;
&lt;p&gt;Many Javanians feel that you shouldn&amp;rsquo;t use direct property access. Instead you
should write a getter and a setter method for the property. This often results
in trivial methods that only clutter up your source. Sure, they can be
automatically generated, but code is read more than it is written so readability
counts heavily.&lt;/p&gt;
&lt;p&gt;Play generates your setters and getters dynamically. Public properties will
become private with public setters/getters, and all direct property access will
use those. Any existing getters or setters you wrote because they actually have
to do something more intelligent will be used by Play. So in this example,
properties &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; will get trivial setters and getters,
whereas the &lt;code&gt;url&lt;/code&gt; property will use the hand-written setter and a dynamically
generated getter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;public class PropDemo {
    public String firstName;
    public String lastName;
    public String url;

    public void setUrl(String url) {
        this.url = UrlLibrary.cleanupUrl(url);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the getters and setters are generated, the objects are still compatible
with the &amp;ldquo;java beans&amp;rdquo; concept, and thus can be freely passed to libraries that
expect them.&lt;/p&gt;
&lt;p&gt;I like this very much. It keeps my code clean, and increases information density
on my screen: more functionality per line of code, with increased readability.&lt;/p&gt;
&lt;h3 id=&#34;authentication-and-authorization&#34;&gt;Authentication and authorization&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Auth &amp;amp; auth&lt;/em&gt; is one of the areas where I&amp;rsquo;m less enthusiastic about Play. There
is no built-in &amp;ldquo;user&amp;rdquo; class, nor groups, roles or rights. The login/logout
controllers are tightly integrated with the rest of the security code, which
makes it a chore if you want to have multiple login pages (for example using one
URL for your users, and another for staff members).&lt;/p&gt;
&lt;p&gt;Django does come with a &amp;ldquo;user&amp;rdquo; class and all the rest, proving that it&amp;rsquo;s very
much possible to make a generic auth &amp;amp; auth system. Application-specific user
properties are delegated to a &amp;ldquo;profile&amp;rdquo; model that you&amp;rsquo;re free to create
yourself, so you don&amp;rsquo;t need to touch the built-in stuff. Very elegantly solved,
and very missing from Play.&lt;/p&gt;
&lt;p&gt;Play also has no template tags that help you with security, for example hiding
links to pages that can&amp;rsquo;t be accessed by the user. The result is that you have
to duplicate your access rules for the controller classes and the template
engine.&lt;/p&gt;
&lt;p&gt;Having said all that, once we had implemented the login system and defined the
roles, it was quite easy to secure controllers. All we needed was something
simple like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;@With(controllers.Secure.class)
@Check(&amp;quot;newsadmin|superuser&amp;quot;)
public class NewsEditor extends Controller {
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;@With&lt;/code&gt; annotation points to a class that checks the user&amp;rsquo;s access, and the
&lt;code&gt;@Check&lt;/code&gt; annotation describes the roles that are allowed to access the
controller. You can also apply &lt;code&gt;@Check&lt;/code&gt; to individual methods.&lt;/p&gt;
&lt;h3 id=&#34;dependency-management&#34;&gt;Dependency management&lt;/h3&gt;
&lt;p&gt;Dependencies are managed by Play too. They can be downloaded from the main Play
repository, but it&amp;rsquo;s also possible to use one or more Maven 2 repositories.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;play --deps&lt;/code&gt; to download the dependencies and install them in the &lt;code&gt;modules&lt;/code&gt;
directory. Add the &lt;code&gt;--sync&lt;/code&gt; option to remove any old dependencies that may still
be lingering around.&lt;/p&gt;
&lt;p&gt;For my project we chose to commit those files to Subversion for a reason that
was good at the time (I still support it but it&amp;rsquo;s no longer necessary due to an
update). I now suggest you do not do this, as syncing the dependencies also
removes the hidden &lt;code&gt;.svn&lt;/code&gt; directories, making Subversion loose its temper (and
its metadata). Of course this also applies to CVS. Mercurial and Git can handle
this just fine, as they no longer have metadata in every directory (they have a
top-level &lt;code&gt;.hg&lt;/code&gt; resp. &lt;code&gt;.git&lt;/code&gt; only).&lt;/p&gt;
&lt;h3 id=&#34;unit-testing-and-cm-rc&#34;&gt;Unit testing and CM-RC&lt;/h3&gt;
&lt;p&gt;The unit testing framework uses JUnit 4. You can subclass Play&amp;rsquo;s &lt;code&gt;UnitTest&lt;/code&gt;
class to run your tests in the Play context, or create a POJO for regular tests
that don&amp;rsquo;t need the database etc.&lt;/p&gt;
&lt;p&gt;By default the unit tests do &lt;strong&gt;not&lt;/strong&gt; run transactionally. This was surprising,
as I&amp;rsquo;m quite accustomed to that. This was fixed by creating an abstract
&lt;code&gt;TransactionalTest&lt;/code&gt; class containing the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;@Before
public void createTransaction() {
    JPA.setRollbackOnly();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By calling &lt;code&gt;JPA.setRollbackOnly()&lt;/code&gt; writes to the database are still allowed, but
rolled back at the end of the transaction.&lt;/p&gt;
&lt;p&gt;The test running isn&amp;rsquo;t restricted to unit tests though; it can also run Selenium
tests. However, we decided against using Selenium in this way, as the Selenium
tests flash by so quickly that you can&amp;rsquo;t see what&amp;rsquo;s going on. They&amp;rsquo;re gone
faster than you can click the pause button. Instead we use

&lt;a href=&#34;https://chessforge.chess-it.com/gf/project/checkmate-rc/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Checkmate-RC&lt;/a&gt; for our
front-end testing.&lt;/p&gt;
&lt;p&gt;Code coverage measurements are possible using the Cobertura plugin. By running
both your unit tests and front-end test in the same &amp;ldquo;play test&amp;rdquo; session you&amp;rsquo;ll
get combined coverage reports. This is a lot easier than trying to get front-end
coverage reports using Tomcat or JBoss.&lt;/p&gt;
&lt;h3 id=&#34;spring-injection&#34;&gt;Spring injection&lt;/h3&gt;
&lt;p&gt;There is a Play plugin for Spring, but it lacks automatic injection into the
controller classes. My guess is that it&amp;rsquo;s due to the static nature of the
controller methods. If your architecture heavily depends on Spring, it may not
be a good idea to tightly integrate it with the Play framework.&lt;/p&gt;
&lt;p&gt;A different approach (one that I quite like in theory, but haven&amp;rsquo;t tried yet) is
to use a multi-tier system: Play for the front-end and a separate server for the
Spring services / business logic. For the communication between those there is a
plethora of RPC tooling.&lt;/p&gt;
&lt;h3 id=&#34;other-front-end-tech&#34;&gt;Other front-end tech&lt;/h3&gt;
&lt;p&gt;During the project we used the following front-end tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;https://jquery.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;jQuery&lt;/a&gt; for most of the JavaScript stuff. It makes
cross-browser scripting a breeze, and easily extendible.&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://datatables.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;DataTables&lt;/a&gt; for more features for displaying
tabular data.&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://jqueryui.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;jQuery-UI&lt;/a&gt; for date pickers, auto-completing text
boxes, and other UI components.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-verdict&#34;&gt;The verdict&lt;/h3&gt;
&lt;p&gt;Above I&amp;rsquo;ve touched on the more important parts of the Play Framework. After
working with it for a couple of months I&amp;rsquo;m quite pleased with it. The things
that are meant to be simple really are simple, and we&amp;rsquo;ve noticed that adding
more features to a webapp that&amp;rsquo;s been in development for months remains simple.&lt;/p&gt;
&lt;p&gt;The different aspects of Play are cleanly separated. You can use it with another
database layer, for example, or even without DB. You can swap out the templating
engine if you like. Not only does this allow you to replace components with
better alternatives, but it also indicates a good underlying design.&lt;/p&gt;
&lt;p&gt;However, there are also downsides. The documentation is really good, but can be
improved. The framework feels rather new, because there seem to be no Best
Practices documented - there are multiple ways to reach the same goal, and they
don&amp;rsquo;t tell you which is the best.&lt;/p&gt;
&lt;p&gt;Some features also seem to be tacked on and left behind. For example, the &lt;code&gt;play war&lt;/code&gt; command should give me a WAR file that runs on Apache Tomcat. I tried it,
but it didn&amp;rsquo;t work.

&lt;a href=&#34;https://groups.google.com/group/play-framework/browse_thread/thread/69f12fce5dc56b36&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Posting&lt;/a&gt;
to the discussion group resulted in no answer what so ever.&lt;/p&gt;
&lt;p&gt;Adding &lt;em&gt;auth &amp;amp; auth&lt;/em&gt; to the application also felt like it wasn&amp;rsquo;t really well
thought out. The &amp;ldquo;security&amp;rdquo; module does its job, but is quite limited. Also the

&lt;a href=&#34;#security-warning&#34;&gt;security warning&lt;/a&gt; I wrote above should have been in the Play
documentation itself, but it&amp;rsquo;s painfully missing.&lt;/p&gt;
&lt;p&gt;Having said all that, I would still recommend Play. It&amp;rsquo;s a pleasure to work
with, bringing a lot of the features I was used to from

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt; into the Java world. Debugging is easy,
the error messages are friendly and informative, and just pressing F5 to refresh
is refreshing.&lt;/p&gt;
&lt;p&gt;Play sticks closely to HTTP, rather than trying to reinvent the wheel, and I
(mostly) kept feeling in control over the application. All the HTTP requests and
responses are as designed, where other Java frameworks try to hide HTML and
HTTP; I feel that knowing what is sent &amp;ldquo;over the wire&amp;rdquo; is part of the interface
contract between client and server application, and as with every client/server
architecture it is important to keep a grip over the communication.&lt;/p&gt;
&lt;p&gt;Kudos to the people behind Play, and sincerely I hope that version 2 will be at
least as appealing.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Photoshoot with Janet</title>
      <link>https://stuvel.eu/post/2011-11-15-photoshoot-with-janet/</link>
      <pubDate>Tue, 15 Nov 2011 14:45:18 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-11-15-photoshoot-with-janet/</guid>
      <description>&lt;p&gt;A week ago my friend 
&lt;a href=&#34;https://www.janetduijn.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Janet&lt;/a&gt; asked for a
photographer on Facebook. The next day she stood in front of me, modeling
outdoors in Amsterdam. I had packed all kind of gear - digital camera, flashes,
light stands, umbrella, reflectors, analogue camera, the whole shebang. Only I
had forgotten to bring any memory cards&amp;hellip; so I left all the digital stuff in
the bag, and only used my trusty 
&lt;a href=&#34;https://www.google.com/search?q=chinonCS&amp;amp;tbm=isch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Chinon
CS&lt;/a&gt; with Kodak Tri-X 400
film.&lt;/p&gt;
&lt;p&gt;I got the negatives developed and scanned, and here are the results!&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6346928121/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6103/6346928121_c131163b2c_b.jpg&#34; alt=&#34;Janet Duijn #15&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6346909489/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6228/6346909489_203ab720ee_b.jpg&#34; alt=&#34;Janet Duijn #7&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6347658018/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6232/6347658018_1627517742_b.jpg&#34; alt=&#34;Janet Duijn #17&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6329598507/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6037/6329598507_973b867013_b.jpg&#34; alt=&#34;Photoshoot with Janet&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6346908639/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6240/6346908639_e940ec5e5e_b.jpg&#34; alt=&#34;Janet Duijn #16&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6347757984/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6019/6347757984_46a2de18f6_b.jpg&#34; alt=&#34;Janet Duijn #30&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Gursky world</title>
      <link>https://stuvel.eu/post/2011-11-15-gursky-world/</link>
      <pubDate>Tue, 15 Nov 2011 12:12:42 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-11-15-gursky-world/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“when you&amp;rsquo;re looking with your eyes, it doesn’t mean you’re seeing.” – Andreas Gursky&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The video below is a 23-minute documentary by Ben Lewis, about the German
photographer Andreas Gursky. Lewis tries to find out what makes a Gursky a
Gursky, and in the mean time learns about the man behind the photos.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://player.vimeo.com/video/17692722&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;vimeo video&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Thanks to Stephen Schaub of 
&lt;a href=&#34;https://figitalrevolution.com/2011/11/10/when-art-becomes-art/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Figital
Revolution&lt;/a&gt; for
posting about this. Very inspiring!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My own dark room</title>
      <link>https://stuvel.eu/post/2011-11-09-my-own-dark-room/</link>
      <pubDate>Wed, 09 Nov 2011 12:50:39 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-11-09-my-own-dark-room/</guid>
      <description>&lt;p&gt;This weekend I got a lot of dark room supplies from friends (thanks Ton &amp;amp; Q!).
Monday I bought the necessary liquids, and yesterday I developed my very first
photo. As soon as I saw the photo appear on the paper I fell in love with the
process. Of course I wasn&amp;rsquo;t satisfied with the first result, so immediately I
started playing around with dodging and burning. It was was easier than I
expected, and very satisfying!&lt;/p&gt;
&lt;p&gt;Right now my &amp;ldquo;dark room&amp;rdquo; is my bathroom, but I plan on changing that in a couple
of weeks. We&amp;rsquo;re (still) renovating our attic, and when that&amp;rsquo;s done I&amp;rsquo;ll build a
proper dark room there.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hacking in Fallout 3 improved</title>
      <link>https://stuvel.eu/post/2011-11-02-hacking-in-fallout-3-improved/</link>
      <pubDate>Wed, 02 Nov 2011 12:08:03 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-11-02-hacking-in-fallout-3-improved/</guid>
      <description>&lt;!-- [![Hacking of a security terminal in Fallout 3](/images/fallout3-terminal.jpg)](https://stuvel.eu/fallout3) --&gt;
&lt;p&gt;Ever since I bought &lt;em&gt;Fallout 3: New Vegas&lt;/em&gt;, I&amp;rsquo;ve been playing their hacking
mini-game again. Of course I&amp;rsquo;m using 
&lt;a href=&#34;https://stuvel.eu/software/fallout/&#34;&gt;my own hacking
tool&lt;/a&gt; to help me. Today I made a small improvement:
it now also suggests which words to try first. It picks the two words that are
most different, and suggests you try those.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/software/fallout/&#34;&gt;Check it out yourself!&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I&#39;m going to do a PhD!</title>
      <link>https://stuvel.eu/post/2011-10-20-i-m-going-to-do-a-phd/</link>
      <pubDate>Thu, 20 Oct 2011 07:41:55 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-10-20-i-m-going-to-do-a-phd/</guid>
      <description>&lt;p&gt;Last Monday I went for a job interview at 
&lt;a href=&#34;https://www.uu.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Universiteit
Utrecht&lt;/a&gt;. Later that day I received a phone call from my
to-be-promoter telling me I&amp;rsquo;m hired! So starting this December, my life will be
radically different. I&amp;rsquo;m looking forward to it :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Summer in The Netherlands</title>
      <link>https://stuvel.eu/post/2011-08-31-summer-in-the-netherlands/</link>
      <pubDate>Wed, 31 Aug 2011 19:40:27 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-08-31-summer-in-the-netherlands/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6100512167/in/photostream/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6205/6100512167_9c33693c83.jpg&#34; alt=&#34;Summer in The Netherlands&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s this year&amp;rsquo;s joke: summer. It&amp;rsquo;s like last spring was confused and acted
all summery, and summer, autumn and winter all think they&amp;rsquo;re autumn.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/6100511999/in/photostream/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6207/6100511999_6a001ff652.jpg&#34; alt=&#34;Summer in The Netherlands&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Still makes for good photos though ;-)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Print Chuck</title>
      <link>https://stuvel.eu/post/2011-08-20-print-chuck/</link>
      <pubDate>Sat, 20 Aug 2011 10:02:56 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-08-20-print-chuck/</guid>
      <description>&lt;figure id=&#34;figure-panorama-of-amsterdam-noord&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm7.static.flickr.com/6003/5893678506_5cbbc1b1a6_b.jpg&#34; data-caption=&#34;Panorama of Amsterdam Noord&#34;&gt;
  &lt;img src=&#34;https://farm7.static.flickr.com/6003/5893678506_5cbbc1b1a6_b.jpg&#34; alt=&#34;Panorama of Amsterdam Noord&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Panorama of Amsterdam Noord
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Alex over at 
&lt;a href=&#34;https://printchuck.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Print Chuck&lt;/a&gt; is using my

&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;FlickrAPI&lt;/a&gt; implementation on their website. He
offered me a free print as a thank you note for writing the software! The print
arrived yesterday, and it looks great. The paper is a thick cotton-based paper,
which feels different from any other print I&amp;rsquo;ve had in my hands. It is super
matte, just the way I like it!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Their website seems to be down. The print still adorns our
bedroom wall, though :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>360-panorama: Sint Bavo Church</title>
      <link>https://stuvel.eu/post/2011-08-10-360-panorama-sint-bavo-church/</link>
      <pubDate>Wed, 10 Aug 2011 15:40:06 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-08-10-360-panorama-sint-bavo-church/</guid>
      <description>&lt;script type=&#34;text/javascript&#34; src=&#34;https://stuvel.eu/media/360/pano2vr_player.js&#34;&gt;/* */&lt;/script&gt;&lt;script type=&#34;text/javascript&#34; src=&#34;https://stuvel.eu/media/360/skin.js&#34;&gt;/* */&lt;/script&gt; &lt;script type=&#34;text/javascript&#34;&gt;var pano = new pano2vrPlayer(&#34;pano_idm8900688&#34;); var skin = new pano2vrSkin(pano, &#39;/media/360/&#39;); pano.readConfigUrl(&#34;/media/360/2011-08-06-st_bavo/360-kerk_fused_out.xml&#34;);&lt;/script&gt;
&lt;p&gt;Fokker, when he was 21 years old, flew a plane over Haarlem, around the Sint
Bavo church. This photo was taken at the centre of that church. Take a look at
the ceiling, it really is amazing! The photo is quite full of detail, so it
won&amp;rsquo;t show its potential while it&amp;rsquo;s in this small window. &lt;strong&gt;Press the right-most
button&lt;/strong&gt; to see it in its full detail.&lt;/p&gt;
&lt;p&gt;This photo is comprised of 80 individual photos, which were exposure blended and
fused into this one (nearly) seamless shot.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>360-panorama: Fokker Spin</title>
      <link>https://stuvel.eu/post/2011-08-07-360-panorama-fokker-spin/</link>
      <pubDate>Sun, 07 Aug 2011 17:06:16 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-08-07-360-panorama-fokker-spin/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: I have to fix the panorama viewer.&lt;/p&gt;
&lt;script type=&#34;text/javascript&#34; src=&#34;https://stuvel.eu/media/360/pano2vr_player.js&#34;&gt;/* */&lt;/script&gt;&lt;script type=&#34;text/javascript&#34; src=&#34;https://stuvel.eu/media/360/skin.js&#34;&gt;/* */&lt;/script&gt; &lt;script type=&#34;text/javascript&#34;&gt;var pano = new pano2vrPlayer(&#34;pano_idm3962928&#34;); var skin = new pano2vrSkin(pano, &#39;/media/360/&#39;); pano.readConfigUrl(&#34;/media/360/2011-08-06-spin/pano.xml&#34;);&lt;/script&gt;
&lt;p&gt;Fokker, when he was 21 years old, flew one of these planes over Haarlem, around
the Sint Bavo church. Today it is exhibited in that very same church. Can you
imagine never having seen a plane, and then this thing flying over your house?
It must have been an amazing sight!&lt;/p&gt;
&lt;p&gt;The photo is quite full of detail, so it won&amp;rsquo;t show its potential while it&amp;rsquo;s in
this small window. &lt;strong&gt;Click the right-most button&lt;/strong&gt; to see it in its full detail.
And be sure to look up at the amazing ceiling too!&lt;/p&gt;
&lt;p&gt;This photo is comprised of 83 individual photos, which were exposure blended and
fused into this one seamless shot.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python-RSA version 3.0 released</title>
      <link>https://stuvel.eu/post/2011-08-05-python-rsa-version-3-0-released/</link>
      <pubDate>Fri, 05 Aug 2011 08:42:23 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-08-05-python-rsa-version-3-0-released/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python-RSA version 3.0&lt;/a&gt; has been released. A lot of
things have been improved:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Much more secure&lt;/li&gt;
&lt;li&gt;Following industrial standard PKCS#1; this means compatibility with OpenSSL&lt;/li&gt;
&lt;li&gt;Ability to create and verify detached signatures&lt;/li&gt;
&lt;li&gt;More elegant method of encrypting large files&lt;/li&gt;
&lt;li&gt;Ability to save and load keys in PEM and DER format&lt;/li&gt;
&lt;li&gt;Extensive 
&lt;a href=&#34;https://stuvel.eu/files/python-rsa-doc/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;More efficient key generation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python-RSA&lt;/a&gt; page for more information!&lt;/p&gt;
&lt;p&gt;Update: in the mean time 3.0.1 has been released, which removes an import of the
&amp;ldquo;abc&amp;rdquo; module. This should make the code compatible with Python 2.5 again. All
the documentation (including installation instructions) are the same as before.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My experience with Wicket</title>
      <link>https://stuvel.eu/post/2011-07-29-my-experience-with-wicket/</link>
      <pubDate>Fri, 29 Jul 2011 07:48:09 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-07-29-my-experience-with-wicket/</guid>
      <description>&lt;p&gt;Today I found out that I&amp;rsquo;m not a Java programmer. The more I look at programming
languages in general, the more I find Java to be clumsy and short-sighted. For a
project at my work I tried 
&lt;a href=&#34;https://wicket.apache.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Wicket&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A lot of web frameworks in Java have the &amp;ldquo;I&amp;rsquo;m scared by the web&amp;rdquo;-syndrome, in
which they try to get rid of CSS and mostly JavaScript, and replace it all with
Java. Wicket is no different in that respect. In my opinion, if you&amp;rsquo;re scared of
the web, don&amp;rsquo;t build a web interface.&lt;/p&gt;
&lt;p&gt;As an aside, a colleague pointed me to the 
&lt;a href=&#34;https://www.playframework.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Play
framework&lt;/a&gt;. It appears to be very much like

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt;, but then for Java and Scala. I&amp;rsquo;ve
given it a go, and it looks very nice!&lt;/p&gt;
&lt;p&gt;Back to Wicket: my dislikes, in no particular order:&lt;/p&gt;
&lt;h3 id=&#34;bad-examples--documentation&#34;&gt;Bad examples &amp;amp; documentation&lt;/h3&gt;
&lt;p&gt;The 
&lt;a href=&#34;https://wicket.apache.org/learn/examples/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;few examples&lt;/a&gt; that they provide
on their page &lt;strong&gt;don&amp;rsquo;t compile&lt;/strong&gt;. You have to tweak them yourself in order to get
things running, and then there are still warnings left. For example, they use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;Form form = new Form(&amp;quot;form&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but that gives me a warning that the &lt;code&gt;Form&lt;/code&gt; class actually requires a type
parameter, like &lt;code&gt;Form&amp;lt;Object&amp;gt;&lt;/code&gt;. The example doesn&amp;rsquo;t tell me anything about what
this parameter should be, and more importantly gives me &lt;strong&gt;no links to more
information&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The documentation also leaves a lot of things undocumented. You&amp;rsquo;re referred to
the source code to see if there are any more examples in there. This is fine for
new projects where they haven&amp;rsquo;t had the time to write proper documentation.
However, this project has existed since 2004, so they&amp;rsquo;ve had 7 years to get this
right.&lt;/p&gt;
&lt;h3 id=&#34;no-clear-request-response-cycle&#34;&gt;No clear request-response cycle&lt;/h3&gt;
&lt;p&gt;You can do a lot with the HTTP headers: authentication, content type
negotiation, language negotiation, status codes, and more. But to use those, you
need access to the request and response objects. With Wicket, these are hidden
away somewhere.&lt;/p&gt;
&lt;p&gt;When wicket was initially developed it was seen as advantageous that the HTTP
model was hidden. SOAP was all the rage, which was designed to be transport
layer transparent (you could do soap-over-SMTP if you wanted to).&lt;/p&gt;
&lt;p&gt;Nowadays we tend to look at more lean protocols, such as JSON over HTTP in
REST-style, and Wicket doesn&amp;rsquo;t appear to be suitable for that.&lt;/p&gt;
&lt;h3 id=&#34;template-language-is-xhtml-and-very-thin&#34;&gt;Template language is (X)HTML and very thin&lt;/h3&gt;
&lt;p&gt;The Wicket template language works by extending the HTML DTD with more tags.
This limits you to templating HTML. What about JavaScript? I want to do
something like this, but it obviously doesn&amp;rsquo;t work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;alert(&amp;quot;Page title: &amp;lt;wicket:message key=&#39;page.title&#39;&amp;gt;&amp;lt;/wicket:message&amp;gt;&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;m much more in favour of the 
&lt;a href=&#34;https://docs.djangoproject.com/en/1.3//topics/templates/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django template
engine&lt;/a&gt;, where you
could write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;alert(&amp;quot;Page title: {{ page.title }}&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &amp;ldquo;very thin&amp;rdquo; I mean that all you have in your HTML is some element with a
&lt;code&gt;wicket:id&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;div wicket:id=&#39;somepanel&#39;&amp;gt;placeholder content&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only thing you can do now to figure out what&amp;rsquo;s going to happen when that&amp;rsquo;s
rendered, is to dive into the Java code. I&amp;rsquo;d like the ability to add custom
templates, so that the template HTML is more descriptive, such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;mytags:slideshow&amp;gt;
  &amp;lt;img src=&#39;https://stuvel.eu/image1.jpg&#39; /&amp;gt;
  &amp;lt;img src=&#39;https://stuvel.eu/image2.jpg&#39; /&amp;gt;
&amp;lt;/mytags:slideshow&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There also doesn&amp;rsquo;t seem any way to template anything that&amp;rsquo;s not an element, such
as part of a string or an HTML attribute. In Django you could do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link rel=&#39;stylesheet&#39; href=&#39;{{ base_path}}/style.css&#39; type=&#39;text/css&#39; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;without having to move the entire element to your Java code.&lt;/p&gt;
&lt;h3 id=&#34;multiple-urls-for-the-same-resource&#34;&gt;Multiple URLs for the same resource&lt;/h3&gt;
&lt;p&gt;If you don&amp;rsquo;t create an explicit &amp;ldquo;BookmarkablePage&amp;rdquo; object for each page, they&amp;rsquo;ll get the URL &lt;code&gt;/page_you_were_before?wicket:bookmarkablePage=:java.classname&lt;/code&gt; (I leave out the &lt;code&gt;https://hostname&lt;/code&gt; part).&lt;/p&gt;
&lt;p&gt;The result is that pages can have multiple URLs. These are two URLs that lead to
the same page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/page1?wicket:bookmarkablePage=:javapackage.Page3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/page2?wicket:bookmarkablePage=:javapackage.Page3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The URL that&amp;rsquo;s used by Wicket will depend on whatever page you were on
previously, breaking the &amp;ldquo;visited&amp;rdquo; colour for links and the simple idea that a
resource should have one URL.&lt;/p&gt;
&lt;h3 id=&#34;overly-complex&#34;&gt;Overly complex&lt;/h3&gt;
&lt;p&gt;Some things are just too complex. Look at this example on 
&lt;a href=&#34;https://wicketstuff.org/wicket14/compref/?wicket:bookmarkablePage=:org.apache.wicket.examples.compref.PageLinkPage&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;how to create a
link&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;add(new PageLink(&amp;quot;pageLink&amp;quot;, new IPageLink() {
    public Page getPage() {
        return new NonBookmarkablePage(PageLinkPage.this);
    }
    public Class getPageIdentity() {
        return NonBookmarkablePage.class;
    }
}));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Granted, the result is that a link to the current page is not clickable, which
increases usability, and that&amp;rsquo;s a Good Thing. Still, from a coding point of view
it&amp;rsquo;s ridiculously complex, compared to something like
&lt;code&gt;&amp;lt;a href=&#39;https://stuvel.eu/somepage.html&#39;&amp;gt;link text&amp;lt;/a&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-good-stuff&#34;&gt;The good stuff&lt;/h3&gt;
&lt;p&gt;Sure, Wicket also has its good sides. The page inheritance model works quite
well. And the links - once you get to implement them - are good too. As I wrote
earlier, they don&amp;rsquo;t link to the page you&amp;rsquo;re actually on. The back button also
keeps working, which is a rare thing in Java webapp land. And if Java is the
only thing you&amp;rsquo;ll ever be interested in, but you still feel the need to write a
web app, it may be very suitable for you.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Eclipse doesn&#39;t support AES-encrypted SSH keys</title>
      <link>https://stuvel.eu/post/2011-07-28-eclipse-doesn-t-support-aes-encrypted-ssh-keys/</link>
      <pubDate>Thu, 28 Jul 2011 08:55:11 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-07-28-eclipse-doesn-t-support-aes-encrypted-ssh-keys/</guid>
      <description>&lt;p&gt;Today all of a sudden I couldn&amp;rsquo;t commit to CVS any more. Eclipse refused to
accept my SSH key passphrase. When trying to load the file, Eclipse tells me
&amp;lsquo;failed to decrypt id_rsa&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;I recently re-encrypted my private key using &lt;code&gt;ssh-keygen -p&lt;/code&gt;, which used AES for
the encryption. It turned out that Eclipse doesn&amp;rsquo;t support that.&lt;/p&gt;
&lt;p&gt;The solution is quite simple: use openssl to re-encrypt using DES3:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;cd ~/.ssh
openssl rsa -in id_rsa -out id_rsa-eclipse -des3
mv id_rsa-eclipse id_rsa&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please note that you may need to restart Eclipse, as it may cache your old key.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lighting course a success</title>
      <link>https://stuvel.eu/post/2011-07-17-lighting-course-a-success/</link>
      <pubDate>Sun, 17 Jul 2011 19:54:44 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-07-17-lighting-course-a-success/</guid>
      <description>&lt;p&gt;Today I gave my first lighting course, Strobist-style. As I&amp;rsquo;ve never done such a
thing like that before it was a little unstructured. However, we were able to
cover a lot of ground, and everybody went home feeling they had learned a lot.
My friend 
&lt;a href=&#34;https://www.marcfaasse.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Marc Faasse&lt;/a&gt; was friendly enough to let
us rent his studio for the day, in the atmospheric NDSM Wharf in Amsterdam.&lt;/p&gt;
&lt;p&gt;It was amazing to see how my students picked up on the techniques. They really
enjoyed how their photos would come out better and better after each photo. I
think I&amp;rsquo;ll do more of those courses in the future!&lt;/p&gt;
&lt;h3 id=&#34;the-students-results&#34;&gt;The students&amp;rsquo; results&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Unfortunately those are all taken offline.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;https://www.catalina.demon.nl/Strobist/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Marc Commandeur&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://www.devreugt.nl/strobist&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Rogier de Vreugt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://www.flickr.com/photos/maritbeimers/sets/72157627093180009/with/5951995592/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Marit Beimers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a 
&lt;a href=&#34;https://www.facebook.com/photo.php?fbid=10150386252903902&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;behind-the-scenes photo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here are some of my photos, modeled by Patric:&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5947725060/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6001/5947725060_a0626b816c_z.jpg&#34; alt=&#34;Patric 1&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Originally this photo was 2:3 in &amp;ldquo;portrait&amp;rdquo; orientation, but I felt it suited a
square cut much better. Speedlite 430EX at low camera right. Shutter at max sync
speed to block out all available light.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5947725272/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6138/5947725272_c726013c5c_z.jpg&#34; alt=&#34;Patric 2&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This photo served as an example on doing whitebalance shifts. Speedlite 430EX
with full CTO and black straw grid snoot from high camera left. Whitebalance set
to tungsten to make the white background blue.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5947169413/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm7.static.flickr.com/6126/5947169413_1310205539_z.jpg&#34; alt=&#34;Patric 3&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This photo shows whitebalance shifting as well as dragging the shutter and
rotating the camera. Speedlite 430EX with full CTO gel, aimed at two pieces of
paper stuck to the monitor. Picked 1/10 sec shutter to be able to easily move
the camera.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Added random padding to Python-RSA</title>
      <link>https://stuvel.eu/post/2011-07-10-added-random-padding-to-python-rsa/</link>
      <pubDate>Sun, 10 Jul 2011 10:53:35 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-07-10-added-random-padding-to-python-rsa/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I&amp;rsquo;m thrilled to let you know that I&amp;rsquo;ve just added encryption and decryption with
random padding to my 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python RSA&lt;/a&gt; module. The code has
become &lt;strong&gt;much more secure&lt;/strong&gt; than it was before, and also makes it capable of
encrypting and decrypting &lt;strong&gt;binary data&lt;/strong&gt;! This is a big step towards the
practicality of the implementation.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve implemented the padding according to the PKCS#1 standard. The 
&lt;a href=&#34;https://www.di-mgt.com.au/rsa_alg.html#pkcs1schemes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSA
Algorithm&lt;/a&gt; page by DI
Management explains how to do this very clearly; cudos to them!&lt;/p&gt;
&lt;p&gt;Right now these changes are unreleased. I want to add signing and verifying
signatures too before I do that. Maybe I&amp;rsquo;ll deprecate the existing functions, as
they are much less secure than all the new stuff I&amp;rsquo;m adding. If you want to try
out what I&amp;rsquo;ve changed so far, feel free to grab a copy off my 
&lt;a href=&#34;https://hg.stuvel.eu/python-rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mercurial
repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE 14:20: I&amp;rsquo;ve also implemented PKCS#1 style signatures and signature verification&lt;/p&gt;
&lt;p&gt;UPDATE 2011-07-12: the implementation is compatible with OpenSSL, making it very
likely compatible with other implementations of PKCS#1 version 1.5!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ilford Delta 3200</title>
      <link>https://stuvel.eu/post/2011-06-28-ilford-delta-3200/</link>
      <pubDate>Tue, 28 Jun 2011 19:53:08 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-06-28-ilford-delta-3200/</guid>
      <description>&lt;p&gt;I fell in love with 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/tags/fujineopan1600/show/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Fuji Neopan 1600
film&lt;/a&gt;,
only to hear that it&amp;rsquo;ll be taken out of production soon (or already has been).
Fortunately I could stack up on some rolls, but they&amp;rsquo;ll run out eventually. To
find an alternative, I tried Ilford Delta 3200, which turned out to be quite
nice too, although it&amp;rsquo;s a little too sensitive for my taste.&lt;/p&gt;
&lt;figure id=&#34;figure-happy-cat-is-happy&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5278/5882184912_b096498dd1_b.jpg&#34; data-caption=&#34;Happy cat is happy&#34;&gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5278/5882184912_b096498dd1_b.jpg&#34; alt=&#34;Happy cat is happy&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Happy cat is happy
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure id=&#34;figure-colin-playing-snooker&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5149/5881598661_57a777f6fd_b.jpg&#34; data-caption=&#34;Colin playing snooker&#34;&gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5149/5881598661_57a777f6fd_b.jpg&#34; alt=&#34;Colin playing snooker&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Colin playing snooker
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure id=&#34;figure-marit-playing-snooker&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm7.static.flickr.com/6099/5881590119_f914362504_b.jpg&#34; data-caption=&#34;Marit playing snooker&#34;&gt;
  &lt;img src=&#34;https://farm7.static.flickr.com/6099/5881590119_f914362504_b.jpg&#34; alt=&#34;Marit playing snooker&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Marit playing snooker
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All photos were taken with my Chinon CS camera and Auto Revuenon 55mm f/1.7
lens.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stüvel Fotografie op Facebook</title>
      <link>https://stuvel.eu/post/2011-06-19-stuvel-fotografie-op-facebook.nl/</link>
      <pubDate>Sun, 19 Jun 2011 16:03:05 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-06-19-stuvel-fotografie-op-facebook.nl/</guid>
      <description>&lt;p&gt;Ik heb een Facebook-pagina gemaakt voor Stüvel Fotografie:

&lt;a href=&#34;https://www.facebook.com/stuvelfotografie/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.facebook.com/stuvelfotografie/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deze keer een Nederlandse pagina &amp;ndash; het blijft m&amp;rsquo;n moedertaal, en genoeg mensen
zijn beter in Nederlands dan in Engels.&lt;/p&gt;
&lt;p&gt;25 likes en ik kan er een betere URL aan geven ;-)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An early bird catches nice light</title>
      <link>https://stuvel.eu/post/2011-06-15-an-early-bird-catches-nice-light/</link>
      <pubDate>Wed, 15 Jun 2011 09:11:48 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-06-15-an-early-bird-catches-nice-light/</guid>
      <description>&lt;p&gt;Some weeks ago I woke up early on a saturday morning. That&amp;rsquo;s nothing like me, as
I love to sleep in late. But still, I wanted to catch the light glimmering off
one of Holland&amp;rsquo;s largest canals and reflecting into the trees, and to get the
right angle of the light I had to get there early.&lt;/p&gt;
&lt;p&gt;This photo shows the relaxed atmosphere of the northern part of Amsterdam, while
in the background there is the busy central train station. Be sure to check it
out 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5833040999/lightbox/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;large&lt;/a&gt;.&lt;/p&gt;
&lt;figure id=&#34;figure-de-rust-van-noord&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm4.static.flickr.com/3452/5833040999_e4467b5018_b.jpg&#34; data-caption=&#34;De rust van Noord&#34;&gt;
  &lt;img src=&#34;https://farm4.static.flickr.com/3452/5833040999_e4467b5018_b.jpg&#34; alt=&#34;De rust van Noord&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    De rust van Noord
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A few hundred meters further north along the same canal I found this spot. Again
the light reflected beautifully off the water. Everybody I met that morning was
friendly, and there was a great atmosphere. I think this photo reflects that
well.&lt;/p&gt;
&lt;figure id=&#34;figure-ochtendritje&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm4.static.flickr.com/3561/5833624018_8050c3ff0e_b.jpg&#34; data-caption=&#34;Ochtendritje&#34;&gt;
  &lt;img src=&#34;https://farm4.static.flickr.com/3561/5833624018_8050c3ff0e_b.jpg&#34; alt=&#34;Ochtendritje&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Ochtendritje
  &lt;/figcaption&gt;
&lt;/figure&gt;
</description>
    </item>
    
    <item>
      <title>Fotofestival Naarden</title>
      <link>https://stuvel.eu/post/2011-06-04-fotofestival-naarden.nl/</link>
      <pubDate>Sat, 04 Jun 2011 21:37:12 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-06-04-fotofestival-naarden.nl/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: The photo on Flickr doesn&amp;rsquo;t seem to be recognised as panorama
any more.&lt;/p&gt;
&lt;p&gt;Fotofestival Naarden was really awesome. The photos by 
&lt;a href=&#34;https://www.stephanvanfleteren.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stephan
Vanfleteren&lt;/a&gt; were amazing. He&amp;rsquo;ll be an
inspiration for my future portraits. His photos (amongst other great
photographers) were on exhibition in the Grote Kerk (large church) in Naarden.
The atmosphere in the town was super relaxed, everybody was enjoying all
beautiful photos and the lovely weather. I shot a 360° panorama at the front
entrance of the church. Have a look around:&lt;/p&gt;
&lt;p&gt;&lt;a data-flickr-embed=&#34;true&#34; href=&#34;https://www.flickr.com/photos/sybrenstuvel/5797977684&#34; title=&#34;Fotofestival Naarden&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/3031/5797977684_b3f733e32b_m.jpg&#34; width=&#34;240&#34; height=&#34;120&#34; alt=&#34;Fotofestival Naarden&#34;&gt;&lt;/a&gt;&lt;script async src=&#34;//embedr.flickr.com/assets/client-code.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Drag your mouse to look up, down, left or right. Scroll to zoom. Double-click
for full screen.&lt;/p&gt;
&lt;p&gt;Photo 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5797977684&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hosted by Flickr&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Awesome sheepies</title>
      <link>https://stuvel.eu/post/2011-05-16-awesome-sheepies/</link>
      <pubDate>Mon, 16 May 2011 11:05:52 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-05-16-awesome-sheepies/</guid>
      <description>&lt;figure id=&#34;figure-awesome-sheepies&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2286/5721982709_e62fd76df1_b.jpg&#34; data-caption=&#34;Awesome Sheepies&#34;&gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2286/5721982709_e62fd76df1_b.jpg&#34; alt=&#34;Awesome Sheepies&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Awesome Sheepies
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We went shooting in one of the most beautiful and relaxing bits of the Dutch
countryside. The photos didn&amp;rsquo;t quite work out as I wanted to &amp;ndash; except for these
two sheepies. They are teh awesome!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>360 panorama: a day at work</title>
      <link>https://stuvel.eu/post/2011-05-12-360-panorama-a-day-at-work/</link>
      <pubDate>Thu, 12 May 2011 19:08:59 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-05-12-360-panorama-a-day-at-work/</guid>
      <description>&lt;p&gt;&lt;a data-flickr-embed=&#34;true&#34; data-vr=&#34;true&#34; href=&#34;https://www.flickr.com/photos/sybrenstuvel/5713999836/&#34; title=&#34;360 panorama: a day at work&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/2054/5713999836_2d4aa0ed3d_m.jpg&#34; width=&#34;240&#34; height=&#34;120&#34; alt=&#34;360 panorama: a day at work&#34;&gt;&lt;/a&gt;&lt;script async src=&#34;//embedr.flickr.com/assets/client-code.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Drag your mouse to look up, down, left or right. Scroll to zoom. Double-click for full screen.&lt;/p&gt;
&lt;p&gt;This is the center part of my office building. I took some photos there today (84 in total), and stiched them together with Hugin. Post processing with Bibble Pro and ImageMagick.&lt;/p&gt;
&lt;p&gt;Photo 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5713999836/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hosted by Flickr&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>360 panorama, Amsterdam Noord</title>
      <link>https://stuvel.eu/post/2011-05-11-360-panorama-amsterdam-noord/</link>
      <pubDate>Wed, 11 May 2011 21:26:54 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-05-11-360-panorama-amsterdam-noord/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve bought myself a Nodal Ninja 3 panorama head. Today I gave it a first test
run, and it worked very well! That&amp;rsquo;s my bike, by the way ;-)&lt;/p&gt;
&lt;p&gt;&lt;a data-flickr-embed=&#34;true&#34; data-vr=&#34;true&#34; href=&#34;https://www.flickr.com/photos/sybrenstuvel/5711451452/&#34; title=&#34;360 panorama, Amsterdam Noord&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/3499/5711451452_4e166915db_m.jpg&#34; width=&#34;240&#34; height=&#34;120&#34; alt=&#34;360 panorama, Amsterdam Noord&#34;&gt;&lt;/a&gt;&lt;script async src=&#34;//embedr.flickr.com/assets/client-code.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Drag your mouse to look up, down, left or right. Scroll to zoom. Double-click
for full screen.&lt;/p&gt;
&lt;p&gt;Photo 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/5711451452/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hosted by Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This panorama was made up of 90 individual photos. I used exposure bracketing at
-3EV, 0EV and +3EV to be able to handle the dynamic range of the scene. Stiching
and HDR fusion was done with Hugin. To create the control points I used
Autopano-SIFT, since I couldn&amp;rsquo;t really be bothered to manually align all those
90 photos. Once the points were created, I hit the Hugin &amp;ldquo;optimize&amp;rdquo; button,
deleted all control points that had a distance over 30, optimized again, deleted
control points with a distance over 10, optimized again, and let Hugin stitch
the lot.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m happily surprised with the result! There are very few alignment issues,
which is quite good for a fully automatic process.&lt;/p&gt;
&lt;p&gt;The software I used was mostly Open Source. The only closed source bit was
Bibble Pro, which I used to import the RAW images, apply some lens correction,
and output as TIFF for Hugin.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python serial comm and RTS pin</title>
      <link>https://stuvel.eu/post/2011-04-29-python-serial-comm-and-rts-pin/</link>
      <pubDate>Fri, 29 Apr 2011 09:52:50 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-04-29-python-serial-comm-and-rts-pin/</guid>
      <description>&lt;p&gt;At my work I&amp;rsquo;m communicating with an embedded device via a serial-to-USB cable.
It works fine, except for one little detail: when the &amp;ldquo;Ready To Send&amp;rdquo; (RTS) pin
is high, the device shuts down. This is by design, but annoying nonetheless,
since almost all serial communication software sets this pin to high. I&amp;rsquo;ve
written a little Python program that opens the serial connection, sets the RTS
pin to low, and shows all data read from it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tested my solution on Linux, not sure if it works on other systems, as I&amp;rsquo;m
using rather low-level calls to get the RTS pin low. Please leave a comment when
you&amp;rsquo;ve tried!&lt;/p&gt;
&lt;p&gt;The Python code defines two functions; one to set the RTS pin, and one to copy
the data from the serial device to stdout. Here is the full code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import fcntl
import struct
import sys
import termios
import time

def set_rts(fileobj, on_off):
    # Get current flags
    p = struct.pack(&#39;I&#39;, 0)
    flags = fcntl.ioctl(fileobj.fileno(), termios.TIOCMGET, p)

    # Convert four byte string to integer
    flags = struct.unpack(&#39;I&#39;, flags)[0]

    if on_off:
        flags |= termios.TIOCM_RTS
    else:
        flags &amp;amp;= ~termios.TIOCM_RTS

    # Set new flags
    p = struct.pack(&#39;I&#39;, flags)
    fcntl.ioctl(fileobj.fileno(), termios.TIOCMSET, p)

def output_data(filedev, ignore = &#39;\r&#39;):
    &#39;&#39;&#39;Outputs data from serial port to sys.stdout.&#39;&#39;&#39;

    while True:
        byte = filedev.read(1)

        if not byte:
            break

        if byte in ignore: continue

        sys.stdout.write(byte)

if len(sys.argv) &amp;lt; 2:
    device = &#39;/dev/ttyUSB0&#39;
else:
    device = sys.argv[1]

# Open device with RTS pin low
print &#39;Device: %s&#39; % device
usb = open(device, &#39;rw&#39;)
set_rts(usb, False)

try:
    output_data(usb)
except KeyboardInterrupt:
    print &#39;Keyboard interrupt, closing.&#39;

usb.close()
print &#39;--- Done ---&#39;
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Analogue photography</title>
      <link>https://stuvel.eu/post/2011-04-24-analogue-photography/</link>
      <pubDate>Sun, 24 Apr 2011 23:07:01 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-04-24-analogue-photography/</guid>
      <description>&lt;figure id=&#34;figure-sheep-number-61&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5061/5651669874_28fc49f627_b.jpg&#34; data-caption=&#34;Sheep Number 61&#34;&gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5061/5651669874_28fc49f627_b.jpg&#34; alt=&#34;&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Sheep Number 61
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ever since I got two old cameras for my birthday last year, I&amp;rsquo;ve been drawn more
and more towards analogue photography. You know, the kind that involves
negatives and chemical processing, and where you don&amp;rsquo;t have to worry about
getting dust on your sensor. There is a certain mistery in not knowing how the
photo will turn out to be. There really is a thrill in cycling to the photo
store and looking at the negatives on their light table. Also I seem to stay
more &amp;ldquo;in the flow&amp;rdquo; while shooting, rather than breaking it by inspecting the LCD
display. This worked very well for the 
&lt;a href=&#34;https://stuvel.eu/blog/138/new-website&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;shoot with
Selina&lt;/a&gt;. And finally I just love the
look of &lt;em&gt;real&lt;/em&gt; black &amp;amp; white photos made with old optics!&lt;/p&gt;
&lt;p&gt;There are downsides, of course. The major one is that it seems to be impossible
to scan an entire negative without having one or two cat hairs on them&amp;hellip;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;My photo gear page hasn&amp;rsquo;t been moved to my new site yet. For those who are
interested, this is the analogue gear that I actively use:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Meopta Flexaret IV&lt;/dt&gt;
&lt;dd&gt;A twin-lens reflex camera from the 1960&#39;s; it was built somewhere in 1961-67. It eats 120 film and makes square photos. It has two 80mm lenses; one to look through and one to make the photo with.&lt;/dd&gt;
&lt;dt&gt;Chinon CS&lt;/dt&gt;
&lt;dd&gt;A 35mm SLR built in 1979. I mostly use it with an Auto Revuenon 50mm f/1.7 lens and a Chinon 28mm f/2.8.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Film-wise my favourite is Kodak Tri-X 400. It has a nice contrast and grain; I
just love the look! If that isn&amp;rsquo;t available, I shoot with Ilford HP5+ 400.
Still have to make up my mind about those two; I haven&amp;rsquo;t shot enough of either
to really have a strong opinion one way or the other.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Relax/yoga/detox/reiki-weekend</title>
      <link>https://stuvel.eu/post/2011-04-08-relax-yoga-detox-reiki-weekend/</link>
      <pubDate>Fri, 08 Apr 2011 15:34:27 +0200</pubDate>
      <guid>https://stuvel.eu/post/2011-04-08-relax-yoga-detox-reiki-weekend/</guid>
      <description>&lt;figure id=&#34;figure-reiki-weekend-lighthouseworks&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5061/5600258535_51436d8011_b.jpg&#34; data-caption=&#34;Reiki-weekend Lighthouseworks&#34;&gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5061/5600258535_51436d8011_b.jpg&#34; alt=&#34;Reiki-weekend Lighthouseworks&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Reiki-weekend Lighthouseworks
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Marit and I went to a relax/yoga/detox/reiki-weekend organized by a friend of
ours. It was very special, very relaxing, and also a bit mustle pain inducing. A
while ago Marit found a 15 year old roll of 35mm negatives, which I used to
shoot some photos during the weekend. They turned out to be quite nice!&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157626330076643/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;To the photos!&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Graffitti @ Mosveld</title>
      <link>https://stuvel.eu/post/2011-03-22-graffitti-mosveld.nl/</link>
      <pubDate>Tue, 22 Mar 2011 19:59:12 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-03-22-graffitti-mosveld.nl/</guid>
      <description>&lt;figure id=&#34;figure-graffiti-bij-mosveld&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5053/5550525449_5d52e0ca79_b.jpg&#34; data-caption=&#34;Graffiti bij Mosveld&#34;&gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5053/5550525449_5d52e0ca79_b.jpg&#34; alt=&#34;Graffiti bij Mosveld&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Graffiti bij Mosveld
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Een groep van 36 kunstenaars uit 6 landen zijn bijeen gekomen om onze stad op te
fleuren. Op dit moment werken ze in Amsterdam Noord bij het Mosveld.&lt;/p&gt;
&lt;p&gt;Natuurlijk kon ik het niet laten om 
&lt;a href=&#34;https://www.flickr.com/search/?q=mosveld&amp;#43;graffiti&amp;amp;w=73509078%40N00&amp;amp;ss=2&amp;amp;z=e&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;wat foto&amp;rsquo;s&lt;/a&gt; er van te schieten.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Version 2.0 of RSA module</title>
      <link>https://stuvel.eu/post/2011-01-09-version-2-0-of-rsa-module/</link>
      <pubDate>Sun, 09 Jan 2011 16:51:53 +0100</pubDate>
      <guid>https://stuvel.eu/post/2011-01-09-version-2-0-of-rsa-module/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2114/2437362208_3d75f0b4f4_b.jpg&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A guy named Dave sent me an email today, telling me that my RSA implementation
was rather insecure due to the use of the &amp;ldquo;pickle&amp;rdquo; Python module. Fortunately I
had some nice improvements by Barry Mead already in version control, eagerly
waiting to be released. Well, Dave gave me a nice insentive to round up Barry&amp;rsquo;s
improvements and send 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;version 2.0&lt;/a&gt; into the world.&lt;/p&gt;
&lt;p&gt;Please note that it&amp;rsquo;s a backward-incompatible change. The 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSA
page&lt;/a&gt; shows how you can re-encrypt your data to be
compatible (and more secure!) again.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New website</title>
      <link>https://stuvel.eu/post/2010-11-24-new-website/</link>
      <pubDate>Wed, 24 Nov 2010 23:55:51 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-11-24-new-website/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm6.static.flickr.com/5241/5204586956_cebd99ba84_b.jpg&#34; &gt;
  &lt;img src=&#34;https://farm6.static.flickr.com/5241/5204586956_cebd99ba84_b.jpg&#34; alt=&#34;Selina with cigarette&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;My old website has been online for april 2006. Since that time it has grown
considerably. My focus also moved from software engineering to photography, and
this new design makes that a lot clearer. Some of the webpages may not yet be
available. Don&amp;rsquo;t worry, most of it will be ported in the next few weeks. If
you&amp;rsquo;re missing something, 
&lt;a href=&#34;https://stuvel.eu/contact&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;let me know&lt;/a&gt; and I&amp;rsquo;ll give
it priority.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also put the photos online of a 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157625334733817&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;photoshoot with model
Selina&lt;/a&gt;. This
was the first time for me doing a model-shoot with my old 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157625115938763/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Flexaret
IV&lt;/a&gt;
twin-lens reflex medium format camera. I must say I&amp;rsquo;m very pleased with the
result! Having only 12 frames on a roll is a nice break from shooting with a 7
FPS digital SLR.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Mijn foto&#39;s op Caro Emerald DVD</title>
      <link>https://stuvel.eu/post/2010-11-02-mijn-foto-s-op-caro-emerald-dvd.nl/</link>
      <pubDate>Tue, 02 Nov 2010 12:34:16 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-11-02-mijn-foto-s-op-caro-emerald-dvd.nl/</guid>
      <description>&lt;figure id=&#34;figure-caro-emerald-in-hoogwoud&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Caro Emerald in Hoogwoud&#34;&gt;
  &lt;img src=&#34;&#34; alt=&#34;Caro Emerald in Hoogwoud&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Caro Emerald in Hoogwoud
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.caroemerald.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Caro Emerald&lt;/a&gt; komt met een platinum release van
haar CD Deleted Scenes from the Cutting Room Floor, met daarbij &amp;ldquo;een overvolle
dvd met extra video-, audio- en fotomateriaal&amp;rdquo;. Jawel, ook mijn foto&amp;rsquo;s! Helemaal
te gek :)&lt;/p&gt;
&lt;p&gt;Naast zo&amp;rsquo;n DVD hier in Nederland komt er ook een zelfde soort DVD uit in Polen,
waar mijn foto&amp;rsquo;s ook op gebruikt gaan worden!&lt;/p&gt;
&lt;p&gt;Je kan de DVD al pre-orderen op

&lt;a href=&#34;https://www.bol.com/nl/p/muziek/deleted-scenes-from-the-cutting-room-floor/1000004010723000/index.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;bol.com&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tentoonstelling in Noorderpark</title>
      <link>https://stuvel.eu/post/2010-10-17-tentoonstelling-in-noorderpark.nl/</link>
      <pubDate>Sun, 17 Oct 2010 18:06:55 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-10-17-tentoonstelling-in-noorderpark.nl/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Helaas is de Noorderpark website down.&lt;/p&gt;
&lt;p&gt;Speciaal voor &lt;em&gt;Crisiskunst&lt;/em&gt; in het 
&lt;a href=&#34;https://osm.org/go/0E5qureyY-&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Noorderpark&lt;/a&gt;
heb ik een foto gemaakt, die nu in de

&lt;a href=&#34;https://www.noorderparkkamer.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Noorderparkkamer&lt;/a&gt; hangt. Elke zondag zijn
hier interessante dingen te beleven, gratis en toegankelijk voor iedereen.&lt;/p&gt;
&lt;p&gt;Deze foto heb ik geschoten in Haarlem. Het is een monumentaal gebouw, en heeft
daardoor een tragisch verhaal. Vanwege het label &amp;ldquo;monumentaal&amp;rdquo; wordt het niet
afgebroken, maar het kost ook zo veel om op te knappen dat dat ook niet gebeurt.
Voor mij was het een mooi beeld van het thema &lt;em&gt;crisis&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;De foto is gemaakt met een Meopta Flexaret IV, een middenformaat tweeogige
spiegelreflexcamera uit de jaren &amp;lsquo;60, deze zomer gekocht in Praag, Tsjechië. De
film was Kodak Tri-X 400, de afdruk is ruim 40x40 cm op mat papier.&lt;/p&gt;
&lt;p&gt;Op zondag 7 november worden de foto’s geveild. De fotografen die hieraan
meewerken zijn: Caro Bonink, Yvonne Witte, Annelore van Herwijnen, Liza de Rijk,
Maaike Koning, Marc Faase, Diana Scherer en Sybren A. Stüvel.&lt;/p&gt;
&lt;p&gt;Voor meer info zie 
&lt;a href=&#34;https://www.noorderparkkamer.nl/project/crisiskunst-kunst-met-de-grote-c-/209&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Crisiskunst - Kunst met de grote
C.&lt;/a&gt;
en 
&lt;a href=&#34;https://www.noorderparkkamer.nl/project/crisiskunst-3/215&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Crisiskunst 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Een quootje over de crisiskunst:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kunst in tijden van crisis gaat over ondernemerschap en creativiteit. Hoe maak
je kunst zonder subsidie? Bedrijven worden gevraagd hun afvalproductie in te
leveren om kunst van te maken, (straat)muzikanten worden uitgenodigd om in het
park te musiceren, fotografen van Noord leggen de crisis op beeld vast en de
foto’s worden geveild in het park. Crisiskunst organiseren we samen met
Stichting Kunstenaars&amp;amp;CO. Kunstenaars krijgen de opdracht om gedurende zes
weken een project te realiseren zonder subsidie, op z´n Berlijns.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>I fixed my camera!</title>
      <link>https://stuvel.eu/post/2010-09-25-i-fixed-my-camera/</link>
      <pubDate>Sat, 25 Sep 2010 11:50:51 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-09-25-i-fixed-my-camera/</guid>
      <description>&lt;p&gt;In Prague I bought an old Flexaret IV, a twin-lens reflex camera from the
1960&amp;rsquo;s. I was very happy with it, until it gave a short &amp;ldquo;click&amp;rdquo; even with a
shutter speed of 1 sec. The shutter refused to open! When I developed the film
it was clear that when I bought the camera it was still in working condition,
and it had also survived the trip back to Amsterdam. After some messing about
with a screwdriver and the moving bits of the camera I found out that the
self-timer was stuck. Moving some pins around got it un-stuck, and so I have a
working camera once again!&lt;/p&gt;
&lt;p&gt;The camera refuses to work when it is closed but has no film in it. One thing I
figured out while toying with it, was that it does work properly without film
when the back has been opened. So if you&amp;rsquo;re unsure whether to buy such a camera
and you want to give it a try without wasting film, just open the back.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I&#39;m a Master of Science!</title>
      <link>https://stuvel.eu/post/2010-09-02-i-m-a-master-of-science/</link>
      <pubDate>Thu, 02 Sep 2010 14:42:15 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-09-02-i-m-a-master-of-science/</guid>
      <description>&lt;p&gt;Yesterday I received my certificate from the Utrecht University! I&amp;rsquo;m now
officially a &lt;em&gt;Master of Science&lt;/em&gt; or &lt;em&gt;Magister Scientiæ&lt;/em&gt; in Computer Science.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Extending Selenium from the client driver</title>
      <link>https://stuvel.eu/post/2010-08-20-extending-selenium-from-the-client-driver/</link>
      <pubDate>Fri, 20 Aug 2010 07:40:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-08-20-extending-selenium-from-the-client-driver/</guid>
      <description>&lt;p&gt;Selenium is a web page testing tool that we use a lot at my work. It can be
extended by supplying it with a &lt;code&gt;user-extensions.js&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re extending our test application to include support for Selenium Grid. In
this setup we can&amp;rsquo;t supply that &lt;code&gt;user-extensions.js&lt;/code&gt; file directly, it has to be
injected via the client driver. However, this happens too late; Selenium doesn&amp;rsquo;t
notice our custom locator functions any more. This is a known issue, also 
&lt;a href=&#34;https://ttwhy.org/home/blog/2008/05/14/selenium-rc-per-session-extension-javascript/#comment-8923&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;noted
by Ross
Patterson&lt;/a&gt;.
I&amp;rsquo;ve found a way to work around this limitation. Add the following to your
&lt;code&gt;user-extensions.js&lt;/code&gt; file such that it&amp;rsquo;s executed after your additions have
loaded:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;objectExtend(selenium.browserbot, PageBot.prototype);
selenium.browserbot._registerAllLocatorFunctions();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems to work just fine without any unwanted side-effects. If you tried this,
please leave a comment to let us know how it worked out for you!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>360 panorama: Amsterdam Central Station</title>
      <link>https://stuvel.eu/post/2010-07-20-360-panorama-amsterdam-central-station/</link>
      <pubDate>Tue, 20 Jul 2010 16:13:02 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-07-20-360-panorama-amsterdam-central-station/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: check out 
&lt;a href=&#34;https://stuvelfoto.nl/panorama/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;my other panoramas on stuvelfoto.nl&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;This panorama shows something that I quite often see; the people here are waiting for the ferry to cross the IJ (the lake that separates the northern part of Amsterdam from the rest).&lt;/p&gt;
&lt;p&gt;&lt;a data-flickr-embed=&#34;true&#34; data-vr=&#34;true&#34; href=&#34;https://www.flickr.com/photos/sybrenstuvel/4812615610/&#34; title=&#34;Pont bij Amsterdam CS&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/4119/4812615610_70e16fbbe8_m.jpg&#34; width=&#34;240&#34; height=&#34;120&#34; alt=&#34;Pont bij Amsterdam CS&#34;&gt;&lt;/a&gt;&lt;script async src=&#34;//embedr.flickr.com/assets/client-code.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Look around by dragging, use your scroll wheel or page up/down keys to zoom. Double-click to view full-screen.&lt;/p&gt;
&lt;p&gt;This photo is 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4812615610/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hosted by Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This time I used Hugin for remapping and aligning the photos, but I merged them by hand in The Gimp. It&amp;rsquo;s quite an easy process, and it gives you much more control. I took the photos without a tripod or any other form of support, so not everything lined up perfectly, which is where the manual control came in handy.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sigma 4.5mm Fisheye - What&#39;s it like?</title>
      <link>https://stuvel.eu/post/2010-06-28-sigma-4-5mm-fisheye-what-s-it-like/</link>
      <pubDate>Mon, 28 Jun 2010 09:14:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-06-28-sigma-4-5mm-fisheye-what-s-it-like/</guid>
      <description>&lt;figure id=&#34;figure-sigma-45mm-f28-fisheye-by-sybren-a-stüvel-on-flickr&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Sigma 4.5mm f/2.8 fisheye by Sybren A. Stüvel, on Flickr&#34;&gt;
  &lt;img src=&#34;&#34; alt=&#34;Sigma 4.5mm f/2.8 fisheye&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Sigma 4.5mm f/2.8 fisheye by Sybren A. Stüvel, on Flickr
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This lens is insane. It&amp;rsquo;s the world&amp;rsquo;s first circular fisheye lens for APS-C
sized sensors, and the first fisheye lens that I own. Looking through the
viewfinder for the first time was a strange sensation. The view was both very
restricted due to the circularness of the lens, and very wide at the same time
due to its 180 degree view all around. For those not intimate with fisheye
lingo, &amp;ldquo;circular&amp;rdquo; means that it projects a circle on the sensor. Outside of the
circle everything&amp;rsquo;s black, inside the circle you have a 180 degree view from
left to right, and top to bottom. So far the best us APS-C shooters could get
was a &amp;ldquo;diagonal&amp;rdquo; fisheye, which means that you only get a 180 degree view from
top left to bottom right. Horizontal and vertical would be less than 180
degrees.&lt;/p&gt;
&lt;figure id=&#34;figure-yellow-volkswagen-van&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm2.static.flickr.com/1216/4723445201_879a9c2a9f_b.jpg&#34; data-caption=&#34;Yellow Volkswagen van&#34;&gt;
  &lt;img src=&#34;https://farm2.static.flickr.com/1216/4723445201_879a9c2a9f_b.jpg&#34; alt=&#34;Yellow Volkswagen van&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Yellow Volkswagen van
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;From the first moment I saw the lens I knew that I just had to have it&amp;hellip;. the
only downside is the price tag. At €650,- it&amp;rsquo;s not the cheapest of lenses, but
it&amp;rsquo;s not that insane compared to other fisheyes. Sigma isn&amp;rsquo;t known for their
good quality control. The shop I bought the lens at had three of them in their
magazine, and the first two had uneven coating on the front element. The store
personnel told me that it wouldn&amp;rsquo;t show on photos, but nevertheless they let me
inspect all three lenses, and one of them had perfectly even coating. For that
price, I wanted to make sure I got the best one.&lt;/p&gt;
&lt;p&gt;I used the lens on my Canon EOS 7D, so besides having a high resolution of 18
megapixels I could also give it a go with video. And boy is it fun! I don&amp;rsquo;t have
a professional setup where I can measure things like distortion or colour
metrics. Instead I&amp;rsquo;ll tell you about practical results I got with this lens, and
how they look with my two eyes. The photos you see here are also processed a
little bit. Unprocessed photos from a digital camera always look a bit flat and
soft, so I don&amp;rsquo;t think that presenting you with such photos would be a true
demonstration of the capabilities of this lens.&lt;/p&gt;
&lt;h3 id=&#34;the-lens&#34;&gt;The lens&lt;/h3&gt;
&lt;figure id=&#34;figure-sigma-45mm-f28-fisheye-by-sybren-a-stüvel-on-flickr&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm2.static.flickr.com/1417/4724653702_3e5bf60bb7_b.jpg&#34; data-caption=&#34;Sigma 4.5mm f/2.8 fisheye by Sybren A. Stüvel, on Flickr&#34;&gt;
  &lt;img src=&#34;https://farm2.static.flickr.com/1417/4724653702_3e5bf60bb7_b.jpg&#34; alt=&#34;Sigma 4.5mm f/2.8 fisheye&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Sigma 4.5mm f/2.8 fisheye by Sybren A. Stüvel, on Flickr
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The lens feels very sturdy. The build is solid, and with a metal mount it
attaches firmly to the camera. At the rear there is a gelatine filter holder,
and you even get a small metal plate you can use to cut the filters to size. I
feel that this filter holder is of limited use, unless you want to insert ND
filters. As the holder doesn&amp;rsquo;t rotate you can&amp;rsquo;t really use polarizers or
graduate ND filters.&lt;/p&gt;
&lt;p&gt;Going further towards the front of the lens, we meet the distance scale. It has
three marks: 13.5cm, 20cm and infinity. Remember these distances are measured
from the sensor; it can focus really, really close. The hypersonic motor
(HSM/USM/whatever you want to call it) does its work quickly and silently. The
focus ring is all the way at the front, and rotates smoothly. I would have liked
it to be a bit further backward, though. My hands are quite big, and it&amp;rsquo;s just
too easy to get some digits into the frame. Every bit of finger that sticks out
from the focus ring will get photographed, so be careful with that.&lt;/p&gt;
&lt;p&gt;The front element bulges out of the lens, to be able to capture the 180 degree
view. The lens cap comes with a metal ring so that it can fit around it. So,
remember to remove the ring as well as the lens cap, or you won&amp;rsquo;t get the full
view.&lt;/p&gt;
&lt;p&gt;The maximum aperture is f/2.8, which is a tad slow for a prime but quite good
for a lens this wide. Combined with the short minimum focus distance you can
even use it to blur the background. A little. The wide aperture is more useful
for low-light shots; it also means that the viewfinder is bright, and that your
autofocus has more light to work with.&lt;/p&gt;
&lt;h3 id=&#34;the-photos&#34;&gt;The photos&lt;/h3&gt;
&lt;p&gt;The centre sharpness of this lens is amazing. Even at very close range - which
is where you want to be with a lens like this - it is very sharp. Towards the
edges it has some serious chromatic aberration and purple fringing in
high-contrast areas. As it&amp;rsquo;s my first and only fisheye lens I can&amp;rsquo;t tell you
whether this is more or less than others. I just know that it&amp;rsquo;s very difficult
to bend light &lt;em&gt;and&lt;/em&gt; keep all the colours where they should be, and at the edges
that light is bent a &lt;em&gt;lot&lt;/em&gt;. The photo below has been corrected, the 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4723445201/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;photo of
the Volkswagen van&lt;/a&gt; up
top hasn&amp;rsquo;t been.&lt;/p&gt;
&lt;figure id=&#34;figure-close-up-of-marit&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm2.static.flickr.com/1088/4723444933_07199b5c29_b.jpg&#34; data-caption=&#34;Close-up of Marit&#34;&gt;
  &lt;img src=&#34;https://farm2.static.flickr.com/1088/4723444933_07199b5c29_b.jpg&#34; alt=&#34;Close-up of Marit&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Close-up of Marit
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The lens flare looks really nice, as it doesn&amp;rsquo;t stick to the circular projection&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it breaks the frame, so to speak. Of course if you don&amp;rsquo;t like it you can
always mask it during post processing. The flare shows that the aperture has six
blades. I would have liked one more - I like odd flare streaks more than even
ones. The aperture makes more noise that I would have expected; more than any
other lens that I own. Now this isn&amp;rsquo;t a lens you can use stealthily anyway, as
you&amp;rsquo;ll have to get right on top of the action or it&amp;rsquo;ll get really, really small,
so a bit more aperture noise isn&amp;rsquo;t a practical issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-panoramas&#34;&gt;The Panoramas&lt;/h3&gt;
&lt;p&gt;The wide view makes this lens very suitable for panorama shots. With only two
photos you&amp;rsquo;ll be able to capture the entire view around you. However, you won&amp;rsquo;t
be able to stitch them together very well; at the edges the quality goes down,
and there wouldn&amp;rsquo;t be much of an overlap anyway. So rather than using the
minimum, I used six shots: north, east, south and west, and straight up and
straight down. And since I was shooting a library with mostly black architecture
and large windows with a bright sun outside, I tripled every shot at -2 EV, 0 EV
and +2 EV to merge them later as HDR photos. The 7D with its 7 photos per second
just whirred through those three shots per direction.&lt;/p&gt;
&lt;!--
&lt;object classid=&#34;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&#34; codebase=&#34;https://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0&#34; title=&#34;Utrecht University Library&#34; width=&#34;100%&#34; height=&#34;320&#34;&gt;&lt;param name=&#34;allowFullScreen&#34; value=&#34;true&#34;&gt; &lt;param name=&#34;movie&#34; value=&#34;/pan0.swf?panoSrc=https://farm2.static.flickr.com/1163/4723421131_f0d90f65b3_o.jpg&amp;amp;tesselation=80&#34;&gt; &lt;param name=&#34;quality&#34; value=&#34;high&#34;&gt; &lt;param name=&#34;BGCOLOR&#34; value=&#34;#AA6666&#34;&gt; &lt;embed src=&#34;https://stuvel.eu/pan0.swf?panoSrc=https://farm2.static.flickr.com/1163/4723421131_f0d90f65b3_o.jpg&amp;amp;tesselation=80&#34; allowfullscreen=&#34;true&#34; quality=&#34;high&#34; pluginspage=&#34;https://www.macromedia.com/go/getflashplayer&#34; type=&#34;application/x-shockwave-flash&#34; bgcolor=&#34;#AADDDD&#34; width=&#34;100%&#34; height=&#34;320&#34;&gt;&lt;/object&gt;
--&gt;
&lt;p&gt;&lt;strong&gt;The panorama is 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4723421131&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;hosted by Flickr&lt;/a&gt;. Double-click to view full-screen, drag to look around.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before I started stitching the photos I loaded the RAW files into 
&lt;a href=&#34;https://www.bibblelabs.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bibble Pro
5.1&lt;/a&gt; and removed most of the chromatic aberration
(C/A). With a few clicks the C/A was as good as gone, and since I had a nice
overlap between different shots the remaining C/A wouldn&amp;rsquo;t pose any problems.
The 18 RAW files were exported to 16-bit TIFFs (100 MB a pop) and then loaded
into 
&lt;a href=&#34;https://hugin.sf.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In 
&lt;a href=&#34;https://hugin.sf.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugin&lt;/a&gt; I manually placed control points, about 5-7
per overlap, optimized the photo and let it do the stitching and HDR processing.
Hugin is very good at producing realistic HDRs. Many HDR programs first create a
photo with a huge dynamic range and then try to compress this range using tone
mapping. This can easily produce those super-saturated, artificial looking
photos. Hugin blends between &amp;ldquo;real&amp;rdquo; pixels, ignoring ones that are under or
over-exposed, blurry, etc. and keeping the good looking ones. This process gives
a much more natural result.&lt;/p&gt;
&lt;p&gt;After exporting the photo in &amp;ldquo;equirectangular&amp;rdquo; projection, I loaded into the
Flash application by 
&lt;a href=&#34;https://pan0.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pan0.net&lt;/a&gt; so that you can look around
in it. The zenith (look straight up) isn&amp;rsquo;t perfect yet, but I&amp;rsquo;m sure I can fix
that if I spend enough time on it. Also know that I took those photos without
any tripod or panorama head.&lt;/p&gt;
&lt;h3 id=&#34;the-videos&#34;&gt;The videos&lt;/h3&gt;
&lt;p&gt;The lens is nearly perfect for video. The video below shows a view from my
Renault Twingo. The music is by my band (I&amp;rsquo;m the drummer) 
&lt;a href=&#34;https://soundabout.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The
Soundabout&lt;/a&gt;, and the drive is from our practice studios
to my home. Click on the cross-like thingy at the bottom of the video to view
full screen.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://player.vimeo.com/video/12690283&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;vimeo video&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;!-- [A quick drive through Amsterdam](https://vimeo.com/12690283) from [Sybren A. Stüvel](https://vimeo.com/sybren) on [Vimeo](https://vimeo.com). --&gt;
&lt;p&gt;So yes, it&amp;rsquo;s good but just not quite perfect for video. It&amp;rsquo;s more an issue with
my 7D than the lens, to be honest. At those lovely modern and crispy 16:9 HD
resolutions the camera crops a few pixels off the bottom of the circle - I would
be much happier if we would have gotten a true 3:2 high-resolution video format,
so that the entire frame could be captured. So Canon, if you&amp;rsquo;re reading this,
pretty please with sugar on top, add a 1920x1280 or 1620x1080 video format!&lt;/p&gt;
&lt;p&gt;As I said, I drum in a band. My girlfriend sometimes records our performances on
video, and will of course start using the Sigma fisheye lens for this. Keep an
eye on 
&lt;a href=&#34;https://soundabout.nl&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;our website&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&#34;the-verdict&#34;&gt;The verdict&lt;/h3&gt;
&lt;figure id=&#34;figure-sigma-45mm-f28-fisheye&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm2.static.flickr.com/1322/4724001093_defeb20530_b.jpg&#34; data-caption=&#34;Sigma 4.5mm f/2.8 fisheye&#34;&gt;
  &lt;img src=&#34;https://farm2.static.flickr.com/1322/4724001093_defeb20530_b.jpg&#34; alt=&#34;Sigma 4.5mm f/2.8 fisheye&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Sigma 4.5mm f/2.8 fisheye
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This lens is unique. The results are very pleasing, and most importantly: it&amp;rsquo;s
great fun. It&amp;rsquo;s really different from anything else in my photo bag. The price
is a bit steep, but given the quality and the fact that they won&amp;rsquo;t sell that
many of them, I think it&amp;rsquo;s justified. If you want to easily shoot 360 panoramas,
record edgy videos or otherwise use an incredibly wide field of view, this lens
is for you.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This article was also published on 
&lt;a href=&#34;https://digital-photography-school.com/sigma-4-5mm-fisheye-whats-it-like&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Digital Photography School&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Graduated as MSc!</title>
      <link>https://stuvel.eu/post/2010-06-23-graduated/</link>
      <pubDate>Wed, 23 Jun 2010 14:42:14 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-06-23-graduated/</guid>
      <description>&lt;p&gt;Last monday I defended 
&lt;a href=&#34;https://stuvel.eu/files/publication/stride_space.pdf&#34;&gt;my thesis&lt;/a&gt; and
succeeded! I got an 8.5 (out of 10) as the grade, with which I&amp;rsquo;m very happy.
This finalizes my &lt;em&gt;Game &amp;amp; Media Technology&lt;/em&gt; computer science master at the
Utrecht University.&lt;/p&gt;
&lt;p&gt;The title is &lt;strong&gt;Stride Space: Humanoid walking animation interpolation using 3D
Delaunay databases&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Abstract:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Precise control over foot placement during character locomotion is crucial to
avoid obstacle collision and to produce natural results. We present a new
exact parameterization technique for generating humanoid walking animations.
Given a database of pre-recorded motion capture data we generate new
animations using a spanning neighbours search in a Delaunay database and
interpolating those neighbours. Our approach results in exact foot placement
while soft constraints such as timing are also taken in account, due to a
novel blend candidates selection strategy. We show that this can be done very
efficiently as to be compatible with real-time applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can download my thesis from

&lt;a href=&#34;https://stuvel.eu/files/publication/stride_space.pdf&#34;&gt;https://stuvel.eu/files/publication/stride_space.pdf&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiple instances of QApplication in one process</title>
      <link>https://stuvel.eu/post/2010-05-22-multiple-instances-of-qapplication-in-one-process/</link>
      <pubDate>Sat, 22 May 2010 09:25:40 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-05-22-multiple-instances-of-qapplication-in-one-process/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m working on a PyQt 4 application for my employer

&lt;a href=&#34;https://www.chess.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Chess&lt;/a&gt;. Of course I&amp;rsquo;m writing plenty of unit tests for
it as well. Those tests have to be cleanly separated from each other, so every
test that requires the entire application to be up and running should have its
own instance. And this is where it gets tricky, as Qt (and thus PyQt) assumes
that &lt;strong&gt;there will only be one application&lt;/strong&gt;, and if that application quits the
process quits.&lt;/p&gt;
&lt;p&gt;In my unit tests, this is not the case. Every test can potentially start and
stop an application, and the test suite will continue running. This caused a
segmentation fault (a.k.a. segfault) the second time the QApplication closed.&lt;/p&gt;
&lt;p&gt;After a lot of puzzling I found out that &lt;strong&gt;QtGui.qApp needs to refer to the
running QApplication instance&lt;/strong&gt;, and be set to &lt;code&gt;None&lt;/code&gt; when the application has
been closed. After I implemented this the segfaults went away.&lt;/p&gt;
&lt;p&gt;This is my &lt;code&gt;ApplicationTest&lt;/code&gt; mix-in class that I use for controlling my
application lifespan. It contains a little trick to stop the application as soon
as it has started:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class MyApplicationClass(QtGui.QApplication):

  started = QtCore.pyqtSignal()

  def exec_(self):
      self.started.emit()
      return QtGui.QApplication.exec_()

class _ApplicationTest(object):
  &#39;&#39;&#39;Mix-in class that can start and stop an application.&#39;&#39;&#39;

  APP_CLASS = MyApplicationClass

  def __init__(self):
      self.app = None
      QtGui.qApp = None

  def create_app(self):
      &#39;&#39;&#39;Creates and returns a new application&#39;&#39;&#39;

      self.app = self.APP_CLASS([])
      QtGui.qApp = self.app
      return self.app

  def stop_app(self):
      &#39;&#39;&#39;Stops the application.&#39;&#39;&#39;

      if not self.app: return

      self.app.started.connect(self.app.quit,
              type=QtCore.Qt.QueuedConnection)
      self.app.exec_()

      QtGui.qApp = None
      self.app = None
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Strobist meeting</title>
      <link>https://stuvel.eu/post/2010-04-19-strobist-meeting/</link>
      <pubDate>Mon, 19 Apr 2010 09:08:52 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-04-19-strobist-meeting/</guid>
      <description>&lt;p&gt;Yesterday 
&lt;a href=&#34;https://ork.be/archive/71/strobist-meet-breukelen/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ork&lt;/a&gt; and I went
to a Strobist meeting in Breukelen, The Netherlands. We had a lot of fun,
joining 18 photographers and 16 models, in an old abandoned industrial building.
Fervently used by graffiti artists and as an illegal dumping site for tires it
was quite a nice setting.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157623883590260/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Browse through the set&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4532360776/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm5.static.flickr.com/4060/4532360776_8a3b2ed3f5_b.jpg&#34; alt=&#34;Dirty Toilet&#34;&gt; &lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4537483221/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt; &lt;img src=&#34;https://farm5.static.flickr.com/4009/4537483221_a46a1779ac_b.jpg&#34; alt=&#34;Tamara wrecks the place&#34;&gt; &lt;/a&gt;

&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/4532582546/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt; &lt;img src=&#34;https://farm3.static.flickr.com/2754/4532582546_3a42bab32a_b.jpg&#34; alt=&#34;A high throne&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most photos of the meeting can be found in the 
&lt;a href=&#34;https://www.flickr.com/groups/dutchstrobists/pool/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dutch Strobist pool&lt;/a&gt; and all should be 
&lt;a href=&#34;https://www.flickr.com/photos/tags/strobistbreukelenapril2010/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;tagged too&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stop-motion: Drunkard</title>
      <link>https://stuvel.eu/post/2010-04-13-stop-motion-drunkard/</link>
      <pubDate>Tue, 13 Apr 2010 05:37:10 +0200</pubDate>
      <guid>https://stuvel.eu/post/2010-04-13-stop-motion-drunkard/</guid>
      <description>&lt;p&gt;Hey folks,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve made my first stop-motion animation! And it&amp;rsquo;s also my first video on
Flickr. Well, video - let&amp;rsquo;s just call it a concatenation of frames. I&amp;rsquo;ve enjoyed
making it, I hope you enjoy watching.&lt;/p&gt;
&lt;p&gt;&lt;a data-flickr-embed=&#34;true&#34; href=&#34;https://www.flickr.com/photos/sybrenstuvel/4512305186/in/dateposted/&#34; title=&#34;The Drunkard&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/4061/4512305186_cee1fbe70f_w.jpg&#34; width=&#34;267&#34; height=&#34;400&#34; alt=&#34;The Drunkard&#34;&gt;&lt;/a&gt;&lt;script async src=&#34;//embedr.flickr.com/assets/client-code.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;The video consists of 66 frames, shot with my Canon EOS 7D and Canon EF 85mm f/1.8 USM lens. The light comes from a gritted 430EX strobe, and the 1/250 shutter speed ensures the ambient light was invisible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Updated my portfolio</title>
      <link>https://stuvel.eu/post/2010-03-14-updated-my-portfolio/</link>
      <pubDate>Sun, 14 Mar 2010 12:23:05 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-03-14-updated-my-portfolio/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: the website linked below has been replaced by 
&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;stuvelfoto.nl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve just updated my 
&lt;a href=&#34;https://portfolio.stuvel.eu/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;portfolio&lt;/a&gt; so I invite you
all to 
&lt;a href=&#34;https://portfolio.stuvel.eu/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;take a look&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bloody Marit</title>
      <link>https://stuvel.eu/post/2010-02-20-bloody-marit/</link>
      <pubDate>Sat, 20 Feb 2010 11:14:58 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-02-20-bloody-marit/</guid>
      <description>&lt;figure id=&#34;figure-bloody-marit-ii&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Bloody Marit II&#34;&gt;
  &lt;img src=&#34;&#34; alt=&#34;Bloody Marit II&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Bloody Marit II
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This photo was made in an old ship factory in Amsterdam Noord (the NDSM Wharf).
We picked a suitable old and faded green wall as the background, set up the
lights, and started shooting.&lt;/p&gt;
&lt;p&gt;The key lights are two Canon Speedlite 430EX strobes. They were pointed up into
tall U-shaped corrugated cardboard sheets that were lined with aluminium foil to
form DIY strip lights; both strobes were set to 1/4 power. The fill light was
provided by a Speedlite 580EX-II at 1/16 power through a shoot-through umbrella.&lt;/p&gt;
&lt;p&gt;I shot with my Canon EF 85mm f/1.8 USM on a Canon EOS 7D. The 1.6x crop factor
makes this a very nice portrait lens. The aperture was f/8 to get sufficiently
deep depth of field and sharp results, and the shutter speed of 1/250 second
ensured that no available light got onto the sensor.&lt;/p&gt;
&lt;figure id=&#34;figure-setup-shot-for-bloody-marit&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2782/4354306860_c9fdd889d1_b.jpg&#34; data-caption=&#34;Setup shot for Bloody Marit&#34;&gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2782/4354306860_c9fdd889d1_b.jpg&#34; alt=&#34;Setup shot for Bloody Marit&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Setup shot for Bloody Marit
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here is a wide shot that shows the setup. I used the 7D as the master, and I was
surprised how well it worked. Because I used my 85mm f/1.8 I could move back a
little (compared to my standard 17-55mm zoom), which made the slave strobes more
into the &amp;ldquo;field of view&amp;rdquo; of the popup flash. The 430EX&amp;rsquo;s &amp;ldquo;looked&amp;rdquo; at Marit
instead of my camera, so I added some aluminium foil to bounce the master flash
into their IR sensors.&lt;/p&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Song title fades in AfterEffects</title>
      <link>https://stuvel.eu/post/2010-02-10-song-title-fades-in-aftereffects/</link>
      <pubDate>Wed, 10 Feb 2010 23:04:08 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-02-10-song-title-fades-in-aftereffects/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been working on a video of 
&lt;a href=&#34;https://soundabout.nl/performance/120&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;our live performance in Winston
Kingdom&lt;/a&gt; using Adobe AfterEffects. To
show the title of a song at the start and end of the song, I used a script to
automate the fading. Assign it as an expression to the opacity of the text layer
and it&amp;rsquo;ll automatically show for a few seconds at the in-point and out-point of
the layer, including nice fades:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fade_time = 1
show_time = 5
if (time &amp;lt; inPoint + fade_time) {
    linear(time, inPoint, inPoint + fade_time, 0, 100)
} else if (time &amp;lt; inPoint + fade_time + show_time) {
    100
} else if (time &amp;lt; inPoint + fade_time + show_time + fade_time) {
    linear(time, inPoint + fade_time + show_time, inPoint + fade_time + show_time + fade_time, 100, 0)
} else if (time &amp;lt; outPoint - fade_time - show_time - fade_time) {
    0
} else if (time &amp;lt; outPoint - fade_time - show_time) {
    linear(time, outPoint - fade_time - show_time - fade_time, outPoint - fade_time - show_time, 0, 100)
} else if (time &amp;lt; outPoint - fade_time) {
    100
} else if (time &amp;lt; outPoint) {
    linear(time, outPoint - fade_time, outPoint, 100, 0)
} else {
   0
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fade_time&lt;/code&gt; is the duration of fade-in and fade-out, &lt;code&gt;show_time&lt;/code&gt; determines how
long the text layer is shown at 100% opacity, both are in seconds. You can make
an animation preset by adding a &amp;ldquo;Solid Composite&amp;rdquo; effect, setting opacity=0% and
assigning the expression to the &amp;ldquo;source opacity&amp;rdquo; property.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python Flickr API 1.4 released</title>
      <link>https://stuvel.eu/post/2010-02-03-python-flickr-api-1-4-released/</link>
      <pubDate>Wed, 03 Feb 2010 16:50:20 +0100</pubDate>
      <guid>https://stuvel.eu/post/2010-02-03-python-flickr-api-1-4-released/</guid>
      <description>&lt;p&gt;The Python FlickrAPI kit has just been released. The new features are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using auth_callback=False when authentication is actually required now ises
a FlickrError exception.&lt;/li&gt;
&lt;li&gt;The implementation uses self.flickr_host so that subclasses can override e
API URLs.&lt;/li&gt;
&lt;li&gt;Support for short URLs was added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course the Python FlickrAPI kit is completely dynamic, and so it always
supports any new FlickrAPI functionality as soon as it is released by the Flickr
team.&lt;/p&gt;
&lt;p&gt;The new version can be found at

&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stuvel.eu/flickrapi&lt;/a&gt; or
the Python Package Index at

&lt;a href=&#34;https://pypi.python.org/pypi/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://pypi.python.org/pypi/flickrapi&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Holiday Special: Sausage</title>
      <link>https://stuvel.eu/post/2009-12-24-holiday-special-sausage/</link>
      <pubDate>Thu, 24 Dec 2009 13:21:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-12-24-holiday-special-sausage/</guid>
      <description>&lt;figure id=&#34;figure-holiday-special-sausage&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm3.static.flickr.com/2609/4211060634_223de3484a_b.jpg&#34; data-caption=&#34;Holiday Special: Sausage&#34;&gt;
  &lt;img src=&#34;https://farm3.static.flickr.com/2609/4211060634_223de3484a_b.jpg&#34; alt=&#34;Holiday Special: Sausage&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Holiday Special: Sausage
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;What are you looking at? It&amp;rsquo;s a sausage. &amp;ldquo;Rookworst&amp;rdquo; (a type of smoked sausage),
to be exact, probably well known to every Dutch reader. It was hand-made by my
parents&amp;rsquo; butcher and wrapped with some Christmas fluff, also by the butcher. He
handed them out as Christmas presents!&lt;/p&gt;
&lt;p&gt;Before we go on the the specifics of this shot, first a few acronyms:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;CTO&lt;/dt&gt;
&lt;dd&gt;Colour Temperature Orange, makes the light warmer.&lt;/dd&gt;
&lt;dt&gt;CTB&lt;/dt&gt;
&lt;dd&gt;Colour Temperature Blue, makes the light colder.&lt;/dd&gt;
&lt;dt&gt;ND&lt;/dt&gt;
&lt;dd&gt;Neutral density, makes the light darker.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The &lt;strong&gt;key light&lt;/strong&gt; from high camera right is a 580EX-II, 1/2 CTO gel, double
gobo&amp;rsquo;d so that it illuminates the sausage thingy and not the background, at
1/4th power. The &lt;strong&gt;fill light&lt;/strong&gt; from camera left is a 430EX-II with a DIY white
diffuser and a full CTB gel. The &lt;strong&gt;third light&lt;/strong&gt; is a 430EX behind the sausage,
at 1/128 power, with a red gel for the effect and a 2-stop ND gel to make it
subtle enough - 1/128 power is as low as it goes, but that was still too bright.&lt;/p&gt;
&lt;p&gt;I chose to work with CTO and CTB gels to add some contrasting colours. The gels
are balanced, which means that where the warm and cold light meet they form
white light again. This makes for some subtly coloured shadows, where only one
light shines and the other is blocked. I chose 1/2 CTO and full CTB because it
just looked better - with a full CTO the colours would become too orange.&lt;/p&gt;
&lt;p&gt;Here you see an incremental buildup of the three lights (click for a larger
version):&lt;/p&gt;
&lt;figure id=&#34;figure-the-making-of-holiday-special-sausage&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;https://farm5.static.flickr.com/4023/4211060232_bb793e74c9_b.jpg&#34; data-caption=&#34;The making of Holiday Special: Sausage&#34;&gt;
  &lt;img src=&#34;https://farm5.static.flickr.com/4023/4211060232_bb793e74c9_b.jpg&#34; alt=&#34;The making of Holiday Special: Sausage&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    The making of Holiday Special: Sausage
  &lt;/figcaption&gt;
&lt;/figure&gt;
</description>
    </item>
    
    <item>
      <title>It&#39;s really winter</title>
      <link>https://stuvel.eu/post/2009-12-20-it-s-really-winter/</link>
      <pubDate>Sun, 20 Dec 2009 19:03:09 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-12-20-it-s-really-winter/</guid>
      <description>&lt;figure id=&#34;figure-jojo-in-the-snow&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Jojo in the snow&#34;&gt;
  &lt;img src=&#34;&#34; alt=&#34;Jojo in the snow&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Jojo in the snow
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Well waddayano, even with all the global warming we can get a few days&amp;rsquo; worth of
real winter in The Netherlands. Clogged up public transportation, taking corners
sideways with our car, and a beautiful white world.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157622913151251/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Photos&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Duplicating audio with ALSA</title>
      <link>https://stuvel.eu/post/2009-12-11-duplicating-audio-with-alsa/</link>
      <pubDate>Fri, 11 Dec 2009 08:35:14 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-12-11-duplicating-audio-with-alsa/</guid>
      <description>&lt;p&gt;On Linux the most used sound system is the Advanced Linux Sound Architecture,
ALSA for short. It&amp;rsquo;s a very configurable system, but it&amp;rsquo;s not easy to dig down
far enough to get to its power.&lt;/p&gt;
&lt;p&gt;What I wanted to do was to get &lt;strong&gt;the same music in the living room and the
computer room&lt;/strong&gt;. The rooms are right next to each other, and my desktop is
sitting with its back towards the living room. My desktop has two audio cards,
one built-in VIA-82xx and my trusty SB Audigy. All I had to do hardware-wise was
to connect the VIA-82xx to the amplifier in the living room and the Audigy to
the amplifier in the computer room.&lt;/p&gt;
&lt;p&gt;But then came the tricky part - to have one application send its sound to both
cards simultaneously. You can configure this on a per-user basis in
&lt;code&gt;~/.asoundrc&lt;/code&gt; or globally for the entire system in &lt;code&gt;/etc/asound.conf&lt;/code&gt;. It takes
two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a virtual &amp;ldquo;sound card&amp;rdquo; that has four channels. Channels 0 and 1 will
be sent to one sound card, and channels 2 and 3 will be sent to the other.&lt;/li&gt;
&lt;li&gt;Create a routing &amp;ldquo;sound card&amp;rdquo; that mixes its stereo input to the
quad-channel virtual sound card.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Place this into &lt;code&gt;~/.asoundrc&lt;/code&gt; or &lt;code&gt;/etc/asound.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;# This is the four-channel card that sends its first two channels
# to one real card, and the other two channels to the other card.
pcm.tworooms {
    type multi;
    slaves {
        a {
           # The first real card, change to &amp;quot;channel:CARD=CardName&amp;quot;
           # for your system.
            pcm &amp;quot;front:CARD=Audigy&amp;quot;;
            channels 2;
        }
        b {
           # The second real card, change to &amp;quot;channel:CARD=CardName&amp;quot;
           # for your system.
            pcm &amp;quot;iec958:CARD=VT82xx&amp;quot;;
            channels 2;
        }
    }

    # This configures how the four channels of this virtual
    # card are distributed amongst the real cards.
    bindings {
        0 { slave a; channel 0; }
        1 { slave a; channel 1; }
        2 { slave b; channel 0; }
        3 { slave b; channel 1; }
    }
}

# This virtual &amp;quot;sound card&amp;quot; mixes two channels up to four.
pcm.both {
    type route

    # Its four-channel output is sent to the &amp;quot;tworooms&amp;quot; device.
    slave {
        pcm &amp;quot;tworooms&amp;quot;
    }

    # This defines how the channels are mixed. Input channel 0 is
    # sent for 100% to channels 0 and 2 of device &amp;quot;tworooms&amp;quot;,
    # and its channel 1 is sent for 100% to channels 1 and 3.
    ttable {
        0 { 0 1.0; 2 1.0 }
        1 { 1 1.0; 3 1.0 }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far so good. Now I want surround sound. Unfortunately, when I change slave
&amp;ldquo;A&amp;rdquo; to &lt;code&gt;surround51:CARD=Audigy&lt;/code&gt; and increase its channels to 6 (updating the
bindings accordingly) it refuses to work. MPlayer tells me &lt;em&gt;The number of output
channels must be between 1 and 6. Current value is 8&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you know how to solve this, please 
&lt;a href=&#34;https://stuvel.eu/contact&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;let me know&lt;/a&gt;.
ALSA should support more than 6 channels, as demonstrated in the 
&lt;a href=&#34;https://www.alsa-project.org/main/index.php/Asoundrc#Virtual_multi_channel_devices&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ALSA
wiki&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New PGP key</title>
      <link>https://stuvel.eu/post/2009-10-26-new-pgp-key/</link>
      <pubDate>Mon, 26 Oct 2009 22:20:03 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-10-26-new-pgp-key/</guid>
      <description>&lt;p&gt;I have superseded my old key with a 
&lt;a href=&#34;https://stuvel.eu/files/sybren@stuvel.eu.pub&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;new PGP
key&lt;/a&gt;. Please import the

&lt;a href=&#34;https://stuvel.eu/files/sybren@stuvel.eu-80B30F24-created-2004-02-07-revokation.asc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;revocation
certificate&lt;/a&gt;
for the old key and the 
&lt;a href=&#34;https://stuvel.eu/files/sybren@stuvel.eu.pub&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;new key&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python Flickr API 1.3 released</title>
      <link>https://stuvel.eu/post/2009-10-03-python-flickr-api-1-3-released/</link>
      <pubDate>Sat, 03 Oct 2009 02:20:56 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-10-03-python-flickr-api-1-3-released/</guid>
      <description>&lt;p&gt;Today I released version 1.3 of the 
&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Flickr
API&lt;/a&gt;. It&amp;rsquo;s clear that I&amp;rsquo;ve been busy with
my study and my work, as the world hasn&amp;rsquo;t seen a release in nearly a year. This
is mostly due to the dynamic nature of the code - it automatically adapts to any
new functionality that&amp;rsquo;s added to Flickr, so no release is required then. This
release adds some nifty new things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added functions to easily walk through sets and search results, querying
Flickr no more than needed.&lt;/li&gt;
&lt;li&gt;Uses the hashlib module, falling back to the md5 module when hashlib is
unavailable.&lt;/li&gt;
&lt;li&gt;Added locking token cache, in case a Flickr API key is used by multiple
processes at the same time on the same machine (or shared filesystem)&lt;/li&gt;
&lt;li&gt;Removed the deprecated fail_on_error parameter.&lt;/li&gt;
&lt;li&gt;Implemented the auth_callback functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go to the 
&lt;a href=&#34;https://stuvel.eu/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Flickr API&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why doesn&#39;t Windows have a package manager?</title>
      <link>https://stuvel.eu/post/2009-09-14-why-doesn-t-windows-have-a-package-manager/</link>
      <pubDate>Mon, 14 Sep 2009 22:59:37 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-09-14-why-doesn-t-windows-have-a-package-manager/</guid>
      <description>&lt;p&gt;After I uninstalled Visual Studio 2005 Pro I got this very long message (I&amp;rsquo;ve
included it at the bottom of this blog post) telling me to manuall uninstall
&lt;em&gt;twenty&lt;/em&gt; other programs, in the correct order.&lt;/p&gt;
&lt;p&gt;They are capable to install all of this with one single button. Why on earth are
they incapable of removing this? Why do I have to remove those programs myself?
I&amp;rsquo;m also fairly sure that I can&amp;rsquo;t even keep the window open so that I have a
reference, because it is an installer and thus locks some DLLs that need to be
uninstalled too.&lt;/p&gt;
&lt;p&gt;Yes, replacing in-use files. It&amp;rsquo;s a thing that systems all over the world have
been capable of doing for years. Microsoft is still unable to do this nifty
little trick that&amp;rsquo;s oh so useful.&lt;/p&gt;
&lt;p&gt;You may wonder why I want to remove Visual Studio in the first place. Well, an
update of Internet Explorer broke some programs, so now I&amp;rsquo;m trying to repair my
installation of Visual Studio. The built-in &amp;ldquo;Repair&amp;rdquo; function didn&amp;rsquo;t work,
without telling me why. So now I&amp;rsquo;m back to manually having to remove and
reinstall every little part.&lt;/p&gt;
&lt;p&gt;Please, Microsoft, join the new millennium and start using a package manager
like all those Linux distributions have been doing for years. They don&amp;rsquo;t use a
package manager to tease you. They use a package manager because it&amp;rsquo;s bloody
useful.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: after hours of waiting while my computer uninstalled and reinstalled
everything, it still didn&amp;rsquo;t solve my problem. Snif.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The message read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Uninstall is complete.&lt;/p&gt;
&lt;p&gt;Next Step: Uninstall additional components&lt;/p&gt;
&lt;p&gt;Additional components might have been installed on your computer by Visual Studio during setup. These components must be manually uninstalled using Add or Remove Programs in the order listed below.&lt;/p&gt;
&lt;p&gt;Note: Uninstalling these components might affect other applications you have installed that rely on these components.&lt;/p&gt;
&lt;p&gt;The following components might have been installed with Visual Studio:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Microsoft MSDN 2005 Express Edition&lt;/li&gt;
&lt;li&gt;Microsoft Visual Studio 2005 Tools for Office Runtime Language Pack&lt;/li&gt;
&lt;li&gt;Microsoft Visual Studio 2005 Tools for Office Runtime&lt;/li&gt;
&lt;li&gt;Microsoft Device Emulator version 1.0&lt;/li&gt;
&lt;li&gt;Microsoft .NET Compact Framework 1.0&lt;/li&gt;
&lt;li&gt;Microsoft .NET Compact Framework 2.0&lt;/li&gt;
&lt;li&gt;Microsoft SQL Mobile 2005 Development Tools&lt;/li&gt;
&lt;li&gt;Microsoft Visual J# 2.0 Redistributable Package&lt;/li&gt;
&lt;li&gt;Microsoft Visual J# 2.0 Redistributable Language Pack&lt;/li&gt;
&lt;li&gt;Microsoft Document Explorer 2005&lt;/li&gt;
&lt;li&gt;Microsoft Document Explorer 2005 Language Pack&lt;/li&gt;
&lt;li&gt;Microsoft Data Access Components 2.8 SP1 (Windows 2000 only)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following components might have been installed with SQL Server Express, and need to be removed in the order listed below:&lt;/p&gt;
&lt;p&gt;Note: Uninstall of the SQL Express instances will leave behind the user-created databases, which can then be re-attached to the new instance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Microsoft SQL Server 2005 Express CTP&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server 2005 Express Tools CTP&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server Setup Support Files&lt;/li&gt;
&lt;li&gt;Microsoft SQL Native Client&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following components must be uninstalled last:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MSXML 6.0 Parser and SDK (only on 32bit)&lt;/li&gt;
&lt;li&gt;MSXML 6.0 Parser and SDK x64 (Only on 64bit)&lt;/li&gt;
&lt;li&gt;Microsoft .NET Framework 2.0 Language Pack&lt;/li&gt;
&lt;li&gt;Microsoft .NET Framework 2.0&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Removing duplicate mails</title>
      <link>https://stuvel.eu/post/2009-09-08-removing-duplicate-mails/</link>
      <pubDate>Tue, 08 Sep 2009 09:53:09 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-09-08-removing-duplicate-mails/</guid>
      <description>&lt;p&gt;To sync my mail between computers I use

&lt;a href=&#34;https://software.complete.org/software/projects/show/offlineimap&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;offlineimap&lt;/a&gt;
on a secure filesystem. Today I mistakenly ran offlineimap before mounting the
secure filesystem, which caused it to duplicate all emails. Not wanting to do
any manual work to fix this, I wrote a small Python 3 program that repaired the
damage.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import mailbox
import glob
import os.path

def dedupe(maildir):
    &#39;&#39;&#39;Removes duplicates from the given dir&#39;&#39;&#39;

    box = mailbox.Maildir(maildir, create=False)
    box.lock()

    seen = set()   # Set of Message IDs we have seen
    delete = set() # Set of message keys to delete

    # Search for messages to delete
    for (key, message) in box.iteritems():
        mid = message[&#39;Message-Id&#39;]

        # If we have seen this Message ID before,
        # remember it for deletion
        if mid in seen:
            delete.add(key)

        seen.add(mid)

    # Delete the messages
    for key in delete:
        box.remove(key)

    box.close()

# Iterate over all subdirectories as maildirs
for dir in glob.glob(&#39;*&#39;):
    if not os.path.isdir(dir): continue

    dedupe(dir)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I just put this here so I wouldn&amp;rsquo;t lose it. Perhaps you find some use for it
too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The current state of Big Brother</title>
      <link>https://stuvel.eu/post/2009-07-22-the-current-state-of-big-brother/</link>
      <pubDate>Wed, 22 Jul 2009 21:32:31 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-07-22-the-current-state-of-big-brother/</guid>
      <description>&lt;p&gt;Big Brother is watching you. More and more invasions of your rights are done in
the quest for &amp;ldquo;digital rights management&amp;rdquo; and &amp;ldquo;protection of intellectual
property&amp;rdquo;. Check out Farhad Manjoo&amp;rsquo;s post 
&lt;a href=&#34;https://www.slate.com/id/2223214/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Why 2024 Will Be Like Nineteen
Eighty-Four&lt;/a&gt;, as he describes it much better
than I ever could.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: how telling that you first have to agree to tracking cookies
before reading the article&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Refusing to continue</title>
      <link>https://stuvel.eu/post/2009-06-30-refusing-to-continue/</link>
      <pubDate>Tue, 30 Jun 2009 15:52:08 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-06-30-refusing-to-continue/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve seen this so many times, and thought about writing about it. Today I found
some code that is too good an example to let it go. I&amp;rsquo;m talking about the
refusal some people have to using the &lt;code&gt;continue&lt;/code&gt; statement. Here is an example
in some pseudo-code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for value in list {
  if value.condition == True {
      do stuff
      do more stuff
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It looks like fine code, but personally I&amp;rsquo;d rather use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for value in list {
  if value.condition == False: continue

  do stuff
  do more stuff
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The philosophy behind my preferred way is to &lt;strong&gt;bail out as soon as possible&lt;/strong&gt;.
It makes your code easier to understand, because you &lt;em&gt;know&lt;/em&gt; there is not going
to be an &lt;code&gt;else&lt;/code&gt; somewhere down the line. If you see &lt;code&gt;continue&lt;/code&gt; you can mentally
let go of that condition, because you know that the rest of the code in the loop
will be skipped.&lt;/p&gt;
&lt;p&gt;This simple principle of using &lt;code&gt;continue&lt;/code&gt; as soon as possible to mentally free
you of keeping track of conditions also applies to other flow control statements
such as &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt;. Here is something I see all too often:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;function(object *values) {
   if(values != null) {
       do something with the values;
   } else {
       handle errors;
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, very simple code, nothing really wrong with it. Until &amp;ldquo;doing something
with the values&amp;rdquo; involves checking for more errors and doing a loop. Things get
nested very deeply very rapidly. Instead I propose to do it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;function(object *values) {
   if(values == null) {
       handle errors;
       return;
   }

   do something with the values;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you have code like this, it is very easy to add more conditions and error
checks &lt;strong&gt;without the main body of the code getting any more indents&lt;/strong&gt;. The level
of indentation is directly proportional to the mental effort required to
understand the code. Being able to add conditions and checks without the code
becoming more complex is a very good thing.&lt;/p&gt;
&lt;p&gt;These were all very simple examples. I have been able to remove several bugs
just by applying the &lt;strong&gt;bail out as soon as possible&lt;/strong&gt; strategy to actually
professionally written production code.&lt;/p&gt;
&lt;h3 id=&#34;a-function-should-have-one-return-point&#34;&gt;A function should have one return point&lt;/h3&gt;
&lt;p&gt;I have heard many times that people were taught that &amp;ldquo;A function should have one
return point&amp;rdquo;. It sounds like a silly thing to me - why would you &lt;em&gt;not&lt;/em&gt; return,
when you already know the work that had to be done is done? Until now people
were only able to explain my &amp;ldquo;Why?&amp;rdquo; question with &amp;ldquo;it was taught to me that
way&amp;rdquo;. Of course learning something only to teach it again is very nice for
folklore but not for programming styles.&lt;/p&gt;
&lt;p&gt;In many modern languages (well, more like non-ancient languages) there are many
more return points to a function than just the &lt;code&gt;return&lt;/code&gt; statement: exceptions.
Any function call can cause an exception, and if you don&amp;rsquo;t handle it that means
that every call can be a potential point of return.&lt;/p&gt;
&lt;p&gt;And now here&amp;rsquo;s a bit of code that triggered me to finally write this down:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;while((item = map_rect_get_item(mr))) {
    first=1;
    while (item_coord_get(item, &amp;amp;c, 1)) {
        if (first)
            first=0;
        else {
            heightline=heightlines;
            rbbox.lu=last;
            rbbox.rl=last;
            coord_rect_extend(&amp;amp;rbbox, &amp;amp;c);
            while (heightline) {
                if (coord_rect_overlap(&amp;amp;rbbox, &amp;amp;heightline-&amp;gt;bbox)) {
                    for (i = 0 ; i &amp;lt; heightline-&amp;gt;count - 1; i++) {
                        if (heightline-&amp;gt;c[i].x != heightline-&amp;gt;c[i+1].x || heightline-&amp;gt;c[i].y != heightline-&amp;gt;c[i+1].y) {
                            if (line_intersection(heightline-&amp;gt;c+i, heightline-&amp;gt;c+i+1, &amp;amp;last, &amp;amp;c, &amp;amp;res)) {
                                diagram_point=g_new(struct diagram_point, 1);
                                diagram_point-&amp;gt;c.x=dist+transform_distance(projection_mg, &amp;amp;last, &amp;amp;res);
                                diagram_point-&amp;gt;c.y=heightline-&amp;gt;height;
                                diagram_point-&amp;gt;next=diagram_points;
                                diagram_points=diagram_point;
                                dbg(0,&amp;quot;%d %d\n&amp;quot;, diagram_point-&amp;gt;c.x, diagram_point-&amp;gt;c.y);
                            }
                        }
                    }
                }
                heightline=heightline-&amp;gt;next;
            }
            dist+=transform_distance(projection_mg, &amp;amp;last, &amp;amp;c);
        }
        last=c;
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a few modifications I changed the code into this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;while((item = map_rect_get_item(mr))) {
    first=1;
    for(; item_coord_get(item, &amp;amp;c, 1); last=c) {
        if (first) {
            first=0;
            continue;
        }

        heightline=heightlines;
        rbbox.lu=last;
        rbbox.rl=last;
        coord_rect_extend(&amp;amp;rbbox, &amp;amp;c);
        for (; heightline; heightline=heightline-&amp;gt;next) {
            if (!coord_rect_overlap(&amp;amp;rbbox, &amp;amp;heightline-&amp;gt;bbox))
                continue

            for (i = 0 ; i &amp;lt; heightline-&amp;gt;count - 1; i++) {
                if (heightline-&amp;gt;c[i].x == heightline-&amp;gt;c[i+1].x &amp;amp;&amp;amp; heightline-&amp;gt;c[i].y == heightline-&amp;gt;c[i+1].y)
                    continue;

                if (!line_intersection(heightline-&amp;gt;c+i, heightline-&amp;gt;c+i+1, &amp;amp;last, &amp;amp;c, &amp;amp;res))
                    continue;

                diagram_point=g_new(struct diagram_point, 1);
                diagram_point-&amp;gt;c.x=dist+transform_distance(projection_mg, &amp;amp;last, &amp;amp;res);
                diagram_point-&amp;gt;c.y=heightline-&amp;gt;height;
                diagram_point-&amp;gt;next=diagram_points;
                diagram_points=diagram_point;
                dbg(0,&amp;quot;%d %d\n&amp;quot;, diagram_point-&amp;gt;c.x, diagram_point-&amp;gt;c.y);
            }
        }
        dist+=transform_distance(projection_mg, &amp;amp;last, &amp;amp;c);
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Granted, it is still a big beast and should be split up into a few small
functions, but still I was able to reduce the nesting level of the main piece of
the code (the &lt;code&gt;diagram_point&lt;/code&gt; lines) by &lt;em&gt;four&lt;/em&gt; levels.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The C code above was taken from

&lt;a href=&#34;https://www.navit-project.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Navit&lt;/a&gt;, an Open Source navigation application.
Big kudos to the team that wrote the application, as it works well. By writing
this article I do not want to imply anything about the quality of the Navit
application in general, just about the small bit of code I copied.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bl3nder CD presentation</title>
      <link>https://stuvel.eu/post/2009-05-24-bl3nder-cd-presentation/</link>
      <pubDate>Sun, 24 May 2009 21:38:20 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-05-24-bl3nder-cd-presentation/</guid>
      <description>&lt;figure id=&#34;figure-bl3nder--cd-presentatie-leipe-shit-ouwe&#34;&gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Bl3nder | CD-presentatie Leipe Shit Ouwe!&#34;&gt;
  &lt;img src=&#34;&#34; alt=&#34;Bl3nder | CD-presentatie Leipe Shit Ouwe!&#34;  &gt;
&lt;/a&gt;
  &lt;figcaption&gt;
    Bl3nder | CD-presentatie Leipe Shit Ouwe!
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was hired to cover the presentation of

&lt;a href=&#34;https://www.myspace.com/bl3nder&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bl3nder&lt;/a&gt;&amp;rsquo;s first album &amp;ldquo;Leipe Shit Ouwe!&amp;rdquo;.
Their performance was energetic and powerful, and I think it shows in 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157617728102910/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the
photos&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157617728102910/show/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Slideshow&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiblend 1.4 released</title>
      <link>https://stuvel.eu/post/2009-04-08-multiblend-1-4-released/</link>
      <pubDate>Wed, 08 Apr 2009 14:29:48 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-04-08-multiblend-1-4-released/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve released a new version of 
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt;! Version 1.4 has the following improvements over the previous version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Display timing info after rendering.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;-E&lt;/code&gt; option to skip existing frames and render only the missing ones.&lt;/li&gt;
&lt;li&gt;Smarter distribution of frames.&lt;/li&gt;
&lt;li&gt;Implemented simpler logging.&lt;/li&gt;
&lt;li&gt;Verifies that the output directory exists before rendering.&lt;/li&gt;
&lt;li&gt;Added &amp;lsquo;cachesync&amp;rsquo; executable that can distribute the Blender cache directory
(such as used with particle systems) to nodes.&lt;/li&gt;
&lt;li&gt;Removed use of the md5 module when using Python 2.6 or newer.&lt;/li&gt;
&lt;li&gt;Replaced the popen2 module with the subprocess module. This limits the
compatibility of Multiblend to Python 2.4 or newer on the master node.&lt;/li&gt;
&lt;li&gt;Split the implementation into several modules to increase maintainability
and insulation of the parts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt; connects to multiple computers on
your network, and lets Blender render in parallel on each. This will drastically
improve your rendering speeds!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fighting for Umlaut</title>
      <link>https://stuvel.eu/post/2009-04-08-fighting-for-umlaut/</link>
      <pubDate>Wed, 08 Apr 2009 11:12:40 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-04-08-fighting-for-umlaut/</guid>
      <description>&lt;p&gt;For my Master of Science course in Game &amp;amp; Media Technology at the Utrecht
University I had to make another 3D animation. This time the focus was on more
traditional animation techniques such as stretch-and-squash.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://player.vimeo.com/video/4059162&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;vimeo video&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;The assignment was to make a 3D animation with your last name playing a role. I
chose this particular subject as many, many computer programmers are having a
hard time separating UTF-8 from Latin-1, which renders my last name as StÃ¼vel
:(&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Cleaning up an Ubuntu system</title>
      <link>https://stuvel.eu/post/2009-03-31-cleaning-up-an-ubuntu-system/</link>
      <pubDate>Tue, 31 Mar 2009 19:12:41 +0200</pubDate>
      <guid>https://stuvel.eu/post/2009-03-31-cleaning-up-an-ubuntu-system/</guid>
      <description>&lt;p&gt;Ubuntu uses quite a nifty package manager. It keeps track of which file belongs
to which package. Not only that - it also keeps track of which packages you
requested, and which were installed as a dependency.&lt;/p&gt;
&lt;p&gt;The package manager can remove unused dependencies automatically. And this is
what we&amp;rsquo;ll be using to clean up your Ubuntu system. You see, you can mark
packages as installed automatically, even if at some point you requested them
yourself. By marking them as &amp;ldquo;automatically installed&amp;rdquo; you can be sure that they
are only removed when they really aren&amp;rsquo;t needed any more. Here&amp;rsquo;s how it&amp;rsquo;s done:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;make a list of manually installed packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;aptitude search &#39;~i!~E&#39; -F &#39;%M %100p&#39; | grep -v ^A &amp;gt; manual_to_auto
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;edit the file and &lt;strong&gt;remove from the file the packages you want to keep&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;read through the &lt;code&gt;manual_to_auto&lt;/code&gt; file again to see whether you can afford
to remove the packages that are in there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;mark all packages that you left in the file as &amp;ldquo;automatic&amp;rdquo;. This will show a
list of packages that will be removed and give you a chance to review the
changes and bail out before anything harmful happens. Feel free to abort,
re-edit the &lt;code&gt;manual_to_auto&lt;/code&gt; file and try again until you&amp;rsquo;re happy&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo aptitude markauto $(&amp;lt; manual_to_auto)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be happy with the free space. I&amp;rsquo;ve freed up 1 GB on one machine and 500 MB
on another with this method.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;I suggest you remove at least the following packages from the &lt;code&gt;manual_to_auto&lt;/code&gt;
file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;linux-generic&lt;/li&gt;
&lt;li&gt;linux-image-generic&lt;/li&gt;
&lt;li&gt;linux-restricted-modules-generic&lt;/li&gt;
&lt;li&gt;ubuntu-standard&lt;/li&gt;
&lt;li&gt;ubuntu-minimal&lt;/li&gt;
&lt;li&gt;ubuntu-keyring&lt;/li&gt;
&lt;li&gt;the &amp;hellip;.-desktop packages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be careful; &lt;strong&gt;if you&amp;rsquo;re in doubt, remove the package from the list&lt;/strong&gt;. Everything
that you remove from the file will be kept as &amp;ldquo;manually installed&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;If you find out that you removed too many packages, you can simply reinstall the
ones you need. Since we haven&amp;rsquo;t purged the configuration files (see below) they
should simply work as before when you reinstall them.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve used information

&lt;a href=&#34;https://ubuntuforums.org/showthread.php?t=299122&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;from&lt;/a&gt;

&lt;a href=&#34;https://algebraicthunk.net/~dburrows/projects/aptitude/doc/en/ch02s04s01.html#secDisplayFormat&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;various&lt;/a&gt;

&lt;a href=&#34;https://www.debian-administration.org/articles/462&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;sources&lt;/a&gt;.
However, most of them fail on long package names like
&lt;code&gt;linux-restricted-modules-2.6.24-23-generic&lt;/code&gt;, because by default Aptitude only
shows the first 30 characters of the package name. I also feel more comfortable
having a file that I can edit and review before actually marking any packages.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Another cleanup step can be performed by removing all configuration files that belong to uninstalled packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;dpkg -l | grep ^r | awk &#39;{ print $2 }&#39; | sudo xargs dpkg --purge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be warned: this command does &lt;strong&gt;not&lt;/strong&gt; ask for any confirmation. Don&amp;rsquo;t come crying
to me when it runs off with your girlfriend.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>RSA version 1.3 released</title>
      <link>https://stuvel.eu/post/2009-01-22-rsa-version-1-3-released/</link>
      <pubDate>Thu, 22 Jan 2009 15:12:42 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-01-22-rsa-version-1-3-released/</guid>
      <description>&lt;p&gt;A new version of my 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pure-Python RSA implementation&lt;/a&gt; has
been released. The one major change is improved compatibility with Windows.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://pypi.python.org/pypi/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Download&lt;/a&gt; EGG files for Python 2.4, Python 2.5 or the source package at 
&lt;a href=&#34;https://pypi.python.org/pypi/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the Python Package index&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Toying with Voronoi diagrams</title>
      <link>https://stuvel.eu/post/2009-01-12-toying-with-voronoi-diagrams/</link>
      <pubDate>Mon, 12 Jan 2009 16:40:44 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-01-12-toying-with-voronoi-diagrams/</guid>
      <description>&lt;p&gt;For my Master of Science degree I have to work with 
&lt;a href=&#34;https://en.wikipedia.org/wiki/Voronoi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Voronoi
diagrams&lt;/a&gt;. They can be easily visualized
(and toyed with) with the 
&lt;a href=&#34;https://www.dr-mikes-maths.com/DotPlacer.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;DotPlacer
applet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just enable the &amp;ldquo;Voronoi&amp;rdquo; check box, and add some points!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bridged networking in KVM</title>
      <link>https://stuvel.eu/post/2009-01-08-bridged-networking-in-kvm/</link>
      <pubDate>Thu, 08 Jan 2009 08:56:13 +0100</pubDate>
      <guid>https://stuvel.eu/post/2009-01-08-bridged-networking-in-kvm/</guid>
      <description>&lt;p&gt;One of the advantages of VMWare is that it has easy to set up bridged
networking. However, I love Open Source so I started to experiment with 
&lt;a href=&#34;https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;KVM,
the Kernel-based Virtual
Machine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Setting up bridging is a bit daunting, but not that complex once you&amp;rsquo;ve gotten
the hang of it. I placed everything in a script for easy invocation. One of the
features I wanted was that ending the script should tear down the bridged
network, even when pressing Ctrl+C. This is my script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash -x

if [ &amp;quot;$USER&amp;quot; != &#39;root&#39; ]; then
    echo &amp;quot;Restarting as root&amp;quot;
    exec sudo &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;
fi

brctl addbr br0
brctl addif br0 eth0
ifconfig eth0 0.0.0.0 promisc up
ifconfig br0 172.27.0.2 netmask 255.255.255.0
route add default gw 172.27.0.1 br0

function restoreNet {
    ifconfig br0 down
    brctl delif br0 eth0
    brctl delbr br0

    ifconfig eth0 172.27.0.2 netmask 255.255.255.0
    route add default gw 172.27.0.1 eth0
}

trap restoreNet EXIT

kvm \
    -localtime \
    -hda kvm-xp.qcow \
    -m 512 \
    -usb -usbdevice tablet \
    -net nic \
    -net tap \
    &amp;quot;$@&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some of the features are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It starts bridging &lt;code&gt;eth0&lt;/code&gt; and the virtual machine&amp;rsquo;s network. This means that
the VM can do a DHCP query and get an address from my DHCP server, for
instance.&lt;/li&gt;
&lt;li&gt;The bridge is always removed when the script ends.&lt;/li&gt;
&lt;li&gt;The mouse simulates a tablet. This allows for absolute positioning, which
you&amp;rsquo;ll notice allows your mouse to transparently move between your host
system and the VM.&lt;/li&gt;
&lt;li&gt;Any commandline arguments you give to the script are passed to KVM.&lt;/li&gt;
&lt;li&gt;To create and remove the bridge, the script needs to run as root. If you
didn&amp;rsquo;t run it as root, it automatically uses sudo.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Things you&amp;rsquo;ll probably want to edit:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;My desktop uses a fixed IP address 172.27.0.2, replace that with your own IP
address.&lt;/li&gt;
&lt;li&gt;My gateway has IP address 172.27.0.1, replace that with your gateway/router
address.&lt;/li&gt;
&lt;li&gt;My desktop uses eth0 to connect to the network. If you use another device,
replace it.&lt;/li&gt;
&lt;li&gt;I use this setup to run Windows XP in KVM. The Windows installation is
stored in &lt;code&gt;kvm-xp.qcow&lt;/code&gt;, replace that with the harddisk image you want to
use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enjoy! If you have any questions or remarks, post a comment below.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I can only get health insurance by breaking the law</title>
      <link>https://stuvel.eu/post/2008-12-28-i-can-only-get-health-insurance-by-breaking-the-law/</link>
      <pubDate>Sun, 28 Dec 2008 14:55:06 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-12-28-i-can-only-get-health-insurance-by-breaking-the-law/</guid>
      <description>&lt;p&gt;&lt;strong&gt;I wrote an updated version of this blog post in 2016, and keep the list of f*ckups up to date there:

&lt;a href=&#34;https://stuvel.eu/post/2016-02-04-my-name-in-the-modern-world/&#34;&gt;My Name in the Modern World&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My last name is Stüvel. Apparently, this is very difficult for many programmers
and testers to understand. Here are a few of the ways that my name is displayed
by various applications:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;St??vel&lt;/li&gt;
&lt;li&gt;St�vel&lt;/li&gt;
&lt;li&gt;St++vel&lt;/li&gt;
&lt;li&gt;StÃ¼vel&lt;/li&gt;
&lt;li&gt;Stüvel&lt;/li&gt;
&lt;li&gt;&amp;hellip; for more, see the link above. I keep that one up to date. The story
below is still relevant though, and I didn&amp;rsquo;t repeat that in the 2016 post:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nowadays it gets so bad that I&amp;rsquo;m having trouble &lt;em&gt;applying for health insurance&lt;/em&gt;!
When applying, I have to fill in my name and other personal information on the
insurer&amp;rsquo;s website. There is much money (and fraud) involved in health insurance,
so they stress that you are &lt;em&gt;obliged by law to correctly fill in your personal
information&lt;/em&gt;. This is something I cannot do. When I give them &amp;ldquo;Stüvel&amp;rdquo;, they ask
me to confirm that my name is &amp;ldquo;Stüvel&amp;rdquo;, which I cannot do by law. Then
again, I am not allowed to give any other name than my real name, so &amp;ldquo;Stuvel&amp;rdquo; is
out of the question - it is forbidden by law. In other words: &lt;strong&gt;I can only get
health insurance by breaking the law&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pretty please with sugar on top, accept that we live in a world that is made up
of more than A-Z and design your systems for it. Unicode has been a published
standard since 1991. Perhaps it&amp;rsquo;s a good idea to start using it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Resting in NWN2: Storm of Zehir</title>
      <link>https://stuvel.eu/post/2008-12-19-resting-in-nwn2-storm-of-zehir/</link>
      <pubDate>Fri, 19 Dec 2008 14:55:23 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-12-19-resting-in-nwn2-storm-of-zehir/</guid>
      <description>&lt;p&gt;The new 
&lt;a href=&#34;https://www.nwn2.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Neverwinter Nights 2&lt;/a&gt; expansion 
&lt;a href=&#34;https://www.atari.com/nwn2/soz/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Storm of
Zehir&lt;/a&gt; disallows resting in many areas. This is
much more restrictive than what we&amp;rsquo;re familiar with in other NWN2 campaigns - or
any other D&amp;amp;D-based game, for that matter. Even after you clean out an entire
dungeon, you&amp;rsquo;re still not allowed to rest there.&lt;/p&gt;
&lt;p&gt;The solution they give is the &lt;strong&gt;Stone of Alarm&lt;/strong&gt;. It sounds an alarm when
enemies get near, allowing you to shut your eyes and get some well deserved
rest. Unfortunately, the stone works only once, and costs around 1000 gold
pieces. I thought this to be rather lame - to have to pay 1000 gold for each
rest is expensive, especially since we&amp;rsquo;re used to always being able to rest.&lt;/p&gt;
&lt;p&gt;My solution: unzip 
&lt;a href=&#34;https://stuvel.eu/files/nwn2-soz-alarmstone.zip&#34;&gt;my altered Stone of Many Alarms&lt;/a&gt; ZIP file in your NWN2/Override directory, and buy a new Stone of Alarm or give it to yourself:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;press ~&lt;/li&gt;
&lt;li&gt;type &amp;ldquo;DebugMode 1&amp;rdquo;, enter&lt;/li&gt;
&lt;li&gt;type &amp;ldquo;giveitem nx2_t_alarmstone 1&amp;rdquo;, enter&lt;/li&gt;
&lt;li&gt;type &amp;ldquo;DebugMode 0&amp;rdquo;, enter&lt;/li&gt;
&lt;li&gt;press ~&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enjoy resting like we&amp;rsquo;re used to!&lt;/p&gt;
&lt;p&gt;PS: the 
&lt;a href=&#34;https://nwvault.ign.com/View.php?view=nwn2scripts.Detail&amp;amp;id=248&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;alarm stone fix&lt;/a&gt; by &amp;ldquo;player1&amp;rdquo; is also part of this new Stone of Many Alarms. Thanks player1!&lt;/p&gt;
&lt;p&gt;Download the 
&lt;a href=&#34;https://stuvel.eu/files/nwn2-soz-alarmstone.zip&#34;&gt;Stone of Many Alarms&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Soundabout performing in Buk Buk</title>
      <link>https://stuvel.eu/post/2008-12-12-the-soundabout-performing-in-buk-buk/</link>
      <pubDate>Fri, 12 Dec 2008 14:45:36 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-12-12-the-soundabout-performing-in-buk-buk/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ll be performing as the drummer of my band 
&lt;a href=&#34;https://soundabout.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The
Soundabout&lt;/a&gt; in 
&lt;a href=&#34;https://www.bukbuk.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;BukBuk&lt;/a&gt;, Heiloo,
this evening. We&amp;rsquo;re a ska/funk/reggae band, and play as support act for De
Skatjes.&lt;/p&gt;
&lt;p&gt;Buk Buk is easy to reach by train, only a two minute walk from the train
station. The doors open at 21h, we play at 22h and De Skatjes start at 23h.
Damage: €5,-&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python Flickr API 1.2 released</title>
      <link>https://stuvel.eu/post/2008-11-15-python-flickr-api-1-2-released/</link>
      <pubDate>Sat, 15 Nov 2008 18:17:08 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-11-15-python-flickr-api-1-2-released/</guid>
      <description>&lt;p&gt;Today I released the 
&lt;a href=&#34;https://www.stuvel.eu/projects/flickrapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python Flickr API&lt;/a&gt;
version 1.2. Originally the Python interface was made by &lt;strong&gt;Beej&lt;/strong&gt;, and since
it&amp;rsquo;s seen many an improvement. Here&amp;rsquo;s what&amp;rsquo;s new in this version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added ElementTree support for Python 2.4.&lt;/li&gt;
&lt;li&gt;Made ElementTree the default response parser.&lt;/li&gt;
&lt;li&gt;The upload and replace methods now take a format parameter.&lt;/li&gt;
&lt;li&gt;Removed deprecated methods.&lt;/li&gt;
&lt;li&gt;Upload and replace methods no longer report progress on their callback
regarding the HTTP headers.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Hacking in Fallout 3, even easier</title>
      <link>https://stuvel.eu/post/2008-11-08-hacking-in-fallout-3-even-easier/</link>
      <pubDate>Sat, 08 Nov 2008 22:41:11 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-11-08-hacking-in-fallout-3-even-easier/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/software/fallout/&#34;&gt;Hacking in Fallout 3&lt;/a&gt; has become easier than
ever. Now all you need is 
&lt;a href=&#34;https://stuvel.eu/software/fallout/&#34;&gt;this website&lt;/a&gt; and
some typing and clicking. No more cracking your brains, no more hard and
difficult counting and checking letters, it&amp;rsquo;s all done for you!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hacking in Fallout 3</title>
      <link>https://stuvel.eu/post/2008-11-06-hacking-in-fallout-3/</link>
      <pubDate>Thu, 06 Nov 2008 20:26:57 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-11-06-hacking-in-fallout-3/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://fallout.bethsoft.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Fallout 3&lt;/a&gt; is my latest addiction. It&amp;rsquo;s a great
game by the makers of 
&lt;a href=&#34;https://www.elderscrolls.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Oblivion&lt;/a&gt;. Part of the
game is the hacking of computer terminals. It is basically a Master Mind game,
but then with letters. You click on a word that shows up in a memory dump of the
terminal you are trying to hack, and the terminal tells you &lt;em&gt;how many letters
are correct and in the correct place&lt;/em&gt;. Of course, a real hacker would write a
program to solve the puzzle. So, here it is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python

known = {
    &#39;detector&#39;: 1,
}

words = &#39;&#39;&#39;
detector carpeted declared detailed dramatic devoured demanded
sinister disposal revealed messages released remained defended
peaceful designed prisoner
&#39;&#39;&#39;

words = set(words.split())

def dist(a, b):
    return sum(la == lb for (la, lb) in zip(a, b))

for k in known:
    for w in set(words):
        if dist(k, w) != known[k]:
            words.discard(w)
print &amp;quot;Try any of:&amp;quot;, &#39;, &#39;.join(words)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variable &lt;code&gt;words&lt;/code&gt; should be filled with all the words you see on the terminal
screen. The &lt;code&gt;known&lt;/code&gt; variable should contain a dictionary with the known
information you got from the terminal. For example, if you pick those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;detector: 1/8 correct&lt;/li&gt;
&lt;li&gt;demanded: 2/8 correct&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;then the &lt;code&gt;known&lt;/code&gt; variable should be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;known = {
    &#39;detector&#39;: 1,
    &#39;demanded&#39;: 2,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you then run the program (using &lt;code&gt;python fallout.py&lt;/code&gt; if you saved the script
as &lt;code&gt;fallout.py&lt;/code&gt;) it will tell you to try &amp;ldquo;carpeted&amp;rdquo; or &amp;ldquo;messages&amp;rdquo; as your next
guess.&lt;/p&gt;
&lt;p&gt;The script requires 
&lt;a href=&#34;https://www.python.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python&lt;/a&gt;, which is installed by
default on most Linux and MacOS systems and should be manually installed on
Windows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;update&lt;/strong&gt;: I have 
&lt;a href=&#34;https://stuvel.eu/post/2008-11-08-hacking-in-fallout-3-even-easier/&#34;&gt;automated the hacking&lt;/a&gt;
so you can easily use this website to make the sometimes difficult hacking a lot easier.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Java does not support Unicode, Python does</title>
      <link>https://stuvel.eu/post/2008-11-03-java-does-not-support-unicode-python-does/</link>
      <pubDate>Mon, 03 Nov 2008 03:41:55 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-11-03-java-does-not-support-unicode-python-does/</guid>
      <description>&lt;p&gt;Sometimes Java just amazes me. As a friend of mine posted,

&lt;a href=&#34;https://pomax.nihongoresources.com/index.php?entry=1225623556&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Java does not support Unicode&lt;/a&gt;.
Of course, my favourite language Python has a much friendlier approach to
Unicode:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; s = &#39;⿱𠂉乙&#39;.decode(&#39;utf-8&#39;)
&amp;gt;&amp;gt;&amp;gt; s
u&#39;\u2ff1\U00020089\u4e59&#39;
&amp;gt;&amp;gt;&amp;gt; s[1]
u&#39;\U00020089&#39;
&amp;gt;&amp;gt;&amp;gt; print s[1]
𠂉
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perhaps,. people will some day start to understand that statically typed
languages are &lt;em&gt;not&lt;/em&gt; a guarantee of a bug-free application. In the end, it&amp;rsquo;s more
important that a language does what it is supposed to do.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pong</title>
      <link>https://stuvel.eu/post/2008-10-29-pong/</link>
      <pubDate>Wed, 29 Oct 2008 06:10:40 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-10-29-pong/</guid>
      <description>&lt;p&gt;For the Utrecht University I made 
&lt;a href=&#34;https://www.vimeo.com/2089199&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;a short animation called
Pong&lt;/a&gt;. together with two fellow students. We used

&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; to add models to the MoCap data we recorded,
and rendered with Blender + 
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;https://player.vimeo.com/video/2089199&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;vimeo video&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

</description>
    </item>
    
    <item>
      <title>Bl3nder at Uitmarkt</title>
      <link>https://stuvel.eu/post/2008-08-30-bl3nder-at-uitmarkt/</link>
      <pubDate>Sat, 30 Aug 2008 21:52:33 +0200</pubDate>
      <guid>https://stuvel.eu/post/2008-08-30-bl3nder-at-uitmarkt/</guid>
      <description>














&lt;figure id=&#34;figure-bl3nder--cyril-directie&#34;&gt;


  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; data-caption=&#34;Bl3nder | Cyril Directie&#34;&gt;


  &lt;img src=&#34;&#34; alt=&#34;&#34;  &gt;
&lt;/a&gt;


  
  
  &lt;figcaption&gt;
    Bl3nder | Cyril Directie
  &lt;/figcaption&gt;


&lt;/figure&gt;

&lt;p&gt;De Uitmarkt is the opening of the cultural season in Amsterdam. We went to see
Bl3nder, and they totally rocked! It was the first time I saw Def P (the world&amp;rsquo;s
best rapper) live, and it was everything I hoped for :) Their drummer was
absolutely amazing!&lt;/p&gt;
&lt;p&gt;Of course, I&amp;rsquo;ve taken 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157607030004773/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;a few
shots&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pure-Python RSA module version 1.2 released under EUPL</title>
      <link>https://stuvel.eu/post/2008-06-06-pure-python-rsa-module-version-1-2-released-under-eupl/</link>
      <pubDate>Fri, 06 Jun 2008 14:20:51 +0200</pubDate>
      <guid>https://stuvel.eu/post/2008-06-06-pure-python-rsa-module-version-1-2-released-under-eupl/</guid>
      <description>&lt;p&gt;By popular demand, we&amp;rsquo;ve re-licensed our 
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pure-Python RSA
module&lt;/a&gt; under the 
&lt;a href=&#34;https://ec.europa.eu/idabc/en/document/7330/5980&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;European Union Public
Licence&lt;/a&gt;
(
&lt;a href=&#34;https://ec.europa.eu/idabc/en/document/7330/5980&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EUPL&lt;/a&gt;). This new licence is
the first open source license to be released by an international governing body.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/rsa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSA version 1.2&lt;/a&gt; is code-wise the same as the
previous version - the only difference is the new license. It is also still
compatible the GPL. Actually, the module is now dual-licensed, under both the
GPL and the EUPL. Take your pick, and use which one suits you best.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Selecting NVidia screens on commandline</title>
      <link>https://stuvel.eu/post/2008-05-24-selecting-nvidia-screens-on-commandline/</link>
      <pubDate>Sat, 24 May 2008 19:33:35 +0200</pubDate>
      <guid>https://stuvel.eu/post/2008-05-24-selecting-nvidia-screens-on-commandline/</guid>
      <description>&lt;p&gt;NVidia has a nice program to manage display devices like monitors, TVs etc. I&amp;rsquo;ve
used this often to play movies on my PC and watch them on our big wide screen
LCD TV. What I wanted to do, is automate switching between monitor and TV. The
final goal is that I can push a button on a remote to switch the output. Hey,
I&amp;rsquo;m a software engineer, I automate things.&lt;/p&gt;
&lt;p&gt;The easiest way to do that would be two write a shell script that can perform
the switch for me. NVidia has be so kind as to provide us with software that can
do that. It&amp;rsquo;s &lt;code&gt;nv-control-dpy&lt;/code&gt;, packaged in the &lt;code&gt;nvidia-settings&lt;/code&gt; source,
combined with &lt;code&gt;xrandr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is a step-by-step guide of how I managed to get things running.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Hook up your TV if you haven&amp;rsquo;t done so.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let X detect the TV:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;nv-control-dpy --probe-dpys
nv-control-dpy --build-modepool
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tell X to include the TV in the current set of displays. You do this by
getting a list of numbers from &lt;code&gt;nv-control-dpy --get-associated-dpys&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Using NV-CONTROL extension 1.14 on :0
Connected Display Devices:
  CRT-0 (0x00000001): Acer AL1906
  CRT-1 (0x00000002): SAMSUNG

associated display device mask: 0x00000001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the two (&lt;code&gt;0x...&lt;/code&gt;) numbers together and include them in the next call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;nv-control-dpy --set-associated-dpys 0x00000003
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a metamode so that X knows which device to enable/disable. The above
command gave you the names and numbers of the display devices - they could
be TV-0, CRT-1, DPY-4, etc. To enable the device, set it to
&amp;ldquo;nvidia-auto-select&amp;rdquo;. To disable a device, set it to &amp;ldquo;NULL&amp;rdquo;. Here is the
command that I gave to disable my Acer monitor and enable my Samsung TV:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;nv-control-dpy --add-metamode \
    &#39;CRT-0: NULL, CRT-1: nvidia-auto-select&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The last step is to tell X to actually perform the switch. You use the
&lt;code&gt;xrandr&lt;/code&gt; command for this. First, get a list of possible resolutions using
&lt;code&gt;xrandr&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Screen 0: minimum 320 x 240, current 1280 x 1024
default connected 1280x1024+0+0 0mm x 0mm
   1280x1024      50.0*    51.0
   1280x960       52.0
   1280x800       53.0
   1280x768       54.0
   1152x864       55.0     56.0
   1152x768       57.0
   1024x768       58.0     59.0     60.0
   832x624        61.0
   800x600        62.0     63.0     64.0     65.0
   800x512        66.0
   720x450        67.0
   700x525        68.0     69.0
   640x480        70.0     71.0     72.0
   576x384        73.0
   512x384        74.0     75.0
   400x300        76.0
   320x240        77.0     78.0
   1360x768       79.0
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The last resolution in that list is the metamode we just added. To switch to
it, use &lt;code&gt;xrandr -s resolution@refreshrate&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xrandr -s 1360x768@79
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To switch back, use the same &lt;code&gt;xrandr -s resolution@refreshrate&lt;/code&gt; trick, in my
case &lt;code&gt;xrandr -s 1280x1024@50&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve figured out the names of the devices, the bit masks and the meta
mode lines, you can of course place the commands in shell scripts and really get
to automate stuff. I&amp;rsquo;ll leave that as an exercise for the reader.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>RSA version 1.1 released</title>
      <link>https://stuvel.eu/post/2008-04-23-rsa-version-1-1-released/</link>
      <pubDate>Wed, 23 Apr 2008 11:42:02 +0200</pubDate>
      <guid>https://stuvel.eu/post/2008-04-23-rsa-version-1-1-released/</guid>
      <description>&lt;figure &gt;
  &lt;a data-fancybox=&#34;&#34; href=&#34;&#34; &gt;
  &lt;img src=&#34;&#34; alt=&#34;Hacking, the analog way&#34;  &gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A pure Python implementation of the RSA cryptographic protocol. It contains
functions for encryption, decryption, signing, verification, and the generation
of keys and prime numbers.&lt;/p&gt;
&lt;p&gt;The recursive nature of RSA version 1.0 prevented the use of large keys. Thanks
to Miguel Angel Vilela of the Google Enterprise Support Team version 1.1 handles
large keys just fine.&lt;/p&gt;
&lt;p&gt;The 
&lt;a href=&#34;https://stuvel.eu/rsa&#34;&gt;RSA module&lt;/a&gt; page contains the 
&lt;a href=&#34;https://stuvel.eu/rsa&#34;&gt;download links and examples&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More info on the use of RSA in Google Apps on &lt;em&gt;App Engine Fan&lt;/em&gt;&amp;rsquo;s

&lt;a href=&#34;https://blog.appenginefan.com/2008/04/appengine-and-encryption.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AppEngine and Encryption&lt;/a&gt; blog entry.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python vs. Java</title>
      <link>https://stuvel.eu/post/2008-04-10-python-vs-java/</link>
      <pubDate>Thu, 10 Apr 2008 09:27:13 +0200</pubDate>
      <guid>https://stuvel.eu/post/2008-04-10-python-vs-java/</guid>
      <description>&lt;p&gt;One of the major reasons my company prefers Java over Python, is Java&amp;rsquo;s static
type declarations (and all the benefits that follow). If only Python had that,
my life would be so much nicer. Here is an example of code I have to work with,
and an example of what the Python equivalent would look like.&lt;/p&gt;
&lt;p&gt;The background of the code: We have a list of &amp;ldquo;identifiers&amp;rdquo; that can identify
people who want to use a parking garage. These can be NFC cards, credit cards,
and bar codes. We want to filter the list of known identifiers and return only
those of type &amp;ldquo;barcode&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The code in Java:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;private List&amp;lt;Identifier&amp;gt; barcodeTypeOnly(List&amp;lt;Identifier&amp;gt; ids)
{
    final List&amp;lt;Identifier&amp;gt; barcodes = new ArrayList&amp;lt;Identifier&amp;gt;();

    for (Identifier id : ids) {
        if (id.getType().equals(Identifier.TYPEBARCODE)) {
            barcodes.add(id);
        }
    }

    return barcodes;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What it would look like in Python:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;ids = the list of identifiers

barcodes = [identifier for identifier in ids
            if identifier.type == Identifier.TYPEBARCODE]&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could write that last one on a single line, but for clarity I wrote it like
this. I understand that the list comprehension construction may not be instantly
recognisable, so I wrote a little explanation after the break.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;a-primer-on-list-comprehensions&#34;&gt;A primer on list comprehensions&lt;/h3&gt;
&lt;p&gt;The idea behind list comprehensions is that an iterable (like a list) goes in, and a list comes out. In its simplest form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;result = [someobject for someobject in somelist]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would give you a shallow copy of the list, so it&amp;rsquo;s a silly example. Here is
a more useful one - let&amp;rsquo;s say all your objects have a name, and you want to
create a list of names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;names = [someobject.name for someobject in somelist]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Java it would be coded like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;private List&amp;lt;String&amp;gt; getNames(List&amp;lt;NamedObject&amp;gt; objects) {
    List&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;String&amp;gt;(objects.size());

    foreach(NamedObject object : objects) {
        names.add(object.name);
    }

    return names;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;adding-a-filter&#34;&gt;Adding a filter&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say you don&amp;rsquo;t want a list of all object names, but those names where
&lt;code&gt;someobject.type == &#39;car&#39;&lt;/code&gt;. That&amp;rsquo;s where the &lt;code&gt;if&lt;/code&gt; clause comes in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;names = [vehicle.name
         for vehicle in somelist
         if vehicle.type == &#39;car&#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Filtering can be very useful; I&amp;rsquo;ve used this in a testing environment, where
commands are executed and can fail or succeed. Getting a list of all failed
commands is as easy as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;failed = [command for command in executed
          if command.status != command.SUCCESS]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;other-similar-constructions&#34;&gt;Other similar constructions&lt;/h3&gt;
&lt;p&gt;You can create a &amp;ldquo;generator expression&amp;rdquo; by using the same syntax, but removing
the blocky brackets. This allows you to efficiently use the &lt;code&gt;any()&lt;/code&gt; or &lt;code&gt;all()&lt;/code&gt;
functions, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;success = all(command.status == command.SUCCESS for command in executed)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will stop iterating the &lt;code&gt;executed&lt;/code&gt; list as soon as a single failed command
was found.&lt;/p&gt;
&lt;p&gt;Recent versions of Python (3.1, 2.7) have other, very similar constructions.
With the same ease you can create and filter sets and dictionaries.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Local transparent HTTP proxy with Squid</title>
      <link>https://stuvel.eu/post/2008-02-15-local-transparent-http-proxy-with-squid/</link>
      <pubDate>Fri, 15 Feb 2008 10:53:15 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-02-15-local-transparent-http-proxy-with-squid/</guid>
      <description>&lt;p&gt;Setting up Squid as a transparent HTTP proxy has been discussed plenty of times.
All of these examples and blogs I&amp;rsquo;ve read on the subject assume that you run
Squid on your network gateway. While this is a very common and sensible set up,
it doesn&amp;rsquo;t suit my need. I need to &lt;strong&gt;lock down one single computer&lt;/strong&gt; and perform
filtering using Squid&amp;rsquo;s ACL mechanism, regardless of the network it&amp;rsquo;s plugged
into.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written an article called 
&lt;a href=&#34;https://stuvel.eu/transproxy&#34;&gt;Local transparent HTTP proxy&lt;/a&gt; on
this subject. It handles IPTables and Squid configuration, and highlights the
special needs that arise when running a mandatory transparent HTTP proxy on a
client machine.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ValueError &amp; Mercurial</title>
      <link>https://stuvel.eu/post/2008-02-05-valueerror-mercurial/</link>
      <pubDate>Tue, 05 Feb 2008 22:30:03 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-02-05-valueerror-mercurial/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been playing with 
&lt;a href=&#34;https://www.selenic.com/mercurial/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mercurial&lt;/a&gt;&amp;rsquo;s hooks
lately. After I updated to the latest version (0.9.5) and toying a bit more with
the hooks, I got this error after a &lt;code&gt;hg push&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ValueError: invalid literal for int() with base 10: &amp;lsquo;1 files updated, 0 files
merged, 0 files removed, 0 files unresolvedn&amp;rsquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The cause was my hook, which produced output that Mercurial didn&amp;rsquo;t expect. The
solution was to redirect the output to a log file. My hook config went from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;[hooks]
changegroup = hg update &amp;amp;&amp;amp; ./localize &amp;amp;&amp;amp; ./restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;[hooks]
changegroup = (hg update &amp;amp;&amp;amp; ./localize &amp;amp;&amp;amp; ./restart) &amp;gt; push.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the hook that&amp;rsquo;s used on my webserver. All I need to do is a &lt;code&gt;hg push&lt;/code&gt;
command on my development machine, and my latest changes are pushed to my
webserver, which in turn updates the website files and restarts the server to
load in the new script.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New look</title>
      <link>https://stuvel.eu/post/2008-02-03-new-look/</link>
      <pubDate>Sun, 03 Feb 2008 15:29:30 +0100</pubDate>
      <guid>https://stuvel.eu/post/2008-02-03-new-look/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve updated the look of this site. Unfortunately for Microsoft Internet
Explorer users, I couldn&amp;rsquo;t get the new look to work in that browser. Its CSS
support is just too limited. Sorry for the die-hard MSIE users. Perhaps it&amp;rsquo;s
time to upgrade to 
&lt;a href=&#34;https://www.firefox.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Firefox&lt;/a&gt;?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>PVR support in MPlayer</title>
      <link>https://stuvel.eu/post/2007-12-28-pvr-support-in-mplayer/</link>
      <pubDate>Fri, 28 Dec 2007 00:25:42 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-12-28-pvr-support-in-mplayer/</guid>
      <description>&lt;p&gt;When toying around with mplayer and my Hauppauge PVR350, I got the following
error when trying to play something:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[pvr] failed with errno 22 when reading 2048 bytes
[pvr] read 0 bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error kept repeating. The solution was to give the proper bitrates. I used
the following for DVD-compatible rates in my &lt;code&gt;~/.mplayer/config&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ivtv]
mpegopts=format=dvd
tv=normid=0:device=/dev/video0:width=720:height=576
pvr=arate=48000:abitrate=384:vbitrate=6000000:
         vpeak=9600000:aspect=1:fmt=dvd
of=mpeg=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To play, use &lt;code&gt;mplayer pvr:// -profile ivtv&lt;/code&gt;. You can also copy this section to
your mencoder config file and store the video stream from your PVR card to a
dvd-compatible MPEG2 stream. I&amp;rsquo;ve successfully burnt such a file using
KMediaFactory and K3B.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tilt wheel &amp; Logitech mx610</title>
      <link>https://stuvel.eu/post/2007-11-03-tilt-wheel-logitech-mx610/</link>
      <pubDate>Sat, 03 Nov 2007 18:07:55 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-11-03-tilt-wheel-logitech-mx610/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve got a Logitech MX610 cordless laser mouse. One of its nicer features is a
tilt wheel. Unfortunately, this is still difficult to get working in Ubuntu
Linux. The problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The tilt wheel is only supported when you&amp;rsquo;re using the &amp;ldquo;evdev&amp;rdquo; driver. Ubuntu
doesn&amp;rsquo;t do this by default.&lt;/li&gt;
&lt;li&gt;Xorg refuses to load an event device if it isn&amp;rsquo;t named &lt;code&gt;/dev/input/eventX&lt;/code&gt;
where X is a single digit.&lt;/li&gt;
&lt;li&gt;The MX610 contains an USB keyboard as well, which is used for certain
buttons. The mouse and the keyboard components have the same name, so the
standard tutorials for getting the tilt wheel working don&amp;rsquo;t work.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After a bit of twiddling, I got everything to work. Edit your &lt;code&gt;/etc/X11/xorg.conf&lt;/code&gt;
file and replace your mouse definition with this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Section &amp;quot;InputDevice&amp;quot;
   Identifier  &amp;quot;Configured Mouse&amp;quot;
   Driver      &amp;quot;evdev&amp;quot;
   Option      &amp;quot;CorePointer&amp;quot;
   Option      &amp;quot;Device&amp;quot;    &amp;quot;/dev/input/event9&amp;quot;
   Option      &amp;quot;ZAxisMapping&amp;quot; &amp;quot;4 5 7 6&amp;quot;
   Option      &amp;quot;Buttons&amp;quot;   &amp;quot;9&amp;quot;
   Option      &amp;quot;Resolution&amp;quot; &amp;quot;800&amp;quot;
EndSection
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Place the following in &lt;code&gt;/etc/udev/rules.d/66-logitech_mouse.rules&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KERNEL!=&amp;quot;event*&amp;quot;, GOTO=&amp;quot;logimouse_rules_end&amp;quot;
ENV{ID_CLASS}!=&amp;quot;mouse&amp;quot;, GOTO=&amp;quot;logimouse_rules_end&amp;quot;
ENV{ID_MODEL}!=&amp;quot;USB_Receiver&amp;quot;, GOTO=&amp;quot;logimouse_rules_end&amp;quot;
ENV{ID_VENDOR}!=&amp;quot;Logitech&amp;quot;, GOTO=&amp;quot;logimouse_rules_end&amp;quot;

ACTION==&amp;quot;remove&amp;quot;, RUN+=&amp;quot;/bin/rm /dev/input/event9&amp;quot;

ACTION!=&amp;quot;add&amp;quot;, GOTO=&amp;quot;logimouse_rules_end&amp;quot;
RUN+=&amp;quot;/bin/bash -c &#39;/bin/mknod /dev/input/event9 c ${MAJOR} ${MINOR}&amp;quot;

LABEL=&amp;quot;logimouse_rules_end&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reboot, and enjoy your tilt wheel!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>More power from your mobile&#39;s battery</title>
      <link>https://stuvel.eu/post/2007-10-09-more-power-from-your-mobile-s-battery/</link>
      <pubDate>Tue, 09 Oct 2007 13:36:35 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-10-09-more-power-from-your-mobile-s-battery/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m the happy owner of a Motorola Razr V3. Its battery used to last quite long,
but now that it&amp;rsquo;s getting older it&amp;rsquo;s drained very quickly. At some point, I
could charge it at night, talk a few minutes during the day, and when I got home
in the evening the battery would be empty.&lt;/p&gt;
&lt;p&gt;Fortunately, I found a solution for this! The phone &amp;ldquo;thinks&amp;rdquo; that the battery is
full way too early, stopping the charging process. To get a full battery that
lasts for days, just turn off your mobile while charging it. This will fill it
up all the way.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Uitmarkt 2007</title>
      <link>https://stuvel.eu/post/2007-08-25-uitmarkt-2007/</link>
      <pubDate>Sat, 25 Aug 2007 14:04:03 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-08-25-uitmarkt-2007/</guid>
      <description>&lt;p&gt;There was a spectacular opening of the Uitmarkt in Amsterdam. Of all the photos
I shot that evening, I&amp;rsquo;ve uploaded the best 11. Take a look at 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157601647143110&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Uitmarkt 2007 -
a photoset on Flickr&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Proper Exception handling</title>
      <link>https://stuvel.eu/post/2007-08-13-proper-exception-handling/</link>
      <pubDate>Mon, 13 Aug 2007 11:10:33 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-08-13-proper-exception-handling/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: The articles below have been taken offline.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The articles below are about Java, but I think they apply equally well to other
languages that have exception handling. It would be nice if more were to read
those articles. I think it would result in better and easier to debug code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;https://today.java.net/pub/a/today/2006/04/06/exception-handling-antipatterns.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Exception-Handling Antipatterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://today.java.net/pub/a/today/2003/12/04/exceptions.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Three Rules for Effective Exception Handling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Highlighting the current line &amp; column in VIM</title>
      <link>https://stuvel.eu/post/2007-07-20-highlighting-the-current-line-column-in-vim/</link>
      <pubDate>Fri, 20 Jul 2007 10:35:16 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-07-20-highlighting-the-current-line-column-in-vim/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s already in the VIM help file, but I never found it until now. To highlight
the current row/line and the current column use this in your &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-vim&#34;&gt;au WinLeave * set nocursorline nocursorcolumn
au WinEnter * set cursorline cursorcolumn
set cursorline cursorcolumn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found this quite useful while programming. Eclipse has a similar feature; when
I got used to that I started missing it in VIM. Until now that is :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Encoding video for the iriver U10</title>
      <link>https://stuvel.eu/post/2007-06-20-encoding-video-for-the-iriver-u10/</link>
      <pubDate>Wed, 20 Jun 2007 21:45:04 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-06-20-encoding-video-for-the-iriver-u10/</guid>
      <description>&lt;p&gt;I own an 
&lt;a href=&#34;https://u10.iriver.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;iriver U10&lt;/a&gt;. It&amp;rsquo;s a great device, that can
play music and video. However, for some reason, &lt;em&gt;none&lt;/em&gt; of the tutorials about
encoding video for the 
&lt;a href=&#34;https://u10.iriver.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;iriver U10&lt;/a&gt; worked. When I try
to play the video, it just gives the message &amp;ldquo;This file format is not
supported&amp;rdquo;. After a lot of trial and error I finally figured out the problem:
the frame rate. According to every guide and manual I found, the U10 can handle
15 frames per second. However, &lt;em&gt;things only started working when I encoded to
14.9 frames per second&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Here is the mencoder command I used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;/usr/bin/mencoder \
  flash_gordon.avi \
  -o flash_gordon-u10.avi \
  -ovc xvid -xvidencopts bitrate=384:max_bframes=0 \
  -oac mp3lame \
  -lameopts mode=0:cbr:br=128 \
  -ofps 14.9 \
  -af resample=44100:1:2 \
  -vf-add scale=320:240,expand=320:240 \
  -vf-add harddup \
  -quiet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;m sure other encoders (GUI or otherwise) will also work, as long as you use
the following settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;14.9 frames per second (FPS)&lt;/li&gt;
&lt;li&gt;AVI output format&lt;/li&gt;
&lt;li&gt;XviD video codec at 384 kbit/sec&lt;/li&gt;
&lt;li&gt;No B-frames (just enter 0 for the number of B-frames)&lt;/li&gt;
&lt;li&gt;Video 320x240 pixels&lt;/li&gt;
&lt;li&gt;MP3 audio codec at 128 kbit/sec, 16 bit, stereo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve verified these settings with Avidemux. And yes, they also work with clips from 
&lt;a href=&#34;https://www.youtube.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Youtube&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Safely copy a SQLite database</title>
      <link>https://stuvel.eu/post/2007-06-15-safely-copy-a-sqlite-database/</link>
      <pubDate>Fri, 15 Jun 2007 08:58:17 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-06-15-safely-copy-a-sqlite-database/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s trivially easy to copy a 
&lt;a href=&#34;https://www.sqlite.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SQLite&lt;/a&gt; database. It&amp;rsquo;s
less trivial to do this in a way that won&amp;rsquo;t corrupt it. Here&amp;rsquo;s how:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sqlite3 some.db
sqlite&amp;gt; begin immediate;
&amp;lt;press CTRL+Z&amp;gt;
$ cp some.db some.db.backup
$ exit
sqlite&amp;gt; rollback;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will give you a nice clean backup that&amp;rsquo;s sure to be in a proper state,
since writing to the database half-way through your copying process is
impossible.&lt;/p&gt;
&lt;p&gt;Thanks to 
&lt;a href=&#34;https://blog.dataloss.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Habbie&lt;/a&gt; for this info!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stuvel.eu moved to a better server</title>
      <link>https://stuvel.eu/post/2007-06-12-stuvel-eu-moved-to-a-better-server/</link>
      <pubDate>Tue, 12 Jun 2007 23:59:30 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-06-12-stuvel-eu-moved-to-a-better-server/</guid>
      <description>&lt;p&gt;The 
&lt;a href=&#34;https://www.stuvel.eu/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stuvel.eu&lt;/a&gt; website has moved from a 1 Mbit ADSL
connection to a real server on a proper 100 Mbit link. If you read this message,
the DNS entries have been updated and you&amp;rsquo;re looking at the new server. I&amp;rsquo;m sure
you&amp;rsquo;ll notice the speed improvement ;-)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Better RAW decoding with Digikam</title>
      <link>https://stuvel.eu/post/2007-06-07-better-raw-decoding-with-digikam/</link>
      <pubDate>Thu, 07 Jun 2007 20:42:43 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-06-07-better-raw-decoding-with-digikam/</guid>
      <description>&lt;p&gt;My favourite photo editor and manager is 
&lt;a href=&#34;https://www.digikam.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Digikam&lt;/a&gt;.
One of its features is easily importing RAW files. However, with its default
settings you may loose details in brightly lit areas of your photos.&lt;/p&gt;
&lt;p&gt;To get the details back, go to Settings, Configure digikam, RAW decoding. In
there, set the &amp;ldquo;Highlights&amp;rdquo; option to &amp;ldquo;Reconstruct&amp;rdquo;. Now that you&amp;rsquo;re there
anyway, set &amp;ldquo;Quality&amp;rdquo; to &amp;ldquo;AHD interpolation&amp;rdquo;, which is the highest quality of
interpolation.&lt;/p&gt;
&lt;p&gt;With these settings, you&amp;rsquo;ll get much higher quality images. They may turn out
dark if the highlight is much brighter than the rest of the image. However, this
is easily reconstructed with the white balance tool (CTRL+W) and playing with
the exposure and gamma settings.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Flickr lens:type machine tag</title>
      <link>https://stuvel.eu/post/2007-06-04-flickr-lens-type-machine-tag/</link>
      <pubDate>Mon, 04 Jun 2007 19:26:39 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-06-04-flickr-lens-type-machine-tag/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m in the process of giving all my photos a &amp;ldquo;lens:type&amp;rdquo; machine tag on Flickr.
This will indicate which lens I used to make the photo. Check it out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/tags/lens%3Atype%3D1755mmf28isusm/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Canon 17-55 mm F/2.8 IS USM&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/tags/lens%3Atype%3D70300mmf456/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Sigma 70-300 mm F/4-5.6&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/tags/lens%3Atype%3D1855mmf3556/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Canon 18-55 mm F/3.5-5.6&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s all done automagically by a Python script I wrote. It analyses things like
the date at which the photo was taken, focal length and aperture size to
determine which lens I used. It&amp;rsquo;s a very boring and repetitive task and I&amp;rsquo;m glad
I could delegate it to a computer.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in the script 
&lt;a href=&#34;https://stuvel.eu/contact&#34;&gt;let me know&lt;/a&gt; and I&amp;rsquo;ll send you a
copy. Since the analysing logic of the program will need adjustment to your set
of lenses, it requires at least some Python knowledge. This is also the reason
why I didn&amp;rsquo;t put the program online - in its current form it&amp;rsquo;s not useful for
anyone else.&lt;/p&gt;
&lt;p&gt;The script uses the 
&lt;a href=&#34;https://www.flickr.com/services/api/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Flickr API&lt;/a&gt; to
interface with Flickr.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Double-sided macro tent</title>
      <link>https://stuvel.eu/post/2007-05-31-double-sided-macro-tent/</link>
      <pubDate>Thu, 31 May 2007 19:14:49 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-05-31-double-sided-macro-tent/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: With Flickr limiting the number of photos you can upload with a
free account, I&amp;rsquo;ve removed these photos.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;ve written a small tutorial about how I set up my 
&lt;a href=&#34;https://www.flickr.com/photos/sybrenstuvel/sets/72157600292098105/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;double-sided macro
tent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea was born out of sheer lack of money. As I spent all of it on glass, I
have to work with just one construction lamp and my built-in flash.&lt;/p&gt;
&lt;p&gt;To get the maximum amount of light out of my limited means, I thought up a nifty
macro tent to suit my needs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Calculating with OpenOffice.org</title>
      <link>https://stuvel.eu/post/2007-05-11-calculating-with-openoffice-org/</link>
      <pubDate>Fri, 11 May 2007 12:33:46 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-05-11-calculating-with-openoffice-org/</guid>
      <description>&lt;p&gt;Joachim Dahl asked me to give an example of using OpenOffice.org spreadsheet
formulas from Python. After a bit of digging I found out that it&amp;rsquo;s rather easy.
I&amp;rsquo;ve added a section to my &amp;ldquo;OpenOffice.org &amp;amp; Python&amp;rdquo; document called

&lt;a href=&#34;https://stuvel.eu/ooo-python#calculating&#34;&gt;Calculating with OpenOffce.org&lt;/a&gt; which gives a simple
example of how it&amp;rsquo;s done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bordering an image</title>
      <link>https://stuvel.eu/post/2007-05-09-bordering-an-image/</link>
      <pubDate>Wed, 09 May 2007 08:25:45 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-05-09-bordering-an-image/</guid>
      <description>&lt;p&gt;Pictures look better when they have a border around them. To make things easy
for me, I&amp;rsquo;ve written a small script that does a lot of boring things for me. It
resizes an image so that it fits a 1000x1000 square, then creates a black border
around it that&amp;rsquo;s a slight bit larger at the bottom and places my name and
website URL on the side. Here is the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash

[ -z &amp;quot;$1&amp;quot; ] &amp;amp;&amp;amp; echo &amp;quot;Usage: $0 &amp;lt;file&amp;gt;&amp;quot; &amp;amp;&amp;amp; exit 1

IN=&amp;quot;$1&amp;quot;
IN_NOEXT=$(echo $IN | sed &#39;s/\\.[^.]\\+$//&#39;)
OUT=&amp;quot;$IN_NOEXT-bordered.jpg&amp;quot;
echo &amp;quot;INPUT: $IN&amp;quot;
echo &amp;quot;OUTPUT: $OUT&amp;quot;

BORDER_BOTTOM=40
BORDER_OTHER=20
POINTSIZE=12
COPYRIGHT=&amp;quot;© 2007 Sybren Stüvel - https://www.stuvel.eu/&amp;quot;

DIFF=$((BORDER_BOTTOM - BORDER_OTHER))
EXIFTOOL=/usr/bin/exiftool

convert &amp;quot;$IN&amp;quot; \
 -geometry 1000x1000 \
 -mattecolor black \
 -frame ${BORDER_BOTTOM}x${BORDER_BOTTOM} \
 -chop ${DIFF}x${DIFF} \
 -gravity SouthEast \
 -chop ${DIFF}x0 \
 -font Bookman-Light \
 -font Helvetica-Narrow \
 -font Helvetica\
 -pointsize $POINTSIZE \
 -gravity SouthWest \
 -fill gray20 \
 -annotate 270x270+$((POINTSIZE+2))+${BORDER_BOTTOM} \
 &amp;quot;$COPYRIGHT&amp;quot; \
 &amp;quot;$OUT&amp;quot;

$EXIFTOOL -TagsFromFile &amp;quot;$IN&amp;quot; &amp;quot;$OUT&amp;quot;
rm -f &amp;quot;${OUT}_original&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Back from holiday</title>
      <link>https://stuvel.eu/post/2007-05-05-back-from-holiday/</link>
      <pubDate>Sat, 05 May 2007 14:00:40 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-05-05-back-from-holiday/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: The photos are no longer online.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;m back from holiday. We went hitchhiking from Amsterdam to Muker in the
Yorkshire Dales (UK). Of course, there are plenty of 
&lt;a href=&#34;https://stuvel.eu/liften2007&#34;&gt;pictures&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We went on a contest - 27 couples were racing to get from Amsterdam to Muker
without paying for their transportation. The only thing we were allowed to pay
was the ferry from Calais to Dover. We started at 17:00 hours (local time) in
Amsterdam, and arrived in Muker at 23:45 (also local time). It was a wonderful
trip!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A shorter self-timer on a Canon EOS 350D</title>
      <link>https://stuvel.eu/post/2007-04-14-a-shorter-self-timer-on-a-canon-eos-350d/</link>
      <pubDate>Sat, 14 Apr 2007 17:47:50 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-04-14-a-shorter-self-timer-on-a-canon-eos-350d/</guid>
      <description>&lt;p&gt;The 
&lt;a href=&#34;https://www.canon.co.uk/For_Home/Product_Finder/Cameras/Digital_SLR/EOS_350D/index.asp&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Canon EOS 350D&lt;/a&gt; has a fixed self-timer of 10 seconds, and the manual doesn&amp;rsquo;t mention any way of shortening it. I use the self-timer for night shots, where even the movement of a button press can mess up an otherwise perfect photo. For such usage, those 10 seconds are quite long.&lt;/p&gt;
&lt;p&gt;I started to play with the &amp;ldquo;mirror lock-up&amp;rdquo; feature. In the custom functions
(C.Fn.) menu you can enable mirror lock-up. If you do this and then use the
self-timer, the timer is reduced to about a second. This means a double
advantage of the mirror lock-up feature: less movement blur and also less
waiting.&lt;/p&gt;
&lt;h3 id=&#34;update&#34;&gt;Update&lt;/h3&gt;
&lt;p&gt;I got some questions about the workings of the mirror lock-up. When you use the
self-timer, taking a photo follows those steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus the camera either manually or with the auto-focus.&lt;/li&gt;
&lt;li&gt;Fully press the shutter button.&lt;/li&gt;
&lt;li&gt;The mirror now locks into the upper position and the self-timer starts to run.&lt;/li&gt;
&lt;li&gt;About a second or two later the photo is taken.&lt;/li&gt;
&lt;li&gt;The mirror comes back down again so you can prepare for another shot.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Which unit do you shoot first?</title>
      <link>https://stuvel.eu/post/2007-04-11-which-unit-do-you-shoot-first/</link>
      <pubDate>Wed, 11 Apr 2007 18:03:46 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-04-11-which-unit-do-you-shoot-first/</guid>
      <description>&lt;p&gt;In every Real Time Strategy game, there comes a time that you face your enemy in
combat. Then you have to decide which unit to attack first. There are many ideas
about optimal strategies, and many of them have good arguments. I decided to
write a small 
&lt;a href=&#34;https://stuvel.eu/files/supcomsim.py&#34;&gt;simulator&lt;/a&gt; to find the optimal strategy.&lt;/p&gt;
&lt;p&gt;I implemented strategies based on the number of hit points and the firepower of
enemy units. Every simulation round all the enemy units fire at me, and I fire
at a single enemy unit. The best strategy? &lt;em&gt;Find the unit with the most
firepower per hit point and whack it&lt;/em&gt;. However, this does requires quite some
math, since the hit points change and thus the firepower / hit point ratio
changes about every second.&lt;/p&gt;
&lt;p&gt;Unless you can do a lot of math in a very short time, easier to fire at the unit
with the most firepower. Almost just as good is shooting at the unit with the
least hit points. Which one of those two is best probably depends on the game
and the units you&amp;rsquo;re facing.&lt;/p&gt;
&lt;p&gt;Focusing your firepower on the unit with the least fire power or the unit with
the most hit points is really bad. It&amp;rsquo;s better to just pick a unit at random.&lt;/p&gt;
&lt;p&gt;Here are the actual results. The number is the total damage the enemy units did
to the simulated &amp;ldquo;me&amp;rdquo;, hence lower is better.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;findMostFPperHP    2934277
findMostFP         3546364
findLeastHP        3603899
findRandom         6908600
findLeastFP        7470776
findLeastFPperHP  10460769
findMostHP        10482618
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Single-click buttons for webapps</title>
      <link>https://stuvel.eu/post/2007-04-04-single-click-buttons-for-webapps/</link>
      <pubDate>Wed, 04 Apr 2007 11:08:33 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-04-04-single-click-buttons-for-webapps/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: the below article is long gone.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Many web applications can&amp;rsquo;t handle it when links and buttons are clicked while a
page request is already being processed. To prevent your application from those
trigger-happy mouse clicking users, read my article about 
&lt;a href=&#34;https://stuvel.eu/singleclick&#34;&gt;single-click
buttons&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Line numbers in VIM&#39;s search &amp; replace</title>
      <link>https://stuvel.eu/post/2007-03-26-line-numbers-in-vim-s-search-replace/</link>
      <pubDate>Mon, 26 Mar 2007 14:30:58 +0200</pubDate>
      <guid>https://stuvel.eu/post/2007-03-26-line-numbers-in-vim-s-search-replace/</guid>
      <description>&lt;p&gt;Often, I have to assign a list of 
&lt;a href=&#34;https://www.openqa.org/selenium/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Selenium&lt;/a&gt;
parameters &lt;code&gt;$p1&lt;/code&gt; through &lt;code&gt;$pN&lt;/code&gt; to a list of more meaningful names. With

&lt;a href=&#34;https://www.vim.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;VIM&lt;/a&gt;, this is easily done. First, place the meaningful
names in the editor, one name per line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name
street
housenumber
city
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then type the command &lt;code&gt;:%s/.*/#set $&amp;amp; = $pXXX&lt;/code&gt; and hit enter. This is the result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#set $name = $pXXX
#set $street = $pXXX
#set $housenumber = $pXXX
#set $city = $pXXX`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all that&amp;rsquo;s left is to change the XXX to the appropriate number. Type
&lt;code&gt;:%s/XXX/\=line(&amp;quot;.&amp;quot;)&lt;/code&gt; and hit enter to get this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#set $name = $p1
#set $street = $p2
#set $housenumber = $p3
#set $city = $p4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this is all rather trivial. However, with longer list and slightly
more complex regular expressions, this is a very powerful technique. Think about
30 files with 20 #set commands per file, and you have to insert one more at the
top and rename the rest. With VIM, that&amp;rsquo;s a piece of cake.&lt;/p&gt;
&lt;p&gt;By the way - both commands could have been combined into one. However, that
would make the commands more complex and hard to understand. For the curious,
the command is &lt;code&gt;:%s/.*/\=&amp;quot;#set $&amp;quot; . submatch(0) . &amp;quot; = $p&amp;quot; . line(&amp;quot;.&amp;quot;)&lt;/code&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Photography</title>
      <link>https://stuvel.eu/post/2007-03-16-photography/</link>
      <pubDate>Fri, 16 Mar 2007 23:49:20 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-03-16-photography/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: The described page about photography is gone from my website,
as well as the Flickr RSS feed link. I still am a photographer, though, so check
out 
&lt;a href=&#34;https://stuvelfoto.nl/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;stuvelfoto.nl&lt;/a&gt; for my work.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;ve been photographing quite a lot lately. and I thought it would be time to
devote some web space to it. Voila, a small page about

&lt;a href=&#34;https://stuvel.eu/photography&#34;&gt;photography&lt;/a&gt;. You&amp;rsquo;ll also notice a link to the 
&lt;a href=&#34;https://api.flickr.com/services/feeds/photos_public.gne?id=73509078@N00&amp;amp;format=rss_200&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RSS photo
feed&lt;/a&gt;
from Flickr.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blame support in Eclipse</title>
      <link>https://stuvel.eu/post/2007-03-15-blame-support-in-eclipse/</link>
      <pubDate>Thu, 15 Mar 2007 10:19:44 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-03-15-blame-support-in-eclipse/</guid>
      <description>&lt;p&gt;Eclipse has support for CVS annotations, also known as &amp;ldquo;blame support&amp;rdquo;.
Right-click on a file, choose &amp;ldquo;Team&amp;rdquo;, &amp;ldquo;Show annotation&amp;rdquo; and you&amp;rsquo;ll see who last
edited which line of code.&lt;/p&gt;
&lt;p&gt;However, if you ever turn off &lt;em&gt;quick diff&lt;/em&gt;, this feature will stop working. The
solution: press Ctrl+Shift+Q to enable &lt;em&gt;quick diff&lt;/em&gt; before you choose &amp;ldquo;Show
annotation&amp;rdquo;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>More Supreme Commander cheats</title>
      <link>https://stuvel.eu/post/2007-02-15-more-supreme-commander-cheats/</link>
      <pubDate>Thu, 15 Feb 2007 20:32:56 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-02-15-more-supreme-commander-cheats/</guid>
      <description>&lt;p&gt;This is an extention of 
&lt;a href=&#34;http://localhost:1313/blog/2007-01-24-supreme-commander-cheat/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;the cheat I published earlier&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before you can copy &amp;amp; paste units and buildings, you have to be able to select
them. You might have noticed that you can&amp;rsquo;t select everything - not enemy units
nor unfinished units/buildings.&lt;/p&gt;
&lt;p&gt;Here is a really powerful trick: press the tilde/backtick button [~] to open the
console, type &amp;ldquo;ui_selectanything&amp;rdquo;, press enter then press the tilde/backtick
button again to close the console. Now you can select anything!&lt;/p&gt;
&lt;p&gt;Try this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start building a building&lt;/li&gt;
&lt;li&gt;Immediately copy &amp;amp; paste&lt;/li&gt;
&lt;li&gt;Now you have a finished building!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This also works for experimental units! Start building a Monkeylord, copy &amp;amp;
paste it, and now you have a fully finished Monkeylord within seconds.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Winter Juggling Weekend</title>
      <link>https://stuvel.eu/post/2007-02-04-winter-juggling-weekend/</link>
      <pubDate>Sun, 04 Feb 2007 21:21:26 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-02-04-winter-juggling-weekend/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: With Flickr limiting the number of photos you can upload with a
free account, I&amp;rsquo;ve removed these photos.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;a href=&#34;https://flickr.com/photos/73509078@N00/sets/72157594517687503/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;img src=&#34;https://farm1.static.flickr.com/184/379697317_182bf69038_s.jpg&#34; alt=&#34;Three unicycles&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This weekend I went to the Winter Juggling Weekend in Heerlen, The Netherlands.
It was the first time I went to such an event, and it was really nice. I also
managed to free-mount a 36&amp;quot; unicycle, and I&amp;rsquo;ve made up my mind - I&amp;rsquo;ll buy one in
a few months when the whether gets better. In the mean time, enjoy the 
&lt;a href=&#34;https://flickr.com/photos/73509078@N00/sets/72157594517687503/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;photos I
made&lt;/a&gt; on Flickr.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Supreme Commander cheat</title>
      <link>https://stuvel.eu/post/2007-01-24-supreme-commander-cheat/</link>
      <pubDate>Wed, 24 Jan 2007 17:33:49 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-01-24-supreme-commander-cheat/</guid>
      <description>&lt;p&gt;After some fiddling with 
&lt;a href=&#34;https://www.supremecommander.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Supreme Commander&lt;/a&gt;,
I found out how to cheat in a skirmish game. Of course, you first have to start
the game with &amp;ldquo;Cheats: on&amp;rdquo;. &lt;strong&gt;You can then copy &amp;amp; paste units&lt;/strong&gt;. Select a unit,
press [Ctrl] + [Shift] + [C] to copy it. Now press [Ctrl] + [Shift] + [V] to
paste it. Lather, rinse, repeat.&lt;/p&gt;
&lt;p&gt;With this, you can create mutliple commanders to build super fast. You can also
build a single unit, then copy it multiple times to create an army. The pasted
units appear below the mouse cursor, so be creative with their placement. Be
careful, though. The game can crash if you paste too many units at the same
location.&lt;/p&gt;
&lt;p&gt;Also note that this method isn&amp;rsquo;t restricted to copying single units - you can
select an entire group and copy that. This means every copy &amp;amp; paste action can
double your strength!&lt;/p&gt;
&lt;p&gt;By the way, I seem to be the first one to publish a cheat for this marvellous
game!&lt;/p&gt;
&lt;p&gt;Also be sure to read my news post 
&lt;a href=&#34;https://stuvel.eu/blog/2007-02-15-more-supreme-commander-cheats/&#34;&gt;More Supreme Commander
cheats&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Plucker-build and Ubuntu</title>
      <link>https://stuvel.eu/post/2007-01-21-plucker-build-and-ubuntu/</link>
      <pubDate>Sun, 21 Jan 2007 15:37:19 +0100</pubDate>
      <guid>https://stuvel.eu/post/2007-01-21-plucker-build-and-ubuntu/</guid>
      <description>&lt;p&gt;Plucker is a PDB (Palm e-book documents) reader and creator. I use it to convert HTML files to PDB format, so that I can comfortly read them on my PDA. Plucker is part of Ubuntu&amp;rsquo;s &amp;ldquo;universe&amp;rdquo; repository, but it installs rather crippled. Do this to fix it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo su - (type your password to become root)
cd /usr/bin
PYPLUCKER=../lib/python2.4/site-packages/PyPlucker
ln -fs $PYPLUCKER/Spider.py plucker-build
ln -fs $PYPLUCKER/PluckerDocs.py plucker-de
ln -fs $PYPLUCKER/PluckerDocs.py plucker-decode
ln -fs $PYPLUCKER/Decode.py plucker-dump
ln -fs $PYPLUCKER/pluck-comics.py pluck-comics
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After doing this, you&amp;rsquo;ll be able to do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;plucker-build somefile.html &amp;gt; somefile.pdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to create the files.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>BUG: soft lockup detected on CPU#0</title>
      <link>https://stuvel.eu/post/2006-12-26-bug-soft-lockup-detected-on-cpu-0/</link>
      <pubDate>Tue, 26 Dec 2006 20:51:28 +0100</pubDate>
      <guid>https://stuvel.eu/post/2006-12-26-bug-soft-lockup-detected-on-cpu-0/</guid>
      <description>&lt;p&gt;I just got me a brand new HP Pavillion DV9000 series laptop. Today, all of a
sudden it refused to boot. This message was shown on the console while booting:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;BUG: soft lockup detected on CPU#0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After some Googling people mentioned this message after inserting a WiFi card. I
did just the opposite, though. The message started to appear when I booted with
my WiFi card disabled by means of the kill switch at the front. Re-enabling the
WiFi card was the solution. If my WiFi is turned on when I boot, my laptop boots
just fine!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Graduation thesis online</title>
      <link>https://stuvel.eu/post/2006-12-08-graduation-thesis-online/</link>
      <pubDate>Fri, 08 Dec 2006 08:41:51 +0100</pubDate>
      <guid>https://stuvel.eu/post/2006-12-08-graduation-thesis-online/</guid>
      <description>&lt;p&gt;Finally, I&amp;rsquo;m able to publish my graduation thesis. It was a secret document at
first, because we were in the process of patenting the idea. Now that that&amp;rsquo;s
done though, I can finally put my thesis online!&lt;/p&gt;
&lt;p&gt;Enjoy reading 
&lt;a href=&#34;https://stuvel.eu/files/publication/sadako.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Sadako: securing a building using IEEE
802.11&lt;/a&gt;. Here is the abstract:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This paper describes the Sadako project. It is a system for securing a
building by using IEEE 802.11 network technology to determine the position
legal occupants of said building. The alarm will be turned off in zones where
those legal occupants are located, and turned on in other areas.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most people know IEEE 802.11 simply as WiFi.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DoS attacks on DNS servers</title>
      <link>https://stuvel.eu/post/2006-12-07-dos-attacks-on-dns-servers/</link>
      <pubDate>Thu, 07 Dec 2006 07:52:06 +0100</pubDate>
      <guid>https://stuvel.eu/post/2006-12-07-dos-attacks-on-dns-servers/</guid>
      <description>&lt;p&gt;Since last Friday, there have been 
&lt;a href=&#34;https://securitywatch.eweek.com/exploits_and_attacks/everydns_opendns_under_botnet_ddos_attack.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;DoS
attacks&lt;/a&gt;
on the 
&lt;a href=&#34;https://www.everydns.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EveryDNS&lt;/a&gt; servers, which also host my
domains. So if you have had trouble reaching this website, you at least know
why. Unfortunately, there is nothing I can do about it except switch DNS
providers. Since EveryDNS generally fulfils my every DNS need, I&amp;rsquo;m not very
eager to do that. If possible, I&amp;rsquo;d rather just wait things out.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Idefisk without fuss</title>
      <link>https://stuvel.eu/post/2006-11-29-idefisk-without-fuss/</link>
      <pubDate>Wed, 29 Nov 2006 20:14:57 +0100</pubDate>
      <guid>https://stuvel.eu/post/2006-11-29-idefisk-without-fuss/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://www.asteriskguru.com/idefisk/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Idefisk&lt;/a&gt; is an IAX Voice over IP client.
It&amp;rsquo;s a nice little program that runs without fuss. The only thing that&amp;rsquo;s bugging
me a bit is its installation procedure in Linux. You have to unpack a tarball,
then copy a library to a system directory (as root), then run a command (as
root) and then you can start Idefisk.&lt;/p&gt;
&lt;p&gt;I generally don&amp;rsquo;t want to mix third-party libraries with system libraries nor do
I want to execute anything as root unless I really have to, and there is no
reason why you should. Idefisk can run just fine without performing any command
as the root user. Place the below script in your Idefisk dir, make it executable
(&amp;ldquo;chmod +x idefisk.sh&amp;rdquo;) and run it. No more root required!&lt;/p&gt;
&lt;p&gt;The contents of the script are quite straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash

export LD_LIBRARY_PATH=$(dirname $0)
$LD_LIBRARY_PATH/idefisk
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Sound card ordering in Ubuntu</title>
      <link>https://stuvel.eu/post/2006-11-05-sound-card-ordering-in-ubuntu/</link>
      <pubDate>Sun, 05 Nov 2006 18:03:13 +0100</pubDate>
      <guid>https://stuvel.eu/post/2006-11-05-sound-card-ordering-in-ubuntu/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: unfortinately the article I link below has been taken offline,
and by now I have no idea what was in there.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;After I got myself a nice new motherboard, Ubuntu thought the onboard sound card
should be the main sound card used by all applications. Since I&amp;rsquo;m the happy
owner of a superior PCI card, this was quite annoying. Fortunately, I ran across
the article 
&lt;a href=&#34;https://doc.gwos.org/index.php/Multisounds/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Multisounds&lt;/a&gt; that
clearly explains how to fix the ordering. After following the instructions, I
had my PCI sound card back as the default. Total fixing time: 60 seconds.&lt;/p&gt;
&lt;p&gt;In my humble opinion, selecting the primary sound card should be easier. Even in
Windoze it&amp;rsquo;s as simple as selecting the sound card from a dropdown list. Maybe
some day I&amp;rsquo;ll write something&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Spam filtering with Postfix</title>
      <link>https://stuvel.eu/post/2006-10-15-spam-filtering-with-postfix/</link>
      <pubDate>Sun, 15 Oct 2006 19:38:29 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-10-15-spam-filtering-with-postfix/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: the link below is unfortunately dead.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;m moving from Exim to Postfix, most of all because of the simplicity of
Postfix&amp;rsquo; configuration files. Most HOWTOs about spam filtering with Postfix
combine it with virus-scanning and other helper software like Amavis. All I
wanted was plain spam filtering - perhaps virus-scanning will be added later,
but for now i want simplicity. The document 
&lt;a href=&#34;https://www.xnote.com/howto/postfix-spamassassin.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Postfix and
Spamassassin&lt;/a&gt; describes
this in just the way I wanted.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Article about OpenOffice.org and Python</title>
      <link>https://stuvel.eu/post/2006-09-05-article-about-openoffice-org-and-python/</link>
      <pubDate>Tue, 05 Sep 2006 22:27:27 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-09-05-article-about-openoffice-org-and-python/</guid>
      <description>&lt;p&gt;The two small snippets I wrote two days ago were well received in the Python Usenet group. With the 
&lt;a href=&#34;https://groups.google.com/group/comp.lang.python/tree/browse_frm/thread/95573667385b2849/0d4034505ca893ce?rnum=1&amp;amp;_done=/group/comp.lang.python/browse_frm/thread/95573667385b2849%3F#doc_4585ecf71b3e5b74&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;danger of being called a hero&lt;/a&gt; I proceded and wrote a proper article about 
&lt;a href=&#34;https://stuvel.eu/ooo-python&#34;&gt;OpenOffice.org and Python&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It contains the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preparation&lt;/li&gt;
&lt;li&gt;Gaining access to a document&lt;/li&gt;
&lt;li&gt;Getting to the data&lt;/li&gt;
&lt;li&gt;Converting from/to Excel or to PDF&lt;/li&gt;
&lt;li&gt;Processing all files in a directory&lt;/li&gt;
&lt;li&gt;Automatically starting OOo&lt;/li&gt;
&lt;li&gt;More information&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enjoy 
&lt;a href=&#34;https://stuvel.eu/ooo-python&#34;&gt;the article&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Article about the Zaurus SL-C3000</title>
      <link>https://stuvel.eu/post/2006-09-04-article-about-the-zaurus-sl-c3000/</link>
      <pubDate>Mon, 04 Sep 2006 00:06:16 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-09-04-article-about-the-zaurus-sl-c3000/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve had a productive day today! Because I wanted to do some testing with the
original Sharp software of my 
&lt;a href=&#34;https://stuvel.eu/zaurus&#34;&gt;Zaurus SL-C3000&lt;/a&gt;, I had to re-flash it.
I took a risk that turned sour, so I had to clear the entire machine and start
from scratch. It took quite a few searches on Google and a couple of downloads
to get everything I needed. To prevent me from having to search all over again,
I took the liberty of combining the info into a single page, including the
downloads.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/zaurus&#34;&gt;The article&lt;/a&gt; contains four small step-by-step HOWTOs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;https://stuvel.eu/zaurus#NANDrestore&#34;&gt;Restoring a known-good NAND&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://stuvel.eu/zaurus#zeroing&#34;&gt;Zeroing an SL-C3000&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://stuvel.eu/zaurus#updatingToLatest&#34;&gt;Updating to the latest Japanese software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;https://stuvel.eu/zaurus#english&#34;&gt;Restoring Japanese to English&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope everybody that likes to tinker with their C3000 enjoys 
&lt;a href=&#34;https://stuvel.eu/zaurus&#34;&gt;this collection
of HOWTOs&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>OOo spreadsheet to Excel with Python</title>
      <link>https://stuvel.eu/post/2006-09-03-ooo-spreadsheet-to-excel-with-python/</link>
      <pubDate>Sun, 03 Sep 2006 18:13:45 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-09-03-ooo-spreadsheet-to-excel-with-python/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: It seems that the website containing the library required by
the below code is down. As such, it&amp;rsquo;s not really useful anymore.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A guy named Alf 
&lt;a href=&#34;https://groups.google.com/group/comp.lang.python/browse_frm/thread/95573667385b2849/0d4034505ca893ce&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;asked me on
Usenet&lt;/a&gt;
about saving 
&lt;a href=&#34;https://www.openoffice.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;OpenOffice.org&lt;/a&gt; spreadsheets to Excel
files, using 
&lt;a href=&#34;https://www.python.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python&lt;/a&gt;. After some more digging, this is
what I came up with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python

&#39;&#39;&#39;Demonstration program for saving an OpenOffice.org spreadsheet as
Excel sheet. Sometimes people refuse to install OOo, even though it&#39;s
completely free...

Requires that OOo is started with:
    ooffice &amp;quot;-accept=socket,host=localhost,port=8100;urp;&amp;quot;

Then open the spreadsheet as usual, and run this Python script.

Also requires Danny&#39;s OOo lib from
    https://www.oooforum.org/forum/viewtopic.php?p=56015
&#39;&#39;&#39;

import Danny.OOo.OOoLib as OOoLib
import unohelper

# For PDF output change the filter to:
# OOoLib.makePropertyValue(&#39;FilterName&#39;, &#39;writer_pdf_Export&#39;),

properties = (
    OOoLib.makePropertyValue(&#39;FilterName&#39;, &#39;MS Excel 97&#39;, -1, 0),
)

filename = &#39;/tmp/test.xls&#39;

path = unohelper.systemPathToFileUrl(filename)
desktop = OOoLib.getDesktop()
doc = desktop.getCurrentComponent()
doc.storeToURL(path, properties)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with 
&lt;a href=&#34;https://stuvel.eu/archive/28/getting-data-from-an-openofficeorg-spreadsheet&#34;&gt;the other script&lt;/a&gt;, this one requires 
&lt;a href=&#34;https://www.oooforum.org/forum/viewtopic.phtml?p=56015#56015&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Danny&amp;rsquo;s OOo lib&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Getting data from an OpenOffice.org spreadsheet</title>
      <link>https://stuvel.eu/post/2006-09-03-getting-data-from-an-openoffice-org-spreadsheet/</link>
      <pubDate>Sun, 03 Sep 2006 14:14:14 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-09-03-getting-data-from-an-openoffice-org-spreadsheet/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: It seems that the website containing the library required by
the below code is down. As such, it&amp;rsquo;s not really useful anymore.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There is an easy way to get data from an

&lt;a href=&#34;https://www.openoffice.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;OpenOffice.org&lt;/a&gt; spreadsheet using

&lt;a href=&#34;https://www.python.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python&lt;/a&gt;. Behold the following simple program. It
allows you to simply get the contents from certain cells and handle them as you
wish. I&amp;rsquo;m using this to fill a database with customer-supplied data in a
spreadsheet.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python

&amp;quot;&amp;quot;&amp;quot;Demonstration program for obtaining data from an OOo
spreadsheet.

Requires that OOo is started with:
    ooffice &amp;quot;-accept=socket,host=localhost,port=8100;urp;&amp;quot;

Then open the spreadsheet as usual, and run this Python script.

Also requires Danny&#39;s OOo lib from
    https://www.oooforum.org/forum/viewtopic.php?p=56015
&amp;quot;&amp;quot;&amp;quot;

import Danny.OOo.OOoLib as OOoLib

desktop = OOoLib.getDesktop()

# access the current document
doc = desktop.getCurrentComponent()
sheet = doc.getSheets().getByIndex(0)

row = 0
while True:
    name = sheet.getCellByPosition(0, row).getFormula()
    email = sheet.getCellByPosition(1, row).getFormula()

    if not email:
        break

    print &#39;%30s %20s&#39; % (name, email)

    row += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As stated in the docstring, it requires 
&lt;a href=&#34;https://www.oooforum.org/forum/viewtopic.phtml?p=56015#56015&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Danny&amp;rsquo;s OOo
lib&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had to do a lot of digging to create this very simple program. The OOo API
documentation is very complex. Hopefully this will simplify things for a lot of
people!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DVDInfo version 1.1 released</title>
      <link>https://stuvel.eu/post/2006-08-13-dvdinfo-version-1-1-released/</link>
      <pubDate>Sun, 13 Aug 2006 11:05:13 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-08-13-dvdinfo-version-1-1-released/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: DVDInfo is offline. For converting DVDs and Blu-ray disks to an
open format I would suggest 
&lt;a href=&#34;https://www.makemkv.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MakeMKV&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A new version of 
&lt;a href=&#34;https://stuvel.eu/dvdinfo&#34;&gt;dvdinfo&lt;/a&gt; has seen the light of day. For those who
don&amp;rsquo;t know it, it&amp;rsquo;s a piece of software that enables you to find the track
number of the main feature film on a DVD, along with audio and subtitle track
information. This is a very easy tool if you want to rip a DVD to another
format.&lt;/p&gt;
&lt;p&gt;The changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only consider a title the main movie if it has an audio track. This ensures
that picture-titles with one chapter per picture aren&amp;rsquo;t considered the main
movie, even though such titles can have a lot of chapters.&lt;/li&gt;
&lt;li&gt;Added the ability to specify which title to read.&lt;/li&gt;
&lt;li&gt;Display 1/? instead of 1/1 if the total number of titles is unknown.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check out the latest release of 
&lt;a href=&#34;https://stuvel.eu/dvdinfo&#34;&gt;dvdinfo&lt;/a&gt; today!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ethernet numbering in Ubuntu</title>
      <link>https://stuvel.eu/post/2006-08-10-ethernet-numbering-in-ubuntu/</link>
      <pubDate>Thu, 10 Aug 2006 10:35:32 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-08-10-ethernet-numbering-in-ubuntu/</guid>
      <description>&lt;p&gt;&lt;strong&gt;update&lt;/strong&gt;: this info is obsolete as of Ubuntu Gutsy (7.10). &amp;lsquo;Bogdan&amp;rsquo; posted a
comment with an approach that works on more modern Ubuntus:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In recent Ubuntu versions (and potentially other Linuxes), the iftab file is
replaced by &lt;code&gt;/etc/udev/rules.d/70-persistent-net.rules&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;(The 70 might change, though.)&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not the same syntax, but you can tell rather easily what it does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;My girlfriend&amp;rsquo;s laptop got bricked, so we replaced it with another laptop of the
same make and model, and put in her original laptop&amp;rsquo;s harddisk. Of course,
Ubuntu ran fine, but there was one issue: instead of having eth0 and eth1 as
WiFi and LAN devices, we had eth2 and eth3. For some reason, Ubuntu refused to
re-use eth0 and eth1.&lt;/p&gt;
&lt;p&gt;After a bit of digging, I found out that /etc/iftab contains the MAC addresses
of network cards:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# This file assigns persistent names to network
# interfaces. See iftab(5).
eth0 mac 00:01:de:ad:be:ef
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is very useful if you have hot-pluggable NICs that need to keep the same
ethX every time you plug them in. Ubuntu&amp;rsquo;s installation put in the MAC addresses
of the original network interfaces, so that&amp;rsquo;s why the new hardware skipped eth0
and eth1 and used eth2 and eth3.&lt;/p&gt;
&lt;p&gt;Setting the correct MAC addresses in /etc/iftab solved the issue.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Two-way tunnelling with NetCat</title>
      <link>https://stuvel.eu/post/2006-08-10-two-way-tunnelling-with-netcat/</link>
      <pubDate>Thu, 10 Aug 2006 10:25:50 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-08-10-two-way-tunnelling-with-netcat/</guid>
      <description>&lt;p&gt;I read this on the comp.lang.python newsgroup. It&amp;rsquo;s a way to have two-way
tunnelling with NetCat. Thanks to Rob Haswell:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mknod backpipe p
$ nc -l -p 8080 &amp;lt; backpipe | nc other 8080 &amp;gt; backpipe
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Move to mod_python</title>
      <link>https://stuvel.eu/post/2006-08-04-move-to-mod-python/</link>
      <pubDate>Fri, 04 Aug 2006 12:49:47 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-08-04-move-to-mod-python/</guid>
      <description>&lt;p&gt;The 
&lt;a href=&#34;https://www.stuvel.eu&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;www.stuvel.eu&lt;/a&gt; website has been moved from the Django development server
software to 
&lt;a href=&#34;https://www.modpython.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;mod_python&lt;/a&gt;. It should be more stable
and also perform a bit better, especially when under heavy load.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Problem with IMDB-Compare</title>
      <link>https://stuvel.eu/post/2006-07-20-problem-with-imdb-compare/</link>
      <pubDate>Thu, 20 Jul 2006 19:23:28 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-07-20-problem-with-imdb-compare/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: All of the below is offline. However, IMDB themselves have

&lt;a href=&#34;https://www.imdb.com/search/common/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;similar functionality&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;When you think &amp;ldquo;their HTML hasn&amp;rsquo;t changed in years&amp;rdquo;, their HTML changes.

&lt;a href=&#34;https://www.imdb.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;IMDB&lt;/a&gt; now features small images next to the author&amp;rsquo;s
names. Nice to look at, but it did break 
&lt;a href=&#34;https://stuvel.eu/imdbcompare&#34;&gt;IMDB-Compare&lt;/a&gt;. No
worries, though, I&amp;rsquo;m already on it trying to fix things.&lt;/p&gt;
&lt;p&gt;Edit: It&amp;rsquo;s fixed!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fighting comment spam</title>
      <link>https://stuvel.eu/post/2006-07-12-fighting-comment-spam/</link>
      <pubDate>Wed, 12 Jul 2006 12:43:06 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-07-12-fighting-comment-spam/</guid>
      <description>&lt;p&gt;The site has the possibility to add comments, and after a few days, the spamming
begins. I&amp;rsquo;m curious if the automated spambots are smart enough to do some math.
The 
&lt;a href=&#34;https://en.wikipedia.org/wiki/Captcha&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;captcha&lt;/a&gt; I&amp;rsquo;ve created is very
simple: just give the answer to &amp;ldquo;1+1&amp;rdquo;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Interview published</title>
      <link>https://stuvel.eu/post/2006-07-07-interview-published/</link>
      <pubDate>Fri, 07 Jul 2006 09:46:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-07-07-interview-published/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: the entire website 
&lt;a href=&#34;https://www.studeren.uva.nl&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;www.studeren.uva.nl&lt;/a&gt; has been taken down,
so also the interview is nowhere to be found.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I got interviewed for the University of Amsterdam. 
&lt;a href=&#34;https://www.studeren.uva.nl/informatica/object.cfm/objectid=151AB92A-399F-4A5F-9FD350FBDC3C8D8B/templateid=41C7B91E-A580-42D3-965E2EF36670CF21&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The interview&lt;/a&gt; has been published on the website for potential new students of the university. 
&lt;a href=&#34;https://www.studeren.uva.nl/informatica/object.cfm/objectid=151AB92A-399F-4A5F-9FD350FBDC3C8D8B/templateid=41C7B91E-A580-42D3-965E2EF36670CF21&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The interview&lt;/a&gt; is in Dutch.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Added comment ability</title>
      <link>https://stuvel.eu/post/2006-07-04-added-comment-ability/</link>
      <pubDate>Tue, 04 Jul 2006 01:51:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-07-04-added-comment-ability/</guid>
      <description>&lt;p&gt;It is now possible to comment on news items! Soon I&amp;rsquo;ll also add backlinks from

&lt;a href=&#34;https://stuvel.eu/software&#34;&gt;software&lt;/a&gt; and 
&lt;a href=&#34;https://stuvel.eu/articles&#34;&gt;articles&lt;/a&gt; to relevant news items, so you
can easily find the comments or post your own. Hopefully this will add some
interaction to this website. I love to know what you think of it!&lt;/p&gt;
&lt;p&gt;For some reason this post attracts a lot of spammers, so commenting on this
particular post has been disabled.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: I&amp;rsquo;ve converted this website to (Hugo)[https://gohugo.io/] and
removed the ability to comment on posts.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Converted my site to Django</title>
      <link>https://stuvel.eu/post/2006-06-28-converted-my-site-to-django/</link>
      <pubDate>Wed, 28 Jun 2006 13:14:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-06-28-converted-my-site-to-django/</guid>
      <description>&lt;p&gt;The automatically generated web-based admin of

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt; made me switch :)

&lt;a href=&#34;https://www.djangoproject.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Django&lt;/a&gt; is easy to work with, is built in a
very modular, structured way, which really appealed to me. It took me only a
couple of hours to convert my website to its template/engine structure.&lt;/p&gt;
&lt;p&gt;There are two things that still need to be converted - the search engine and the
news archive. Don&amp;rsquo;t worry, they&amp;rsquo;ll be online again soon!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;edit&lt;/em&gt;: the 
&lt;a href=&#34;https://stuvel.eu/archive&#34;&gt;archive&lt;/a&gt; is online.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;edit&lt;/em&gt;: the 
&lt;a href=&#34;https://stuvel.eu/search&#34;&gt;search page&lt;/a&gt; is online too!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: I&amp;rsquo;ve converted my website to 
&lt;a href=&#34;https://gohugo.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hugo&lt;/a&gt;, and
the above URLs are no longer valid.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Finished my study!</title>
      <link>https://stuvel.eu/post/2006-06-27-finished-my-study/</link>
      <pubDate>Tue, 27 Jun 2006 20:40:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-06-27-finished-my-study/</guid>
      <description>&lt;p&gt;I finally finished my study! In two weeks, I&amp;rsquo;ll oficially be a Bachelor of
Computer Science! It&amp;rsquo;s really weird to be done studying, since I&amp;rsquo;ve done that
for nearly all my life. Good to have an official title :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>We won first price!</title>
      <link>https://stuvel.eu/post/2006-06-23-we-won-first-price/</link>
      <pubDate>Fri, 23 Jun 2006 12:20:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-06-23-we-won-first-price/</guid>
      <description>&lt;p&gt;Science Park Amsterdam organized a contest for new ideas. We joined the
competition with my graduation project Sadako, and won first price!
Unfortunately, I can&amp;rsquo;t go into detail about Sadako, since that would get in the
way of obtaining the patent ;-)&lt;/p&gt;
&lt;p&gt;For more information, check out 
&lt;a href=&#34;https://www.scienceparkamsterdam.org/detail.jsp?page=detail_nl&amp;amp;id=7967&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Science Park Amsterdam Nieuwe Ideeën Prijs
uitgereikt&lt;/a&gt;
(Dutch).&lt;/p&gt;
&lt;p&gt;Another article appeared: 
&lt;a href=&#34;https://www.science.uva.nl/object.cfm/objectID=0AFCE1D5-EA50-46F7-B752D9ADCAC72948&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UvA-medewerkers winnen Science Park Amsterdam Nieuwe Ideeën Prijsvraag&lt;/a&gt;. Also in Dutch.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DVDInfo</title>
      <link>https://stuvel.eu/post/2006-06-12-dvdinfo/</link>
      <pubDate>Mon, 12 Jun 2006 21:05:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-06-12-dvdinfo/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: DVDInfo is offline. For converting DVDs and Blu-ray disks to an
open format I would suggest 
&lt;a href=&#34;https://www.makemkv.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MakeMKV&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Ever wanted to rip a DVD with 
&lt;a href=&#34;https://www.mplayerhq.hu/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mencoder&lt;/a&gt;? You would
then need to find the right title number, the right subtitle track and and audio
channel ID. With 
&lt;a href=&#34;https://stuvel.eu/dvdinfo&#34;&gt;DVDInfo&lt;/a&gt; this has been made really easy. Just run
DVDInfo, and it will find the longest title on the DVD and display all audio and
subtitle IDs, together with the language and audio format. With this tool, you
can spend less time tweaking, and more time watching movies!&lt;/p&gt;
&lt;p&gt;Take a look at the latest creation of Stüvel IT, 
&lt;a href=&#34;https://stuvel.eu/dvdinfo&#34;&gt;DVDInfo version 1.0&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rop Gonggrijp on Dutch television</title>
      <link>https://stuvel.eu/post/2006-06-07-rop-gonggrijp-on-dutch-television/</link>
      <pubDate>Wed, 07 Jun 2006 21:17:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-06-07-rop-gonggrijp-on-dutch-television/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: Unfortunately the video has been taken down.&lt;/p&gt;
&lt;p&gt;Internet pioneer, hacker and man with a good vision on the future. He was on
Dutch television on the 24th of may. In the final minutes of the show, he talked
about privacy and databases of personal information. I was so impressed by his
words, I just had to share with the rest of the world.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&#34;https://video.google.com/videoplay?docid=-2785902447748328966&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;About databases and human tracking&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The video is in Dutch.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiblend 1.3 released</title>
      <link>https://stuvel.eu/post/2006-05-29-multiblend-1-3-released/</link>
      <pubDate>Mon, 29 May 2006 07:36:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-05-29-multiblend-1-3-released/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve released a new version of 
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt;! Version 1.3 has the
following improvements over the previous version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added possibility to select the scene to render.&lt;/li&gt;
&lt;li&gt;Added nice level to the config possibilities.&lt;/li&gt;
&lt;li&gt;Added possibility to skip node testing.&lt;/li&gt;
&lt;li&gt;Fixed chunk size bug when number of nodes is larger than number of frames to render.&lt;/li&gt;
&lt;li&gt;Fixed encoding bug when stdout is not a terminal.&lt;/li&gt;
&lt;li&gt;Start &amp;lsquo;sh&amp;rsquo; immediately on the node. This prevents &amp;rsquo;last logged in on &amp;hellip;&amp;rsquo;
messages ologin, and thus improves compatability with different systems.&lt;/li&gt;
&lt;li&gt;Added echoing_node to the config possibilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt; connects to multiple computers on your network, and
lets Blender render in parallel on each. This will drastically improve your
rendering speeds!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>IMDB Compare</title>
      <link>https://stuvel.eu/post/2006-05-28-imdb-compare/</link>
      <pubDate>Sun, 28 May 2006 21:53:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-05-28-imdb-compare/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: All of the below is offline. However, IMDB themselves have

&lt;a href=&#34;https://www.imdb.com/search/common/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;similar functionality&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Something I&amp;rsquo;ve always missed in the 
&lt;a href=&#34;https://www.imdb.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Internet Movie
Database&lt;/a&gt; is the ability to compare two movies. Sometimes
I forget an actor&amp;rsquo;s name, but I do know at least two movies he or she is in.
With Stüvel IT&amp;rsquo;s 
&lt;a href=&#34;https://stuvel.eu/imdbcompare&#34;&gt;IMDB Compare&lt;/a&gt;, everybody can compare two movies
and get a list of actors that star in both. All you need to do is copy &amp;amp; paste
two URLs and hit a button! It can&amp;rsquo;t get simpler than that.&lt;/p&gt;
&lt;p&gt;Go ahead and 
&lt;a href=&#34;https://stuvel.eu/imdbcompare&#34;&gt;try it yourself&lt;/a&gt; or look at our

&lt;a href=&#34;https://stuvel.eu/imdbcompare?url1=https://www.imdb.com/title/tt0376994/&amp;amp;url2=https://www.imdb.com/title/tt0338526/#compare&#34;&gt;example&lt;/a&gt;
first.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Two-pass MPEG4 encoding with mencoder</title>
      <link>https://stuvel.eu/post/2006-05-23-two-pass-mpeg4-encoding-with-mencoder/</link>
      <pubDate>Tue, 23 May 2006 14:18:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-05-23-two-pass-mpeg4-encoding-with-mencoder/</guid>
      <description>&lt;p&gt;I keep forgetting this, so I&amp;rsquo;ll put it here for everyone (including me) to see:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mencoder dvd:// -o movie.avi \
  -oac mp3lame \
  -ovc lavc -lavcopts \
  vcodec=mpeg4:mbd=1:vqmax=10:lmax=10:keyint=130:vpass=1:turbo \
  -sid 3 -aid 130 \
  -vf scale=720:405,expand=720:576:0:25:1 \
  -spuaa 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the second pass, change &lt;code&gt;vpass=1:turbo&lt;/code&gt; to &lt;code&gt;vpass=2&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tried Plone, but it&#39;s too much</title>
      <link>https://stuvel.eu/post/2006-05-14-tried-plone-but-it-s-too-much/</link>
      <pubDate>Sun, 14 May 2006 21:42:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-05-14-tried-plone-but-it-s-too-much/</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2019&lt;/strong&gt;: UnrealTower has been down for quite some years now.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This weekend, I took a good look at 
&lt;a href=&#34;https://www.plone.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Plone&lt;/a&gt;. It&amp;rsquo;s a very
nice content management framework for creating websites. It&amp;rsquo;s written in

&lt;a href=&#34;https://www.python.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Python&lt;/a&gt;, easy for users that want to publish articles
without knowledge about HTML and databases, and quite easy to get going. Besides
that, you can manage your website entirely from the comfort of your own website.&lt;/p&gt;
&lt;p&gt;The downside however, is that it&amp;rsquo;s tricky to customize the HTML and the CSS. The
supplied HTML/CSS is quite large too - a simple page is about 235 Kbytes.
Compare that to the 16 Kbytes of my current pages. My engine is a &lt;em&gt;lot&lt;/em&gt; simpler,
but therefore also a &lt;em&gt;lot&lt;/em&gt; faster. The HTML is also much simpler, therefore it
is a lot easier to get the looks I want.&lt;/p&gt;
&lt;p&gt;Adding up the pros and the cons, 
&lt;a href=&#34;https://www.plone.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Plone&lt;/a&gt; is nice, but
personally for me, it can&amp;rsquo;t measure up to my

&lt;a href=&#34;https://www.unrealtower.org/engine&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UnrealTower Engine&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiblend version 1.2 released</title>
      <link>https://stuvel.eu/post/2006-05-10-multiblend-version-1-2-released/</link>
      <pubDate>Wed, 10 May 2006 15:28:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-05-10-multiblend-version-1-2-released/</guid>
      <description>&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt; version 1.2 has been released. With this version, NFS
is no longer required, so the usage has become a lot easier. There are now only
two requirements left: be able to SSH to the nodes without password, and pack
all required files into the .blend file. That should be easy!&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re upgrading from previous versions, please note the configuration file
format has changed a little bit. The path to &amp;lsquo;scp&amp;rsquo; needs to be set, and instead
of &amp;lsquo;projectpath&amp;rsquo; the nodes now have a &amp;lsquo;workdir&amp;rsquo; option. It should be fairly easy
to get things going.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiblend</title>
      <link>https://stuvel.eu/post/2006-04-30-multiblend/</link>
      <pubDate>Sun, 30 Apr 2006 22:25:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-04-30-multiblend/</guid>
      <description>&lt;p&gt;For all the people that want to have an easy way to use distributed rendering
with 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt;, I have the solution:

&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt;. It is a Python script that feeds chunks of frames to
each computer on your network, allowing them to render in parallel and &lt;em&gt;greatly
improve rendering speeds&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend&lt;/a&gt; is a Python script that needs only a simple
configuration file and a well setup network. Of course, instructions on how to
install and use it are on the 
&lt;a href=&#34;https://stuvel.eu/multiblend&#34;&gt;Multiblend page&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blender game engine on Ubuntu</title>
      <link>https://stuvel.eu/post/2006-04-14-blender-game-engine-on-ubuntu/</link>
      <pubDate>Fri, 14 Apr 2006 10:19:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-04-14-blender-game-engine-on-ubuntu/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m learning how to work with 
&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&amp;rsquo;s&lt;/a&gt; game engine.
Unfortunately, as soon as I press &amp;lsquo;p&amp;rsquo; to start the engine, Blender crashes with
a segmentation fault. Fortunately, I&amp;rsquo;ve found a way to fix this on Ubuntu Linux.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install the dynamically linked version of Blender from the

&lt;a href=&#34;https://www.blender.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Blender&lt;/a&gt; website.&lt;/li&gt;
&lt;li&gt;As root, type &amp;ldquo;apt-get build-dep blender&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Run Blender.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Online!</title>
      <link>https://stuvel.eu/post/2006-04-10-online/</link>
      <pubDate>Mon, 10 Apr 2006 16:47:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-04-10-online/</guid>
      <description>&lt;p&gt;Finally, the Stüvel IT website can be reached by everyone. I&amp;rsquo;ve moved a lot of
content from 
&lt;a href=&#34;https://www.unrealtower.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UnrealTower&lt;/a&gt; to this site, because
this is a better place for it. I hope everybody enjoys my new site!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stuvel.eu finally online!</title>
      <link>https://stuvel.eu/post/2006-04-08-stuvel-eu-finally-online/</link>
      <pubDate>Sat, 08 Apr 2006 13:49:00 +0200</pubDate>
      <guid>https://stuvel.eu/post/2006-04-08-stuvel-eu-finally-online/</guid>
      <description>&lt;p&gt;Fortunately, stuvel.eu became mine. Welcome to my new domain!
It&amp;rsquo;s nice to finally have a personal domain :)&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
