<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.1">Jekyll</generator><link href="https://posts.boy.sh/feed.xml" rel="self" type="application/atom+xml" /><link href="https://posts.boy.sh/" rel="alternate" type="text/html" /><updated>2026-03-17T23:14:28+00:00</updated><id>https://posts.boy.sh/feed.xml</id><title type="html">posts.boy</title><subtitle>Articles about computers, apps, games, modding and programming.
</subtitle><entry><title type="html">On Dumbphones</title><link href="https://posts.boy.sh/on-dumbphones" rel="alternate" type="text/html" title="On Dumbphones" /><published>2026-03-17T00:00:00+00:00</published><updated>2026-03-17T00:00:00+00:00</updated><id>https://posts.boy.sh/on-dumbphones</id><content type="html" xml:base="https://posts.boy.sh/on-dumbphones"><![CDATA[<p>My iPhone 15 Pro takes gorgeous pictures and can access any part of my (digital) life whenever I want. It’s also heavy and a distraction when I’m with my kids.</p>

<p>To minimize the negative aspects I’ve disabled everything except the bare necessities using <a href="https://www.foqos.app">Foqos</a>. I haven’t read a full news article in about a week. My AI Agent sends me the headlines every morning and that’s it. I also block search engines. The phone is barely worth picking up anymore. Now that its weight and size aren’t set off by its usefulness it feels ridiculous to carry around.</p>

<p>That’s why I’ve been on the hunt for an alternative phone. One that’s small and basic but allows me to stay connected; it’s impossible to be completely offline if you have kids.</p>

<h2 id="the-setup">The Setup</h2>

<p>I’m currently running a <a href="https://www.punkt.ch/products/mp02-4g-minimalist-phone">Punkt MP02</a> as my daily driver. It’s beautifully designed and feels like a deliberate statement against modern smartphones.</p>

<p><img src="/assets/blog/dumbphones/punkt-mp02.webp" alt="Punkt MP02" /></p>

<p>Like any phone it can place calls and send text messages. It’s a step up from dumbphones in that it has 4G LTE, can tether that connection and offers its own implementation of Signal — called Pigeon.</p>

<p><em>What makes this setup work for me is adding my Apple Watch. I can leave the iPhone at home, enable tethering on the Punkt and use the Apple Watch for essential notifications and contactless payments.</em></p>

<p>It’s a compromise that feels liberating.</p>

<h2 id="in-reality">In Reality</h2>

<p>The Punkt itself is stunning. It feels premium, the keyboard is satisfying to type on and the tiny screen is appealing to look at. I find myself holding it in my hand for no reason but to feel it.</p>

<p>But there are trade-offs.</p>

<p>Battery life is disappointing. The Punkt barely lasts a full day, which feels backwards for a device that’s supposed to be simpler. If I tether a lot I can turn it into a paperweight in mere hours.</p>

<p>Then there’s typing. Using Pigeon to respond to Signal messages is… not great. The keyboard is tiny, the interface is clunky, and you quickly realize how much you take for granted when you have a full-size touchscreen.</p>

<h2 id="whats-next">What’s Next</h2>

<p>I’ve ordered a <a href="https://mudita.com/products/phones/mudita-kompakt/">Mudita Kompakt</a> in hopes that it’ll solve the battery issue. It’s another privacy-focused phone with a similar philosophy but hopefully better power management. It also has an e-ink display that I’m looking forward to seeing in action.</p>

<p><img src="/assets/blog/dumbphones/mudita-kompakt.webp" alt="Mudita Kompakt" /></p>

