<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="https://www.w3.org/2005/Atom">
 
 <title>Mads Ravn</title>
 <link href="https://madsravn.dk/atom.xml" rel="self"/>
 <link href="https://madsravn.dk/"/>
 <updated>2025-01-06T13:42:21+01:00</updated>
 <id>http://madsravn.dk</id>
 <author>
   <name>Mads Ravn</name>
 </author>
 
 
 <entry>
   <title>2025 - My year in books</title>
   <link href="https://madsravn.dk/posts/my-year-in-books.html"/>
   <updated>2025-01-06T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/my-year-in-books</id>
   <content type="html">&lt;p&gt;Ever since I was introduced to audiobooks in 2015, I have consumed all my fiction books in audiobooks. I have still read my non-fiction books on actual paper - I am computer scientist on most of the non-fiction books that I read contain code. In 2024, I changed things up a bit. I read my first fiction book on paper. Reading on paper instead of listening to the books has also changed my reading habits. But it has been a most welcome change.&lt;/p&gt;&#xA;&lt;h1&gt;Reading on paper&lt;/h1&gt;&#xA;&lt;p&gt;Okay, I said &amp;quot;books on actual paper&amp;quot;. I lied. I bought a Kindle Paperwhite to read on. It provides faster access to the books that I want to read and in the long run it will be much cheaper to buy e-books rather than paperbacks. And I have no intention of creating a collection of books at home. I have stuff enough. &lt;/p&gt;&#xA;&lt;p&gt;It has been change, for sure. Reading, like everything else, feels like a muscle you need to train. Try reading a book for the first time in a long time and you will find your attention drifting a bit and your focus will move elsewhere. &amp;quot;You could stop now and check your phone&amp;quot;.&lt;/p&gt;&#xA;&lt;p&gt;Luckily for me, the reason I changed to paper-books instead of audiobooks was because the latest book in the series I wanted to read had not been released on audiobook yet and I was dying to read it. Book 6 of Ivan Kal&apos;s Infinite Realm series, &lt;a href=&quot;https://www.goodreads.com/book/show/214295082-the-runesmith&quot;&gt;The Runesmith&lt;/a&gt;. For me, starting with a really exciting book helped me combat the bad attention span one might have with a first book. And then moving on the next book was a breeze. &lt;/p&gt;&#xA;&lt;h1&gt;Changing reading habits&lt;/h1&gt;&#xA;&lt;p&gt;Being an avid audiobook consumer since 2015, I obviously had to change some of my reading habits. Since 2015 and up until Aug. 17th, I had consumed 8 months and 5 days worth of audiobooks. That was mostly in the car to and from work, on walks, on runs or 30 minutes before going to sleep at night. &lt;/p&gt;&#xA;&lt;p&gt;Now that I have changed to reading instead of listening, I can read during the days at home as well. I have two kids and a wife, and I do not want to put in earplugs and close myself off to them when they are home. But with a book, I can still listen to when they need my attention. I still read before going to sleep at night. However, I cannot read when driving or running anymore. &lt;/p&gt;&#xA;&lt;p&gt;Reading has also broadened the amount of books that I can read. Before when I was listening to books I had to make sure the narration was good in addition to the content of the book being good. Now I can just focus on the content of the book. There has been series of books that I had to skip because of poor narration.&lt;/p&gt;&#xA;&lt;h1&gt;Books I read&lt;/h1&gt;&#xA;&lt;p&gt;I bought The Runesmith Aug. 17th. And after that the ball just kept rolling. I finished 18 books in 2024, starting from Aug. 17th. Some long, some short and most of them medium in length. I read mostly fantasy, but also some science fiction. Here is a list of the books.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Infinite Realm - The Runesmith&lt;/li&gt;&#xA;&lt;li&gt;The Sunsurge Quartet - Empress of the Fall &lt;/li&gt;&#xA;&lt;li&gt;The Sunsurge Quartet - Prince of the Spear&lt;/li&gt;&#xA;&lt;li&gt;The Sunsurge Quartet - Hearts of Ice&lt;/li&gt;&#xA;&lt;li&gt;The Sunsurge Quartet - Mother of Daemons&lt;/li&gt;&#xA;&lt;li&gt;The Blacktongue Thief&lt;/li&gt;&#xA;&lt;li&gt;The Daughter&apos;s War&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - Dungeon Crawler Carl&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - Carl&apos;s Doomsday Scenario&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - The Dungeon Anarchist&apos;s Cookbook&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - The Gate of the Feral Gods&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - The Butcher&apos;s Masquerade&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - The Eye of the Bedlam Bride&lt;/li&gt;&#xA;&lt;li&gt;Dungeon Crawler Carl - This Inevitable Ruin&lt;/li&gt;&#xA;&lt;li&gt;Murderbot Diaries - All Systems Red&lt;/li&gt;&#xA;&lt;li&gt;Murderbot Diaries - Artificial Condition&lt;/li&gt;&#xA;&lt;li&gt;Infinite Realm - Monsters and Legends&lt;/li&gt;&#xA;&lt;li&gt;Infinite Realm - The Price of Power&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This amounts to 18 books and approximately 11.500 pages. It feels nice to be actually reading again. I have a lot of books on my to-read list and I might slow down a little bit in order to find a nice pace for myself. But 2025 in books looks pretty good and I am sure I will have a lot of interesting books to read. &lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Finished 'Writing an interpreter in Go'</title>
   <link href="https://madsravn.dk/posts/i-finished-a-book.html"/>
   <updated>2023-11-13T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/i-finished-a-book</id>
   <content type="html">&lt;p&gt;I did it. I finished a non-fiction book and completed all the exercises in the book. I just completed &lt;a href=&quot;https://interpreterbook.com/&quot;&gt;&apos;Writing an interpreter in Go&apos;&lt;/a&gt; by Thorsten Ball. I read the entire book, cover to cover.&lt;/p&gt;&#xA;&lt;p&gt;With a fulltime job, wife, kids and a house it is not often I find the time to finish a book like this. Sure, I read a bit here and there - but I don&apos;t always find the time to sit down and do the actual work of the books that I read. So completing the last page of the book felt like an achievement of sorts. It helped me along the way that it was a cool subject and that Ball is able to convey the content in a clear way. He writes very conversationally while still delivering a good theoretical background. &lt;/p&gt;&#xA;&lt;h1&gt;About the book&lt;/h1&gt;&#xA;&lt;p&gt;The subject of the book should not come as a surprise after having read the title. &apos;Writing an interpreter in Go&apos; is about.... writing an interpreter in Go. And one of the goals Ball sets is to use no 3rd party libraries. And he actually keeps to this promise. Most of the time when I see such promises in books there is always exceptions and they end up using one or two libraries anyways. This goal makes it very easy to translate the implementation from Go to any other language. You can see on the &lt;a href=&quot;https://monkeylang.org/&quot;&gt;Monkey Language webpage&lt;/a&gt; that the interpreter has been implemented in pretty much all languages. Using no 3rd party libraries also helps you understand every bit of the interpreter: Nothing is hidden behind a magic function. &lt;/p&gt;&#xA;&lt;p&gt;The language that you implement an interpreter for is the Monkey Language. It looks a bit like javascript and behaves similarly. But it is easy to read and write and does not have too much fuzz about it. This makes it easy to follow along on the examples and code snippets because you do not have to waste time figuring out why the language behaves strangely or why a line of Monkey language code does something that seems like magic. If you know how to program in pretty much any language, you should be able to easily decipher the Monkey language.&lt;/p&gt;&#xA;&lt;p&gt;You will start from scratch with no code, no tests and no project files and 250 pages later you will have a fully functioning interpreter. There is a lot of code in the book and everything is done in TDD fashion. &lt;/p&gt;&#xA;&lt;p&gt;If you are interested in compilers or interpreters and want an easy-to-follow project, this is definitely the book for you. It was fun and leaves you with a fully working interpreter that you can easily extend by yourself. Ball describes the reasoning for all the steps and provides you enough theory to take new concepts and add them to the finished codebase. &lt;/p&gt;&#xA;&lt;h1&gt;Writing an interpreter in Go ... in Java?&lt;/h1&gt;&#xA;&lt;p&gt;I chose to write the implementation of the interpreter in Java. I know, I know, Java is not very sexy and sooo last year (decade?). All the cool kids are either doing it in Go or Rust today. I actually started doing it in Rust and with the pattern matching in Rust it felt like a great fit. But then I decided that I wanted a chance to test out the new features in recent Java version that I do not get to try out at work. It is also rare that I create a Java project from scratch so that was a small exercise. Trying out pattern match for switch (as mentioned &lt;a href=&quot;https://belief-driven-design.com/looking-at-java-21-switch-pattern-matching-14648/&quot;&gt;here&lt;/a&gt;) was a fun experience. Java might not be sooo last year anymore. &lt;/p&gt;&#xA;&lt;p&gt;This might be sacrilegious to say but I definitely prefer the code structure of Java compared to Rust and Go. I have many small logical files with clear names instead of bigger files containing lots and lots of structs. And with Functional Interfaces, streams, pattern matching and records I do not really feel like I am missing out on the modern cool stuff that attracts people to Go and Rust. &lt;/p&gt;&#xA;&lt;h1&gt;What&apos;s next?&lt;/h1&gt;&#xA;&lt;p&gt;I left a bunch of TODO&apos;s in my code that I need to fix. I also have a few ideas for how to make the code prettier and easier to read. So I will work on that. I think it could be fun to throw the code into a backend and then create a website where you can REPL the Monkey language and explore the AST. So there is definitely still work to be done on the code even though I am done with the book.&lt;/p&gt;&#xA;&lt;p&gt;Thorsten Ball has also written a successor to this book. It is called &apos;Writing a compiler in Go&apos;. That is a project I will start maybe first thing in the new year. It is a little thicker than his interpreter book with around 330 pages. &lt;/p&gt;&#xA;&lt;h1&gt;I think you should read it too&lt;/h1&gt;&#xA;&lt;p&gt;The subject of the book was easy to digest because of the writing style of Ball. It is far from dry and he talks you through thing rather than just stating facts. If you are able and willing to do the code in the book you are rewarded with a working interpreter and a lot of green checkmarks due to the test driven development style of the book.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Creating a concept for a dev diary</title>
   <link href="https://madsravn.dk/posts/creating-a-concept-for-dev-diary.html"/>
   <updated>2023-03-08T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/creating-a-concept-for-dev-diary</id>
   <content type="html">&lt;p&gt;As we all do, I work on different projects: There are a few at work, a few of my own hobby projects and occasionally I contribute to open source projects. They all have different commands for buildings, different commands for testing, different commands for deploying and some even have different commands for committing and pushing your changes. And sometimes you just forget that one pesky command for what you are trying to do right now. &lt;/p&gt;&#xA;&lt;p&gt;Recently as I was fixing an issue for the rust-lang project, I had forgotten the command to execute just the test suite for just that one part of the compiler I was working one. Running all the tests takes a long time, so I went searching in my history file. I found the command I was looking for, but I also saw some of the other ones I had used the last time I was contributing to the rust-lang project. I copied them into a separate file and saved it for a rainy day. I forgot that one command today - obviously I am going to forget one or more commands in the future. &lt;/p&gt;&#xA;&lt;p&gt;And then it hit me. I should make this more organized than just copying a few commands. I should add some context: Put in some comments and maybe add a concept of order of execution. With that extra information added to the file it could even serve as documentation for some projects. Just like you can transfer around postman files within your project group, you could transfer this file around and have it injected into your history file and you would be good to with a reverse search in your terminal.&lt;/p&gt;&#xA;&lt;p&gt;I think I will call this a &apos;dev diary&apos;. It is a file where I can easily store some commands and comments about the current projects I working on so that I can yank it back in the future where I probably have forgotten about it. It is me writing something now for me in the future.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>First post with Hyde</title>
   <link href="https://madsravn.dk/posts/first-post-with-hyde.html"/>
   <updated>2022-03-22T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/first-post-with-hyde</id>
   <content type="html">&lt;p&gt;Nearly ten years ago, I wrote my first post on this blog. It was about just having configured &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; as my static site generator for this blog. Jekyll is also the main driver for github pages where my website lives. Since then I have tried to twist and turn Jekyll into something that would meet all my goals. But I haven&apos;t been able to. So I decided to write my own static site generator: Hyde. Currently it is a very specialized piece of software - it compiles only this webpage. &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&#xA;&lt;p&gt;I started out with one goal when I sat down and started writing Hyde: To take the same input files that I have been using with Jekyll for the last ten years and compile the same page. I didn&apos;t want to go back and change the format of my old posts or change the layout system. I have now reached that goal. This post is compiled with Hyde. I have replaced Jekyll with Hyde. &lt;/p&gt;&#xA;&lt;h3&gt;Background&lt;/h3&gt;&#xA;&lt;p&gt;I picked Rust as the language for Hyde. Rust is quickly becoming my new favorite language over C++. It feels like a modern approach to both high-level and low-level coding. It has a very nice package manager called &lt;a href=&quot;https://doc.rust-lang.org/cargo/&quot;&gt;Cargo&lt;/a&gt;. This is also a very nice exercise for me while learning the language: To create an actual product which will live longer than just the hours it takes for me to create it and run the program for a solution.&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&#xA;&lt;p&gt;As mentioned the first goal for Hyde was to eat the same input as Jekyll did. Jekyll uses markdown and liquid. Liquid is a template language which I have used to write my layouts in. A layout is the container for the content of the page - essentially the HTML with my menu and the like so I don&apos;t have to write that more than once. It was easy to compile markdown to HTML. I found &lt;a href=&quot;https://github.com/raphlinus/pulldown-cmark&quot;&gt;pulldown-cmark&lt;/a&gt; and saw it easily translated a markdown document to HTML. There are some very minute differences in the output from Jekyll and pulldown-cmark, but nothing noticeable. Compiling liquid required a bit more work from me - it wasn&apos;t just plug&apos;n&apos;play. I wrote about it in my &lt;a href=&quot;https://madsravn.dk/posts/using-liquid-rust-with-serde.html&quot;&gt;previous post&lt;/a&gt;. But once I figured it out things started to work pretty quickly.&lt;/p&gt;&#xA;&lt;h3&gt;The Future&lt;/h3&gt;&#xA;&lt;p&gt;So now that I have a working prototype of my static site generator, what is next? The reason I moved away from Jekyll was because I was missing features. So implementing these features is my next goal. I want to have a wikipedia-like page linking to pages where I can write notes about links, articles and books. I also want to add a configuration file so I can change things on my page much easier. &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&#xA;&lt;p&gt;I can&apos;t see anyone ever using Hyde over the million other static site generators out there, but I want to aim for making Hyde production ready for other users. I need to create a test suite. I need to make Hyde much general purpose than &amp;quot;compile madsravn.dk&amp;quot;. I might also need to find another name since &lt;a href=&quot;https://github.com/hyde/hyde&quot;&gt;Hyde&lt;/a&gt; exists - even though it is 6 years in the grave. &lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Using liquid-rust with serde</title>
   <link href="https://madsravn.dk/posts/using-liquid-rust-with-serde.html"/>
   <updated>2021-12-13T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/using-liquid-rust-with-serde</id>
   <content type="html">&lt;p&gt;I have been running Jekyll for 9 years now. I wrote about it &lt;a href=&quot;first-post.html&quot;&gt;in this post&lt;/a&gt;. At this point, my needs and patience have outgrown Jekyll. There is a few features that I miss and there is some annoyance that comes with running Ruby, I feel.&lt;br&gt;&lt;br&gt;&lt;/p&gt;&#xA;&lt;p&gt;I have decided to write my own static site generator. I need something that I control - something that bends to my will. But because I am lazy, I will keep the content structure of Jekyll. This way I can just run my new static site generator on the exact same content that I already have. It means that I have to use markdown for my content and it means that I have to use liquid as my templating system. And I have no problem with this.&lt;br&gt;&lt;br&gt;&lt;/p&gt;&#xA;&lt;p&gt;It was easy to find a markdown compiler for the project. I chose pulldown-cmark. It seems easy to use and passes all the compilations of my current markdown files. After looking for a good liquid crate, I fell upon &lt;a href=&quot;https://github.com/cobalt-org/liquid-rust&quot;&gt;liquid-rust&lt;/a&gt;. It seems to be written for cobalt, which is a static site generator written in Rust. And it was damn easy to get started on. Until I hit my first speed bump. How do I put non-trivial objects into the templating engine?&lt;br&gt;&lt;br&gt;&lt;/p&gt;&#xA;&lt;p&gt;I have this piece liquid code in my html for my posts:&#xA;{% raw %}&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;&amp;lt;section class=&amp;quot;content&amp;quot;&amp;gt;&#xA;  &amp;lt;ul class=&amp;quot;listing&amp;quot;&amp;gt;&#xA;    {% for post in site.posts %}&#xA;    &amp;lt;li&amp;gt;&#xA;       &amp;lt;a href=&amp;quot;{{ post.url }}&amp;quot;&amp;gt;{{ post.title }}&amp;lt;/a&amp;gt; &amp;lt;span class=&amp;quot;left&amp;quot;&amp;gt;{{ post.date | date: &amp;quot;%B %e, %Y&amp;quot; }}&amp;lt;/span&amp;gt;&#xA;       &amp;lt;hr&amp;gt;&#xA;    &amp;lt;/li&amp;gt;&#xA;    {% endfor %}&#xA;  &amp;lt;/ul&amp;gt;&#xA;&amp;lt;/section&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;{% endraw %}&lt;/p&gt;&#xA;&lt;p&gt;&lt;br&gt;&lt;br&gt;&#xA;Problem was just that all the examples I could find showed how to inject a very simple structure into the templating engine. The example is showed below and is showing to how put in a primitive type.&#xA;{% raw %}&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;let template = liquid::ParserBuilder::with_stdlib()&#xA;  .build().unwrap()&#xA;  .parse(&amp;quot;Liquid! {{num | minus: 2}}&amp;quot;).unwrap();&#xA;&#xA;let mut globals = liquid::object!({&#xA;  &amp;quot;num&amp;quot;: 4f64&#xA;});&#xA;&#xA;let output = template.render(&amp;amp;globals).unwrap();&#xA;assert_eq!(output, &amp;quot;Liquid! 2&amp;quot;.to_string());&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;{% endraw %}&lt;/p&gt;&#xA;&lt;p&gt;&lt;br&gt;&lt;br&gt;&#xA;My goal is just to inject a complex type which holds a list of &lt;code&gt;post&lt;/code&gt; and where each post object holds &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;date&lt;/code&gt;. I scoured the internet for a way of doing this and came up empty. I found the author of the crate was on the official Rust Discord and I introduced myself and my problem. And he showed me the simple solution. Use serde. &lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;use serde::{Serialize, Deserialize};&#xA;&#xA;#[derive(Serialize, Deserialize, Debug)]&#xA;struct Post {&#xA;  title: String,&#xA;  url: String,&#xA;  date: String,&#xA;}&#xA;&#xA;#[derive(Serialize, Deserialize, Debug)]&#xA;struct Posts {&#xA;  posts: Vec&amp;lt;Post&amp;gt;,&#xA;}&#xA;&#xA;#[derive(Serialize, Deserialize, Debug)]&#xA;struct Globals {&#xA;  site: Posts,&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;br&gt;&lt;br&gt;&#xA;And now with complex data structure described in serde, it was as easy as creating the objects and using them as input to the templating engine:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;let site = Globals {&#xA;    site: p3&#xA;};&#xA;&#xA;let index = fs::read_to_string(&amp;quot;_build/index.html&amp;quot;).expect(&amp;quot;Should be able to read the index file&amp;quot;);&#xA;let template = liquid::ParserBuilder::with_stdlib()&#xA;       .build().unwrap()&#xA;       .parse(&amp;amp;index).unwrap();&#xA;let globals = liquid::to_object(&amp;amp;site).expect(&amp;quot;Should be able to parse&amp;quot;);&#xA;    &#xA;let output = template.render(&amp;amp;globals).unwrap();&#xA;println!(&amp;quot;index: {}&amp;quot;, output);&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;br&gt;&lt;br&gt;&#xA;It took me some time to find the solution - or find the person who could give me the solution. But now that it is here, it seems so easy. And with with that, I can finalize my static site generator. &lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Created my first keyboard from scratch</title>
   <link href="https://madsravn.dk/posts/created-my-first-keyboard.html"/>
   <updated>2021-03-09T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/created-my-first-keyboard</id>
   <content type="html">&lt;h2&gt;The Past&lt;/h2&gt;&#xA;&lt;p&gt;I love mechanical keyboards. I frequent &lt;code&gt;r/mechanicalkeyboards&lt;/code&gt; and &lt;code&gt;#mechboards&lt;/code&gt;. I probably have a few keyboards too many (as if).&lt;/p&gt;&#xA;&lt;p&gt;I started out by buying a Coolermaster Quickfire Rapid-i with brown switches. Going from a regular keyboard to a mechanical was like a dream come true. I dream that I didn&apos;t even know I had. A few years ago I started getting into electronics and soldering. I bought a few mechanical keyboard kits. After that I have created a few open source keyboards - people giving away their hard work by putting the design files freely available on Github. My latest keyboard is an &lt;a href=&quot;https://github.com/omkbd/ErgoDash/&quot;&gt;ErgoDash&lt;/a&gt; - a nice split keyboard with lots of features.&lt;/p&gt;&#xA;&lt;img src=&quot;../images/image.jpg&quot; width=&quot;400&quot; height=&quot;300&quot; /&gt;&#xA;&lt;h2&gt;Now&lt;/h2&gt;&#xA;&lt;p&gt;I recently purchased a 3D printer. A Prusa i3 MK3S+. I never thought I would own a 3D printer, but here we are. It seems like an excellent printer with nice support from the official slicer software. I found that Fusion 360 is pretty easy to learn for people who have never done 3D modelling before. I wanted to create a small macro pad for 2x2 LEGO bricks. I also wanted the possibility to build bricks on top of multiple keys, so I needed to design a keyboard where the keys had the correct distance between them. I went to the drawing board:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;../images/ODNiEeN.jpeg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt; &lt;img src=&quot;../images/QHoj4Lv.jpeg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;When I had printed the top and bottom of the new keyboard, I started soldering. For most of my own keyboards I have used the Pro Micro. It&apos;s a cheap and well tested dev board which does the job! I had never handwired a keyboard before, so that was a fun experience. I am using &lt;a href=&quot;https://beta.docs.qmk.fm/&quot;&gt;QMK&lt;/a&gt; for the firmware on the Pro Micro and I had to figure out how to create my own keyboard and layout. I used the &lt;code&gt;DIRECT_PINS&lt;/code&gt; mode because I have so few keys on my board that I do not need to create a matrix.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;../images/jSB2xYc.jpeg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt; &lt;img src=&quot;../images/eS5NsIT.jpeg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;Once assembled and flashed, it was time to test. It works fine. Now I just need to find a purpose for it. It looks fine and I imagine that it can be used a gimmick keyboard.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;../images/IMG_20210308_092718.jpg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt; &lt;img src=&quot;../images/IMG_20210309_090056.jpg&quot; width=&quot;300&quot; height=&quot;400&quot; /&gt;&lt;/p&gt;&#xA;&lt;h2&gt;The Future&lt;/h2&gt;&#xA;&lt;p&gt;It&apos;s fun to design your own keyboard. I had never thought I would do it. But now that I have done it, I want to make more. And I want to make bigger keyboards. Maybe even keyboards with the entire alphabet on them. The only limitation I have right now is the printing surface on the Prusa printer.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>My year in books, 2020</title>
   <link href="https://madsravn.dk/posts/2020-My-Year-In-Books.html"/>
   <updated>2020-12-31T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/2020-My-Year-In-Books</id>
   <content type="html">&lt;p&gt;Inspired by threads on Reddit, this is &lt;em&gt;My year in books, 2020&lt;/em&gt;. I listen to most of my books. Or I listen to all of my fiction books, at least. I listen to books mostly when driving to and from work, going for a walk, going to sleep or doing menial tasks around the house or garden.&lt;/p&gt;&#xA;&lt;p&gt;The genres I prefer are mostly fantasy, science fiction and crime. I listened to 46 books in 2020. &lt;/p&gt;&#xA;&lt;h3&gt;Fantasy&lt;/h3&gt;&#xA;&lt;p&gt;What really stood out, fantasy-wise, for me in the books I listened to in 2020 was &lt;em&gt;The Highwayman&lt;/em&gt; by R.A. Salvatore, &lt;em&gt;Kings of the Wylde&lt;/em&gt; by Nicholas Eames, &lt;em&gt;The Licanius Trilogy&lt;/em&gt; by James Islington and &lt;em&gt;The Rage of Dragons&lt;/em&gt; by Evan Winter.&lt;/p&gt;&#xA;&lt;p&gt;A special shout out to Joe Abercrombie for the second book in the &lt;em&gt;Age of Madness Trilogy&lt;/em&gt;. He really delivers! His books also have great re-read value. If possible, his writing style keeps improving and surprising. In the middle of combat he changes the point of view from one fighter to his opponent giving a broader feel of the fight. He has a light sarcastic tone. I love the world and the story, but his style keeps me interested!&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Kings of the Wylde&lt;/em&gt; was also a very good story. There was something nostalgic about these old friends getting back together and fighting again. The world is also very interesting where the new generation has a whole new idea of what a band is. &lt;/p&gt;&#xA;&lt;p&gt;This category&apos;s big let down was the &lt;em&gt;Ascendant&lt;/em&gt; trilogy by Craig Alanson. Nobody out there can tell me that they don&apos;t like Tim Gerard Reynolds. He is in my top 5 of narrators and I would probably listen to a book just because of him. However, this book was a giant let down. It is misunderstanding after misunderstanding. Nobody learns from their mistakes. The main character is the strongest wizard the world has ever seen and we get to see him &amp;quot;fight&amp;quot; with magic 2 times in a trilogy of 46+ hours. &lt;/p&gt;&#xA;&lt;h3&gt;Science Fiction&lt;/h3&gt;&#xA;&lt;p&gt;This category also contains some letdowns. I read &lt;em&gt;The Foundation Trilogy&lt;/em&gt; by Isaac Asimov. I love the romantic idea that Asimov have about the future - but in the end his series was quite boring. I felt you never really got to learn much about the characters because we skip so much time.&lt;/p&gt;&#xA;&lt;p&gt;Timothy Zahn with a new Thrawn book - who wouldn&apos;t be super hyped for the first instalment of the new &lt;em&gt;Thrawn Ascendency&lt;/em&gt;? I think I was too hyped because Thrawn already have a great trilogy in the &lt;em&gt;Thrawn Trilogy&lt;/em&gt; and this really didn&apos;t do it justice! It was with a sad heart that I realized I probably will not listen to book two and three in this trilogy.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Enabling LaTeX rendering with jekyll</title>
   <link href="https://madsravn.dk/posts/enabling-latex-with-jekyll.html"/>
   <updated>2020-11-10T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/enabling-latex-with-jekyll</id>
   <content type="html">&lt;p&gt;I was looking for a good way render some LaTeX math while writing blog posts with jekyll. I couldn&apos;t find a jekyll plugin which would allow me to inline LaTeX equation and have them rendered client-side. I ended up finding &lt;a href=&quot;https://www.mathjax.org/&quot;&gt;mathjax.org&lt;/a&gt;. It is an easy solution - it is as simple as adding these two lines to my layout document:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script src=&amp;quot;https://polyfill.io/v3/polyfill.min.js?features=es6&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&#xA;&amp;lt;script id=&amp;quot;MathJax-script&amp;quot; async src=&amp;quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;After adding these two lines it gets as simple as just writing your LaTeX equation within &lt;code&gt;$$...$$&lt;/code&gt;. It&apos;s pretty straight forward plug&apos;n&apos;play compared to some other solutions. And it also works just as well for other blog solutions and static site generators. It was just jekyll I was looking for a solution for.&lt;/p&gt;&#xA;&lt;p&gt;As an example, here is a rendered equation from my thesis: &lt;code&gt;$$\sum\limits_{i=1}^{\lg_B \lg n} \frac{\lg n}{B^i} \cdot \mathcal{O}(B^i) = \mathcal{O}(\lg n \cdot \lg_B \lg n)$$&lt;/code&gt; &lt;/p&gt;&#xA;&lt;p&gt;$$\sum\limits_{i=1}^{\lg_B \lg n} \frac{\lg n}{B^i} \cdot \mathcal{O}(B^i) = \mathcal{O}(\lg n \cdot \lg_B \lg n)$$&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Contributing to Clang</title>
   <link href="https://madsravn.dk/posts/contributing-to-clang.html"/>
   <updated>2017-06-20T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/contributing-to-clang</id>
   <content type="html">&lt;p&gt;A year or so ago I started contributing code to Clang. For those of you who doesn&apos;t know what &lt;a href=&quot;https://clang.llvm.org/&quot;&gt;Clang&lt;/a&gt; is; it is a C and C++ front-end for LLVM. In short, a C++ compiler. I have mostly been doing work on &lt;a href=&quot;https://clang.llvm.org/extra/clang-tidy/&quot;&gt;Clang-Tidy&lt;/a&gt; which is a Clang-based C++ linter. It can help you find errors, enforce coding guidelines or modernize your project. it is a very helpful tool which can be an effective part of your tool chain. It is also very easy to extend Clang-Tidy with your own checks - and it also easy to have this code accepted into the official Clang project. &lt;/p&gt;&#xA;&lt;p&gt;So if you are looking for a fun open source project to contribute to, look no further. In this post I will quickly explain the few steps you need to follow in order to extend Clang-Tidy and have it accepted into the Clang project.&lt;/p&gt;&#xA;&lt;h2&gt;Get the code!&lt;/h2&gt;&#xA;&lt;p&gt;First you need to get the source code for the project. The process is described on the &lt;a href=&quot;https://clang.llvm.org/get_started.html&quot;&gt;getting started page&lt;/a&gt;. Clang-Tidy is located in the clang-tools-extra repository. So you will have to check out llvm first, then clang and finally clang-tools-extra. &lt;/p&gt;&#xA;&lt;h2&gt;Time for some code&lt;/h2&gt;&#xA;&lt;p&gt;Once you have checked the code out, you want to prepare the project by running CMake to get your build environment up and running. Once you have done that and opened the project, I can recommend that you &lt;a href=&quot;https://clang.llvm.org/extra/clang-tidy/#writing-a-clang-tidy-check&quot;&gt;read this post&lt;/a&gt; about writing a clang-tidy check. Pay attention to the tools being used. In particular, &lt;code&gt;add_new_check.py&lt;/code&gt;. Using this tool will create the files you need in the right places and add them to the CMake files of the clang-tools-extra project.&lt;/p&gt;&#xA;&lt;h2&gt;Done coding? Get some comments!&lt;/h2&gt;&#xA;&lt;p&gt;When you are done coding - when you have made your own Clang-tidy check and some tests for it - you are going to put the changes in for code review. This is done by using Phabricator. Take a look at the &lt;a href=&quot;https://llvm.org/docs/Phabricator.html&quot;&gt;LLVM page for Phabricator&lt;/a&gt; to see how you create a &apos;Differential&apos; for your patch. If it is your first time creating code for the LLVM project there are bound to be some comments. Just take all the help you can get and be patient.&lt;/p&gt;&#xA;&lt;h2&gt;Closing statement&lt;/h2&gt;&#xA;&lt;p&gt;I think the Clang project is super fun to work on. The people I have met through my contributions are super friendly and smart. They are willing to help out a lot. If you want to meet some folk, just drop by the IRC channel. It is at #llvm @ irc.oftc.net. If you want to reach out, my nick is mfrstar.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Meeting C++ trip report</title>
   <link href="https://madsravn.dk/posts/meeting-cpp-trip-report.html"/>
   <updated>2016-11-22T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/meeting-cpp-trip-report</id>
   <content type="html">&lt;p&gt;Last week I attended my first ever C++ conference. It was the Meeting C++ conference in Berlin. The conference was very nicely planned with some good speakers and good topics. There were only a few minor details which was inconvinient. Below I will try to express some thoughts about the different talks I saw and about the conference in general.&lt;/p&gt;&#xA;&lt;h2&gt;The Keynote&lt;/h2&gt;&#xA;&lt;p&gt;The keynote this year was presented by Bjarne Stroustrup. I have seen Bjarne a few times before and it never gets boring. He talked about what his thoughts were when he created C++ and how he is trying to stay true to those thoughts going into newer versions of C++. As always he talked expressing intent - both for the readers and the compiler. He then showed what kind of features we can expect from C++17 and what he hopes will come with C++2z. I am always impressed at the questions he gets and how he answers them. He is getting all kind of weird and technical questions and he answers them all in a very calm manner. There was one question he didn&apos;t want to answer though, which was about which languages he likes and dislikes. &lt;/p&gt;&#xA;&lt;h2&gt;All your cache is belong to us&lt;/h2&gt;&#xA;&lt;p&gt;I also saw a talk about caches by Timur Doumler. It was very good. He had some excellent points accompanied by good figures and thought-out experiments. I never thought the subject of caching could become fun and interesting, but Doumler actually nailed it. Unfortunately, this presentation did not allow for questions due to time being short. This was the one single talk I had a question for. He also showed snippets of code as to how you would write better code if you are interested in cache friendliness.&lt;/p&gt;&#xA;&lt;h2&gt;A million lines of code&lt;/h2&gt;&#xA;&lt;p&gt;Next on the schedule was Peter Bindels from Tomtom talking about their own software. He talked about how they had had problems with way too many lines of codes. He presented some guidelines for how to handle it and talked about a tool Tomtom had developed to show internal code dependencies. This tool had been very successfull in helping them make their code more clear and expressive. He mentioned that their tool could find code dependency cycles and how you did want to have these. I found this talk very good. Peter was very engaging and talked about practical experience which is easy to convert into your own work.&lt;/p&gt;&#xA;&lt;h2&gt;A little dash of functional&lt;/h2&gt;&#xA;&lt;p&gt;The last talk of the day was Phil Nash with his &apos;Functional C++ for Fun and Profit&apos;. I was a little vary when joining this talk. Sometimes when people talk about functional C++ it just becomes a garbage can of metaprogramming. Nash had none of this. His talk was concise with some very nice points from his practical experience. He showed how to express intent with functional programming and how to strive towards the idea of purity. He talked a little about some persistent data structure before showing how to make some nice functional programming with lambda expressions and &lt;code&gt;std::optional&lt;/code&gt;. It was very intereting. This was easily the best talk of the day for me.&lt;/p&gt;&#xA;&lt;h2&gt;Party time!&lt;/h2&gt;&#xA;&lt;p&gt;At this point we got some food. It was OK - nothing too good. And there was no beer with the meal! However, after the meal there was a C++ quiz by conan.io. It was very fun to try. We did OK, I think we got 5-6th place or something. After the quiz, at 9:00 PM the beer finally arrived. I went around, drank some beer and talked to some interesting people! This was also one of the best things about the conference: just talking to people about stuff. Too bad we only had one evening to do that. But next years Meeting C++ with one more day of conference will be better!&lt;/p&gt;&#xA;&lt;h2&gt;Saturday morning functional programming&lt;/h2&gt;&#xA;&lt;p&gt;First thing on the schedule saturday was &apos;Functional Reactive Programming in C++&apos; by Ivan Cukic. I have to give it to Cukic for bringing a very relevant and easy to use presentation! Again, I had expected some metaprogramming, but it was good on the conceptual level as to how you want to explore funcation reactive programming! Was an excellent presentation. Cukic also shared free copies of his future book on this exact subject!&lt;/p&gt;&#xA;&lt;h2&gt;Static analysis!&lt;/h2&gt;&#xA;&lt;p&gt;Next up was Gabor Horvath with his talk about static analysis. Gabor is a PhD student with subject in static analysis, so this talk was a little academic. But it was indeed very interesting. He had good examples and nice slides on the subject. When the presentation was over I was much more curious about static analysis and wanted to look more into it. This was also one of my favorite talks of the conference. &lt;/p&gt;&#xA;&lt;h2&gt;The end&lt;/h2&gt;&#xA;&lt;p&gt;Unfortunately I didn&apos;t get to see the closing keynote due to my travel plans. I had to get home. But that was OK - I had had an awesome first conference. I am very inspired about the things I learned there. I can feel there are a lot of things I still need to learn and I look forward to this! I got to speak with some interesting people and share laughs with others! I hope I can take some of the subjects I heard about and incorporate them into my work. &lt;/p&gt;&#xA;&lt;p&gt;This was all in all a good conference and an awesome experience!&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Master thesis done - lessons learned</title>
   <link href="https://madsravn.dk/posts/master-thesis-done-lessons-learned.html"/>
   <updated>2015-11-21T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/master-thesis-done-lessons-learned</id>
   <content type="html">&lt;p&gt;I graduated from Aarhus University with a degree in Computer Science this june. Now, I&apos;m finally getting around to publishing my code (as I linked in my thesis). I thought that I would give a quick summary of the process of writing my thesis as well. You can find my thesis and the code I developed for my thesis &lt;a href=&quot;./../../BIS/index.html&quot;&gt;here&lt;/a&gt;. The title of my thesis is Orthogonal Range Searching in 2D with Ball Inheritance and my advisor was &lt;a href=&quot;https://cs.au.dk/~larsen/&quot;&gt;Kasper Green Larsen&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Before I started writing my thesis, I followed a course called Master Thesis Preparation by &lt;a href=&quot;https://cs.au.dk/~danvy/&quot;&gt;Olivier Danvy&lt;/a&gt;. He has advised for quite a few PhD students so far, so he certainly has a good experience with it. The course consisted of a lot of good tips, tricks and good stories (which is his modus operandi). One of the few things which really stuck with me was to remember an advisor has a limited amount of time for you and it is your responsibility to use it as best as possible. My advisor was awesome enough to read some of what I had written each time we met. And in order to maximize what I got from this, I always compiled a &apos;diff-version&apos; of my thesis for him. A &apos;diff-version&apos; was made using &lt;code&gt;latexdiff&lt;/code&gt;. Each time I handed something in, I saved the latex files for that version. Next time I handed something in, I would then run &lt;code&gt;latexdiff&lt;/code&gt; on the current version and what I handed in last time. With this it was easy to see what was removed, what was added and what was the same as last time he read it. This worked out pretty good.&lt;/p&gt;&#xA;&lt;p&gt;My thesis was half theoretical and half practical. So while I had to write some code and analyze some results, the actual written thesis was still the main focus. And we all know that writing code is funnier than writing a thesis. So I forced myself to write the draft for the introduction chapter and another chapter before I started coding. This way I did not get lost in just having fun coding and postpone the writing for later (where &apos;later&apos; might too late).&lt;/p&gt;&#xA;&lt;p&gt;To conclude, remember to:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Find tools to streamline your process.&lt;/li&gt;&#xA;&lt;li&gt;Use the time of your advisor as best as possible. Invest some time to prepare for your meetings.&lt;/li&gt;&#xA;&lt;li&gt;Focus on the important aspects of your thesis, and don&apos;t get lost in what is interesting or fun.&lt;/li&gt;&#xA;&lt;li&gt;Find yourself a book on writing. &lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>What is better - Xbox One or Playstation 4?</title>
   <link href="https://madsravn.dk/posts/what-is-better-xbox-or-playstation.html"/>
   <updated>2013-11-19T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/what-is-better-xbox-or-playstation</id>
   <content type="html">&lt;p&gt;With the two new consoles being released soon, there is a lot of hype about it online. There is a lot of articles online describing the differences in performance, games, design and usability - reading the comparisons of the consoles almost seems like a bigger time consumption than actually playing on the console.&lt;/p&gt;&#xA;&lt;p&gt;So I read all the posts and summarized it for you. Which console is the best? Here&apos;s the answer: &lt;/p&gt;&#xA;&lt;img src=&quot;https://madsravn.dk/images/xboxplaystation.png&quot; /&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Simple image processing with CUDA</title>
   <link href="https://madsravn.dk/posts/simple-image-processing-with-cuda.html"/>
   <updated>2013-10-27T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/simple-image-processing-with-cuda</id>
   <content type="html">&lt;p&gt;I like graphics and image processing. So I have been fiddling a little with NVIDIAs CUDA in order to capatilize on some multithreaded programming. I have made a little starter edition for people who wants to try forces with CUDA for image processing.&lt;/p&gt;&#xA;&lt;p&gt;I am using &lt;a href=&quot;https://lodev.org/lodepng/&quot;&gt;lodepng&lt;/a&gt; for loading and saving images for the filtering. It is very easy to easy, has no dependencies and just works. In my example code I am reading filenames for input and output images from the command line parameters.&lt;/p&gt;&#xA;&lt;p&gt;Enough talk, let&apos;s see some code:&lt;/p&gt;&#xA;&lt;p&gt;In my &lt;code&gt;main.cpp&lt;/code&gt; file I load and save images and call the filter. &lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;int main(int argc, char** argv) {&#xA;    if(argc != 3) {&#xA;        std::cout &amp;lt;&amp;lt; &amp;quot;Run with input and output image filenames.&amp;quot; &amp;lt;&amp;lt; std::endl;&#xA;        return 0;&#xA;    }&#xA;&#xA;    // Read the arguments&#xA;    const char* input_file = argv[1];&#xA;    const char* output_file = argv[2];&#xA;&#xA;    std::vector&amp;lt;unsigned char&amp;gt; in_image;&#xA;    unsigned int width, height;&#xA;&#xA;    // Load the data&#xA;    unsigned error = lodepng::decode(in_image, width, height, input_file);&#xA;    if(error) std::cout &amp;lt;&amp;lt; &amp;quot;decoder error &amp;quot; &amp;lt;&amp;lt; error &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; lodepng_error_text(error) &amp;lt;&amp;lt; std::endl;&#xA;&#xA;    // Prepare the data&#xA;    unsigned char* input_image = new unsigned char[(in_image.size()*3)/4];&#xA;    unsigned char* output_image = new unsigned char[(in_image.size()*3)/4];&#xA;    int where = 0;&#xA;    for(int i = 0; i &amp;lt; in_image.size(); ++i) {&#xA;       if((i+1) % 4 != 0) {&#xA;           input_image[where] = in_image.at(i);&#xA;           output_image[where] = 255;&#xA;           where++;&#xA;       }&#xA;    }&#xA;&#xA;    // Run the filter on it&#xA;    filter(input_image, output_image, width, height); &#xA;&#xA;    // Prepare data for output&#xA;    std::vector&amp;lt;unsigned char&amp;gt; out_image;&#xA;    for(int i = 0; i &amp;lt; in_image.size(); ++i) {&#xA;        out_image.push_back(output_image[i]);&#xA;        if((i+1) % 3 == 0) {&#xA;            out_image.push_back(255);&#xA;        }&#xA;    }&#xA;    &#xA;    // Output the data&#xA;    error = lodepng::encode(output_file, out_image, width, height);&#xA;&#xA;    //if there&apos;s an error, display it&#xA;    if(error) std::cout &amp;lt;&amp;lt; &amp;quot;encoder error &amp;quot; &amp;lt;&amp;lt; error &amp;lt;&amp;lt; &amp;quot;: &amp;quot;&amp;lt;&amp;lt; lodepng_error_text(error) &amp;lt;&amp;lt; std::endl;&#xA;&#xA;    delete[] input_image;&#xA;    delete[] output_image;&#xA;    return 0;&#xA;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We notice how easy lodepng is to use. We tell it we want our image loaded into our vector and voila, we have it. We then remove the alpha channel, as I was not using it in my project. You can however change it to your preferences. We then give our image data to the &lt;code&gt;filter&lt;/code&gt; function - this is the function which will load the data onto our GPU and call the CUDA kernel which runs our filter. We then save our image, clean up and exits.&lt;/p&gt;&#xA;&lt;p&gt;Now let&apos;s look at some actual CUDA stuff. The code below resides in &lt;code&gt;kernels.cu&lt;/code&gt;. The CUDA compiler, nvcc, is sort of picky as to what filename extensions it will compile as what. For now, just let the name be.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt; void filter (unsigned char* input_image, unsigned char* output_image, int width, int height) {&#xA;&#xA;    unsigned char* dev_input;&#xA;    unsigned char* dev_output;&#xA;    getError(cudaMalloc( (void**) &amp;amp;dev_input, width*height*3*sizeof(unsigned char)));&#xA;    getError(cudaMemcpy( dev_input, input_image, width*height*3*sizeof(unsigned char), cudaMemcpyHostToDevice ));&#xA; &#xA;    getError(cudaMalloc( (void**) &amp;amp;dev_output, width*height*3*sizeof(unsigned char)));&#xA;&#xA;    dim3 blockDims(512,1,1);&#xA;    dim3 gridDims((unsigned int) ceil((double)(width*height*3/blockDims.x)), 1, 1 );&#xA;&#xA;    filter&amp;lt;&amp;lt;&amp;lt;gridDims, blockDims&amp;gt;&amp;gt;&amp;gt;(dev_input, dev_output, width, height); &#xA;&#xA;&#xA;    getError(cudaMemcpy(output_image, dev_output, width*height*3*sizeof(unsigned char), cudaMemcpyDeviceToHost ));&#xA;&#xA;    getError(cudaFree(dev_input));&#xA;    getError(cudaFree(dev_output));&#xA;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We allocate and copy our data to the GPU. We need the data on the GPU for the kernels to be able to read it. We also allocate storage for the output image, so we have a place to write the result of the filter to. The &amp;lt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;gt; is CUDA syntax and will be interpreted when compiled. It tells the compiler how many blocks and grids we are going to use. Mostly every CUDA function an enum &lt;code&gt;cudaError_t&lt;/code&gt; which is why every CUDA call is surrounded by &lt;code&gt;getError&lt;/code&gt;. This way we get an error printed to the screen if anything goes wrong. Don&apos;t worry too much about it, you can see the code for it in &lt;code&gt;helpers.cpp&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Now, let&apos;s look at the actual filter, also located in &lt;code&gt;kernels.cu&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;__global__&#xA;void blur(unsigned char* input_image, unsigned char* output_image, int width, int height) {&#xA;&#xA;    const unsigned int offset = blockIdx.x*blockDim.x + threadIdx.x;&#xA;    int x = offset % width;&#xA;    int y = (offset-x)/width;&#xA;    int fsize = 5; // Filter size&#xA;    if(offset &amp;lt; width*height) {&#xA;&#xA;        float output_red = 0;&#xA;        float output_green = 0;&#xA;        float output_blue = 0;&#xA;        int hits = 0;&#xA;        for(int ox = -fsize; ox &amp;lt; fsize+1; ++ox) {&#xA;            for(int oy = -fsize; oy &amp;lt; fsize+1; ++oy) {&#xA;                if((x+ox) &amp;gt; -1 &amp;amp;&amp;amp; (x+ox) &amp;lt; width &amp;amp;&amp;amp; (y+oy) &amp;gt; -1 &amp;amp;&amp;amp; (y+oy) &amp;lt; height) {&#xA;                    const int currentoffset = (offset+ox+oy*width)*3;&#xA;                    output_red += input_image[currentoffset]; &#xA;                    output_green += input_image[currentoffset+1];&#xA;                    output_blue += input_image[currentoffset+2];&#xA;                    hits++;&#xA;                }&#xA;            }&#xA;        }&#xA;        output_image[offset*3] = output_red/hits;&#xA;        output_image[offset*3+1] = output_green/hits;&#xA;        output_image[offset*3+2] = output_blue/hits;&#xA;        }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Again, the &lt;strong&gt;global&lt;/strong&gt; is a CUDA keyword. For each pixel in the input image we take the average of each of the neighbouring pixels and writes it to the output image. This filter is known as a Box blur. A better blur filter would be the Gaussian blur. I have written a Gaussian function in &lt;code&gt;helpers.cpp&lt;/code&gt; if you want to try. However, before doing that, just try to play around it and see what happens. I learn best from trial and error, and that is also why graphics and image processing is a subject I like - because you can see the result of your work in an easily understanded way instead of reading thousands of lines of output data.&lt;/p&gt;&#xA;&lt;p&gt;Notice that we check if our &lt;code&gt;offset&lt;/code&gt; is actually within the range of &lt;code&gt;width*height&lt;/code&gt; because it can happen that it will be outside due to the blocks CUDA will run, so remember to keep that. Also we need to remember to check whether or not the pixel we read are actually in our image when doing the box blur as well. You can try to remove them one at a time and see what happens.&lt;/p&gt;&#xA;&lt;p&gt;So now, try running the program on an image and look at the output image. Blurred, huh? &lt;/p&gt;&#xA;&lt;p&gt;I have made a simple compile script for the project as well - it works for linux and MAC OSX. Under Windows I guess it&apos;s pretty easy to get it up and running in Visual Studio as well. Good luck. &lt;a href=&quot;https://github.com/madsravn/easyCuda&quot;&gt; The code can be found on my github&lt;/a&gt;.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Improving performance with packet tracing and other methods</title>
   <link href="https://madsravn.dk/posts/final-handin-for-rendalg.html"/>
   <updated>2013-04-10T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/final-handin-for-rendalg</id>
   <content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The subject I chose for final handin in the rendering algorithms course was improving the rendering time of a given scene, the Sponza scene as seen below. The scene consist of 66,454 triangles which are rather compact and from any given viewpoint pretty stacked - i.e. if you shoot a ray through a triangle you are pretty sure to hit at least a few other triangles either behind or in front of it.&lt;/p&gt;&#xA;&lt;img src=&quot;https://madsravn.dk/images/mravn_sponza.png&quot; alt=&quot;sponza scene&quot; /&gt;&#xA;&lt;h2&gt;The methods&lt;/h2&gt;&#xA;&lt;p&gt;Firstly I used an acceleration data structure to put all my geometry in a tree which can be traversed. An acceleration data structure is an improvement in itself, but with this tree it became possible to make some further improvements using packet tracing. Packet tracing is a method where you group some of your rays together and traverse the tree of the data structure with them packed instead of a single ray at a time. This way you don&apos;t have to traverse many of the nodes of the tree so many times and you can also do some early miss testing by making a frustum of this group of rays and cheaply check if they all miss a bounding box with a single frustum/AABB intersection test instead of doing 16 to 512 ray/box intersection tests. &lt;/p&gt;&#xA;&lt;img src=&quot;https://madsravn.dk/images/mravn_ads.png&quot; alt=&quot;ads&quot; /&gt;&#xA;&lt;h2&gt;The results&lt;/h2&gt;&#xA;&lt;p&gt;I checked my implementation of packet tracing compared to the same scene with only early ray termination. I got these numbers&lt;/p&gt;&#xA;&lt;h3&gt;Normal ray tracing with early ray termination yielded the following results:&lt;/h3&gt;&#xA;&lt;p&gt;Did 6,503,630 triangle intersections&lt;/p&gt;&#xA;&lt;p&gt;Did 20,193,290 traversals&lt;/p&gt;&#xA;&lt;p&gt;Did 33,267,596 box intersections&lt;/p&gt;&#xA;&lt;h3&gt;Packet tracing with a packet size of 4x4:&lt;/h3&gt;&#xA;&lt;p&gt;Did 6,560,144 triangle intersections&lt;/p&gt;&#xA;&lt;p&gt;Did 1,877,640 traversals&lt;/p&gt;&#xA;&lt;p&gt;Did 11,500,952 box intersections&lt;/p&gt;&#xA;&lt;h3&gt;Packet tracing with a packet size of 8x8:&lt;/h3&gt;&#xA;&lt;p&gt;Did 9,904,128 triangle intersections&lt;/p&gt;&#xA;&lt;p&gt;Did 602,404 traversals&lt;/p&gt;&#xA;&lt;p&gt;Did 10,080,299 box intersections&lt;/p&gt;&#xA;&lt;h3&gt;Packet tracing with a packet size of 16x16:&lt;/h3&gt;&#xA;&lt;p&gt;Did 20,155,648 triangle intersections&lt;/p&gt;&#xA;&lt;p&gt;Did 248,074 traversals&lt;/p&gt;&#xA;&lt;p&gt;Did 10,991,985 box intersections&lt;/p&gt;&#xA;&lt;h2&gt;Path tracing&lt;/h2&gt;&#xA;&lt;p&gt;A part of the handin was also to implement either photon mapping or path tracing. I chose path tracing with 512 samples per pixel. The result can be seen here&lt;/p&gt;&#xA;&lt;img src=&quot;https://madsravn.dk/images/teapot.pathtracing.png&quot; alt=&quot;pathtracing&quot; /&gt;&#xA;&lt;h2&gt;The conclusion&lt;/h2&gt;&#xA;&lt;p&gt;This was a very fun project to work on and an exciting way to finish of a good course in rendering algorithms. I wish I could have had more time doing this project because I don&apos;t think I was far from getting much better results using leaf traversal. As you can see on my numbers above the amount of ray/triangle intersection tests explode at packet size 16x16, while the traversal is pretty low. &lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Chess summary for January</title>
   <link href="https://madsravn.dk/posts/chess-summary-for-january.html"/>
   <updated>2013-01-31T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/chess-summary-for-january</id>
   <content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Back in November I saw a video posted on Reddit. It was a video of an analysis of a chess game. This got me motivated to try playing chess and I really liked it. I also like numbers, so I have decided that I want to sum up each month of chess from now on. &lt;/p&gt;&#xA;&lt;p&gt;Unfortunately January has been a exam month, so the number of chess games are sort of scarce. But I felt chess was a welcome distraction when I wanted a little breathing room from all the reading.&lt;/p&gt;&#xA;&lt;h2&gt;The Numbers&lt;/h2&gt;&#xA;&lt;p&gt;I made &lt;a href=&quot;https://github.com/madsravn/pgn-divider/blob/master/divider.sh&quot;&gt;a little script&lt;/a&gt; to sort out the data from one big file of pgn annotation since chesscube will not let me download pgn files other than manually. From this I could deduce some statistics.&lt;/p&gt;&#xA;&lt;p&gt;I made a fancy chart with the help of &lt;a href=&quot;https://www.chartgo.com&quot;&gt;www.chartgo.com&lt;/a&gt;. &lt;/p&gt;&#xA;&lt;img src=&quot;https://madsravn.dk/images/chess1.png&quot; alt=&quot;games&quot; /&gt;&#xA;&lt;p&gt;I played 46 games in January. Luckily for my ego I won more than I lost. I won nearly the same amount of games playing white as I did playing black. A fun difference is noticeable in the games I lost: I only lost 6 games as white compared to the 12 games I lost as black. Of course only having played 46 games this doesn&apos;t seem like a big leap.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately the game history chesscube saves only includes the rating of the players after the game. So I can make any analysis to whether players had higher or lower rating than me at the time of the game since if I had played a player near my rating and won he would probably have lower rating than me after the game. Of the 27 games I won only 3 of my opponents had a higher rating than me AFTER the game. So I think I can conclude that most of my victories were over players with a lower rating than my own.&lt;/p&gt;&#xA;&lt;p&gt;In the end I went from 1326 to 1352 rating on chesscube. Even though I haven&apos;t really moved significantly up I feel like I have learned a lot from just playing and experiencing.&lt;/p&gt;&#xA;&lt;p&gt;I had imagined I could have made more charts (Who doesn&apos;t love charts?), but seeing that I can&apos;t do any analysis of the ratings, it seems futile to make charts of more than just win/lose. If you have any idea what I can of further analysis with data given in a pgn file containing the rating after the game, please let me know. You can see how what kind of data is in the chesscube pgn in my &lt;a href=&quot;https://github.com/madsravn/pgn-divider/blob/master/january-2013.pgn&quot;&gt;January PGN chunk here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2&gt;The conclusion&lt;/h2&gt;&#xA;&lt;p&gt;I really like playing chess. I like that the game doesn&apos;t include any form of randomness that many other games like card games and backgammon have. I also feel like I am training my concentration by playing and trying to think some moves ahead while keeping my head in current situation of the game.&lt;/p&gt;&#xA;&lt;p&gt;I would like to thank &lt;a href=&quot;https://www.youtube.com/user/Ruxistico/videos?view=0&quot;&gt;Rune Friborg&lt;/a&gt; for making the video who initially got me motivated to play. He also invited me to an awesome facebook group &amp;quot;Fucking Skak&amp;quot; (Fucking Chess) and then challenged me to a game and gave me an analysis of the game afterwards - this was an awesome start on my chess adventure. I&apos;d also like to thank the awesome facebook group Fucking skak for constant motivation and chess news. The people in the group seems like good and dedicated players and this is the first facebook group I have been in which actually contributes content of very high quality!&lt;/p&gt;&#xA;&lt;p&gt;And I cannot forget the huge impact both &lt;a href=&quot;https://www.youtube.com/user/kingscrusher&quot;&gt;kingcrusher&lt;/a&gt; and &lt;a href=&quot;https://www.reddit.com/r/chess&quot;&gt;/r/chess&lt;/a&gt; have had on my game. Both definitely delivers good content on a regular basis!&lt;/p&gt;&#xA;&lt;p&gt;It&apos;s obvious I have a long way to go and A LOT more games to play before I can call myself a decent chess player. But the journey there seems fun and the goal worthwhile.&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Raspberry Pi with slow external hard drive</title>
   <link href="https://madsravn.dk/posts/raspberry-with-slow-external-hard-drive.html"/>
   <updated>2013-01-01T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/raspberry-with-slow-external-hard-drive</id>
   <content type="html">&lt;p&gt;On a day like January 1st I mostly like relaxing in front of the TV with some movies or series and I had been looking forward to it. I got a powered USB hub for Christmas since our external hard drive, a Verbatim N446, is USB powered and the Raspberry doesn&apos;t provide enough power for it. So we plugged in our new USB hub and plugged the drive to that. Discovery and mounting went fine, but when we started watching something it would take 3 seconds before it would start to buffer - it actually used more time buffered than playing.&lt;/p&gt;&#xA;&lt;p&gt;A &lt;code&gt;hdparm -tT /dev/sda&lt;/code&gt; showed some disturbing news:&#xA;/dev/sda:&#xA;Timing cached reads:   160 MB in  2.02 seconds =  79.35 MB/sec&#xA;Timing buffered disk reads:  14 MB in 33.51 seconds = 427.79 kB/sec&lt;/p&gt;&#xA;&lt;p&gt;No way we could watch a movie with 428 kB/sec. A little internet research showed that our Raspberry Pi atleast treats it&apos;s USB ports as a USB hub already and when connecting a new one only the four first ports are given decent speed. Checking &lt;code&gt;lsusb&lt;/code&gt; I saw it might make sense since the Raspberry had two entries for &amp;quot;USB-2.0 4-Port HUB&amp;quot;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;Bus 001 Device 005: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB&#xA;Bus 001 Device 006: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB&#xA;Bus 001 Device 008: ID 18a5:0237 Verbatim, Ltd Portable Harddrive (500 GB)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I found this weird and with a disbelief I tried swapping my external drive to the first port on the hub. &lt;code&gt;hdparm -tT /dev/sdb&lt;/code&gt; revealed it was working much better now: &#xA;/dev/sdb:&#xA;Timing cached reads:   154 MB in  2.00 seconds =  77.01 MB/sec&#xA;Timing buffered disk reads:  40 MB in  3.10 seconds =  12.89 MB/sec&#xA;an increase in speed with a factor 30 was pretty convincing. I tried comparing this speed to the speed on the Raspberrys SD card&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;Timing cached reads:   162 MB in  2.02 seconds =  80.26 MB/sec&#xA;Timing buffered disk reads:  52 MB in  3.03 seconds =  17.17 MB/sec&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;which shows that now the external drives speed was now close enough to decent speed. Happily we could now lie lifeless on the couch for some hours watching some mindless stuff :)&lt;/p&gt;&#xA;&lt;p&gt;I hope this can help others to try this simple solution before going the tech-route with installing and configuring a bunch of needless stuff.&lt;/p&gt;&#xA;&lt;p&gt;Equipment used:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Raspberry Pi Model B rev. 2&lt;/li&gt;&#xA;&lt;li&gt;Verbatim N446&lt;/li&gt;&#xA;&lt;li&gt;Trust 7 Port USB2 Powered Hub (HU-5870V)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>Music or audiobooks or ...</title>
   <link href="https://madsravn.dk/posts/music-or-audiobooks-or.html"/>
   <updated>2012-12-13T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/music-or-audiobooks-or</id>
   <content type="html">&lt;p&gt;Many people today listen to music on the go - to work, to school or just between places.  When I look around on any given day most people either have ear plugs in their ears or headphones over them.  Some people actually play so loud that you can just behind them and enjoy their music for free, while others I look at and wonder what they&apos;re playing.&lt;/p&gt;&#xA;&lt;p&gt;I used to listen to music myself back in the days. However, I tend to hear the same songs too much in a small period of time and then I get sick of them. This trend of mine required me to swap my music out on a regular basis and I am not really good at finding new music, and not in that small amount of time. So instead I started listening to radio. We have a pretty good radio station here in Denmark, called &lt;a href=&quot;https://www.dr.dk/p3&quot;&gt;P3&lt;/a&gt;. The talk a bit... quite a lot actually and I quickly realized I liked the parts with people talking more than I liked their mainstream pop (and Danish pop really sucks), so I decided to try an audiobook instead. I started out with a book which had been on my to-reread list for a while: Sun Tzus Art of War. &lt;/p&gt;&#xA;&lt;p&gt;It worked out great. The book was quickly &amp;quot;read&amp;quot; since I usually walk home from school or work instead of taking the bus because I find it relaxing to just walk, get some air and not think of work/school before I come home and start working on the weekly handins. So I went on listening to some more books - I found that I enjoyed non-fiction over fiction when listening to an audiobook while normally I like both genres. The latest book I heard was Atul Gawandes The Checklist Manifesto which actually exceeded my expectations: It was exciting and I learned a bit from it. &lt;/p&gt;&#xA;&lt;p&gt;But then some weeks ago I decided to re-watch &lt;a href=&quot;https://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style&quot;&gt;Bjarne Stroustrups keynote from GoingNative 2012&lt;/a&gt; since I liked some of the ideas for style that he presented. Then I noticed that you could download the talk in MP3 (Audio only). I then thought to myself that I would just listen to it on my way home from school the day after. It was just as good - an audio-only version of Bjarne was plenty. So when I got home I went online to &lt;a href=&quot;https://channel9.msdn.com&quot;&gt;channel9.msdn.com&lt;/a&gt; to see what else there was. There&apos;s a lot of very nice talks, interviews and such on there. Since I programming languages and that sort of stuff I mainly browse &lt;a href=&quot;https://channel9.msdn.com/Shows/Going+Deep&quot;&gt;Going Deep&lt;/a&gt; for videos I want to hear when I walk home. Lately I heard the interview Anders Hejlsberg and Lars Bak talking about &lt;a href=&quot;https://channel9.msdn.com/Shows/Going+Deep/Anders-Hejlsberg-and-Lars-Bak-TypeScript-JavaScript-and-Dart&quot;&gt;Typescript, Javascript and Dart&lt;/a&gt; since we&apos;re covering all three languages in a course in school so I thought I could learn a little extra about it anyways. It was very exciting as well.&lt;/p&gt;&#xA;&lt;p&gt;I&apos;m fairly sure I&apos;m not the inventor of this concept. I just found out about it myself and I&apos;m enjoying myself with it. I can warmly recommend it. So what do you listen to?&lt;/p&gt;&#xA;</content>
 </entry>
 
 <entry>
   <title>First post with Jekyll</title>
   <link href="https://madsravn.dk/posts/first-post.html"/>
   <updated>2012-10-07T00:00:00+01:00</updated>
   <id>https://madsravn.dk/posts/first-post</id>
   <content type="html">&lt;p&gt;&lt;b&gt;First post with jekyll:&lt;/b&gt; This is my first post with the jekyll engine. While I have yet to understand all the wonders of it, I find it most awesome.&#xA;You can find more information about the jekyll engine on Github &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;here&lt;/a&gt;. I am also using &lt;a href=&quot;https://daringfireball.net/projects/markdown/syntax&quot;&gt;this short overview&lt;/a&gt; to learn the markdown syntax used by Github to render the pages on github pages.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;p&gt;I have been following &lt;a href=&quot;https://zachholman.com/&quot;&gt;Zach Holmans blog&lt;/a&gt; for some time now and I eagerly been reading about his work at Github and what he feels is a hot topic on a given blog-post date. I came to admire him: Writing exciting stuff, working at github and having friendly and funny discussion on Twitter and at Hacker News.&lt;/p&gt;&#xA;&lt;p&gt;I then did what others do when they strive to achieve: I imitated the person having what I wanted to have. I have borrowed the idea of using Jekyll on Github and the design of the blog from Zach - with permission of course. I have it a bit, though - my name instead of his name, some small details as sizes in the style and then &lt;a href=&quot;https://evafrederiksen.blogspot.dk/&quot;&gt;my girlfriend&lt;/a&gt; made some new icons for my menu since the ones Zach had weren&apos;t free.&lt;/p&gt;&#xA;&lt;p&gt;My idea is to change the look and feel of the site gradually over time since design isn&apos;t really my strong suit and right now I&apos;m quite content with the look. But I can imagine that eventually I want a site which I have made mostly entirely myself instead of a site where only 10% of the design is my own.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;p&gt;So what do I want to do with this site? I want to showcase my current projects, write about solutions to problems I encounter at school or at work, tell people about my interest and what I think could be a hot topic. I am recent convert to vim and I have also recently begun playing a great deal of chess, so I could imagine I am going to write some posts about that since I would both like to share my thoughts on those topic and get some input on my thoughts.&lt;/p&gt;&#xA;</content>
 </entry>
 
 
</feed>
