<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Daniel Parker</title><link>https://danpker.com/posts/</link><description>Recent content in Posts on Daniel Parker</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><lastBuildDate>Mon, 22 Feb 2021 22:41:37 +0000</lastBuildDate><atom:link href="https://danpker.com/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Tmuxinator</title><link>https://danpker.com/posts/tmuxinator/</link><pubDate>Mon, 22 Feb 2021 22:41:37 +0000</pubDate><guid>https://danpker.com/posts/tmuxinator/</guid><description>&lt;p&gt;I wanted to share a tool I use daily, that does what does so well that I sometimes even forget that it&amp;rsquo;s there.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/tmuxinator/tmuxinator"&gt;Tmuxinator&lt;/a&gt; is a wrapper around Tmux that lets you create and manage sessions really easily.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that you have a project that you want to open in Tmux and you have two windows, one window contains a full screen editor and the other window is vertically split with logs on one side and a shell on the other. The traditional way to do this is to either do it manually or create a shell script that will run those manual steps for you in order.&lt;/p&gt;
&lt;p&gt;Tmuxinator makes this much more simple by handling creation for you from a Yaml config file. Here&amp;rsquo;s a config based on the example above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;project&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;~/project&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;even-vertical&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;panes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;tail -f log/development.log&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- {}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(A default config is created when you run &lt;code&gt;tmux new [project_name]&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;This creates a named session called &lt;code&gt;project&lt;/code&gt; with two windows, named &lt;code&gt;editor&lt;/code&gt; and &lt;code&gt;output&lt;/code&gt;. The &lt;code&gt;editor&lt;/code&gt; window runs &lt;code&gt;vim&lt;/code&gt; whilst the &lt;code&gt;output&lt;/code&gt; window uses the &lt;code&gt;even-vertical&lt;/code&gt; layout to display a pane tailing logs and another pane in which no commands are ran.&lt;/p&gt;
&lt;p&gt;To create the session and start working, you run &lt;code&gt;mux project&lt;/code&gt;. That&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;In addition, future invocations of &lt;code&gt;mux project&lt;/code&gt; will attach to the open session, rather than creating a new one. This even works when you are already in another Tmux session (it just changes which session you are attached to).&lt;/p&gt;
&lt;p&gt;I mainly use this to set up Tmux sessions for each work related project I am working on and switch between them (the &lt;code&gt;mux stop [project_name]&lt;/code&gt; works well to kill any sessions you&amp;rsquo;re not working on anymore).&lt;/p&gt;</description></item><item><title>Remembering everything with Anki</title><link>https://danpker.com/posts/remember-everything-with-anki/</link><pubDate>Tue, 09 Feb 2021 22:00:00 +0000</pubDate><guid>https://danpker.com/posts/remember-everything-with-anki/</guid><description>&lt;p&gt;When I read an interesting book or article, I always struggle to remember the things I&amp;rsquo;m learning. For example, I&amp;rsquo;m currently reading &lt;a href="https://realpython.com/products/cpython-internals-book/"&gt;cPython Internals&lt;/a&gt; and there a lot of information in this book to process.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a myriad of different approaches to this problem; note-taking, reading twice, summarising and more. But these have never worked. They may help understanding in the short term, but what about in a year, two years? Will I remember what I have learnt then?&lt;/p&gt;
&lt;p&gt;One of the applications I use almost every single day is &lt;a href="https://apps.ankiweb.net"&gt;Anki&lt;/a&gt;. Anki is a solution to this dilemma which, at its surface, is just a flash card application. But it is so much more than that.&lt;/p&gt;
&lt;p&gt;Anki relies on &lt;a href="https://en.wikipedia.org/wiki/Spaced_repetition"&gt;Spaced repetition&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Active_recall"&gt;Active recall&lt;/a&gt; to do all of the heavy lifting. Both of which are backed by scientific research and I won&amp;rsquo;t try and explain them in too much detail (there are many better places that it&amp;rsquo;s been done), but I will explain their basic concepts.&lt;/p&gt;
&lt;h2 id="spaced-repetition"&gt;Spaced Repetition&lt;/h2&gt;
&lt;p&gt;Over time, we forget stuff. The rate at which we forget stuff is based on how many times we have reviewed those things in the past. For example, if fact A days 10 days to forget, but we review fact A on day 5, then it will then take 15 days to forget fact A.&lt;/p&gt;
&lt;p&gt;This makes sense, if we&amp;rsquo;re constantly reminded of something, then we are far less likely to forget it. However, the key with Spaced repetition is timing &lt;em&gt;when&lt;/em&gt; you review something. Going back to fact A, if we were to review it on day 9, right before we forget it, then you can be more efficient about how much time you spend reminding yourself of stuff. This gives you more time to learn new things!&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/ForgettingCurve.svg"&gt;&lt;figcaption&gt;
&lt;h4&gt;The Forgetting Curve&lt;/h4&gt;&lt;p&gt;
&lt;a href="https://commons.wikimedia.org/wiki/File:ForgettingCurve.svg"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="active-recall"&gt;Active Recall&lt;/h2&gt;
&lt;p&gt;Again, better resources for learning about Active recall exist, but put simply it is the idea &lt;em&gt;actively recalling&lt;/em&gt; information is better than passively reviewing it.&lt;/p&gt;
&lt;p&gt;For example, answering questions from a prompt requires you to actively think about the subject and then recall the correct answer. Reading notes about the same thing just requires you to passively process that same information. The former is a much better way at making information &amp;lsquo;stick&amp;rsquo;.&lt;/p&gt;
&lt;h2 id="how-anki-fits-in"&gt;How Anki fits in&lt;/h2&gt;
&lt;p&gt;Anki allows you to create flash cards. Flash cards promote &lt;em&gt;Active recall&lt;/em&gt; by providing you with a prompt and you need to recall the information that is on the other side of the card. It then uses a form of the &lt;a href="https://www.supermemo.com/en/archives1990-2015/english/ol/sm2"&gt;SM2 Algorithm&lt;/a&gt; to schedule when you review cards; based on previous performance, when you last reviewed them and the number of times you&amp;rsquo;ve reviewed that card in the past.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/anki-cards.png"&gt;&lt;figcaption&gt;
&lt;h4&gt;Front and back card example&lt;/h4&gt;&lt;p&gt;
&lt;a href="https://ankiweb.net/shared/info/490209917"&gt;Periodic table memory pegs deck&lt;/a&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;All in all, I use Anki to create a set of cards for nearly every non-fiction book I read. It can be a challenging process, as you need to understand the subject you are trying to work on really well in order to create understandable cards. However, this works as an indirect benefit as you can&amp;rsquo;t just gloss over things you don&amp;rsquo;t fully get.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s certainly helped me retain a lot more of what I&amp;rsquo;ve been learning, so much so that I use it every single day to create and review the cards i&amp;rsquo;ve created.&lt;/p&gt;</description></item><item><title>spotifyd and spotify-tui for Low Memory Usage Music</title><link>https://danpker.com/posts/spotifyd-and-spotifytui/</link><pubDate>Fri, 18 Sep 2020 18:26:55 +0100</pubDate><guid>https://danpker.com/posts/spotifyd-and-spotifytui/</guid><description>&lt;p&gt;Spotify is a great service that embodies the idea that piracy is a
&lt;a href="https://v1.escapistmagazine.com/news/view/114391-Valves-Gabe-Newell-Says-Piracy-Is-a-Service-Problem"&gt;distribution
problem&lt;/a&gt;
not a money problem. There&amp;rsquo;s just one small (or very large depending on your
viewpoint) problem.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/spotify-memory.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Like all electron or electron-like apps, Spotify carries an entire instance of
Chromium inside of it, which bloats its memory usage significantly.&lt;/p&gt;
&lt;p&gt;There is where &lt;a href="https://github.com/Spotifyd/spotifyd"&gt;&lt;code&gt;spotifyd&lt;/code&gt;&lt;/a&gt; comes in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spotifyd streams music just like the official client, but is more lightweight
and supports more platforms. Spotifyd also supports the Spotify Connect
protocol, which makes it show up as a device that can be controlled from the
official clients.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Speaking of being more lightweight usage:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/spotifyd-memory.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;Wow! Being a UNIX style daemon has its benefits over running inside a web
browser.&lt;/p&gt;
&lt;p&gt;The only real downside is the lack of a user interface. However, as it works as
a Spotify Connect device, you can use your phone to control it. Or, you can use
&lt;a href="https://github.com/Rigellute/spotify-tui"&gt;&lt;code&gt;spotify-tui&lt;/code&gt;&lt;/a&gt;. It&amp;rsquo;s basically a
terminal interface for the Spotify Web Client, except you&amp;rsquo;re able to also
connect to the &lt;code&gt;spotifyd&lt;/code&gt; daemon and you&amp;rsquo;ve got yourself a frontend for Spotify
in a really tiny amount of memory usage.&lt;/p&gt;</description></item><item><title>Creating Your Own Kindle Newspaper</title><link>https://danpker.com/posts/creating-your-own-kindle-newspaper/</link><pubDate>Sun, 06 Sep 2020 15:00:50 +0100</pubDate><guid>https://danpker.com/posts/creating-your-own-kindle-newspaper/</guid><description>&lt;p&gt;One of the interesting features of Kindle is the ability to subscribe to
newspapers or magazines and get them delivered to your Kindle when a new
issue is released. This works great for publications that are sold on the
Kindle store, but what about your subscribed RSS feeds? I wanted to see if it
was possible to create a daily &amp;rsquo;newspaper&amp;rsquo;, containing all of my RSS
aggregator&amp;rsquo;s unread articles and a weekly &amp;lsquo;magazine&amp;rsquo; of unread items I&amp;rsquo;d saved
to Pocket.&lt;/p&gt;
&lt;p&gt;Things you&amp;rsquo;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some RSS feeds to read. Either published from your own aggregator or a
collection of individual feeds.&lt;/li&gt;
&lt;li&gt;A server somewhere. You don&amp;rsquo;t need much power, a free F1-micro in Google
Cloud should do it (I am using a $5/month Linode server).&lt;/li&gt;
&lt;li&gt;Calibre, for creating the ebook.&lt;/li&gt;
&lt;li&gt;A Sendgrid account for sending emails to your Kindle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="feeds"&gt;Feeds&lt;/h2&gt;
&lt;p&gt;I have two main feeds I am using, one to build the &amp;rsquo;newspaper&amp;rsquo; and another to
build the &amp;lsquo;magazine&amp;rsquo;.&lt;/p&gt;
&lt;h3 id="newspaper"&gt;Newspaper&lt;/h3&gt;
&lt;p&gt;My FreshRSS instance publishes an aggregated feed of all of my RSS
subscriptions. This feed also allows you to use query parameters to filter what
is returned. I use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;state=2&lt;/code&gt; to only get unread articles.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get=c_n&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is a category id. To get articles from a specific
category (I use this to break the &amp;rsquo;newspaper&amp;rsquo; into different sections).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="magazine"&gt;Magazine&lt;/h3&gt;
&lt;p&gt;For the &amp;lsquo;magazine&amp;rsquo; I&amp;rsquo;m using my &lt;a href="http://getpocket.com"&gt;Pocket&lt;/a&gt; account&amp;rsquo;s RSS
feed, which contains unread items I&amp;rsquo;ve saved to Pocket. This lets me save
interesting things during the week and I can get them all together in one issue
on the weekend to read.&lt;/p&gt;
&lt;h2 id="calibre"&gt;Calibre&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://calibre-ebook.com"&gt;Calibre&lt;/a&gt; is an open source tool for managing your
ebook library. It actually has the perfect feature, the ability to download RSS
feeds and package them into an ebook. In fact, you can do everything in this
post just using Calibre and a Sendgrid account. However, you need to have
Calibre open for scheduling to work or run the full suite on a server
somewhere.&lt;/p&gt;
&lt;p&gt;Luckily, Calibre provides a bunch of command line tools that actually power
what it&amp;rsquo;s doing behind the UI. In our case, &lt;code&gt;ebook-convert&lt;/code&gt; is what we can use
to download RSS feeds and output an ebook. This tool takes a &lt;code&gt;.recipe&lt;/code&gt; file
(its a &lt;code&gt;.py&lt;/code&gt; file with a different name), handles all of the feed downloading
and parsing and packages it up into the right output format. A recipe file
looks something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyNewRecipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BasicNewsRecipe&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;feeds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;feed.com/feed.rss&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot more options you can specify, here&amp;rsquo;s some of my favourites:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Give the cover a random picture each time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cover_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://source.unsplash.com/random/600x800&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Make the title on Kindle include the date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;custom_title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Newspaper - &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt; %b %Y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Fix feeds that use UTF-8 chars&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;utf8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can find more options
&lt;a href="https://manual.calibre-ebook.com/news_recipe.html"&gt;here&lt;/a&gt;. You can get super
complicated and fancy with styling and article parsing using different function
hooks in your recipe class. Calibre also has plenty of &lt;a href="https://github.com/kovidgoyal/calibre/tree/master/recipes"&gt;built-in
recipes&lt;/a&gt; for popular
sites.&lt;/p&gt;
&lt;p&gt;Once you have your recipe file ready, you can create an ebook from it by
running the following (outputting &lt;code&gt;mobi&lt;/code&gt; here as that&amp;rsquo;s what Kindle will accept
via email):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ebook-convert myrecipe.recipe myrecipe.mobi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All you have to do is run this in a cron job whenever you want to produce a new
issue of your &amp;rsquo;newspaper&amp;rsquo; and it&amp;rsquo;s all created for you. The next step is
delivering this to your Kindle.&lt;/p&gt;
&lt;h2 id="sendgrid"&gt;Sendgrid&lt;/h2&gt;
&lt;p&gt;I chose Sendgrid for this because frankly, it was the first thing I thought of
and it lets you send 100 emails a day with a free plan. Plenty for sending
stuff to your Kindle. You could, however, use whatever email service you want.
I was limited by the fact that Linode blocks sending email by default, so the
Send Grid Web API made things a lot easier.&lt;/p&gt;
&lt;p&gt;I could probably go into a lot of detail here about how this works for me, but
at the end of the day it&amp;rsquo;s just using the &lt;a href="https://www.amazon.com/gp/sendtokindle/email"&gt;send to
Kindle&lt;/a&gt; service. I was limited by
the fact my server is on Alpine (for reasons) and Linode&amp;rsquo;s email policy so I
ended up creating a Docker image that scoops up files and emails them. If
you&amp;rsquo;re interested in this monstrosity, you can see the source
&lt;a href="https://github.com/danpker/dockerfiles/tree/master/sendgrid-emailer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="putting-it-all-together"&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;The final part is just setting up a job on your server to run the
&lt;code&gt;ebook-convert&lt;/code&gt; command and whatever email sending method you&amp;rsquo;ve chosen that
sends it out. Make sure you allow your email sender to send documents to Kindle
and you&amp;rsquo;re ready to go. The finished article(s):&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/kindle-newspaper.jpg"&gt;
&lt;/figure&gt;</description></item><item><title>Faster Bash Startup</title><link>https://danpker.com/posts/faster-bash-startup/</link><pubDate>Sun, 02 Aug 2020 09:13:19 +0100</pubDate><guid>https://danpker.com/posts/faster-bash-startup/</guid><description>&lt;p&gt;My Bash start-up time is around 1.7 seconds. This doesn&amp;rsquo;t sound like it&amp;rsquo;s too
bad, but it feels like hours when you want to open a new window to only run one
command.&lt;/p&gt;
&lt;p&gt;The first step is to run a profile of your Bash start-up, to try and find out
what exactly is taking so long.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/5014823/how-to-profile-a-bash-shell-script-slow-startup/20855353"&gt;How to profile a bash shell script slow
startup?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This should give you a timestamp against each Bash command that gets
run, which you can use to work out which ones are taking the most time.&lt;/p&gt;
&lt;p&gt;For me, there are a few things that were highlighted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Everything here will be specific to my setup (MacOS, Alacitty, Bash, Tmux) and so may and probably will differ.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I tested the difference between each change by using &lt;code&gt;hyperfine&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hyperfine &lt;span class="s1"&gt;&amp;#39;bash --login&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dynamic-paths"&gt;Dynamic paths&lt;/h3&gt;
&lt;p&gt;One of the big culprits for slowness is trying to be too clever. For example,
Homebrew has a prefix directory where it installs everything, and environment
variables that are set are set relative to this directory.&lt;/p&gt;
&lt;p&gt;For example, you might have some code that looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="k"&gt;$(&lt;/span&gt;brew --prefix&lt;span class="k"&gt;)&lt;/span&gt;/etc/bash_completion &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; . &lt;span class="k"&gt;$(&lt;/span&gt;brew --prefix&lt;span class="k"&gt;)&lt;/span&gt;/etc/bash_completion
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To allow for changing the default prefix directory, there is a command
&lt;code&gt;brew --prefix&lt;/code&gt; that will resolve to where the prefix directory is. However,
this command can be quite slow and just replacing it with a hardcoded path can
give you a decent speed up:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: bash prefix.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 289.9 ms ± 4.5 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 178.9 ms, System: 103.6 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 285.4 ms … 300.7 ms &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#2: bash no_prefix.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 236.1 ms ± 2.4 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 157.7 ms, System: 75.9 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 231.6 ms … 241.8 ms &lt;span class="m"&gt;12&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Summary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;bash no_prefix.sh&amp;#39;&lt;/span&gt; ran
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.23 ± 0.02 &lt;span class="nb"&gt;times&lt;/span&gt; faster than &lt;span class="s1"&gt;&amp;#39;bash prefix.sh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is even more significant if you have a prefix command that specifies a
particular library. E.g:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="k"&gt;$(&lt;/span&gt;brew --prefix openssl&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;OPENSSL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;brew --prefix openssl&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;OPENSSL_INCLUDE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPENSSL_PREFIX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/include&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;OPENSSL_LIB_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPENSSL_PREFIX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/lib&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, using a hard coded path has a &lt;em&gt;significant&lt;/em&gt; speed up.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: bash prefix.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 1.095 s ± 0.015 s &lt;span class="o"&gt;[&lt;/span&gt;User: 627.0 ms, System: 444.6 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 1.079 s … 1.131 s &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#2: bash no_prefix.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 3.1 ms ± 0.4 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 1.2 ms, System: 1.0 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 2.5 ms … 5.4 ms &lt;span class="m"&gt;389&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Warning: Command took less than &lt;span class="m"&gt;5&lt;/span&gt; ms to complete. Results might be inaccurate.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Summary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;bash no_prefix.sh&amp;#39;&lt;/span&gt; ran
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 358.57 ± 47.07 &lt;span class="nb"&gt;times&lt;/span&gt; faster than &lt;span class="s1"&gt;&amp;#39;bash prefix.sh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Avoid &lt;code&gt;$(give_me_a_path)&lt;/code&gt; where possible by using a hard coded path.
Especially avoid &lt;code&gt;brew --prefix &amp;lt;formula&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="bash-completions"&gt;Bash completions&lt;/h3&gt;
&lt;p&gt;The other major slow down in my Bash start-up was Bash completions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: source .profile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 208.6 ms ± 5.7 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 90.0 ms, System: 115.6 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 203.7 ms … 223.7 ms &lt;span class="m"&gt;13&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#2: source .profile &amp;amp;&amp;amp; source /usr/local/etc/bash_completion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 442.3 ms ± 3.3 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 240.2 ms, System: 198.4 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 438.1 ms … 449.2 ms &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Summary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;source .profile&amp;#39;&lt;/span&gt; ran
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.12 ± 0.06 &lt;span class="nb"&gt;times&lt;/span&gt; faster than &lt;span class="s1"&gt;&amp;#39;source .profile &amp;amp;&amp;amp; source /usr/local/etc/bash_completion&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see above, adding completions doubles the start-up time of my Bash
session. I honestly don&amp;rsquo;t know if I have ever even used them, so it was an easy
trade-off for me to make by removing them for a bit more speed. If I had used
them I would have thought more carefully about it.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Using variations on the above I&amp;rsquo;ve managed to shave quite a bit of time from my
Bash startup (ignore the name change):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: source ~/.bashrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 1.669 s ± 0.025 s &lt;span class="o"&gt;[&lt;/span&gt;User: 924.4 ms, System: 706.6 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 1.644 s … 1.728 s &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: source ~/.profile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 216.2 ms ± 5.9 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 94.2 ms, System: 119.5 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 210.2 ms … 234.0 ms &lt;span class="m"&gt;13&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I could keep tweaking in an attempt to make it even faster, but anything else at
this point is likely to suffer from diminishing returns. I mean, it has to take
&lt;em&gt;some&lt;/em&gt; time.&lt;/p&gt;</description></item><item><title>Hyperfine: Easy benchmarking</title><link>https://danpker.com/posts/hyperfine/</link><pubDate>Sat, 18 Jul 2020 23:27:38 +0100</pubDate><guid>https://danpker.com/posts/hyperfine/</guid><description>&lt;p&gt;Very often, when I want to test the performance of something, most of the time I end
up using &lt;code&gt;time&lt;/code&gt;. &lt;code&gt;time&lt;/code&gt;, however, lacks a certain amount of scientific rigor, it
only runs the thing you&amp;rsquo;re testing once and gives three different times which
can mean slightly different things in different contexts.&lt;/p&gt;
&lt;p&gt;Enter, &lt;a href="https://github.com/sharkdp/hyperfine"&gt;Hyperfine&lt;/a&gt;. Here are three things
I love about it:&lt;/p&gt;
&lt;h2 id="1-it-runs-commands-multiple-times"&gt;1. It runs commands multiple times.&lt;/h2&gt;
&lt;p&gt;This ensures that there is no random variation in your testing, it even warns
you if there are major outliers:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ hyperfine &lt;span class="s1"&gt;&amp;#39;ls&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: ls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 1.6 ms ± 0.3 ms &lt;span class="o"&gt;[&lt;/span&gt;User: 0.6 ms, System: 0.8 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 1.2 ms … 5.1 ms &lt;span class="m"&gt;516&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Warning: Command took less than &lt;span class="m"&gt;5&lt;/span&gt; ms to complete. Results might be inaccurate.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet PC without any interferences from other programs. It might &lt;span class="nb"&gt;help&lt;/span&gt; to use the &lt;span class="s1"&gt;&amp;#39;--warmup&amp;#39;&lt;/span&gt; or &lt;span class="s1"&gt;&amp;#39;--prepare&amp;#39;&lt;/span&gt; options.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2-parameters"&gt;2. Parameters&lt;/h2&gt;
&lt;p&gt;You can provide a lister of parameters (or even ranges) and they can be
substituted in, letting you see how a program scales with different variables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ hyperfine --parameter-list duration 1,2,3 &lt;span class="s1"&gt;&amp;#39;sleep {duration}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#1: sleep 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 1.009 s ± 0.001 s &lt;span class="o"&gt;[&lt;/span&gt;User: 1.0 ms, System: 1.8 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 1.006 s … 1.011 s &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#2: sleep 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 2.008 s ± 0.002 s &lt;span class="o"&gt;[&lt;/span&gt;User: 1.2 ms, System: 2.3 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 2.005 s … 2.011 s &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Benchmark &lt;span class="c1"&gt;#3: sleep 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Time &lt;span class="o"&gt;(&lt;/span&gt;mean ± σ&lt;span class="o"&gt;)&lt;/span&gt;: 3.009 s ± 0.003 s &lt;span class="o"&gt;[&lt;/span&gt;User: 1.3 ms, System: 2.4 ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Range &lt;span class="o"&gt;(&lt;/span&gt;min … max&lt;span class="o"&gt;)&lt;/span&gt;: 3.005 s … 3.012 s &lt;span class="m"&gt;10&lt;/span&gt; runs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Summary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;sleep 1&amp;#39;&lt;/span&gt; ran
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1.99 ± 0.00 &lt;span class="nb"&gt;times&lt;/span&gt; faster than &lt;span class="s1"&gt;&amp;#39;sleep 2&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2.98 ± 0.00 &lt;span class="nb"&gt;times&lt;/span&gt; faster than &lt;span class="s1"&gt;&amp;#39;sleep 3&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3-its-just-so-simple"&gt;3. It&amp;rsquo;s just so simple&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s just as easy as running &lt;code&gt;time command&lt;/code&gt;, except it is far more accurate and
repeatable, and if you want to use some more advanced features, they&amp;rsquo;re super
simple too.&lt;/p&gt;</description></item><item><title>Free RSS Aggregation</title><link>https://danpker.com/posts/free-rss-aggregator/</link><pubDate>Sun, 12 Jul 2020 17:35:32 +0100</pubDate><guid>https://danpker.com/posts/free-rss-aggregator/</guid><description>&lt;p&gt;One of the downsides to the great &lt;a href="http://reederapp.com"&gt;Reeder&lt;/a&gt; app is syncing
feeds between Desktop and Mobile. Many services offer this, but
they are almost all paid services.&lt;/p&gt;
&lt;p&gt;The free option is to use &lt;a href="https://feedly.com"&gt;Feedly&lt;/a&gt;. However, with the free
tier of Feedly, you are limited to 100 sources and 3 feeds. For normal use, this
is more than adequate, but something is limiting about there being a limit
at all&amp;hellip;&lt;/p&gt;
&lt;p&gt;This is where &lt;a href="https://tt-rss.org"&gt;Tiny Tiny RSS&lt;/a&gt; comes in. It is a free and
open-source feed reader and aggregator. When combined with the &lt;a href="https://github.com/DigitalDJ/tinytinyrss-fever-plugin"&gt;Fever API
plugin&lt;/a&gt;, it can be used
as a free hosted source of content for Reeder.&lt;/p&gt;
&lt;p&gt;To make this truly free by not paying for hosting, I am running it on
an &lt;code&gt;f1-micro&lt;/code&gt; instance in Google Cloud, part of the free tier. It is a very
small instance size, but you don&amp;rsquo;t need something powerful to just serve up
text.&lt;/p&gt;</description></item><item><title>Mutability and Containers</title><link>https://danpker.com/posts/mutability-and-containers/</link><pubDate>Sun, 08 Dec 2019 13:03:57 +0000</pubDate><guid>https://danpker.com/posts/mutability-and-containers/</guid><description>&lt;h1 id="containers"&gt;Containers&lt;/h1&gt;
&lt;p&gt;A container is an object that contains a reference to another object. A common
example would be a &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;milk&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bread&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eggs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;onions&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;milk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bread&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eggs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;onions&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4563363056&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4563363056&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, we are creating a List called &lt;code&gt;shopping_list&lt;/code&gt; and added the
&lt;code&gt;onions&lt;/code&gt; object to it. &lt;code&gt;shopping_list&lt;/code&gt; contains a reference to the &lt;code&gt;onions&lt;/code&gt;
variable. We can easily see that by checking the identity of &lt;code&gt;onions&lt;/code&gt; and the
element in the List we have just added.&lt;/p&gt;
&lt;h1 id="mutability"&gt;Mutability&lt;/h1&gt;
&lt;p&gt;An objects mutability tells us whether or not we can change its value. If it is
mutable, we can change it. If it is immutable, we cannot. An object&amp;rsquo;s mutability
comes from its type.&lt;/p&gt;
&lt;p&gt;It is important not to get an objects mutability confused with the mutability of
a variable. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4362428304&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4362428336&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, we have the object &lt;code&gt;5&lt;/code&gt; assigned to the variable &lt;code&gt;number&lt;/code&gt;. We
then increment &lt;code&gt;number&lt;/code&gt; by 1. Number objects in Python are immutable (well, you
can&amp;rsquo;t change the value of 5 to something else can you?) so what we see here is
that the result of the expression is a new object (in this case the object for
the number 6). This is then assigned to the &lt;code&gt;number&lt;/code&gt; variable. We can see this
in action by looking at the identity of the object behind the &lt;code&gt;number&lt;/code&gt; variable
before and after the expression.&lt;/p&gt;
&lt;p&gt;Other common immutable types in Python are strings, bools and tuples.&lt;/p&gt;
&lt;h2 id="mutable-containers"&gt;Mutable Containers&lt;/h2&gt;
&lt;p&gt;You might be asking what types are mutable. There are two common mutable types.
Dictionaries and Lists.&lt;/p&gt;
&lt;p&gt;A List is mutable because you can add and remove items. E.g.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4456599792&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;milk&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4456599792&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, we create the List &lt;code&gt;shopping_list&lt;/code&gt; and add &amp;ldquo;milk&amp;rdquo; to it. The
identity behind the &lt;code&gt;shopping_list&lt;/code&gt; variable doesn&amp;rsquo;t change, so we know that it
is the same object. However, we have changed its value (by adding an element to
the List) so we know it must be mutable.&lt;/p&gt;
&lt;h2 id="immutable-containers"&gt;Immutable Containers&lt;/h2&gt;
&lt;p&gt;The official documentation on the &lt;a href="https://docs.python.org/3/reference/datamodel.html"&gt;Python Data
Model&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In most cases, when we talk about the value of a container, we imply the values, not the identities of the contained objects; however, when we talk about the mutability of a container, only the identities of the immediately contained objects are implied. So, if an immutable container (like a tuple) contains a reference to a mutable object, its value changes if that mutable object is changed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What does this mean? Well, it means several things:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1. The value of a container is typically the combination of the value of the items it contains.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;milk&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;milk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;bread&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;milk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bread&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we add &amp;ldquo;bread&amp;rdquo; to the shopping list, the List&amp;rsquo;s value changes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2. A container is immutable if the collection of things it holds cannot change.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;milk&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;bread&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;shopping_list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;milk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bread&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;final_shopping_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shopping_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;final_shopping_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;eggs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ne"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tuple&amp;#39;&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;append&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A tuple is immutable, you cannot add additional items to it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;3. Normally, an immutable object&amp;rsquo;s value cannot change however, when it is a
container that holds mutable objects, its value can change.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_tuple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_tuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tuple&amp;#39;&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_tuple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;two&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A tuple that contains a number, cannot change that number. This is because the
number object is immutable, so to have a different number would mean having a
different number. Because a tuple is an immutable container, the identities it
contains cannot change. So the number cannot change.&lt;/p&gt;
&lt;p&gt;However, a List is a mutable type. We can append to the List and change its
value, and therefore the tuple&amp;rsquo;s value. The List is the same object as before,
with the same identity, so this is possible.&lt;/p&gt;</description></item><item><title>Identity Types and Values</title><link>https://danpker.com/posts/identity-types-and-values/</link><pubDate>Thu, 21 Nov 2019 20:29:57 +0000</pubDate><guid>https://danpker.com/posts/identity-types-and-values/</guid><description>&lt;p&gt;Everything in Python is an object. From an instance of a class to an attribute
of that instance and even the class itself.&lt;/p&gt;
&lt;p&gt;An Object has three basic properties that govern all of its behaviours. These
are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identity&lt;/li&gt;
&lt;li&gt;Type&lt;/li&gt;
&lt;li&gt;Value&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="identity"&gt;Identity&lt;/h2&gt;
&lt;p&gt;The identity of an object distinguishes it from other objects and will never
change. You can get the identity of an object using the &lt;code&gt;id()&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;John&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;4375513072&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also compare two variables and see if they have the same identity with
the &lt;code&gt;is&lt;/code&gt; operator.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is important to point out that a variable is different to an object (in fact
a variable is a reference to an object) so two different variables may resolve
to the same identity and therefore the same object.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;also_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;also_a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;In CPython, and object&amp;rsquo;s identity is its address in memory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="type"&gt;Type&lt;/h2&gt;
&lt;p&gt;The type of an object determines what operations it supports and also what
possible values it can hold. It can never change once an object is created.&lt;/p&gt;
&lt;p&gt;You can find the type of an object using the &lt;code&gt;type()&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nc"&gt;str&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nc"&gt;bool&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="value"&gt;Value&lt;/h2&gt;
&lt;p&gt;An object&amp;rsquo;s value may be represented differently depending on its type. For
example, the value of a string is the sequence of characters it represents,
whereas the value of a List can be the sequence of objects that it holds, as
well as the composite value of each item in the List.&lt;/p&gt;
&lt;p&gt;Whether or not an object&amp;rsquo;s value can change depends on the mutability of its
type. Note that in some situations an immutable object&amp;rsquo;s value may change if it
is a container holding mutable objects, but more on that next time.&lt;/p&gt;</description></item><item><title>Cool Things: basecs</title><link>https://danpker.com/posts/base-cs/</link><pubDate>Wed, 13 Feb 2019 17:19:17 +0000</pubDate><guid>https://danpker.com/posts/base-cs/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Cool Things is a series of intereting things, resources or projects that I&amp;rsquo;ve
found.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://medium.com/basecs"&gt;basecs&lt;/a&gt; is a great blog series by Vaidehi Joshi on
some of the Computer Science fundamentals that you might not have picked up if
you don&amp;rsquo;t have a formal education, or like me, faded from your memory.&lt;/p&gt;</description></item><item><title>Cool Things: Data Structure Visualisations</title><link>https://danpker.com/posts/data-structure-visualisations/</link><pubDate>Sun, 10 Feb 2019 16:35:35 +0000</pubDate><guid>https://danpker.com/posts/data-structure-visualisations/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Cool Things is a series of intereting things, resources or projects that I&amp;rsquo;ve
found.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html"&gt;Data Structure Visualisations&lt;/a&gt;
is a site containing a number of visualisations of data structures and
algorithms.&lt;/p&gt;
&lt;p&gt;Really cool when you&amp;rsquo;re struggling to understand how an algorithm works and
just seeing it as an animation makes everything much more clear.&lt;/p&gt;
&lt;p&gt;I wish I had the Graph Algorithms section available during my alogrithm classes
at University&amp;hellip;&lt;/p&gt;</description></item><item><title>Kindle vs iPad Revisited</title><link>https://danpker.com/posts/kindle-vs-ipad-2/</link><pubDate>Thu, 31 Jan 2019 17:50:28 +0000</pubDate><guid>https://danpker.com/posts/kindle-vs-ipad-2/</guid><description>&lt;p&gt;I was transferring old blog posts from Blogspot to Hugo a few days ago and came
across a post I wrote in 2010 about the benefits of reading an eBook on Kindle
vs the newly released iPad. Specifically the visual benefits of an eink display
over a backlit LCD.&lt;/p&gt;
&lt;p&gt;At the time I had a Kindle 2, twice the size of modern models and with a full
sized keyboard. It was a great device for reading on, before a hoard of
different options at different price points arrived.&lt;/p&gt;
&lt;p&gt;The ironic thing now though, is that I don&amp;rsquo;t use a Kindle for reading, or even
any other eReader for that mater. I use my iPhone.&lt;/p&gt;
&lt;p&gt;This sounds a bit shocking, especially when you consider the tone of my
original post! (oh the benefits of hindsight). But let&amp;rsquo;s consider a few
improvements in the screen space in the past nine years.&lt;/p&gt;
&lt;h3 id="pixel-density"&gt;Pixel Density&lt;/h3&gt;
&lt;p&gt;My iPhone 8 has a pixel density of &lt;a href="https://www.apple.com/uk/iphone-8/specs/"&gt;326PPI&lt;/a&gt;,
the original iPad had a pixel density of &lt;a href="https://support.apple.com/kb/SP580?locale=en_GB"&gt;132PPI&lt;/a&gt;.
This is nearly a 2.5x improvement. This increase in density makes words on the
screen appear much closer to print, making it clearer and a lot easiest to read.&lt;/p&gt;
&lt;h3 id="night-shift"&gt;Night Shift&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://justgetflux.com"&gt;F.lux&lt;/a&gt; was around in 2010, but not for the iPad or
iPhone. In 2016, Apple released Night Shift in iOS, which achieves much the
same thing. Night Shift makes reading on my iPhone at night a lot more bearable
and less likely to keep me awake.&lt;/p&gt;
&lt;h3 id="portability"&gt;Portability&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s just face it. I take my phone &lt;em&gt;everywhere&lt;/em&gt;. The Kindle cannot compete
with that level of portability. The level of portability where I can just take
my phone out of my pocket and read.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;These 3 things have meant that I&amp;rsquo;ve not used my Kindle in over 2 years. The
ability to open iBooks anywhere and just read. Especially in bed, where I can
turn on Night Shift, set the background to black with white text and turn the
brightness right down. The Kindle is still a great device, but the displays on
smart phones has developed to the point where I just don&amp;rsquo;t think it&amp;rsquo;s needed
anymore.&lt;/p&gt;</description></item><item><title>How Twitch Doesnt Really Have a Choice</title><link>https://danpker.com/posts/how-twitch-doesnt-really-have-a-choice/</link><pubDate>Wed, 13 Aug 2014 08:01:43 +0000</pubDate><guid>https://danpker.com/posts/how-twitch-doesnt-really-have-a-choice/</guid><description>&lt;p&gt;5 days ago Twitch, the popular streaming platform for games, delivered the following bombshell.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Starting today, Twitch will be implementing technology intended to help broadcasters avoid the storage of videos containing unauthorized third-party audio. We respect the rights of copyright owners, and are voluntarily undertaking this effort to help protect both our broadcasters and copyright owners.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This caused a predictable outrage as it emerged that large numbers of VODs were now muted, even those that had permission to use the offending music. It was even the case that some of Twitch’s own videos had also had section muted. Some blamed Google (despite the lack of an official announcement that Twitch had been bought by Google), while others lamented and predicted the sharp decline in the number of Twitch viewers in the near future.&lt;/p&gt;
&lt;p&gt;Firstly, Twitch has made a gigantic mess of this. Suddenly springing a huge change to the service, with no warning to it’s user base. Then, releasing it with what seemed like very little testing (I mentioned some of the official Twitch videos were muted). False positives everywhere for music that’s in the public domain, music that was licensed to be broadcast and even the arbitrary decision to muted 30 minute blocks at a time.&lt;/p&gt;
&lt;p&gt;This doesn&amp;rsquo;t however, remove the fact that Twitch really has no choice to remove copyrighted music.&lt;/p&gt;
&lt;p&gt;A huge number of streamers on Twitch stream copyrighted music, either knowingly or accidentally. In turn these get made into VODs which can be played on demand (hence the acronym). Do you see why this may easily become a legal problem for Twitch?&lt;/p&gt;
&lt;p&gt;The only alternative is the one they have implemented, automatically scanning and pattern matching copyrighted material. Hiring enough people to listen to them all manually just isn&amp;rsquo;t cost effective, even then, how do they know if a piece of audio is copyrighted? A program that can match stuff is probably the only way.&lt;/p&gt;
&lt;p&gt;What can Twitch do? It’s really a no win situation. Until someone makes a content matching system that actually works, or copyright law is changed, Twitch is stuck with a sub par solution.&lt;/p&gt;</description></item><item><title>History of Ancient Egypt in an Audiobook</title><link>https://danpker.com/posts/history-of-ancient-egypt-in-an-audiobook/</link><pubDate>Tue, 12 Aug 2014 07:58:54 +0000</pubDate><guid>https://danpker.com/posts/history-of-ancient-egypt-in-an-audiobook/</guid><description>&lt;p&gt;What would you do if you lived for 3000 years? If someone sat down and wrote a biography of your life, how long would it be? Now take that and apply it to an entire civilisation. That should give you a rough image of how much history there is for Ancient Egypt.&lt;/p&gt;
&lt;p&gt;Preferring to listen to something in audio format, I went in search of an audiobook that would allow me to learn more about this vast period of history. On Audible I quickly came across The History of Ancient Egypt by the Teaching Company and narrated by Bob Brier, a well known Egyptologist.&lt;/p&gt;
&lt;p&gt;The history of Ancient Egypt is such a vast topic that it can be very difficult to get a concise overview. Now, 24 hours isn’t exactly short, but when you consider that that on average, the pace is about 125 years an hour, it doesn’t seem so long after all.&lt;/p&gt;
&lt;p&gt;Bob Brier does a spectacular job at keeping you hooked for the full length of the audiobook; his speaking skill, expert knowledge and pure passion for Egypt makes the entire listen extremely entertaining. The course (that’s how it’s structured, as a course) takes you through the history of Egypt in chronological fashion, from nomads in the desert, to the death of Cleopatra and the end of 3000 years of fascinating history. There’s a few stops along the way, including an almost unbelievable part on Bob Brier’s own experience attempting to mummify an actual human cadaver in the Ancient Egyptian style.&lt;/p&gt;
&lt;p&gt;My personal favourite section is the history of the Rosetta Stone and Napoleon’s expedition in Egypt, a wonderful example of interlocking history, one of the main reasons for my love of history. Essentially, Napoleon a naval battle in Egypt called the Battle of the Nile and so spends a large amount of time in Egypt finding many artefacts including the Rosetta Stone. The British take position of the stone in a peace deal, but not before the French make rubbings that are eventually translated by Jean-François Champollion. It’s truly a story that could not have been created as fiction.&lt;/p&gt;
&lt;p&gt;Audiobooks are fantastic for your daily commute or to listen to whilst drifting off to sleep. If you have any interest in Egypt at all, the History of Egypt is a spectacular listen.&lt;/p&gt;</description></item><item><title>Is this the worst game ever made?</title><link>https://danpker.com/posts/worst-game-ever-made/</link><pubDate>Mon, 13 Feb 2012 21:03:07 +0000</pubDate><guid>https://danpker.com/posts/worst-game-ever-made/</guid><description>&lt;p&gt;Back in the rose-tinted days of the 1990&amp;rsquo;s, when the sun was always shining and flowers blomed all year round, I had a Super Nintendo Entertainment System, probably more commonly known as a SNES. Some of the best games of all time were on this system; Super Mario World, Earthbound, Chrono Trigger, and many, many more.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/virtual-soccer-title.jpg"&gt;&lt;figcaption&gt;
&lt;h4&gt;It&amp;#39;s soccer, but virtual.&lt;/h4&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It&amp;rsquo;s soccer, but virtual
I remember playing this one game, one that I played quite a lot, Virtual Soccer. As the name implies, it&amp;rsquo;s a football game, but one like no other. In a traditional football game, the gameplay attempts to emulate the play of a game of football. You can pass, shoot, tackle and run with the ball, just as if you were playing a real game.&lt;/p&gt;
&lt;p&gt;Virtual Soccer has the basics, but they&amp;rsquo;re so disjointed and awkward that the only thing reminding you that you&amp;rsquo;re playing football is the hypnotically green pitch.&lt;/p&gt;
&lt;p&gt;Tackling is form of gambling, with it being apparently a 50% chance that the tackle will fail, ending in a horrible skid and the player being on the ground for several seconds. If you do make a successful tackle, don&amp;rsquo;t think it&amp;rsquo;s over yet, as most of the time your player runs into the player they just tackled, losing the ball again with a curious grunting sound.&lt;/p&gt;
&lt;p&gt;Passing isn&amp;rsquo;t much better, mostly due to the fact that the speed of a passed ball is a lot slower than a running player. Meaning that most passes end up behind their target and are usually lost entirely. Shooting the ball can only be done in 8 different directions, which makes hitting the net a real pain.&lt;/p&gt;
&lt;p&gt;By far the worst part of the game is the AI. Lets start first with your own team, who have a habit of running between the player you&amp;rsquo;re controlling and the goal you&amp;rsquo;re trying to shoot at. For some reason they don&amp;rsquo;t like to &amp;lsquo;activate&amp;rsquo; (become controllable) until the ball is so close that it&amp;rsquo;s too late to do anything with it, contributing to the extraordinary amount of lost passes.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://danpker.com/virtual-soccer-game.jpg"&gt;
&lt;/figure&gt;
&lt;p&gt;The opposition AI is a true wonder. A mixture of stupidly fast reaction times and inhuman precision makes any set piece an instant turnover as they seem to be able to run at your player and tackle before you can even take the freekick. Goalkeepers will stop anything that comes towards them, regardless of which direction they are facing, meaning that if you want to score, you have to drag them away from the net be going close, then shoot around them. A feat, which due to the 8 directions you can shoot, is only possible from 2 locations on the pitch.&lt;/p&gt;
&lt;p&gt;Despite all of these game breaking problems, I can&amp;rsquo;t seem to stop playing. Maybe it&amp;rsquo;s the sadist in me, maybe it&amp;rsquo;s the amazing feeling whenever something impossible like scoring a goal happens. All I know is that this game is awful, yet, forget FIFA, I&amp;rsquo;d rather play this.&lt;/p&gt;</description></item><item><title>Computers and Languages</title><link>https://danpker.com/posts/computers-and-languages/</link><pubDate>Mon, 28 Mar 2011 23:28:12 +0000</pubDate><guid>https://danpker.com/posts/computers-and-languages/</guid><description>&lt;p&gt;So, I&amp;rsquo;m trying to learn French. What better way to pick up certain keywords and phrases than a trial-by-fire? That is, setting my computer&amp;rsquo;s settings (something I use pretty much all the time) to French and then trying to get through my normal, everyday life forced to practice French.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m gonna break this post down into two sections; webpages and programs, and it will hopefully provide some insight into how well, and how commonly used software handles a change in language.&lt;/p&gt;
&lt;h2 id="web-pages"&gt;Web Pages&lt;/h2&gt;
&lt;h3 id="twitter"&gt;Twitter&lt;/h3&gt;
&lt;p&gt;Possibly one of the easiest sites to change language on, it&amp;rsquo;s a simple option in your user preferences page, and while there&amp;rsquo;s nothing really special with the way Twitter handles this change, most of the key words on a page appear in French proving an opportunity to learn some new words. Specific Twitter terms, for example, &amp;ldquo;Retweet&amp;rdquo; are still in English, but is there even a French word for that? Again, nothing flashy, but it gets the job done.&lt;/p&gt;
&lt;h3 id="facebook"&gt;Facebook&lt;/h3&gt;
&lt;p&gt;Although Facebook has come under fire for many of it&amp;rsquo;s user experience and design choices over the past few years, one area in which I think they completely nailed it is languages. Translation on Facebook is done by the users, this means that nearly everything is crowd sourced and fully translated to a great deal of accuracy, even down to the phrases, such as, &amp;ldquo;Afficher mon sexe sur mon profil&amp;rdquo; (Show gender on my profile). Quotes on walls are done correctly as well, and whilst adding your interests, search is done in French.&lt;/p&gt;
&lt;p&gt;Overall, Facebook has really pulled out all the stops, and it makes sense. As a social networking site, language plays a big part.&lt;/p&gt;
&lt;h2 id="applicationsoperating-systems"&gt;Applications/Operating Systems&lt;/h2&gt;
&lt;h3 id="osx"&gt;OSX&lt;/h3&gt;
&lt;p&gt;Changing language on OSX can&amp;rsquo;t really get much simpler, you just move French to a higher priority than English, restart and you&amp;rsquo;re done. As well as the standard keyword and phrase translations for the OS , default applications (iLife, Finder, Preview, etc) are fully translated, so are folder names in your home directory. After that, it really comes down to each application. Chrome will automatically change to French and so will other programs, such as Adium, Spotify and Gimp. Some of the programs that I found either didn&amp;rsquo;t support French or didn&amp;rsquo;t automatically switch are; Office 2011 and Twitter for Mac.&lt;/p&gt;
&lt;p&gt;One area that OSX seems to be lacking, for some reason, is day and month names. Both iCal and the top bar use English names for days and names.&lt;/p&gt;
&lt;h3 id="windows-7"&gt;Windows 7&lt;/h3&gt;
&lt;p&gt;Unfortunately, I haven&amp;rsquo;t been able to test using French on Windows. It comes down to not being able to change the language unless you have Ultimate (I have professional). I do, however, hope to get a copy of Windows 7 in French in order to see what it&amp;rsquo;s like and how it does.&lt;/p&gt;
&lt;h3 id="steam"&gt;Steam&lt;/h3&gt;
&lt;p&gt;Possibly one of the best programs for the polyglot gamer. Altering your language on Steam not only changes the applications language, but checks if any of your games support French. If so, it automatically downloads the correct language pack with zero hassle at all. I haven&amp;rsquo;t had much chance to test the games that do support French, but I do know that Left 4 Dead 2 does (very well in fact) and so does Mass Effect 1 and 2.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I still have a number of programs and sites to change language on, but so far my experience has been pretty good. Sometimes I get lost and have to look something up (which leads to me actually learning something!) and sometimes I am driven by almost a muscle reflex, showing how much of an applications UI we actually read once we are familiar with it.&lt;/p&gt;
&lt;p&gt;I still want to try out Windows 7 in French, and when I have access to my Linux machine again, I am definitely going to try that one out and I will also be switching the language on my phone soon too. Until then, I continue learning French, one word at a time.&lt;/p&gt;</description></item><item><title>Off to the Uk Finals</title><link>https://danpker.com/posts/off-to-the-uk-finals/</link><pubDate>Thu, 10 Mar 2011 16:00:50 +0000</pubDate><guid>https://danpker.com/posts/off-to-the-uk-finals/</guid><description>&lt;p&gt;A little delayed (it has been a very busy few weeks) but still important announcement from Inspiratech: We have advanced to the UK final!&lt;/p&gt;
&lt;p&gt;If you are unfamiliar with the format for the Imagine Cup, entrants who advanced to the second round had to produce a video showcasing their project. If you haven&amp;rsquo;t see our video go watch it now on our website: RefuCate Video &lt;code&gt;(sadly now a dead link)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;So what happens now? At the UK final there will be 6 different teams showing off their idea and project, each with a 30 minute timeslot to have their presentation, answer questions, etc. We&amp;rsquo;re really looking forward to having the opportunity to show our idea to the world and also to see what other great ideas that other teams have come up with.&lt;/p&gt;</description></item><item><title>New Year</title><link>https://danpker.com/posts/new-year/</link><pubDate>Wed, 05 Jan 2011 22:40:10 +0000</pubDate><guid>https://danpker.com/posts/new-year/</guid><description>&lt;p&gt;So it&amp;rsquo;s a brand new year, I&amp;rsquo;m still getting used to seeing and writing 2011 instead of 2010 - a mistake i&amp;rsquo;ll probably still be making in August.&lt;/p&gt;
&lt;p&gt;Twenty-eleven is certainly going to be an exciting year, what with the Imagine Cup set to take up a large portion of my time in the first half of the year and not forgetting the Facebook Hacker Cup kicking off this Friday (2011-01-07).&lt;/p&gt;
&lt;p&gt;Other than programming competitions, I want to try and learn a bit more Python this year, as i&amp;rsquo;m finding it an amazing language to use (although i&amp;rsquo;m going through the lambda overuse phase at the moment). I&amp;rsquo;m currently using it for coursework in an Algorithms class and the language is so malleable and straight forward that writing code is almost as easy as thinking about what you want your code to do. It&amp;rsquo;s definitely more fun than Ruby (don&amp;rsquo;t hit me), easier than C and not a pain like JAVA.&lt;/p&gt;
&lt;p&gt;Another one of my my big goals this year is also about languages, but not programming ones. I know a fair bit of French already, but I want to build at lot more on this. First off, I have bought a verb book, as French has more tenses than stars, and there&amp;rsquo;s about a thousand different ways to say each verb depending on it&amp;rsquo;s use, all of which has led me to be pretty bad at them. Secondly I want to listen to more French radio. I tried this last year, but I only kept up with a couple of words, my basic goal is to try and understand a few phrases and maybe even more. My ultimate goal, however is to try and get into watching French TV and to try and have some conversations in French, no matter how bad I am at speaking in it under pressure.&lt;/p&gt;
&lt;p&gt;In order to measure success for 2011, here is a list of goals. I hope to try and add to them, as well as tick them off as the year goes on!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compete in the Facebook Hacker Cup (hopefully win a t-shirt!)&lt;/li&gt;
&lt;li&gt;Reach the UK finals in the Imagine Cup (hopefully win and go to the finals!)&lt;/li&gt;
&lt;li&gt;Learn more French&lt;/li&gt;
&lt;li&gt;Specifically, understand French radio&lt;/li&gt;
&lt;li&gt;Watch French TV&lt;/li&gt;
&lt;li&gt;Have lots of French conversations&lt;/li&gt;
&lt;li&gt;Find lots more goals to achieve&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh and, Happy New Year!&lt;/p&gt;</description></item><item><title>The Theory of Computer Science</title><link>https://danpker.com/posts/the-theory-of-computer-science/</link><pubDate>Wed, 29 Dec 2010 11:56:09 +0000</pubDate><guid>https://danpker.com/posts/the-theory-of-computer-science/</guid><description>&lt;p&gt;Lots of people think Computer Science is all about programming. A degree where you get shipped off to University and only learn how to write software, or even worse, how to use a computer.&lt;/p&gt;
&lt;p&gt;As per the excellent book, The Structure and Interpretation of Computer Programs, Computer Science is neither about computers or a science. It&amp;rsquo;s a way of talking about process and the way of doing things rather than talking about what it is.&lt;/p&gt;
&lt;p&gt;For example, the standard, declarative way to explain a square root would be to say that it is a number that, if multiplied by it&amp;rsquo;s self, the result would be your original number. While this tells us how to check if we have a square number or not, it doesn&amp;rsquo;t tell us how to find the square root of a number. It doesn&amp;rsquo;t provide us with a simple to follow series of steps that result in the correct answer.&lt;/p&gt;
&lt;p&gt;And so, while programming is something I deeply enjoy the more I delve into the theory side of things, the more I become fascinated by trees, graphs, logic, algorithms. The list goes on and on.&lt;/p&gt;</description></item><item><title>Facebook Hacker Cup</title><link>https://danpker.com/posts/facebook-hacker-cup/</link><pubDate>Wed, 15 Dec 2010 12:02:58 +0000</pubDate><guid>https://danpker.com/posts/facebook-hacker-cup/</guid><description>&lt;p&gt;It seems that the most popular way to find new talent these days is to run some sort of competition, Microsoft have the Imagine Cup, Google have the Google Code Jam, not to mention TopCoder. Now Facebook is joining the game (although technically they were already in it with Facebook Puzzles) with the Facebook Hacker Cup.&lt;/p&gt;
&lt;p&gt;Despite some of the hilarious and misinformed comments on the competitions page, this competition isn&amp;rsquo;t actually about breaking into websites and making off with all their datas. No, it&amp;rsquo;s actually going to be a series of algorithmic challenges solvable in a number of different languages. (If you want a great overview of the word &amp;ldquo;hacker&amp;rdquo; and it&amp;rsquo;s different meanings there&amp;rsquo;s a great essay by Paul Graham on the subject: &lt;a href="http://www.paulgraham.com/gba.html"&gt;Link&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There are a number of rounds with the last 300 getting a t-shirt and the final 25 being flown to California for the final, with cash prizes for the top 3. I will be participating, so why don&amp;rsquo;t you? Registration starts on the 20th December and the first round is in January.&lt;/p&gt;</description></item><item><title>Road to the Imagine Cup: Update</title><link>https://danpker.com/posts/road-to-the-imagine-cup-update/</link><pubDate>Sat, 11 Dec 2010 23:52:09 +0000</pubDate><guid>https://danpker.com/posts/road-to-the-imagine-cup-update/</guid><description>&lt;p&gt;Roughly 3 months ago I blogged about the creation of our Imagine Cup team; Inspiratech. We&amp;rsquo;ve come along way since those lovely, warm and well lit days of autumn as we find ourselves on the relaxing side of the First Round submission. For practically the first time in student history a project was completed on time, 2 days in advance in fact.&lt;/p&gt;
&lt;p&gt;So what are Inspiratech up to now you ask? Well, we&amp;rsquo;re eagerly awaiting the results for this first round, mentioned on the ukic10 website as the 12th December (which is tomorrow as I write this!), whilst enjoying a little down time as we prepare to start more coding work, as for the Second Round deadline we&amp;rsquo;ll need to create a video walkthrough of RefuCate so far. This is of course, if we make it through.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates soonish, hopefully with the results of our First Round submission!&lt;/p&gt;</description></item><item><title>Refucate</title><link>https://danpker.com/posts/refucate/</link><pubDate>Tue, 23 Nov 2010 11:36:59 +0000</pubDate><guid>https://danpker.com/posts/refucate/</guid><description>&lt;p&gt;Progress on RefuCate is coming along nicely, with our first submission a mere 2 weeks away, it&amp;rsquo;s all starting to come together now. Although we all have University deadlines and commitments to adhere to, our Functional Specification is nearing completion and i&amp;rsquo;m confident that it&amp;rsquo;s going to be great and give us the base we need to build an amazing solution!&lt;/p&gt;
&lt;p&gt;The key challenge for us at this stage is to make sure we incorporate all the functionality we need whilst not overdoing it, how many products have you seen that have had too many features? Solving this problem is no trivial task, we want to make sure enough information is collected so that people can be identified and reunited. On the other hand, there are time constraints, legal issues, performance and other issues which prevent us from taking a &amp;lsquo;bottomless pit&amp;rsquo; approach. Getting the balance right with the right amount of information and features is going to be crucial to our success. Remember, we&amp;rsquo;re not building a database - we&amp;rsquo;re connecting people.&lt;/p&gt;</description></item><item><title>Inspiratech is live!</title><link>https://danpker.com/posts/inspiratech-live/</link><pubDate>Mon, 01 Nov 2010 20:35:42 +0000</pubDate><guid>https://danpker.com/posts/inspiratech-live/</guid><description>&lt;p&gt;After weeks of toiling in front of a hot monitor, Josh has finished the Inspiratech website!&lt;/p&gt;
&lt;p&gt;Link &lt;code&gt;(sadly i'm now a dead link)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Still here? No, seriously, go check it out, it&amp;rsquo;s awesome: Link &lt;code&gt;(also dead)&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Noat</title><link>https://danpker.com/posts/noat/</link><pubDate>Thu, 07 Oct 2010 20:46:00 +0000</pubDate><guid>https://danpker.com/posts/noat/</guid><description>&lt;p&gt;I&amp;rsquo;m currently working on a small project for WP7, in order to help familiarise myself with the tool set in preparation for the Imagine Cup. So I thought I&amp;rsquo;d post a video of it, let me know what you think!&lt;/p&gt;
&lt;p&gt;noat.avi &lt;code&gt;(sadly now a dead link)&lt;/code&gt;&lt;/p&gt;</description></item><item><title>A Microsoft Tech Day</title><link>https://danpker.com/posts/microsoft-tech-day/</link><pubDate>Thu, 07 Oct 2010 20:30:04 +0000</pubDate><guid>https://danpker.com/posts/microsoft-tech-day/</guid><description>&lt;p&gt;First of all I would like to thank Microsoft for inviting me to what was a truly awesome event!&lt;/p&gt;
&lt;p&gt;The Microsoft UK Tech Days Special was a one off event showcasing some of Microsoft&amp;rsquo;s new toys, to a developer audience this was a little like Christmas day when you were a kid, except your rich aunt is Microsoft and that Power Ranger action figure who&amp;rsquo;s head can flip inside it&amp;rsquo;s body - is technology.&lt;/p&gt;
&lt;p&gt;Suffice to say that it was really amazing - and I haven&amp;rsquo;t mentioned Steve Ballmer yet.&lt;/p&gt;
&lt;h1 id="the-keynote"&gt;The Keynote&lt;/h1&gt;
&lt;p&gt;Probably the most anticipated talk of the day.&lt;/p&gt;
&lt;p&gt;Actually, that&amp;rsquo;s a bit of an understatement. If you live under a rock or Smurf Village and have no idea why seeing Steve Ballmer delivering a keynote would be exciting to a room full of geeks, please watch the following video: Link&lt;/p&gt;
&lt;p&gt;Now, Steve didn&amp;rsquo;t go that crazy, but he defiantly wasn&amp;rsquo;t a boring speaker either. He talked about this being an exciting time for software developers and how there is more opportunity now than there has ever been before, especially with exciting new cloud, phone and internet technologies.&lt;/p&gt;
&lt;p&gt;Steve didn&amp;rsquo;t reveal much secrets regarding the future, but he did say that Windows Phone 7 is two weeks away and that slate devices with Windows 7 are on their way.&lt;/p&gt;
&lt;p&gt;After the keynote, the day moved on to four, 45 minute sessions (called Deep Dives). These went much more into depth regarding what Steve Ballmer touched on during his presentation. The four talks were on; Azure, Windows Phone 7, IE9 and Windows 7. A lot of content was covered in these sessions, and will be the subject of later blogs. For now, however, I leave you with more Steve Ballmer and a well known friend of his.&lt;/p&gt;</description></item><item><title>Microsoft Tech Days Prologue</title><link>https://danpker.com/posts/microsoft-tech-days-prologue/</link><pubDate>Tue, 05 Oct 2010 07:05:32 +0000</pubDate><guid>https://danpker.com/posts/microsoft-tech-days-prologue/</guid><description>&lt;p&gt;Today Microsoft are running a very special event in London and I am very please to have the opportunity to attend!&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s going to happen? Well there are five different sessions planned throughout the day, based around WP7, IE9, Windows 7, Windows Azure and a keynote speech by Steve Ballmer himself.&lt;/p&gt;
&lt;p&gt;Look out for my tweets and others during the event on the hashtag; #ukdevdays and look out for more blog posts about what happend during the day.&lt;/p&gt;</description></item><item><title>Ruby Koans</title><link>https://danpker.com/posts/ruby-koans/</link><pubDate>Thu, 23 Sep 2010 23:13:43 +0000</pubDate><guid>https://danpker.com/posts/ruby-koans/</guid><description>&lt;p&gt;I&amp;rsquo;m trying out one of the more impressive ways to learn a new language - Ruby Koans&lt;/p&gt;
&lt;p&gt;The basic idea is to learn a language by doing, not by reading or blindly following tutorials. You follow a &amp;ldquo;path of enlightenment&amp;rdquo; adding bits of code in order to progress to the next little test. One of the advantages of this method is that there are no large chunks of text to read, you learn everything you need to by doing it yourself, a far more rewarding and permanent way of learning.&lt;/p&gt;
&lt;p&gt;Not only do you learn how to code in Ruby, you also learn the culture, TDD and some library features and of course, a little bit of humour. All this adds up to a really fun and worthwhile way to learn Ruby.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in learning Ruby then I really do recommend Koans, it&amp;rsquo;s easy to setup (if you have Ruby installed it&amp;rsquo;s as simple as &amp;lsquo;ruby path_to_enlightenment.rb&amp;rsquo;) and definitely far better than a simple tutorial.&lt;/p&gt;</description></item><item><title>Heroku - magic easy deployment</title><link>https://danpker.com/posts/heroku/</link><pubDate>Sun, 19 Sep 2010 01:15:21 +0000</pubDate><guid>https://danpker.com/posts/heroku/</guid><description>&lt;p&gt;Ever wanted to easy test your shiny new Rails app on a real web server? Well there&amp;rsquo;s a really simple way - Heroku&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Git for your source control (which you should be if you aren&amp;rsquo;t) then deploying your app to the internet couldn&amp;rsquo;t be any easier. The first step is to sign up for an account over at &lt;a href="http://heroku.com/"&gt;http://heroku.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The next step is to get the Heroku gem, easily done with :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;gem install heroku
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: you may or may not have to use sudo&lt;/p&gt;
&lt;p&gt;Next you need to tell Heroku your ssh public key (if you don&amp;rsquo;t have one, Google it, it&amp;rsquo;s simple to get one) in order to verify your identity, this is done like so:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;heroku keys:add
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You&amp;rsquo;ll have to login with your username and password, but once it&amp;rsquo;s done, the rest is simple&lt;/p&gt;
&lt;p&gt;In order to deploy run the following commands inside your apps directory :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;heroku create
git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&amp;rsquo;s it! All done. Admire your work by opening your app in the browser :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;heroku open
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Road to the Imagine Cup</title><link>https://danpker.com/posts/road-to-the-imagine-cup/</link><pubDate>Thu, 09 Sep 2010 20:13:41 +0000</pubDate><guid>https://danpker.com/posts/road-to-the-imagine-cup/</guid><description>&lt;p&gt;Each year Microsoft runs a competition called the Imagine Cup, the world&amp;rsquo;s largest student technology competition. Thousands of students around the world participate in the competition each year and it produces some truly amazing projects aimed at solving some of the worlds toughest problems. Because of this I am thrilled to be part of a team for this year&amp;rsquo;s competition.&lt;/p&gt;
&lt;p&gt;The team: &lt;strong&gt;Inspiratech&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Inspiratech consists of myself, Ian Field and Josh Homerston. We&amp;rsquo;re planning an ambitious and very exciting project with the aim of helping charities use technology to solve some very tough challenges. We&amp;rsquo;re an extremely passionate group of people and although we don&amp;rsquo;t even have a logo yet and are only in the basic planning stages, our project is already looking really good. Some of the technology we are planning to use is cutting edge (and not fully released either!) and out of this world, making it much easier to imagine a world where technology solves the world&amp;rsquo;s toughest problems.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s going to be an extremely fun and rewarding road, hopefully ending at the world finals in July. I look forward to talking more about our project and my experiences in the future!&lt;/p&gt;</description></item><item><title>Swarmation</title><link>https://danpker.com/posts/swarmation/</link><pubDate>Tue, 31 Aug 2010 23:22:06 +0000</pubDate><guid>https://danpker.com/posts/swarmation/</guid><description>&lt;p&gt;One of the highlights of Node Knockout (which by the way, had some really amazing entries - and there&amp;rsquo;s still time to vote) is Swarmation.
Essentially, you are a pixel and along with other pixels you have to get into different patterns in order to score points. But here&amp;rsquo;s the twist - the other pixels aren&amp;rsquo;t computer controlled, they&amp;rsquo;re real people.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s no communication at all, meaning a successful pattern really does feel like an achievement. In one game a fellow pixel got trapped inside a box we were making meaning someone had to move out of the way to let him out - risking his spot in the successful formation.&lt;/p&gt;
&lt;p&gt;Points of course, are the main point of the game, harder patterns reward more points, and have more generous time limits to complete them.&lt;/p&gt;
&lt;p&gt;Swarmation really is a fun game to play and you quickly find yourself screaming at little pixels to move out the way in order for you to receive your points. It&amp;rsquo;s not perfect, there are some issues with detecting some patterns but I really recommend you try it - just don&amp;rsquo;t get too addicted like me.&lt;/p&gt;</description></item><item><title>Kindle vs iPad</title><link>https://danpker.com/posts/kindle-vs-ipad/</link><pubDate>Thu, 17 Jun 2010 12:47:46 +0000</pubDate><guid>https://danpker.com/posts/kindle-vs-ipad/</guid><description>&lt;p&gt;I hate this argument. I really do.&lt;/p&gt;
&lt;p&gt;When the iPad was first announced, there was a huge rush to compare it to the Kindle, and a huge rush to say how much better the iPad is. Apps this, colour screen that. Completely neglecting of course, that the Kindle isn’t actually a tablet.&lt;/p&gt;
&lt;p&gt;Comparing the iPad to the Kindle is a little bit like comparing an MP3 player with a Laptop. Your shiny new iPad can in fact, browse the internet in colour, rendering every page perfectly and in good time. It is also rumoured that the iPad has a touch screen. Why would anyone want a Kindle and not an iPad you ask? The answer is really, really simple; the iPad cannot do eBooks. Oh yes it’s got iBooks, and thousands of eBooks on the iBookstore; but reading on an iPad is like reading from, well, your computer screen.&lt;/p&gt;
&lt;p&gt;Glare from your computer screen can cause all sorts of problems. The most annoying of which is eye strain; this can be really painful sometimes can cause headaches. Not exactly something that goes along well with a good book. But it doesn’t end there; your iPad, with it’s headache inducing backlight, can also ruin your sleep. Your computer screen and iPad are designed to have the same temperature of the Sun. This doesn’t mean your face melts every time you check for email; it means that, during the day, displays have the same colours as the world outside - nice and bright. During the night however, the colours around you get warmer, while your computer screen stays like the Sun. Anyone who does a lot of travelling can tell you what happens next.&lt;/p&gt;
&lt;p&gt;With all this knowledge, why would anyone want to read for long periods of time from, what is essentially, a huge light? Why would you want to reawaken yourself while you read Winnie the Pooh from your iPad?&lt;/p&gt;
&lt;p&gt;If you want an internet device, something to check email or to play games; by all means, get an iPad. But if you want to read an eBook, please, please get a Kindle, your eyes and brain will love you. Maybe if you are super rich, you could get both? Because they are two very different devices; admittedly with some overlap, but the Kindle does one thing very well, and the iPad does, er, what exactly?&lt;/p&gt;
&lt;p&gt;(please ignore the Kindles web browser, this is not what the device was designed for, be happy that it’s all free anyway)&lt;/p&gt;
&lt;p&gt;(if you do value your sleep check out f.lux. It changes the colour temperature of your monitor through the day)&lt;/p&gt;</description></item><item><title>A Fun, Free Friday</title><link>https://danpker.com/posts/fun-free-friday/</link><pubDate>Mon, 14 Jun 2010 21:31:43 +0000</pubDate><guid>https://danpker.com/posts/fun-free-friday/</guid><description>&lt;p&gt;On Friday 11th June I had the privilege to attend Microsoft’s ‘Fun, Free Friday’ event; showcasing many different and free applications and how they can be used for learning. There were demos of no less than 30 products or schemes which are all available for free when used for education. The whole day was extremely fun, and it was great to see a number of new products, as well as some that I already had knowledge of.&lt;/p&gt;
&lt;p&gt;Oh, and free stuff is always a huge bonus.&lt;/p&gt;
&lt;p&gt;One of my favourite demos of the day was the Live @ edu demo, mostly because the University of Reading is switching over to this system next year; replacing ‘Prayer’ which is quite frankly, awful. In fact, next year i might actually send an email, rather than just reading them because i have to. Also, I’m really excited about calendar integration, which will make working in a team a whole lot easier.&lt;/p&gt;
&lt;p&gt;Here’s the full list of demos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bing Maps&lt;/li&gt;
&lt;li&gt;Photosynth&lt;/li&gt;
&lt;li&gt;Community Clips&lt;/li&gt;
&lt;li&gt;Worldwide Telescope&lt;/li&gt;
&lt;li&gt;Pivot&lt;/li&gt;
&lt;li&gt;DeepZoom&lt;/li&gt;
&lt;li&gt;Live @ edu&lt;/li&gt;
&lt;li&gt;SkyDrive and Live Sync&lt;/li&gt;
&lt;li&gt;Office Web Apps&lt;/li&gt;
&lt;li&gt;Windows Live Messenger&lt;/li&gt;
&lt;li&gt;Bing Translator&lt;/li&gt;
&lt;li&gt;Windows Live Writer&lt;/li&gt;
&lt;li&gt;Windows Live Photo Gallery&lt;/li&gt;
&lt;li&gt;Windows Live Movie Maker&lt;/li&gt;
&lt;li&gt;Songsmith&lt;/li&gt;
&lt;li&gt;Maths Worksheet Generator&lt;/li&gt;
&lt;li&gt;Photostory 3&lt;/li&gt;
&lt;li&gt;Office Moodle Add-In&lt;/li&gt;
&lt;li&gt;Autocollage&lt;/li&gt;
&lt;li&gt;Kodu&lt;/li&gt;
&lt;li&gt;DreamSpark&lt;/li&gt;
&lt;li&gt;Digital Literacy Curriculum&lt;/li&gt;
&lt;li&gt;Office Ribbon Hero&lt;/li&gt;
&lt;li&gt;Mouse Mischief&lt;/li&gt;
&lt;li&gt;Flashcards&lt;/li&gt;
&lt;li&gt;Internet Explorer Accelerators&lt;/li&gt;
&lt;li&gt;PPTPlex&lt;/li&gt;
&lt;li&gt;XNA Game Studio&lt;/li&gt;
&lt;li&gt;Innovids&lt;/li&gt;
&lt;li&gt;Partners in Learning Network&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Look out for some more information about the demos later this week!&lt;/p&gt;</description></item><item><title>I caved…</title><link>https://danpker.com/posts/ive-caved/</link><pubDate>Sat, 12 Jun 2010 15:02:43 +0000</pubDate><guid>https://danpker.com/posts/ive-caved/</guid><description>&lt;p&gt;So I’ve caved and I’m going to start blogging again. Look forward to an overview of the fantastic Mircosoft Fun Free Friday event as well as some Mercurial love soon. In the future, look out for details of my futile projects and my take on the latest tech news. Look out for a proper blog post soon.&lt;/p&gt;</description></item></channel></rss>