<p>It’s confronting how cumbersome it feels to walk around with a phone that doesn’t offer much assistance when you’re out and about. The Mudita provides a few extra lifelines: it has a map, a basic camera, flashlight and can even side-load some apps.</p>]]></content><author><name></name></author><category term="dumbphones" /><category term="digital-minimalism" /><category term="privacy" /><summary type="html"><![CDATA[I'm trying to move away from using my iPhone towards a Punkt MP02 or Mudita Kompakt.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Install native arm64 Ruby through rbenv on Apple Silicon</title><link href="https://posts.boy.sh/install-ruby-on-apple-silicon" rel="alternate" type="text/html" title="Install native arm64 Ruby through rbenv on Apple Silicon" /><published>2022-11-09T00:00:00+00:00</published><updated>2022-11-09T00:00:00+00:00</updated><id>https://posts.boy.sh/install-ruby-on-apple-silicon</id><content type="html" xml:base="https://posts.boy.sh/install-ruby-on-apple-silicon"><![CDATA[<p>Having recently acquired an Apple Silicon powered MacBook, I noticed the new architecture comes with a few challenges:</p>
<ol>
  <li>There are no native binaries available for older applications. This includes legacy versions of Ruby,  Python and other tools.</li>
  <li>You have to take care to not mix <code class="language-plaintext highlighter-rouge">arm64</code> and <code class="language-plaintext highlighter-rouge">x86_64</code>.</li>
</ol>

<p>These two points combined mean that you might have to upgrade some of your projects. I had to migrate all my websites from Jekyll 3.x on Ruby 2.x to Jekyll 4.3.1 on Ruby 3.1.2.</p>

<p><em>Fight the urge to try and get your projects running with outdated software. You’ll quickly run into issue number two and be tempted to run your Terminal under Rosetta, like some posts suggest. Please don’t do this. You’ll regret it later.</em></p>

<p>In this guide I’ll help you install Homebrew, rbenv and a recent version of Ruby all compiled for the <code class="language-plaintext highlighter-rouge">arm64</code> architecture.</p>

<h2 id="setup">Setup</h2>

<p>Before we get started, make sure you’re not already running your Terminal of choice under Rosetta:</p>
<ol>
  <li>Right-click your Terminal app.</li>
  <li>Make sure Open Using Rosetta is disabled.</li>
</ol>

<h3 id="remove-x86_64-installations-if-necessary">Remove <code class="language-plaintext highlighter-rouge">x86_64</code> installations if necessary</h3>

<p>If you’ve somehow migrated your Homebrew, rbenv or Ruby installations from a previous Intel Mac, you’ll first have to uninstall the <code class="language-plaintext highlighter-rouge">x86_64</code> code.</p>

<p>Just to be sure, check if you have any files present under <code class="language-plaintext highlighter-rouge">/usr/local</code>. That’s was the path Homebrew used before. The new path is <code class="language-plaintext highlighter-rouge">/opt/Homebrew</code>.</p>

<h4 id="rbenv">rbenv</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew uninstall rbenv
</code></pre></div></div>

<p>Check if there’s anything left under <code class="language-plaintext highlighter-rouge">~/.rbenv</code>. Get rid of the folder if it’s still there.</p>

<h4 id="homebrew">Homebrew</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/bash <span class="nt">-c</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="install-homebrew">Install Homebrew</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/bin/bash <span class="nt">-c</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>Make sure the following line is present in your <code class="language-plaintext highlighter-rouge">~/.zshrc</code> (or other shell’s config):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"/opt/Homebrew/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="install-rbenv">Install rbenv</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>rbenv readline openssl
</code></pre></div></div>

<p>Add the following lines to your <code class="language-plaintext highlighter-rouge">~/.zshrc</code> (or other shell’s config):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.rbenv/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>rbenv init -<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="install-xcodes-command-line-tools">Install Xcode’s Command Line Tools</h2>

<p>You might already have Xcode and its Command Line Tools installed, but there is a chance that rbenv won’t find it.</p>

<p>You can find the standalone release here: <a href="https://developer.apple.com/download/all/">https://developer.apple.com/download/all/</a>.</p>

<h2 id="install-ruby">Install Ruby</h2>

<p>Add the following to your <code class="language-plaintext highlighter-rouge">~/.zshrc</code> (or other shell’s config):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">local </span><span class="nv">READLINE_PATH</span><span class="o">=</span><span class="si">$(</span>brew <span class="nt">--prefix</span> readline<span class="si">)</span>
<span class="nb">local </span><span class="nv">OPENSSL_PATH</span><span class="o">=</span><span class="si">$(</span>brew <span class="nt">--prefix</span> openssl<span class="si">)</span>

<span class="nb">export </span><span class="nv">LDFLAGS</span><span class="o">=</span><span class="s2">"-L</span><span class="nv">$READLINE_PATH</span><span class="s2">/lib -L</span><span class="nv">$OPENSSL_PATH</span><span class="s2">/lib"</span>
<span class="nb">export </span><span class="nv">CPPFLAGS</span><span class="o">=</span><span class="s2">"-I</span><span class="nv">$READLINE_PATH</span><span class="s2">/include -I</span><span class="nv">$OPENSSL_PATH</span><span class="s2">/include"</span>
<span class="nb">export </span><span class="nv">PKG_CONFIG_PATH</span><span class="o">=</span><span class="s2">"</span><span class="nv">$READLINE_PATH</span><span class="s2">/lib/pkgconfig:</span><span class="nv">$OPENSSL_PATH</span><span class="s2">/lib/pkgconfig"</span>

<span class="nb">export </span><span class="nv">RUBY_CONFIGURE_OPTS</span><span class="o">=</span><span class="s2">"--with-openssl-dir=</span><span class="nv">$OPENSSL_PATH</span><span class="s2">"</span>

<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$OPENSSL_PATH</span>/bin:<span class="nv">$PATH</span>

<span class="nb">export </span><span class="nv">SDKROOT</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span>xcrun <span class="nt">--show-sdk-path</span><span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>This makes sure the compiler knows where to find all the dependencies it requires.</p>

<p>Now get a list of the most recent Ruby versions:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv <span class="nb">install</span> <span class="nt">--list</span>
</code></pre></div></div>
<p>Output:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2.6.10
2.7.6
3.0.4
3.1.2
jruby-9.3.9.0
mruby-3.1.0
picoruby-3.0.0
rbx-5.0
truffleruby-22.3.0
truffleruby+graalvm-22.3.0

Only latest stable releases <span class="k">for </span>each Ruby implementation are shown.
Use <span class="s1">'rbenv install --list-all / -L'</span> to show all <span class="nb">local </span>versions.
</code></pre></div></div>

<p>Depending on when you run this command the output will be different. Just pick the latest release.</p>

<p><em>If you need Ruby 2, you might have to install OpenSSL 1.1.x. To do this, change every mention of <code class="language-plaintext highlighter-rouge">openssl</code> to <code class="language-plaintext highlighter-rouge">openssl@1.1</code>. So, <code class="language-plaintext highlighter-rouge">brew install openssl@1.1</code> and <code class="language-plaintext highlighter-rouge">local OPENSSL_PATH=$(brew --prefix openssl@1.1)</code>.</em></p>

<p>To install Ruby 3.1.2:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv <span class="nb">install </span>3.1.2
</code></pre></div></div>

<p>Hopefully the command will now complete successfully and you’ll be able to use Ruby. To make it the default on your system use this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv global 3.1.2
</code></pre></div></div>

<p><strong>That’s it. All done.</strong> 🥳</p>]]></content><author><name></name></author><category term="apple-silicon" /><category term="ruby" /><category term="tutorial" /><category term="jekyll" /><summary type="html"><![CDATA[A step-by-step guide on how to properly install Ruby on Apple Silicon powered computers.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fix Windows 10 2004 update Blue Screen on Corsair ONE</title><link href="https://posts.boy.sh/corsair-one-windows-10-2004-update" rel="alternate" type="text/html" title="Fix Windows 10 2004 update Blue Screen on Corsair ONE" /><published>2020-06-10T00:00:00+00:00</published><updated>2020-06-10T00:00:00+00:00</updated><id>https://posts.boy.sh/corsair-one-windows-10-2004-update</id><content type="html" xml:base="https://posts.boy.sh/corsair-one-windows-10-2004-update"><![CDATA[<p>TL;DR: Install <a href="CORSAIR LINK 4.4.4.9 for CORSAIR ONE (2017/2018)">the latest version of Corsair Link</a> to fix the issue.</p>

<p>Microsoft recently released the 2004 version update for Windows 10. It includes a bunch of cool new features, like <a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions">WSL 2</a> which integrates Linux even better into the Windows operating system.</p>

<p>I immediately jumped at the opportunity to install the update when it presented itself, only to be disappointed during the installation. It repeatedly failed with a BSOD mentioning <code class="language-plaintext highlighter-rouge">cpuz141_x64.sys</code> caused a <code class="language-plaintext highlighter-rouge">PAGE_FAULT_IN_NONPAGED_AREA</code>.</p>

<p>At first I was confused, because I wasn’t aware a CPU-Z driver was installed at all. After some digging I discovered it’s used by the <a href="https://www.corsair.com/eu/en/corsairlink">Corsair Link</a> utility installed on all 2017/2018 <a href="https://www.corsair.com/eu/en/Categories/Products/Systems/CORSAIR-ONE/CORSAIR-ONE-GAMING-PC/p/CS-9020003-EU">Corsair ONE</a> models.</p>

<p>Corsair Link is mandatory as it’s solely responsible for updating the fan speeds while the system is in use.  Without it the computer will overheat. A terrible depedency I wasn’t fully aware of when I bought the machine.</p>

<p><img src="/assets/blog/blog_CORSAIR-ONE-ELITE-PRO-PLUS-Content-3.jpg" alt="A picture of the Corsair ONE with its components visible" /></p>

<p>It’s pretty though and fast.</p>

<p>The in-app update mechanism for Corsair Link promised me I was running the latest version. That was concerning. It suggested I might not be able to install the 2004 update at all. Luckily I came across this topic on the Corsair forum: <a href="https://forum.corsair.com/v3/showthread.php?t=175259">CORSAIR LINK 4.4.4.9 for CORSAIR ONE (2017/2018)</a>. Posted in 2018 it provides a download link to an updated version of Corsair Link. Why this version isn’t available through the in-app updater is unknown to me.</p>

<p>After installing the newer version, Windows continued the OS update without a hitch. 🥳</p>]]></content><author><name></name></author><category term="windows" /><summary type="html"><![CDATA[Update Corsair Link to resolve the blue screen you get while updating.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fix ‘broken’ iPad Pro (2nd gen) Smart Keyboard Folio</title><link href="https://posts.boy.sh/fix-ipad-pro-keyboard-folio" rel="alternate" type="text/html" title="Fix ‘broken’ iPad Pro (2nd gen) Smart Keyboard Folio" /><published>2020-05-04T00:00:00+00:00</published><updated>2020-05-04T00:00:00+00:00</updated><id>https://posts.boy.sh/fix-ipad-pro-keyboard-folio</id><content type="html" xml:base="https://posts.boy.sh/fix-ipad-pro-keyboard-folio"><![CDATA[<p>My Smart Keyboard Folio has been unresponsive for months. I was almost getting ready to trash it. Every time I folded it into position, the onscreen keyboard slid up as if a physical keyboard wasn’t connected at all.</p>

<p>It <em>was</em> attached though and I tried everything to get it to work:</p>

<ul>
  <li>Force-rebooting my iPad with the keyboard disconnected, then connecting it afterwards. Didn’t work.</li>
  <li>Cleaning the contacts with alcohol and a clean cloth. Didn’t work.</li>
  <li>Nudging it from the bottom left or right corner. Worked at first, then nothing.</li>
</ul>

<p>The problem manifested over a few weeks, getting worse every day. I thought the ribbon cable had been damaged. Nothing I could do to fix it.</p>

<p>Then I tried bending the magnets that snap the keyboard into place. 🧲</p>

<p>I couldn’t believe it at first, but the problem was resolved instantly. After folding and unfolding it several times it still works. I’m actually typing this article on it.</p>

<p>The trick is to bend the magnets slightly towards where it connects with the iPad. Don’t overdo it, just curve them up a tiny bit. I can’t even see the difference on mine, but the effect is there.</p>

<p><img src="/assets/blog/bend-smart-keyboard-folio.jpg" alt="A photo showing to bend the corners of the Smart Keyboard Folio upwards" /></p>

<p>So, if you’ve ruled out all software-related issues, you might want to give this a go. <a href="https://www.twitter.com/boyvanamstel">Let me know</a> if you got yours working again too!</p>

<p><strong>Note: I’m not responsible for any damage you cause to your keyboard. Be careful and use common sense.</strong></p>]]></content><author><name></name></author><category term="hardware" /><category term="ipad" /><summary type="html"><![CDATA[Bend the magnets to fix an unresponsive iPad Pro (2nd generation) Smart Keyboard Folio]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">VMWare Fusion 10 on macOS Catalina</title><link href="https://posts.boy.sh/vmware-fusion-catalina" rel="alternate" type="text/html" title="VMWare Fusion 10 on macOS Catalina" /><published>2019-10-18T00:00:00+00:00</published><updated>2019-10-18T00:00:00+00:00</updated><id>https://posts.boy.sh/vmware-fusion-catalina</id><content type="html" xml:base="https://posts.boy.sh/vmware-fusion-catalina"><![CDATA[<p><em>This post is for those of us running an older version of VMWare Fusion on macOS Catalina. <a href="https://blogs.vmware.com/teamfusion/2019/09/vmware-fusion-11-5-available-now.html">VMWare Fusion 11.5</a> supports macOS 10.15 out of the box.</em></p>

<p>I use VMWare Fusion 10 to test <a href="https://www.dangercove.com">my apps</a> on previous and future versions of macOS. Since this fall, that’s become problematic. The screen remains blank when I start one of my virtuals on Catalina. Oddly enough the preview in the virtual machine overview works fine.</p>

<p>Catalina requires apps to request permission for various tasks. Recording the screen is one of them. Apparently Fusion uses this feature, but neglects to ask for permission. Thus the screen stays black.</p>

<p><a href="https://communities.vmware.com/message/2884329#2884329">Some people</a> found a way to get around this by granting permission manually. Here’s how that works.</p>

<p>⚠️ <strong>Note that this requires running Terminal commands in Recovery Mode. Make sure you’re comfortable with these steps. I don’t offer any support and am not responsible if things don’t go as planned.</strong> ⚠️</p>

<h3 id="create-the-script">Create the script</h3>

<p>Create a new script file where you can easily access it. I recommend <code class="language-plaintext highlighter-rouge">/tmp/fixfusion.sh</code>. Paste in the following:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh  </span>

<span class="c"># Change the following to fit your system</span>
<span class="nv">root</span><span class="o">=</span><span class="s2">"/Volumes/Macintosh HD"</span>  
  
<span class="s2">"</span><span class="nv">$root</span><span class="s2">/usr/bin/sqlite3"</span> <span class="s2">"</span><span class="k">${</span><span class="nv">root</span><span class="k">}</span><span class="s2">/Library/Application Support/com.apple.TCC/TCC.db"</span> <span class="s1">'insert into access values ("kTCCServiceScreenCapture", "com.vmware.fusion", 0, 1, 1, "", "", "", "UNUSED", "", 0,1565595574)'</span>  
</code></pre></div></div>

<h3 id="enter-recovery-mode">Enter Recovery Mode</h3>

<p>Enter Recovery Mode by restarting your Mac and holding down <code class="language-plaintext highlighter-rouge">⌘</code> + <code class="language-plaintext highlighter-rouge">R</code> while it boots.</p>

<p>Start a Terminal window by selecting <code class="language-plaintext highlighter-rouge">Utilities</code> → <code class="language-plaintext highlighter-rouge">Terminal</code> from the menu bar when you’ve reached Recovery Mode.</p>

<h4 id="unlock-your-disk-if-necessary">Unlock your disk if necessary</h4>

<p>If your primary drive is encrypted using FileVault (it should be), unlock it first by running the following command:</p>

<p><code class="language-plaintext highlighter-rouge">diskutil apfs unlock "Macintosh HD"</code></p>

<p><em>(Again, adjust the command if your disk isn’t called “Macintosh HD”.)</em></p>

<p>Enter your passphrase when it asks for it.</p>

<h3 id="run-the-script">Run the script</h3>

<p>You can now run the script you created earlier:</p>

<p><code class="language-plaintext highlighter-rouge">sh "/Volumes/Machintosh HD/tmp/fixfusion.sh"</code></p>

<p>It’s supposed to not show any output. If there’s no error, it worked.</p>

<h3 id="reboot">Reboot</h3>

<p>Check <code class="language-plaintext highlighter-rouge">System Preferences</code> → <code class="language-plaintext highlighter-rouge">Security &amp; Privacy</code> → <code class="language-plaintext highlighter-rouge">Privacy</code> → <code class="language-plaintext highlighter-rouge">Screen Recording</code> and you’ll notice VMWare Fusion has the permission it needs.</p>

<p><img src="/assets/blog/vmware-permission.png" alt="A screenshot of System Preferences showing permission for VMWare Fusion to record the screen" /></p>

<p>That’s it. Your virtual machines should properly work again. 🥳</p>]]></content><author><name></name></author><category term="virtualization" /><summary type="html"><![CDATA[Here's how to run VMWare Fusion 10 and 11 on macOS Catalina.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Migrating away from DevMate: redirecting Sparkle updates</title><link href="https://posts.boy.sh/migrating-away-from-devmate-sparkle" rel="alternate" type="text/html" title="Migrating away from DevMate: redirecting Sparkle updates" /><published>2019-09-13T00:00:00+00:00</published><updated>2019-09-13T00:00:00+00:00</updated><id>https://posts.boy.sh/migrating-away-from-devmate-sparkle</id><content type="html" xml:base="https://posts.boy.sh/migrating-away-from-devmate-sparkle"><![CDATA[<p><em>Originally appeared on <a href="https://www.dangercove.com/news/migrating-away-from-devmate-sparkle/">dangercove.com</a></em></p>

<p>DevMate is the service I use to gather download and install statistics for most of my apps. It also serves the update feeds for all non-Mac App Store apps. Earlier this year <a href="https://announcement.devmate.com">DevMate announced its retiring the platform</a> in December.</p>

<p><img src="/assets/blog/devmate-dashboard.jpg" alt="A screenshot of my DevMate dashboard, showing about 50 downloads and 30 installs for Timeless in the past 30 days and 100 downloads and 60 installs for Pipvid" /></p>

<p>In this post I’ll outline how I’m preparing my apps to migrate to a new update feed. Christian Tietze mentions <a href="https://christiantietze.de/posts/2019/09/devmate-feed-redirect/">asking DevMate to point the Sparkle update feed to a new location</a>. He also recommends to not rely on DevMate’s redirect to work forever. That’s where my approach comes in.</p>

<p>I urge you to take control over the feed URL entirely and redirect it yourself. <a href="https://github.com/DevMate/DevMateKit">DevMateKit</a> uses <a href="https://sparkle-project.org">Sparkle</a> under the hood. This means a custom update URL can be specified by implementing a Sparkle delegate method.</p>

<h3 id="setting-the-url">Setting the URL</h3>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">ApplicationCoordinator</span><span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt">Coordinator</span> <span class="p">{</span>

  <span class="o">...</span>
  
  <span class="kd">private</span> <span class="kd">func</span> <span class="nf">configureUpdates</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">DM_SUUpdater</span><span class="o">.</span><span class="nf">shared</span><span class="p">()</span><span class="o">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="k">self</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">ApplicationCoordinator</span><span class="p">:</span> <span class="kt">DM_SUUpdaterDelegate_DevMateInteraction</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">feedURLString</span><span class="p">(</span><span class="k">for</span> <span class="nv">updater</span><span class="p">:</span> <span class="kt">DM_SUUpdater</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">String</span><span class="p">?</span> <span class="p">{</span>
        <span class="k">if</span> <span class="kt">Defaults</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="nf">isEnabled</span><span class="p">(</span><span class="nv">setting</span><span class="p">:</span> <span class="o">.</span><span class="n">betaUpdates</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="o">.</span><span class="n">appcastBetaURLString</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="o">.</span><span class="n">appcastURLString</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">String</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">let</span> <span class="nv">appcastURLString</span> <span class="o">=</span> <span class="s">"https://updates.dangr.co/</span><span class="se">\(</span><span class="kt">Bundle</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="n">bundleIdentifier</span><span class="o">!</span><span class="se">)</span><span class="s">/appcast.xml"</span>
    <span class="kd">static</span> <span class="k">let</span> <span class="nv">appcastBetaURLString</span> <span class="o">=</span> <span class="s">"https://updates.dangr.co/</span><span class="se">\(</span><span class="kt">Bundle</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="n">bundleIdentifier</span><span class="o">!</span><span class="se">)</span><span class="s">/beta-appcast.xml"</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After this change <a href="/timeless">Timeless</a> will check for updates at:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://updates.dangr.co/com.dangercove.Timeless.Mac/appcast.xml
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">updates.dangr.co</code> domain is mine and I can set redirects for it however I want.</p>

<h3 id="redirecting">Redirecting</h3>

<p>I use <a href="https://www.netlify.com">Netlify</a> to handle <a href="https://github.com/DangerCove/updates.dangr.co/blob/master/_redirects">the redirects</a>. Here’s what that looks like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>com.dangercove.Timeless.Mac/appcast.xml*      https://updates.devmate.com/com.dangercove.Timeless.Mac.xml:splat       301
com.dangercove.Timeless.Mac/beta-appcast.xml* https://updates.devmate.com/beta/com.dangercove.Timeless.Mac.xml:splat  301
</code></pre></div></div>

<p>As you can see I currently redirect to the feed at DevMate, but I can redirect it anywhere else whenever I want. This allows me to use DevMate for as long as possible and switch to any other service that uses Sparkle. I’m keeping a close eye on <a href="https://appcenter.ms">App Center by Microsoft</a>. They put Sparkle feeds for macOS on <a href="https://github.com/microsoft/appcenter/issues/202">the roadmap for September</a>.</p>]]></content><author><name></name></author><category term="xcode" /><category term="infrastructure" /><summary type="html"><![CDATA[DevMate will retire its service in December, so I setup redirects for my Sparkle update feeds.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fix “mapped file has no Team ID and is not a platform binary” in Xcode 11</title><link href="https://posts.boy.sh/fix-mapped-file-has-no-team-id-xcode" rel="alternate" type="text/html" title="Fix “mapped file has no Team ID and is not a platform binary” in Xcode 11" /><published>2019-09-11T00:00:00+00:00</published><updated>2019-09-11T00:00:00+00:00</updated><id>https://posts.boy.sh/fix-mapped-file-has-no-team-id-xcode</id><content type="html" xml:base="https://posts.boy.sh/fix-mapped-file-has-no-team-id-xcode"><![CDATA[<p>After applying the preferred project settings in Xcode 11 you might be confronted with the following error while loading a Library at runtime:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dyld: Library not loaded: @rpath/DCOAboutWindow.framework/Versions/A/DCOAboutWindow
  Referenced from: /Users/username/Library/Developer/Xcode/DerivedData/Pipvid-adwfbkaurzovizgaarwkmugeihce/Build/Products/Debug/Pipvid.app/Contents/MacOS/Pipvid
  Reason: no suitable image found.  Did find:
	/Users/username/Library/Developer/Xcode/DerivedData/Pipvid-adwfbkaurzovizgaarwkmugeihce/Build/Products/Debug/Pipvid.app/Contents/MacOS/../Frameworks/DCOAboutWindow.framework/Versions/A/DCOAboutWindow: code signature in (/Users/username/Library/Developer/Xcode/DerivedData/Pipvid-adwfbkaurzovizgaarwkmugeihce/Build/Products/Debug/Pipvid.app/Contents/MacOS/../Frameworks/DCOAboutWindow.framework/Versions/A/DCOAboutWindow) not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?)
</code></pre></div></div>

<p>The issue is caused by a new entry in your <code class="language-plaintext highlighter-rouge">project.pbxproj</code> that specifies the signing identity: <code class="language-plaintext highlighter-rouge">CODE_SIGN_IDENTITY = "-";</code>. It’s set to <em>Sign to Run Locally</em> by default.</p>

<p>Changing <em>Signing Certificate</em> to <em>Development</em> under <em>Signing Capabilities</em> in the project settings resolves the issue. You could also manually update the entry to <code class="language-plaintext highlighter-rouge">CODE_SIGN_IDENTITY = "Apple Development";</code>.</p>

<p><img src="/assets/blog/xcode-fix-mapped-file-has-no-team.jpg" alt="A screenshot showing that you should set 'Signing Certificate' to 'Development'" /></p>]]></content><author><name></name></author><category term="xcode" /><summary type="html"><![CDATA[A quick fix for when you receive an error after applying the Xcode 11 GM's preferred settings.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Related content with Jekyll and other Liquid tricks</title><link href="https://posts.boy.sh/implementing-the-homepage-and-news-redesigns" rel="alternate" type="text/html" title="Related content with Jekyll and other Liquid tricks" /><published>2019-09-05T00:00:00+00:00</published><updated>2019-09-05T00:00:00+00:00</updated><id>https://posts.boy.sh/implementing-the-homepage-and-news-redesigns</id><content type="html" xml:base="https://posts.boy.sh/implementing-the-homepage-and-news-redesigns"><![CDATA[<p><em>This article originally appeared on <a href="https://www.dangercove.com/news/implementing-the-homepage-and-news-redesigns/">dangercove.com</a></em></p>

<p><a href="https://www.dangercove.com/news/updated-homepage-and-news-overview/">As promised</a>, in this second part of the website redesign story I’ll go over the technical details of the changes I made to <a href="https://www.dangercove.com">dangercove.com</a>.</p>

<h3 id="stack--frameworks">Stack &amp; frameworks</h3>

<p>To get a sense of how the website’s built, here’s an overview of what I use to layout and serve its content.</p>

<ul>
  <li><a href="https://jekyllrb.com">Jekyll</a></li>
  <li><a href="https://bulma.io">Bulma</a></li>
  <li><a href="https://www.netlify.com">Netlify</a></li>
</ul>

<p>It’s a simple setup. The entire site is statically generated by Jekyll and then served by Netlify. Bulma is a CSS framework that allows me to style templates quickly.</p>

<h3 id="homepage">Homepage</h3>

<p>Let’s take a look at the homepage first. The list of apps is generated by including the <code class="language-plaintext highlighter-rouge">app/overview.html</code> template and assigning it a set of <em>apps pages</em>.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">live</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">pages</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">where</span><span class="p">:</span><span class="w"> </span><span class="s1">'layout'</span><span class="p">,</span><span class="w"> </span><span class="s1">'app/live'</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">announced</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">pages</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">where</span><span class="p">:</span><span class="w"> </span><span class="s1">'layout'</span><span class="p">,</span><span class="w"> </span><span class="s1">'app/announced'</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">apps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">announced</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">concat</span><span class="p">:</span><span class="w"> </span><span class="nv">live</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>app/overview.html<span class="w"> </span><span class="na">apps</span><span class="o">=</span><span class="nv">apps</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>

<p>I fetch the <em>apps</em> to display by querying <code class="language-plaintext highlighter-rouge">site.pages</code> for pages that use the <code class="language-plaintext highlighter-rouge">app/live</code> and <code class="language-plaintext highlighter-rouge">app/announced</code> layout. Then I concatenate both arrays into a single <code class="language-plaintext highlighter-rouge">apps</code> variable and pass that to the includable <code class="language-plaintext highlighter-rouge">app/overview.html</code> template.</p>

<p><img src="/assets/blog/dangercove-homepage-2019-box.png" alt="A screenshot of the homepage after the changes. It shows a compact row of boxes that represent all the apps." /></p>

<h4 id="overview-template">Overview template</h4>

<p>The <a href="https://github.com/DangerCove/dangercove.com/blob/master/_includes/app/overview.html"><code class="language-plaintext highlighter-rouge">app/overview.html</code></a> template checks if it’s on the homepage (<code class="language-plaintext highlighter-rouge">if page.layout == "home"</code>) and adds the Danger Cove logo accordingly.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
<span class="p">{%</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">layout</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"home"</span><span class="w"> </span><span class="p">%}</span>
&lt;div class="column is-4-widescreen is-half-desktop is-full-tablet is-full-mobile"&gt;
  &lt;div class="box is-shadowless has-text-centered"&gt;
    <span class="p">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>logo/retro.html<span class="w"> </span><span class="p">%}</span>
    &lt;h1 class="title is-size-2-mobile is-1 is-spaced"&gt;<span class="p">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="p">}}</span>&lt;/h1&gt;
    &lt;h2 class="subtitle is-size-5-mobile is-4"&gt;<span class="p">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">subtitle</span><span class="w"> </span><span class="p">}}</span>&lt;/h2&gt;
  &lt;/div&gt;
&lt;/div&gt;
<span class="p">{%</span><span class="w"> </span><span class="kr">endif</span><span class="w"> </span><span class="p">%}</span>
...
</code></pre></div></div>

<p>Then it loops over the provided <em>apps</em> and includes <code class="language-plaintext highlighter-rouge">app/introduction.html</code> for each. This is the actual visual representation of the app, in the form of a  <em>card</em>. Pulling it out into a separate include makes it trivial to display the <em>app card</em> anywhere else. I’ll use it again when showing related apps with blog posts. More on that a little further down.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
<span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">app</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">apps</span><span class="w"> </span><span class="p">%}</span>
&lt;div class="column is-4-widescreen is-half-desktop is-full-tablet is-full-mobile"&gt;
  <span class="p">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>app/introduction.html<span class="w"> </span><span class="na">app</span><span class="o">=</span><span class="nv">app</span><span class="w"> </span><span class="p">%}</span>
&lt;/div&gt;
<span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
...
</code></pre></div></div>

<p>Notice the convenient column CSS classes that Bulma provides. It’s trivial to scale the layout from mobile to widescreen devices.</p>

<h4 id="front-matter">Front matter</h4>

<p>The <a href="https://github.com/DangerCove/dangercove.com/blob/master/_includes/app/introduction.html"><code class="language-plaintext highlighter-rouge">app/introduction.html</code></a> template pulls the <em>title</em>, <em>subtitle</em>, <em>description</em> and <em>colors</em> from the app’s <a href="https://jekyllrb.com/docs/front-matter/"><em>front matter</em></a>. This is what the <em>front matter</em> for <a href="https://www.usetimeless.app">Timeless</a> looks like:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">layout</span><span class="pi">:</span> <span class="s">app/announced</span>
<span class="na">site_title</span><span class="pi">:</span> <span class="s">Don't get distracted by time</span>
<span class="na">title</span><span class="pi">:</span> <span class="s">Timeless</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s">Reduce time anxiety</span>
<span class="na">description</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">Get a more subtle sense of what time it is. Reducing time pressure and distraction.</span>
<span class="na">date</span><span class="pi">:</span> <span class="s">2018-07-18</span>
<span class="na">icon</span><span class="pi">:</span> <span class="s">timeless-clock_512.png</span>
<span class="na">hero</span><span class="pi">:</span> 
  <span class="na">icon</span><span class="pi">:</span> <span class="s">timeless-clock_512.png</span>
  <span class="na">dominant_color</span><span class="pi">:</span> 
    <span class="na">r</span><span class="pi">:</span> <span class="m">200</span>
    <span class="na">g</span><span class="pi">:</span> <span class="m">200</span>
    <span class="na">b</span><span class="pi">:</span> <span class="m">200</span>
<span class="na">features</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">Specify several, customizable 'time segments'.</span>
  <span class="pi">-</span> <span class="s">Indicates the current segment in the menu bar.</span>
  <span class="pi">-</span> <span class="s">Display the actual time and date with a single click.</span>
<span class="na">tags</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">macOS</span>
  <span class="pi">-</span> <span class="s">Productivity</span>
<span class="na">topic</span><span class="pi">:</span> <span class="s">timeless</span>
<span class="na">mailchimp</span><span class="pi">:</span> 
  <span class="na">interests</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">2</span><span class="pi">]</span>
<span class="na">permalink</span><span class="pi">:</span> <span class="s">/timeless/</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>Every <em>card</em> shows a specific rainbow of colors in its bottom right corner. Storing this information in the page’s <em>front matter</em> allows me to pull it out in the template and apply per-app design details.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">app</span><span class="p">.</span><span class="nv">hero</span><span class="p">.</span><span class="nv">dominant_color</span><span class="w"> </span><span class="p">%}</span>
&lt;div class="box" style="background-image: linear-gradient(135deg,
transparent 80%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.25) 80%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.25) 85%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.5) 85%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.5) 90%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.75) 90%,
rgba(<span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">r</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">g</span><span class="w"> </span><span class="p">}}</span>, <span class="p">{{</span><span class="w"> </span><span class="nv">color</span><span class="p">.</span><span class="nv">b</span><span class="w"> </span><span class="p">}}</span>, 0.75) 95%,
transparent 95%)
;"&gt;
...
</code></pre></div></div>

<p>It’s hard to get around using <code class="language-plaintext highlighter-rouge">style=""</code> for this loop. On the app’s landing pages I apply the colors to <a href="https://github.com/DangerCove/dangercove.com/blob/master/_includes/base/head.html#L22">a generic CSS class</a> that I can use in the template.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
{% if page.hero.dominant_color %}
{% assign color = page.hero.dominant_color %}
<span class="nt">&lt;style&gt;</span>
  <span class="nc">.hero-app</span> <span class="p">{</span>
    <span class="nl">background</span><span class="p">:</span> <span class="n">linear-gradient</span><span class="p">(</span><span class="m">35deg</span><span class="p">,</span>
    <span class="nb">transparent</span> <span class="m">60%</span><span class="p">,</span>
    <span class="n">rgba</span><span class="p">(</span><span class="err">{{</span> <span class="n">color</span><span class="p">.</span><span class="n">r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">0</span><span class="o">.</span><span class="err">25</span><span class="o">)</span> <span class="err">60</span><span class="o">%,</span>
    <span class="nt">rgba</span><span class="o">(</span><span class="p">{</span><span class="err">{</span> <span class="err">color.r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">0</span><span class="o">.</span><span class="err">25</span><span class="o">)</span> <span class="err">70</span><span class="o">%,</span>
    <span class="nt">rgba</span><span class="o">(</span><span class="p">{</span><span class="err">{</span> <span class="err">color.r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">0</span><span class="o">.</span><span class="err">5</span><span class="o">)</span> <span class="err">70</span><span class="o">%,</span>
    <span class="nt">rgba</span><span class="o">(</span><span class="p">{</span><span class="err">{</span> <span class="err">color.r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">0</span><span class="o">.</span><span class="err">5</span><span class="o">)</span> <span class="err">80</span><span class="o">%,</span>
    <span class="nt">rgba</span><span class="o">(</span><span class="p">{</span><span class="err">{</span> <span class="err">color.r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">1</span><span class="o">)</span> <span class="err">80</span><span class="o">%,</span>
    <span class="nt">rgba</span><span class="o">(</span><span class="p">{</span><span class="err">{</span> <span class="err">color.r</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.g</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="p">{</span><span class="err">{</span> <span class="err">color.b</span> <span class="p">}</span><span class="err">}</span><span class="o">,</span> <span class="err">1</span><span class="o">)</span> <span class="err">90</span><span class="o">%,</span>
    <span class="nt">transparent</span> <span class="err">90</span><span class="o">%);</span>
  <span class="err">}</span>
<span class="o">...</span>
</code></pre></div></div>

<p>Setting <code class="language-plaintext highlighter-rouge">class="hero-app"</code> atomatically applies the rainbow background for each app.</p>

<h3 id="news-overview">News overview</h3>

<p>Before:
<img src="/assets/blog/dangercove-news-overview-2019-old.png" alt="A screenshot of the news overview before the changes. It showed an endless list of post titles." />
After:
<img src="/assets/blog/dangercove-news-overview-2019-full-post.png" alt="A screenshot of the news overview after the changes. It's a paginated list of full articles. Ready to read." /></p>

<h4 id="pagination">Pagination</h4>

<p>Loading all posts on the <code class="language-plaintext highlighter-rouge">/news</code> page would be madness. The first step I took was to implement the <code class="language-plaintext highlighter-rouge">jekyll-paginate-v2</code> plugin:</p>

<ol>
  <li>Add <code class="language-plaintext highlighter-rouge">gem "jekyll-paginate-v2"</code> to <code class="language-plaintext highlighter-rouge">Gemfile</code>:
    <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">group</span> <span class="ss">:jekyll_plugins</span> <span class="k">do</span>
   <span class="o">...</span>
   <span class="n">gem</span> <span class="s2">"jekyll-paginate-v2"</span>
 <span class="k">end</span>
</code></pre></div>    </div>
  </li>
  <li>Activate the plugin in <code class="language-plaintext highlighter-rouge">_config.yml</code>:
    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">plugins</span><span class="pi">:</span>
   <span class="s">...</span>
    <span class="s">- jekyll-paginate-v2</span>
      
 <span class="na">pagination</span><span class="pi">:</span>
   <span class="na">enabled</span><span class="pi">:</span> <span class="no">true</span>
   <span class="na">sort_reverse</span><span class="pi">:</span> <span class="no">true</span> <span class="c1"># Required in my setup to order posts from new to old </span>
   <span class="na">permalink</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/page/:num/"</span>
</code></pre></div>    </div>
  </li>
  <li>Add pagination settings to the <code class="language-plaintext highlighter-rouge">news.markdown</code> <em>front matter</em>:
    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="s">---</span>
 <span class="s">...</span>
 <span class="s">pagination</span><span class="err">:</span>
   <span class="na">enabled</span><span class="pi">:</span> <span class="no">true</span>
   <span class="na">per_page</span><span class="pi">:</span> <span class="m">5</span>
<span class="err"> </span><span class="s">---</span>
</code></pre></div>    </div>
  </li>
</ol>

<p>The pagination plugin is ready to be implemented in <a href="https://github.com/DangerCove/dangercove.com/blob/master/_layouts/news/home.html"><code class="language-plaintext highlighter-rouge">_layouts/news/home.html</code></a> at this point. It comes down to two things:</p>

<ol>
  <li>Replacing <code class="language-plaintext highlighter-rouge">{% for post in site.posts %}</code> with <code class="language-plaintext highlighter-rouge">{% for post in paginator.posts %}</code> in the template.</li>
  <li>Including <a href="https://github.com/DangerCove/dangercove.com/blob/master/_includes/post/pagination.html">the paginator controls</a> somewhere on the page.</li>
</ol>

<h3 id="full-post-content">Full post content</h3>

<p>I updated <a href="https://github.com/DangerCove/dangercove.com/blob/master/_includes/post/preview.html"><code class="language-plaintext highlighter-rouge">_includes/post/preview.html</code></a> to show the entire post instead of just a preview. That’s it.</p>

<h3 id="related-apps">Related apps</h3>

<p><img src="/assets/blog/dangercove-related-app-2019.png" alt="A screenshot of the Timeless 'card' shown under an article about Timeless." /></p>

<p>This new feature uses some <em>front matter</em> magic to allow me to pull in related content with a blog post. Consider the <code class="language-plaintext highlighter-rouge">_includes/post/related.html</code> template:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">tags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">include</span><span class="p">.</span><span class="nv">tags</span><span class="w"> </span><span class="p">%}</span>

<span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">tags</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">app</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">pages</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">where</span><span class="p">:</span><span class="w"> </span><span class="s1">'topic'</span><span class="p">,</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">first</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="kr">if</span><span class="w"> </span><span class="nv">app</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>app/introduction.html<span class="w"> </span><span class="na">app</span><span class="o">=</span><span class="nv">app</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="kr">endif</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>

<p>Usage: <code class="language-plaintext highlighter-rouge">{% include post/related.html tags=post.tags %}</code></p>

<p>It loops through all tags assigned to a post and then searches <code class="language-plaintext highlighter-rouge">site.pages</code> for a page that has a <code class="language-plaintext highlighter-rouge">topic</code> that matches the <code class="language-plaintext highlighter-rouge">tag</code>.</p>

<p>Imagine I write a post about Timeless and tag it like this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="nn">...</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">updates</span><span class="pi">,</span> <span class="nv">timeless</span><span class="pi">]</span>
<span class="nn">...</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>If you look in the <em>front matter</em> for Timeless above, you’ll notice its topic:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="nn">...</span>
<span class="na">topic</span><span class="pi">:</span> <span class="s">timeless</span>
<span class="nn">...</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">app</code> variable gets assigned and the <code class="language-plaintext highlighter-rouge">app/introduction.html</code> <em>card</em> template gets included. If the tags include multiple apps, each is shown.</p>

<h3 id="open-source">Open-source</h3>

<p>The full source code for dangercove.com is <a href="https://github.com/DangerCove/dangercove.com">available on GitHub</a>. For a comprehensive list of all changes made for this redesign, take a look at this <em>diff</em>: <a href="https://github.com/DangerCove/dangercove.com/compare/3493aae..4518428">3493aae..4518428</a></p>

<p>I hope you enjoyed this in-depth look at how I keep dangercove.com up-to-date. If you have any feedback, questions or comments <a href="https://www.twitter.com/boyvanamstel">let me know on Twitter</a>.</p>]]></content><author><name></name></author><category term="jekyll" /><category term="liquid" /><category term="bulma" /><summary type="html"><![CDATA[An in-depth look at implementing some design changes for dangercove.com. Involves Jekyll templating and Bulma CSS updates.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fake GBA carts</title><link href="https://posts.boy.sh/fake-gba-carts" rel="alternate" type="text/html" title="Fake GBA carts" /><published>2019-08-07T00:00:00+00:00</published><updated>2019-08-07T00:00:00+00:00</updated><id>https://posts.boy.sh/fake-gba-carts</id><content type="html" xml:base="https://posts.boy.sh/fake-gba-carts"><![CDATA[<p>I’m selling all my Game Boy Advance carts. While taking pictures I noticed two cartridges looking a little off. The logos on both Metroid Fusion (AGB-AMTP-EUR) and Final Fantasy VI Advance (AGB-BZ6P-EUR) seemed fuzzy.</p>

<p><img src="/assets/blog/metroid-fusion-front.jpeg" alt="A picture of Metroid Fusion for GBA showing that the logo on the cart is fuzzy" />
<img src="/assets/blog/metroid-fusion-fuzzy.jpeg" alt="A close-up picture of Metroid Fusion for GBA showing that the logo on the cart is fuzzy" />
<img src="/assets/blog/ff6-fuzzy.jpeg" alt="A close-up picture of Final Fantasy VI for GBA showing that the logo on the cart is fuzzy" /></p>

<p>That’s not a good sign and I decided to open them up and take a look at the circuit boards.</p>

<p>Here’s a picture of an authentic, Nintendo manufactured circuit board for Golden Sun (AGB-AGSP-EUR). It looks neat, tidy and well put together.</p>

<p><img src="/assets/blog/goldensun-print.jpeg" alt="A close-up picture of the circuit board of Golden Sun for GBA showing that it's authentic" /></p>

<p>The contrast with the boards below is striking.</p>

<p><img src="/assets/blog/metroid-fusion-print.jpeg" alt="A close-up picture of the circuit board of Metroid Fusion for GBA showing that it's fake" /></p>

<p>This is the inside of the Metroid Fusion cart. The board is dirty, the fonts and logos are incorrect, there’s even a label on one of the chips (it says something about a ‘North Star’).</p>

<p><img src="/assets/blog/ff6-print.jpeg" alt="A close-up picture of the circuit board of Final Fantasy VI Advance for GBA showing that it's fake" /></p>

<p>The Final Fantasy VI Advance cart is less dramatic, but a reproduction nonetheless. The Nintendo logo looks awful.</p>

<p>I haven’t decided what I’ll do with these. Either I’ll throw them out, or I’ll drop them off at the local thrift store. Trashing them means somebody else won’t be able to buy (or sell) them anymore.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’m selling all my Game Boy Advance carts. While taking pictures I noticed two cartridges looking a little off. The logos on both Metroid Fusion (AGB-AMTP-EUR) and Final Fantasy VI Advance (AGB-BZ6P-EUR) seemed fuzzy.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Distracted by time</title><link href="https://posts.boy.sh/distracted-by-time" rel="alternate" type="text/html" title="Distracted by time" /><published>2019-07-18T07:00:00+00:00</published><updated>2019-07-18T07:00:00+00:00</updated><id>https://posts.boy.sh/distracted-by-time</id><content type="html" xml:base="https://posts.boy.sh/distracted-by-time"><![CDATA[<p>It’s widely accepted that there exists a state of mind that allows you to perform exceptionally. Most people call it ‘the zone’ or ‘flow’. Achieving it helps you to get things done almost effortlessly. It’s fragile though; a single distraction can break it.</p>

<p>The clock is one of those distractions for me:</p>

<ul>
  <li>10.00 – Only 10 am?? It feels like I’ve been doing nothing for ages.</li>
  <li>11.30 – Better not start something new because it’ll be lunch time soon.</li>
  <li>14.00 - Sheesh this day is never going to end…</li>
  <li>16.00 – It’s already 4 pm?? I did nothing today and it’s too late to start now.</li>
</ul>

<p>This gets worse when I have appointments throughout the day. The example is a bit extreme, but you catch my drift.</p>

<h3 id="hiding-time">Hiding time</h3>
<p>As an experiment, I removed every time indicator from my screen six months ago. The effects are noticeable: I can just sit, work and not care about how the day is progressing. This lack of attachment in turn makes it easier to lose myself in what I’m doing, thus comfortably achieving more.</p>

<p>There are downsides: it also stops me from getting up and do basic things like drink water or getting some fresh air. I work from home and if I’m not careful I skip lunch and scramble to make something for diner because I forgot to buy groceries.</p>

<h3 id="notifications">Notifications</h3>
<p>Notifications help with this. My calendar and reminders pop up every now and then so I don’t forget anything important. I could start wearing my Apple Watch again to remind me to get up, set additional reminders to help me take proper care of myself and do mundane tasks during the day.</p>

<p>That’s a bit much, I think. It would make me feel like a robot.</p>

<h3 id="timeless">Timeless</h3>
<p>I’m working on a more natural way of getting the most out of my day: it’s an app called Timeless. At its core it gives me a generic sense of what part of the day I’m in: morning, lunch time, noon etc.</p>

<p>Instead of breaking concentration or induce stress it lets me continue working when I’m still in the time range I’m expecting to get stuff done. Then, in a glance, it lets me know that I’ve entered a new part of the day. If it’s between 12pm and 2pm I should probably get lunch.</p>

<p>There’s no notification to ‘get lunch now’, just a hint that when I’m ready I should probably go grab something to eat.</p>

<p>Even when combined with more urgent interruptions, like water breaks, it allows me to comfortably get back to work. I don’t feel any pressure or hesitance because of how much time I have left in the day.</p>

<h3 id="beta-sign-up">Beta sign-up</h3>
<p>I’m getting ready to let others give this a go as well. If you’d like to be invited to try the beta, <a href="https://www.dangercove.com/timeless">subscribe to the mailing list</a>. Thanks!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[It’s widely accepted that there exists a state of mind that allows you to perform exceptionally. Most people call it ‘the zone’ or ‘flow’. Achieving it helps you to get things done almost effortlessly. It’s fragile though; a single distraction can break it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://posts.boy.sh/assets/img/avatar.jpg" /><media:content medium="image" url="https://posts.boy.sh/assets/img/avatar.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>