<?xml version='1.0' encoding='UTF-8'?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>Luke Briggs</title>
    <link>https://lukebriggs.dev/</link>
    <description>I'm Luke Briggs: a Computer Science student from the UK studying at Newcastle University</description>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <image>
      <url>/Users/luke/Documents/Projects/lukebriggs.dev/public/favicon.ico</url>
      <title>Luke Briggs</title>
      <link>https://lukebriggs.dev/</link>
    </image>
    <language>en</language>
    <lastBuildDate>Thu, 23 Mar 2023 23:22:41 +0000</lastBuildDate>
    <item>
      <title>The First Line of Code
</title>
      <link>https://lukebriggs.dev/posts/the-first-line-of-code</link>
      <description>&lt;img class='post-hero' src='static/postimages/1/code.png' alt='&lt;div&gt;The First Line of Code&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;The First Line of Code&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“The Guide says there is an art to flying”, said Ford, “or
rather a knack. The knack lies in learning how to throw
yourself at the ground and miss.”&lt;/p&gt;
&lt;p&gt;-Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I always had a desire to look under the hood of the video games and software I spent so much time on growing up but I was greeted with a rainbow of semi-colons and syntax before immediately closing the lid of my laptop and retiring back to being merely an end-user.&lt;/p&gt;
&lt;p&gt;It took until a computer science course at age 14 in my school before I was finally able to understand just the basics of what I could do with a keyboard. The language was python and the atmosphere wasn’t me alone in a bedroom at a monitor scratching my head in fury, it was a class effort. None of us understood what was going on and it made it all the more accessible.&lt;/p&gt;
&lt;p&gt;In my current exploration of programming languages I see far too many people telling those learning to code of how you ‘must’ do this and I watch videos of monotonous commentators who half explain some concepts that fly over newcomers heads. I feel the steep learning curve that programming has is a mighty feat without an actual teacher or a series of quality YouTube videos that only come around once in a blue moon.&lt;/p&gt;
&lt;p&gt;This blog will be a documentation of my journey from having basic grasps of a few programming languages through a higher education computer science course and my video-game creating antics on the side. It will detail my learning experiences and may help anyone else wanting to learn what the pathway is like.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/1/code.png' alt='&lt;div&gt;The First Line of Code&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;The First Line of Code&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“The Guide says there is an art to flying”, said Ford, “or
rather a knack. The knack lies in learning how to throw
yourself at the ground and miss.”&lt;/p&gt;
&lt;p&gt;-Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I always had a desire to look under the hood of the video games and software I spent so much time on growing up but I was greeted with a rainbow of semi-colons and syntax before immediately closing the lid of my laptop and retiring back to being merely an end-user.&lt;/p&gt;
&lt;p&gt;It took until a computer science course at age 14 in my school before I was finally able to understand just the basics of what I could do with a keyboard. The language was python and the atmosphere wasn’t me alone in a bedroom at a monitor scratching my head in fury, it was a class effort. None of us understood what was going on and it made it all the more accessible.&lt;/p&gt;
&lt;p&gt;In my current exploration of programming languages I see far too many people telling those learning to code of how you ‘must’ do this and I watch videos of monotonous commentators who half explain some concepts that fly over newcomers heads. I feel the steep learning curve that programming has is a mighty feat without an actual teacher or a series of quality YouTube videos that only come around once in a blue moon.&lt;/p&gt;
&lt;p&gt;This blog will be a documentation of my journey from having basic grasps of a few programming languages through a higher education computer science course and my video-game creating antics on the side. It will detail my learning experiences and may help anyone else wanting to learn what the pathway is like.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 23 Jun 2018 16:42:40 +0000</pubDate>
    </item>
    <item>
      <title>A Game of Two Halves
</title>
      <link>https://lukebriggs.dev/posts/a-game-of-two-halves</link>
      <description>&lt;img class='post-hero' src='static/postimages/2/construct2.jpg' alt='&lt;div&gt;A Game of Two Halves&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;A Game of Two Halves&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“It is a mistake to think you can solve any major problems
just with potatoes.”&lt;/p&gt;
&lt;p&gt;-Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first videogame I ever played was Crash Bandicoot for the PlayStation One. I spent many an hour running my little orange friend across precarious ledges and away from Raiders of the Lost Ark levels of boulderage.  As is usually the case with videogames during your early childhood, I imagine I didn’t get anywhere near as far as I think. I will never know though as not long into my tenure in videogames I suffered my first casualty. My PS1 and all its saves froze in a pixellated mess on my screen and in the words of John Cleese, “ceased to be”.&lt;/p&gt;
&lt;p&gt;As I played more advanced and thought-provoking games I wondered what it would take to make my own and after numerous false starts I  finally made my first game (sort of). The game , Fallen Stars, was made using [Construct 2] (&lt;a href="https://www.scirra.com/"&gt;https://www.scirra.com/&lt;/a&gt;). Construct is the piece of software that makes making games so easy you can create your first game within a day, rather than programming scripts and dealing with forces you utilise an incredibly powerful ‘drag and drop’ interface with the ability to create some pretty professional looking software. I recommend watching &lt;a href="https://www.youtube.com/watch?v=zxAjmicdeiU&amp;amp;list=PLRDhcp_8c7uAPQfE6WMBo7PCNlkQIOLdO"&gt;3kliksphilip’s Game Making Journey&lt;/a&gt; for an almost videogame origin story as well an explanation of what these types of tools can do. I would thoroughly recommend those who don’t know where to begin to give these prototyping software ago as it is by far the way to get the quickest turnaround of a videogame from concept to executable.&lt;/p&gt;
&lt;p&gt;Following my escapades in construct my game making took back seat as I switched to learning more programming languages past the rudimentary python skills gained at age 14 in school and final exams loomed in summer 2018. I furthered my knowledge of python and used websites such as &lt;a href="https://www.codecademy.com/"&gt;Codeacademy&lt;/a&gt; to pickup the basics of JavaScript and C#; this is very useful in showing you what all different types of languages there are and the uses of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I would like to stress at this moment I only have a basic knowledge of these thee languages. Instantiation is as advanced as it gets at the moment, just wanted to reassure anyone wanting to learn to program that you don’t need to be an expert at all these to get a grasp of what programming is like or in order to get a good base for game development.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Fast-forward to now, summer 2018, and I have time for game development again and I wanted it to more closely link to my programming and software work. I chose Unity as my editor of choice for three reasons.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It allows me to use the C# skills I had already put the effort in learning.&lt;/li&gt;
&lt;li&gt;It seems a lot more accessible than other engines as the structure seems more straightforward and you can get almost all features for free.&lt;/li&gt;
&lt;li&gt;It is versatile. You can make both 2D and 3D games for pretty much all platforms.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is with Unity that I went on to make my next game Ping.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/2/construct2.jpg' alt='&lt;div&gt;A Game of Two Halves&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;A Game of Two Halves&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“It is a mistake to think you can solve any major problems
just with potatoes.”&lt;/p&gt;
&lt;p&gt;-Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first videogame I ever played was Crash Bandicoot for the PlayStation One. I spent many an hour running my little orange friend across precarious ledges and away from Raiders of the Lost Ark levels of boulderage.  As is usually the case with videogames during your early childhood, I imagine I didn’t get anywhere near as far as I think. I will never know though as not long into my tenure in videogames I suffered my first casualty. My PS1 and all its saves froze in a pixellated mess on my screen and in the words of John Cleese, “ceased to be”.&lt;/p&gt;
&lt;p&gt;As I played more advanced and thought-provoking games I wondered what it would take to make my own and after numerous false starts I  finally made my first game (sort of). The game , Fallen Stars, was made using [Construct 2] (&lt;a href="https://www.scirra.com/"&gt;https://www.scirra.com/&lt;/a&gt;). Construct is the piece of software that makes making games so easy you can create your first game within a day, rather than programming scripts and dealing with forces you utilise an incredibly powerful ‘drag and drop’ interface with the ability to create some pretty professional looking software. I recommend watching &lt;a href="https://www.youtube.com/watch?v=zxAjmicdeiU&amp;amp;list=PLRDhcp_8c7uAPQfE6WMBo7PCNlkQIOLdO"&gt;3kliksphilip’s Game Making Journey&lt;/a&gt; for an almost videogame origin story as well an explanation of what these types of tools can do. I would thoroughly recommend those who don’t know where to begin to give these prototyping software ago as it is by far the way to get the quickest turnaround of a videogame from concept to executable.&lt;/p&gt;
&lt;p&gt;Following my escapades in construct my game making took back seat as I switched to learning more programming languages past the rudimentary python skills gained at age 14 in school and final exams loomed in summer 2018. I furthered my knowledge of python and used websites such as &lt;a href="https://www.codecademy.com/"&gt;Codeacademy&lt;/a&gt; to pickup the basics of JavaScript and C#; this is very useful in showing you what all different types of languages there are and the uses of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I would like to stress at this moment I only have a basic knowledge of these thee languages. Instantiation is as advanced as it gets at the moment, just wanted to reassure anyone wanting to learn to program that you don’t need to be an expert at all these to get a grasp of what programming is like or in order to get a good base for game development.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Fast-forward to now, summer 2018, and I have time for game development again and I wanted it to more closely link to my programming and software work. I chose Unity as my editor of choice for three reasons.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It allows me to use the C# skills I had already put the effort in learning.&lt;/li&gt;
&lt;li&gt;It seems a lot more accessible than other engines as the structure seems more straightforward and you can get almost all features for free.&lt;/li&gt;
&lt;li&gt;It is versatile. You can make both 2D and 3D games for pretty much all platforms.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is with Unity that I went on to make my next game Ping.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 23 Jun 2018 17:20:33 +0000</pubDate>
    </item>
    <item>
      <title>Inspection &amp; Dissection: Ping! – My First Game in Unity
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-ping</link>
      <description>&lt;img class='post-hero' src='static/postimages/3/unity.jpg' alt='&lt;div&gt;Inspection &amp; Dissection: Ping! – My First Game in Unity&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: Ping! – My First Game in Unity&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Human beings, who are almost unique in having the ability to learn from the &amp;gt; experience of others, are also remarkable for their apparent disinclination to
do so.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Available at my &lt;a href="projects"&gt;project&lt;/a&gt; page&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Such a Simple Game?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because I wouldn’t have made a game otherwise. You need to affirm any skills in the most basic of games. Even if it kills you making a game so boring, at least you’ve made a game and proved that you can do it. It is an important lesson to learn that you will lose interest in a project and you will have to force yourself to carry on through the mid-development slog. To get around this you have to break a project into stages and set small goals. For instance, while making pong you may set yourself the goal of making a paddle that moves with keyboard inputs and can collide with things, next you might set the goal of making a ball that can bounce off of walls, next a working scoring system and so on. Another important thing to remember is you are almost definitely doing this as a hobby so don’t spend hours forcing yourself to do something you don’t want to do. Sometimes you do have to face it but it is almost always better leaving it and waiting until the next day to finish it when you have a clear head and can be bothered to continue. Burnout can often strike.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where did you start?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First I only had the idea of making a game in unity, that’s it, so I watched a series by the excellent YouTube channel &lt;a href="https://www.youtube.com/watch?v=j48LtUkZRjU&amp;amp;list=PLPV2KyIb3jR53Jce9hP7G5xC4O9AgnOuL"&gt;Brackeys&lt;/a&gt; that put me on the first step to knowing what I would have to do to make a game. I then decided on pong due to the reasons answered in the previous question. If I got stuck, I consulted the Incredible &lt;a href="https://docs.unity3d.com/Manual/index.html"&gt;Unity Documentation&lt;/a&gt;,  Google or follow a guide by &lt;a href="https://www.awesomeincu.com/tutorials/unity-pong/"&gt;Awesome Inc&lt;/a&gt;. Whilst the guide was necessary for some parts, specifically the ball bouncing, I made sure I did as much as I could with only the Unity documentation and Google searches as I often found on previous years of false starts I would just copy code and not learn anything whereas figuring out these things yourself means you are much more engaged and likely to remember it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do you think the game turned out?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As my first serious game, I am pleased. The game could be made more fun with more sporadic ball movements and a single player A.I. The paddle also glitches out slightly if you keep hitting into walls but it was meant to be nothing more than proving to myself that I can make a game in Unity. It has taught me the necessary skills and I have learned from the experience enough to move onto a slightly bigger project (not much bigger). Game development is a game in itself, you start off with a tutorial then make your way up increasingly difficult stages,  you wouldn’t jump into a level 50 area when your only level 5 and you wouldn’t go straight to the glowing sea in fallout 4 when all you’ve got is a is vault jumpsuit and a baseball bat.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/3/unity.jpg' alt='&lt;div&gt;Inspection &amp; Dissection: Ping! – My First Game in Unity&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: Ping! – My First Game in Unity&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Human beings, who are almost unique in having the ability to learn from the &amp;gt; experience of others, are also remarkable for their apparent disinclination to
do so.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Available at my &lt;a href="projects"&gt;project&lt;/a&gt; page&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Such a Simple Game?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because I wouldn’t have made a game otherwise. You need to affirm any skills in the most basic of games. Even if it kills you making a game so boring, at least you’ve made a game and proved that you can do it. It is an important lesson to learn that you will lose interest in a project and you will have to force yourself to carry on through the mid-development slog. To get around this you have to break a project into stages and set small goals. For instance, while making pong you may set yourself the goal of making a paddle that moves with keyboard inputs and can collide with things, next you might set the goal of making a ball that can bounce off of walls, next a working scoring system and so on. Another important thing to remember is you are almost definitely doing this as a hobby so don’t spend hours forcing yourself to do something you don’t want to do. Sometimes you do have to face it but it is almost always better leaving it and waiting until the next day to finish it when you have a clear head and can be bothered to continue. Burnout can often strike.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where did you start?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First I only had the idea of making a game in unity, that’s it, so I watched a series by the excellent YouTube channel &lt;a href="https://www.youtube.com/watch?v=j48LtUkZRjU&amp;amp;list=PLPV2KyIb3jR53Jce9hP7G5xC4O9AgnOuL"&gt;Brackeys&lt;/a&gt; that put me on the first step to knowing what I would have to do to make a game. I then decided on pong due to the reasons answered in the previous question. If I got stuck, I consulted the Incredible &lt;a href="https://docs.unity3d.com/Manual/index.html"&gt;Unity Documentation&lt;/a&gt;,  Google or follow a guide by &lt;a href="https://www.awesomeincu.com/tutorials/unity-pong/"&gt;Awesome Inc&lt;/a&gt;. Whilst the guide was necessary for some parts, specifically the ball bouncing, I made sure I did as much as I could with only the Unity documentation and Google searches as I often found on previous years of false starts I would just copy code and not learn anything whereas figuring out these things yourself means you are much more engaged and likely to remember it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do you think the game turned out?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As my first serious game, I am pleased. The game could be made more fun with more sporadic ball movements and a single player A.I. The paddle also glitches out slightly if you keep hitting into walls but it was meant to be nothing more than proving to myself that I can make a game in Unity. It has taught me the necessary skills and I have learned from the experience enough to move onto a slightly bigger project (not much bigger). Game development is a game in itself, you start off with a tutorial then make your way up increasingly difficult stages,  you wouldn’t jump into a level 50 area when your only level 5 and you wouldn’t go straight to the glowing sea in fallout 4 when all you’ve got is a is vault jumpsuit and a baseball bat.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 23 Jun 2018 17:52:33 +0000</pubDate>
    </item>
    <item>
      <title>Where I Began
</title>
      <link>https://lukebriggs.dev/posts/where-i-began</link>
      <description>&lt;img class='post-hero' src='static/postimages/4/code.jpg' alt='&lt;div&gt;Where I Began&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Where I Began&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“It can be very dangerous to see things from somebody else’s point of view
without the proper training.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I have said before, my first outreach into programming began with  a GCSE Computer Science course which was cancelled after 7 months for various reasons. Those 7 months were possibly the best way to get a strong foundation of how programming languages work and the general structure in which they follow. The lessons consisted of us being taught a feature (how to do ‘if’ statements, how to call functions, how to cycle through array, etc) and then being given a series of tasks that we had to create a program to complete. The first and simplest of these tasks was Bob’s Change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Problem:&lt;/span&gt;
&lt;span class="sd"&gt;Bob would like to buy some sweets, which cost 50p.&lt;/span&gt;
&lt;span class="sd"&gt;Bob has some money but, unfortunately, Bob is only 3&lt;/span&gt;
&lt;span class="sd"&gt;and has no concept of money yet. Bob’s solution to this&lt;/span&gt;
&lt;span class="sd"&gt;is to just hand over the whole of his change and hope the&lt;/span&gt;
&lt;span class="sd"&gt;shopkeeper will sort it out for him.&lt;/span&gt;
&lt;span class="sd"&gt;The function bobs_change takes in a number representing&lt;/span&gt;
&lt;span class="sd"&gt;how much money Bob has handed over (in pence). It should print&lt;/span&gt;
&lt;span class="sd"&gt;the amount of change owed if he has enough, or&lt;/span&gt;
&lt;span class="sd"&gt;“Sorry Bob, you don’t have enough” if he is short.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The program would then consist of if statements returning an answer after comparing the money Bob has to the price of a product. For those starting out programming, tests of these kind are a rewarding and fun way of practicing and reinforcing skills that you have learned. When learning a programming language I would strongly suggest using these sorts of tests after learning something new to ensure you both remember that skill better and to also give you a sense of progression as a new programming language can be hard to remember if it goes unused. The rest of the tasks we went through in that course can be downloaded &lt;a href="https://github.com/LukeBriggsDev/GCSE-Code-Tasks"&gt;here&lt;/a&gt;. And an entire assortment of more advanced tasks in many different languages can be found at &lt;a href="https://www.codewars.com"&gt;codewars.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Really learning a skill and then practicing it is all you need to further your knowledge of programming. Once you have a grasp of basic features, you can then start to make more advanced programs using numerous packages and modules that give you the tools to create graphics and deeper features.&lt;/p&gt;
&lt;p&gt;This was how I learned to program. It broke the stages up so I wasn’t daunted by the fact I only knew what for loops were and there was so much more in the language, I only focused on the task and I found with every task I got closer to an understanding where I could begin to realise what could be done and put me on good footing for future projects.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/4/code.jpg' alt='&lt;div&gt;Where I Began&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Where I Began&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“It can be very dangerous to see things from somebody else’s point of view
without the proper training.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I have said before, my first outreach into programming began with  a GCSE Computer Science course which was cancelled after 7 months for various reasons. Those 7 months were possibly the best way to get a strong foundation of how programming languages work and the general structure in which they follow. The lessons consisted of us being taught a feature (how to do ‘if’ statements, how to call functions, how to cycle through array, etc) and then being given a series of tasks that we had to create a program to complete. The first and simplest of these tasks was Bob’s Change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Problem:&lt;/span&gt;
&lt;span class="sd"&gt;Bob would like to buy some sweets, which cost 50p.&lt;/span&gt;
&lt;span class="sd"&gt;Bob has some money but, unfortunately, Bob is only 3&lt;/span&gt;
&lt;span class="sd"&gt;and has no concept of money yet. Bob’s solution to this&lt;/span&gt;
&lt;span class="sd"&gt;is to just hand over the whole of his change and hope the&lt;/span&gt;
&lt;span class="sd"&gt;shopkeeper will sort it out for him.&lt;/span&gt;
&lt;span class="sd"&gt;The function bobs_change takes in a number representing&lt;/span&gt;
&lt;span class="sd"&gt;how much money Bob has handed over (in pence). It should print&lt;/span&gt;
&lt;span class="sd"&gt;the amount of change owed if he has enough, or&lt;/span&gt;
&lt;span class="sd"&gt;“Sorry Bob, you don’t have enough” if he is short.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The program would then consist of if statements returning an answer after comparing the money Bob has to the price of a product. For those starting out programming, tests of these kind are a rewarding and fun way of practicing and reinforcing skills that you have learned. When learning a programming language I would strongly suggest using these sorts of tests after learning something new to ensure you both remember that skill better and to also give you a sense of progression as a new programming language can be hard to remember if it goes unused. The rest of the tasks we went through in that course can be downloaded &lt;a href="https://github.com/LukeBriggsDev/GCSE-Code-Tasks"&gt;here&lt;/a&gt;. And an entire assortment of more advanced tasks in many different languages can be found at &lt;a href="https://www.codewars.com"&gt;codewars.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Really learning a skill and then practicing it is all you need to further your knowledge of programming. Once you have a grasp of basic features, you can then start to make more advanced programs using numerous packages and modules that give you the tools to create graphics and deeper features.&lt;/p&gt;
&lt;p&gt;This was how I learned to program. It broke the stages up so I wasn’t daunted by the fact I only knew what for loops were and there was so much more in the language, I only focused on the task and I found with every task I got closer to an understanding where I could begin to realise what could be done and put me on good footing for future projects.&lt;/p&gt;
</content:encoded>
      <pubDate>Wed, 27 Jun 2018 18:40:06 +0000</pubDate>
    </item>
    <item>
      <title>Making a Mobile App – Chapter 1: A Few False Starts
</title>
      <link>https://lukebriggs.dev/posts/making-a-mobile-app-chapter-1</link>
      <description>&lt;img class='post-hero' src='static/postimages/5/phone.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 1: A Few False Starts&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 1: A Few False Starts&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“I may not have gone where I intended to go, but I think I have ended up
where I needed to be.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Self-learning is often like trying to solve a maze, you follow the first path you see as far as you can. You reach a dead end. Then use what you learned in that path to give you an idea of where you could go next.&lt;/p&gt;
&lt;p&gt;I’ve been trying to find a new small project for a while now. I lacked the enthusiasm to spend time making games as I generally find it is something you need to take a running jump at with a fresh idea and be able to maintain that flair through the tidal wave of texture drawing, physics calculations and gameplay design. At some point I will go back to game development but I wanted something new.&lt;/p&gt;
&lt;p&gt;It was around this time that the opportunity came up to develop an app that may or may not be used for a local business. It had the vague deadline that let me experiment but gave me the pressure to finish it, it let me design something that was professional and would have to be used practically and it was something I’d never done before on a platform I had never developed for.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/5/phone.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 1: A Few False Starts&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 1: A Few False Starts&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“I may not have gone where I intended to go, but I think I have ended up
where I needed to be.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Self-learning is often like trying to solve a maze, you follow the first path you see as far as you can. You reach a dead end. Then use what you learned in that path to give you an idea of where you could go next.&lt;/p&gt;
&lt;p&gt;I’ve been trying to find a new small project for a while now. I lacked the enthusiasm to spend time making games as I generally find it is something you need to take a running jump at with a fresh idea and be able to maintain that flair through the tidal wave of texture drawing, physics calculations and gameplay design. At some point I will go back to game development but I wanted something new.&lt;/p&gt;
&lt;p&gt;It was around this time that the opportunity came up to develop an app that may or may not be used for a local business. It had the vague deadline that let me experiment but gave me the pressure to finish it, it let me design something that was professional and would have to be used practically and it was something I’d never done before on a platform I had never developed for.&lt;/p&gt;
</content:encoded>
      <pubDate>Sun, 09 Dec 2018 19:57:21 +0000</pubDate>
    </item>
    <item>
      <title>Making a Mobile App – Chapter 2: A Bad Worker Blames His Tools
</title>
      <link>https://lukebriggs.dev/posts/making-a-mobile-app-chapter-2</link>
      <description>&lt;img class='post-hero' src='static/postimages/6/phone.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 2: A Bad Worker Blames His Tools&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 2: A Bad Worker Blames His Tools&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Don’t Panic.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finding the right tool for the job might be the most important thing I’ve learned &amp;gt;in my short time in the world of development. The classic conversation everyone who wants to get into development goes something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;New Guy: “What programming language is best.”&lt;/p&gt;
&lt;p&gt;Pro: “There isn’t one.”&lt;/p&gt;
&lt;p&gt;New Guy: “Ok. Well what programming language should I use for X.”&lt;/p&gt;
&lt;p&gt;Pro: “It depends.”&lt;/p&gt;
&lt;p&gt;New Guy: “Fine. Well what should I use if I want to use X for Y.”&lt;/p&gt;
&lt;p&gt;Pro: “Whatever you are comfortable with.”&lt;/p&gt;
&lt;p&gt;New Guy: “What do you mean comfortable. I’ve never programmed before,
anyway its not as if a language is some sort of sofa. Hey! Where are you going!
you can’t just leave me here!”&lt;/p&gt;
&lt;p&gt;Google: “Hello.”&lt;/p&gt;
&lt;p&gt;New Guy: “What.”&lt;/p&gt;
&lt;p&gt;Google: “I’m your new best friend.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are so many use cases and things you might want to develop that almost every instance of someone’s development is bespoke to what they want. This is something that you have to have experiences before you understand it which makes it more useful for a new developer to learn while doing rather than learning then doing.&lt;/p&gt;
&lt;p&gt;I had to find the right tools for what I wanted. My requirements for this app were based off of the time constraints I had, the lack of experience I had and the needs I felt the app had:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Needed to be easy to port to different platforms.&lt;/li&gt;
&lt;li&gt;Had to be easy to integrate design and programming elements together.&lt;/li&gt;
&lt;li&gt;Needed to be able to make a professional and modern look.
4.Didn’t require low level access&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I settled on &lt;a href="https://facebook.github.io/react-native/"&gt;React Native&lt;/a&gt; with the &lt;a href="https://expo.io/"&gt;Expo toolchain&lt;/a&gt;. I felt React was by far the best option I had. The only other options were using C# to make a Xamarin.Forms app which felt a bit like using a jackhammer to do teeth surgery or learning to use Java and Objective-C/Swift to do native development and use a completely different codebase, not only would I have to learn two languages and systems at once but also would need to fork out an initial cost of $99 for an apple developer account and develop on an Mac which I neither have nor want.&lt;/p&gt;
&lt;p&gt;I’m using Expo because it means the app will be fully cross platform and I don’t need to interact with any of the awkward SDK’s and system specific stuff. Expo also provides a neat app that you run on your Android or iOS which connects to a local server with the app files and allows you to run your app within their app, no compiling, no apple developer account, no Mac. This made testing incredibly easy. Expo also handles keystoring for Android and all that fancy stuff.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/6/phone.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 2: A Bad Worker Blames His Tools&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 2: A Bad Worker Blames His Tools&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Don’t Panic.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finding the right tool for the job might be the most important thing I’ve learned &amp;gt;in my short time in the world of development. The classic conversation everyone who wants to get into development goes something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;New Guy: “What programming language is best.”&lt;/p&gt;
&lt;p&gt;Pro: “There isn’t one.”&lt;/p&gt;
&lt;p&gt;New Guy: “Ok. Well what programming language should I use for X.”&lt;/p&gt;
&lt;p&gt;Pro: “It depends.”&lt;/p&gt;
&lt;p&gt;New Guy: “Fine. Well what should I use if I want to use X for Y.”&lt;/p&gt;
&lt;p&gt;Pro: “Whatever you are comfortable with.”&lt;/p&gt;
&lt;p&gt;New Guy: “What do you mean comfortable. I’ve never programmed before,
anyway its not as if a language is some sort of sofa. Hey! Where are you going!
you can’t just leave me here!”&lt;/p&gt;
&lt;p&gt;Google: “Hello.”&lt;/p&gt;
&lt;p&gt;New Guy: “What.”&lt;/p&gt;
&lt;p&gt;Google: “I’m your new best friend.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are so many use cases and things you might want to develop that almost every instance of someone’s development is bespoke to what they want. This is something that you have to have experiences before you understand it which makes it more useful for a new developer to learn while doing rather than learning then doing.&lt;/p&gt;
&lt;p&gt;I had to find the right tools for what I wanted. My requirements for this app were based off of the time constraints I had, the lack of experience I had and the needs I felt the app had:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Needed to be easy to port to different platforms.&lt;/li&gt;
&lt;li&gt;Had to be easy to integrate design and programming elements together.&lt;/li&gt;
&lt;li&gt;Needed to be able to make a professional and modern look.
4.Didn’t require low level access&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I settled on &lt;a href="https://facebook.github.io/react-native/"&gt;React Native&lt;/a&gt; with the &lt;a href="https://expo.io/"&gt;Expo toolchain&lt;/a&gt;. I felt React was by far the best option I had. The only other options were using C# to make a Xamarin.Forms app which felt a bit like using a jackhammer to do teeth surgery or learning to use Java and Objective-C/Swift to do native development and use a completely different codebase, not only would I have to learn two languages and systems at once but also would need to fork out an initial cost of $99 for an apple developer account and develop on an Mac which I neither have nor want.&lt;/p&gt;
&lt;p&gt;I’m using Expo because it means the app will be fully cross platform and I don’t need to interact with any of the awkward SDK’s and system specific stuff. Expo also provides a neat app that you run on your Android or iOS which connects to a local server with the app files and allows you to run your app within their app, no compiling, no apple developer account, no Mac. This made testing incredibly easy. Expo also handles keystoring for Android and all that fancy stuff.&lt;/p&gt;
</content:encoded>
      <pubDate>Sun, 09 Dec 2018 20:07:21 +0000</pubDate>
    </item>
    <item>
      <title>Making a Mobile App – Chapter 3: The Setup
</title>
      <link>https://lukebriggs.dev/posts/making-a-mobile-app-chapter-3</link>
      <description>&lt;img class='post-hero' src='static/postimages/7/drawingboard.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 3: The Setup&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 3: The Setup&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“He attacked everything in life with a mix of extraordinary genius and naive &amp;gt;incompetence, and it was often difficult to tell which was which.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Setting up your React/Expo app is fairly straightforward but does require using the command line and some basic knowledge. You can find further detail &lt;a href="https://expo.io/learn"&gt;here&lt;/a&gt; but I’ll summarise it now.&lt;/p&gt;
&lt;p&gt;Firstly you will need to download and install &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; This is quite self explanatory as it has an actual wizard thus not requiring any command line interaction. Node is necessary for almost anything running local javascript. Next you’ll need to open the command line (found on windows by typing ‘cmd’ into the start menu) and run this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;npm install expo-cli --global&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You will then be asked to create an Expo account. Next you want no navigate to the directory where you want to store your app, this is done in windows by typing ‘cd’ followed by the directory. For example :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;cd C:\Users\&amp;lt;Your Username&amp;gt;\Documents\app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run the commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;expo init my-new-project&lt;/span&gt;
&lt;span class="go"&gt;cd my-new-project&lt;/span&gt;
&lt;span class="go"&gt;expo start&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;‘expo start’ will be the command you run in the directory whenever you want to run your Expo app. I would also recommend starting with the ‘tabs’ template as it places some very useful files and means you don’t need to set up your own navigation bars. After you have ran the start command your browser will open up with a QR code. Scan the QR code in the Expo app (&lt;a href="https://play.google.com/store/apps/details?id=host.exp.exponent&amp;amp;hl=en_GB"&gt;Google Play&lt;/a&gt; and &lt;a href="https://itunes.apple.com/us/app/expo-client/id982107779?mt=8"&gt;iOS&lt;/a&gt;) and behold your first expo app. If you have experience in ReactJS, you can dive into the files with your text editor of choice (I prefer &lt;a href="https://code.visualstudio.com/"&gt;VS Code&lt;/a&gt;) and follow the instructions both in the app and consulting the &lt;a href="https://docs.expo.io/versions/v31.0.0/workflow/up-and-running"&gt;documentation&lt;/a&gt;.  If you don’t have experience, I would recommend using the &lt;a href="https://www.codecademy.com/learn"&gt;Codeacademy&lt;/a&gt; course on ReactJS and Javascript. Also remember Google is your best friend, if you don’t know something don’t be afraid to google it.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/7/drawingboard.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 3: The Setup&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 3: The Setup&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“He attacked everything in life with a mix of extraordinary genius and naive &amp;gt;incompetence, and it was often difficult to tell which was which.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Setting up your React/Expo app is fairly straightforward but does require using the command line and some basic knowledge. You can find further detail &lt;a href="https://expo.io/learn"&gt;here&lt;/a&gt; but I’ll summarise it now.&lt;/p&gt;
&lt;p&gt;Firstly you will need to download and install &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; This is quite self explanatory as it has an actual wizard thus not requiring any command line interaction. Node is necessary for almost anything running local javascript. Next you’ll need to open the command line (found on windows by typing ‘cmd’ into the start menu) and run this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;npm install expo-cli --global&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You will then be asked to create an Expo account. Next you want no navigate to the directory where you want to store your app, this is done in windows by typing ‘cd’ followed by the directory. For example :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;cd C:\Users\&amp;lt;Your Username&amp;gt;\Documents\app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run the commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;expo init my-new-project&lt;/span&gt;
&lt;span class="go"&gt;cd my-new-project&lt;/span&gt;
&lt;span class="go"&gt;expo start&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;‘expo start’ will be the command you run in the directory whenever you want to run your Expo app. I would also recommend starting with the ‘tabs’ template as it places some very useful files and means you don’t need to set up your own navigation bars. After you have ran the start command your browser will open up with a QR code. Scan the QR code in the Expo app (&lt;a href="https://play.google.com/store/apps/details?id=host.exp.exponent&amp;amp;hl=en_GB"&gt;Google Play&lt;/a&gt; and &lt;a href="https://itunes.apple.com/us/app/expo-client/id982107779?mt=8"&gt;iOS&lt;/a&gt;) and behold your first expo app. If you have experience in ReactJS, you can dive into the files with your text editor of choice (I prefer &lt;a href="https://code.visualstudio.com/"&gt;VS Code&lt;/a&gt;) and follow the instructions both in the app and consulting the &lt;a href="https://docs.expo.io/versions/v31.0.0/workflow/up-and-running"&gt;documentation&lt;/a&gt;.  If you don’t have experience, I would recommend using the &lt;a href="https://www.codecademy.com/learn"&gt;Codeacademy&lt;/a&gt; course on ReactJS and Javascript. Also remember Google is your best friend, if you don’t know something don’t be afraid to google it.&lt;/p&gt;
</content:encoded>
      <pubDate>Mon, 10 Dec 2018 20:14:17 +0000</pubDate>
    </item>
    <item>
      <title>Making a Mobile App – Chapter 4: Fast and Flash
</title>
      <link>https://lukebriggs.dev/posts/making-a-mobile-app-chapter-4</link>
      <description>&lt;img class='post-hero' src='static/postimages/8/desk.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 4: Fast and Flash&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 4: Fast and Flash&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“A common mistake that people make when trying to design something
completely foolproof is to underestimate the ingenuity of complete fools.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As this app will be for a business, it has to serve some purposes. First it has to present the company as a professional entity and also fit with its branding to provide not only a consistent experience but to also strengthen that companies place in your head, making them more likely to go to them rather than anyone else. Next it has to serve a point, it’s all well and good having some fancy spiel about company ethos and dedication to the craft but you want the user to have a reason to not only to install your app but to also keep using it. Finally, it has to be straightforward to use and foolproof. Well, nothing is foolproof proof. Well, nothing is foolproof.&lt;/p&gt;
&lt;a name='branding'&gt;&lt;/a&gt;&lt;h4&gt;Branding&lt;/h4&gt;
&lt;p&gt;The company colours were red, dark grey and white. It therefore makes sense for the app to only use the colours red dark grey and white, seems simple enough.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/redapp.png" alt="red app" /&gt;&lt;/p&gt;
&lt;p&gt;Eww, a red pastel background with black text and mismatch white buttons and icons. It looks like a tomato soup can just exploded in the microwave. It’s all about complimentary colours and keeping things clean. The main colour of any app or website shouldn’t be something outrageous or garish, you want to present professionalism and minimalism. It’s good to have an accent colour that pops and has your brand stand out but if you end up with too much it is both nauseating and ugly.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/blackapp.png" alt="black app" /&gt;&lt;/p&gt;
&lt;p&gt;Ahh Much better. Character is nice but flamboyance is very easily annoying&lt;/p&gt;
&lt;a name='purpose'&gt;&lt;/a&gt;&lt;h4&gt;Purpose&lt;/h4&gt;
&lt;p&gt;Like I say, your app needs a purpose otherwise what’s the point?&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/menu.png" alt="menu" /&gt;
&lt;img src="static/postimages/8/times.png" alt="times" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see the app act doesn’t revolutionise e-commerce but what it does do is act as a hub for everything involved with this company. You can click a button and google maps opens up with the locations for shops and restaurants already plugged in and ready to plan a route. You can call to book a table for a restaurant and there are galleries of menus and images to see what products and dishes are on offer (As a side note if you are making a ReactJS app in Expo then &lt;a href="https://www.npmjs.com/package/react-native-image-view"&gt;react-native-image-view&lt;/a&gt; is a godsend, it is a bit fiddly to get working but it means you can keep using Expo without having to delve into Android files and java SDKs).&lt;/p&gt;
&lt;a name='foolproofness-and-expandability'&gt;&lt;/a&gt;&lt;h4&gt;Foolproofness and Expandability&lt;/h4&gt;
&lt;p&gt;To make your app accessible you have to ensure it is something easy to navigate and intuitive to use. Since this is my first mobile app I felt it was more of a case of making sure it doesn’t look out of place compared to the modern selection of mobile apps that supermarkets and resteraunts have on offer. It uses clear icons and a navigation bar at the bottom which is the current style. I wanted the user to not be confused upon opening the app but feel comfortable in using it and having a smooth experience.&lt;/p&gt;
&lt;p&gt;One of the brilliant things about React Native is the modules are not only easy to use but also offer a great deal of wiggle room to do what you want. For example, creating new screens is as easy as adding a function to that screens javascript add sticking a call to it in a main navigator script; this allows the room to expand quite quickly once you’ve got a baseline set giving scalability without what some projects have which is a feeling of trying to balance on one leg while trying to solve a rubik’s cube.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/8/desk.jpg' alt='&lt;div&gt;Making a Mobile App – Chapter 4: Fast and Flash&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 4: Fast and Flash&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“A common mistake that people make when trying to design something
completely foolproof is to underestimate the ingenuity of complete fools.”&lt;/p&gt;
&lt;p&gt;Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As this app will be for a business, it has to serve some purposes. First it has to present the company as a professional entity and also fit with its branding to provide not only a consistent experience but to also strengthen that companies place in your head, making them more likely to go to them rather than anyone else. Next it has to serve a point, it’s all well and good having some fancy spiel about company ethos and dedication to the craft but you want the user to have a reason to not only to install your app but to also keep using it. Finally, it has to be straightforward to use and foolproof. Well, nothing is foolproof proof. Well, nothing is foolproof.&lt;/p&gt;
&lt;a name='branding'&gt;&lt;/a&gt;&lt;h4&gt;Branding&lt;/h4&gt;
&lt;p&gt;The company colours were red, dark grey and white. It therefore makes sense for the app to only use the colours red dark grey and white, seems simple enough.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/redapp.png" alt="red app" /&gt;&lt;/p&gt;
&lt;p&gt;Eww, a red pastel background with black text and mismatch white buttons and icons. It looks like a tomato soup can just exploded in the microwave. It’s all about complimentary colours and keeping things clean. The main colour of any app or website shouldn’t be something outrageous or garish, you want to present professionalism and minimalism. It’s good to have an accent colour that pops and has your brand stand out but if you end up with too much it is both nauseating and ugly.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/blackapp.png" alt="black app" /&gt;&lt;/p&gt;
&lt;p&gt;Ahh Much better. Character is nice but flamboyance is very easily annoying&lt;/p&gt;
&lt;a name='purpose'&gt;&lt;/a&gt;&lt;h4&gt;Purpose&lt;/h4&gt;
&lt;p&gt;Like I say, your app needs a purpose otherwise what’s the point?&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/8/menu.png" alt="menu" /&gt;
&lt;img src="static/postimages/8/times.png" alt="times" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see the app act doesn’t revolutionise e-commerce but what it does do is act as a hub for everything involved with this company. You can click a button and google maps opens up with the locations for shops and restaurants already plugged in and ready to plan a route. You can call to book a table for a restaurant and there are galleries of menus and images to see what products and dishes are on offer (As a side note if you are making a ReactJS app in Expo then &lt;a href="https://www.npmjs.com/package/react-native-image-view"&gt;react-native-image-view&lt;/a&gt; is a godsend, it is a bit fiddly to get working but it means you can keep using Expo without having to delve into Android files and java SDKs).&lt;/p&gt;
&lt;a name='foolproofness-and-expandability'&gt;&lt;/a&gt;&lt;h4&gt;Foolproofness and Expandability&lt;/h4&gt;
&lt;p&gt;To make your app accessible you have to ensure it is something easy to navigate and intuitive to use. Since this is my first mobile app I felt it was more of a case of making sure it doesn’t look out of place compared to the modern selection of mobile apps that supermarkets and resteraunts have on offer. It uses clear icons and a navigation bar at the bottom which is the current style. I wanted the user to not be confused upon opening the app but feel comfortable in using it and having a smooth experience.&lt;/p&gt;
&lt;p&gt;One of the brilliant things about React Native is the modules are not only easy to use but also offer a great deal of wiggle room to do what you want. For example, creating new screens is as easy as adding a function to that screens javascript add sticking a call to it in a main navigator script; this allows the room to expand quite quickly once you’ve got a baseline set giving scalability without what some projects have which is a feeling of trying to balance on one leg while trying to solve a rubik’s cube.&lt;/p&gt;
</content:encoded>
      <pubDate>Mon, 10 Dec 2018 21:57:21 +0000</pubDate>
    </item>
    <item>
      <title>Making a Mobile App – Chapter 5: Go Your Own Way
</title>
      <link>https://lukebriggs.dev/posts/making-a-mobile-app-chapter-5</link>
      <description>&lt;img class='post-hero' src='static/postimages/9/xkcd378.png' alt='&lt;div&gt;Making a Mobile App – Chapter 5: Go Your Own Way&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 5: Go Your Own Way&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Real programmers set the universal constants at the start such that the &amp;gt;universe evolves to contain the disk with the data they want .”&lt;/p&gt;
&lt;p&gt;xkcd 378&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wanted to add a gallery for users to be able to scroll through a variety of images so I did a quick google search about how I was going to go about it and I found &lt;a href="https://www.npmjs.com/package/react-native-image-view"&gt;react-native-image-view&lt;/a&gt;. In 6 lines of code and an array of Imgur links you can have a decent and working image gallery, job sorted! Right?&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/9/gallery.webp" alt="gallery" /&gt;&lt;/p&gt;
&lt;p&gt;In truth, it unsettled me. Was this cheating? Should I have created my own gallery? This package was better than anything I could come up with and something I wasn’t prepared to spend time on but I still felt like a part of the app was no longer mine.&lt;/p&gt;
&lt;p&gt;These sorts of ideas are things I have seen keep cropping up across everything I have done. I see other people’s enemy movement packages in Unity and magic code on StackOverflow that does everything you need, but are these a step to far? Are you losing what it means to actuallly create something? I’ve had all these questions and I think I will always question myself about the balance between hard coding everything from scratch and using magic boxes that do the gruntwork for you, but for now I have decided it’s about scope. It is not within the scope of this project to make an image gallery, it is just a small feature in an app that is for doing something else. The amount of time it would take to create something like this is time that could be spent doing something else that is specific to this app and does require the time spent on it.&lt;/p&gt;
&lt;p&gt;The way I intend to go about my projects is to learn what I need out of it and the crucial elements of it. If I’m making a game in Unity I would feel uncomfortable using someone else’s movement package, movement is such a core aspect of a game’s feel that I think I should have control over its nuance. Equally, I am ok with using an image viewer package as it means I can spend more time on bigger features and I will write my own image viewer if this one is no longer fit for purpose. This is a pet project and so it is really only my own motivation that is going to get it finished. The more time I spend on a time consuming feature, the less likely it is that the project will get finished. What I want out of this app is to come out the other side of it with something that is complete and to achieve this I need to pick and choose my battles.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/9/xkcd378.png' alt='&lt;div&gt;Making a Mobile App – Chapter 5: Go Your Own Way&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Making a Mobile App – Chapter 5: Go Your Own Way&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;“Real programmers set the universal constants at the start such that the &amp;gt;universe evolves to contain the disk with the data they want .”&lt;/p&gt;
&lt;p&gt;xkcd 378&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I wanted to add a gallery for users to be able to scroll through a variety of images so I did a quick google search about how I was going to go about it and I found &lt;a href="https://www.npmjs.com/package/react-native-image-view"&gt;react-native-image-view&lt;/a&gt;. In 6 lines of code and an array of Imgur links you can have a decent and working image gallery, job sorted! Right?&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/9/gallery.webp" alt="gallery" /&gt;&lt;/p&gt;
&lt;p&gt;In truth, it unsettled me. Was this cheating? Should I have created my own gallery? This package was better than anything I could come up with and something I wasn’t prepared to spend time on but I still felt like a part of the app was no longer mine.&lt;/p&gt;
&lt;p&gt;These sorts of ideas are things I have seen keep cropping up across everything I have done. I see other people’s enemy movement packages in Unity and magic code on StackOverflow that does everything you need, but are these a step to far? Are you losing what it means to actuallly create something? I’ve had all these questions and I think I will always question myself about the balance between hard coding everything from scratch and using magic boxes that do the gruntwork for you, but for now I have decided it’s about scope. It is not within the scope of this project to make an image gallery, it is just a small feature in an app that is for doing something else. The amount of time it would take to create something like this is time that could be spent doing something else that is specific to this app and does require the time spent on it.&lt;/p&gt;
&lt;p&gt;The way I intend to go about my projects is to learn what I need out of it and the crucial elements of it. If I’m making a game in Unity I would feel uncomfortable using someone else’s movement package, movement is such a core aspect of a game’s feel that I think I should have control over its nuance. Equally, I am ok with using an image viewer package as it means I can spend more time on bigger features and I will write my own image viewer if this one is no longer fit for purpose. This is a pet project and so it is really only my own motivation that is going to get it finished. The more time I spend on a time consuming feature, the less likely it is that the project will get finished. What I want out of this app is to come out the other side of it with something that is complete and to achieve this I need to pick and choose my battles.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 09 Mar 2019 20:47:46 +0000</pubDate>
    </item>
    <item>
      <title>Probably
</title>
      <link>https://lukebriggs.dev/posts/probably</link>
      <description>&lt;h1 class='post-title'&gt;&lt;div&gt;Probably&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;We are currently in a scholarly purgatory. The time between July and
September where you are attached to no institution, have no motivation and
spend months fretting over how your past self will affect your future self
(neither of which do anything for your current self)&lt;/p&gt;
&lt;p&gt;At 11 am I received my AS results via e-mail (how modern) and received AAB
+ Distinction. I am happy with this. It’s literally the second-best results I
could have achieved at this point, but there is still an unsettling feeling around
me. Something is gnawing away at me that prevents me from enjoying this now.&lt;/p&gt;
&lt;p&gt;During the summer months there isn’t a clear track to follow. No daily
lessons, no scheduled assignments. Any events just seem to be smeared across
what could possibly be discerned to be a date on close inspection. Nothing
tangible appears to be happening in terms of progress for long term goals and
as such there is no certainty.&lt;/p&gt;
&lt;p&gt;The longer the time between terms, the more in flux my future appears to be.
I could always fall back on the ‘everything is fine’ mantra but then it feels
as if I’m not striving towards what I want, or that I’m setting myself up for
future regret about not putting in the effort where it needed to be. My mind
runs through permutations of events, “someone probably got 3 As, they’re
the ones who are going to receive your university offer” I feel myself
fretting. I shouldn’t fret, but I do. I know people who failed they’re exams
and they have to repeat a year of their life, they would kill to be in my
situation. There are also people who seem like demigods to me who always get
perfect scores along with having elaborate and incredible side projects. To
some my worries will seem preposterous, to others I will seem I don’t know how
lucky I am. Perhaps I’m both these things and perhaps I’m neither.&lt;/p&gt;
&lt;p&gt;But I’m not in their situation, I’m in my situation and can only act within
the context of it. I want to achieve the best possible results I can, and I
didn’t. I wasn’t far off; in fact, I was damn close but it doesn’t matter the distance.
Out of the 216 combinations, I have satisfied 215, and the person inside me
that wanted that last one remains dissatisfied.&lt;/p&gt;
&lt;p&gt;Will 1 mark affect whether I get an offer from my preferred university?
Probably not. &lt;em&gt;Probably&lt;/em&gt; not. Probably is the most terrifying
word in the English language. There are no certainties in life, everything can
be prefixed with the word probably. Yet we feel the need to stick it
before only a few things, I presume this is to deliberately remind us of the
very large improbability of the task we about to undertake and then
what is the point of even specifying a chance in the first place? Perhaps a
wandering mind is a good sign. I’m not struggling to finance my education
through a side job or agonizing over planning to resist a year, I have a
supportive family and am grateful to my past self for not screwing everything
up terrible.&lt;/p&gt;
&lt;p&gt;So. Is everything fine?&lt;/p&gt;
&lt;p&gt;Probably.&lt;/p&gt;
</description>
      <content:encoded>&lt;h1 class='post-title'&gt;&lt;div&gt;Probably&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;We are currently in a scholarly purgatory. The time between July and
September where you are attached to no institution, have no motivation and
spend months fretting over how your past self will affect your future self
(neither of which do anything for your current self)&lt;/p&gt;
&lt;p&gt;At 11 am I received my AS results via e-mail (how modern) and received AAB
+ Distinction. I am happy with this. It’s literally the second-best results I
could have achieved at this point, but there is still an unsettling feeling around
me. Something is gnawing away at me that prevents me from enjoying this now.&lt;/p&gt;
&lt;p&gt;During the summer months there isn’t a clear track to follow. No daily
lessons, no scheduled assignments. Any events just seem to be smeared across
what could possibly be discerned to be a date on close inspection. Nothing
tangible appears to be happening in terms of progress for long term goals and
as such there is no certainty.&lt;/p&gt;
&lt;p&gt;The longer the time between terms, the more in flux my future appears to be.
I could always fall back on the ‘everything is fine’ mantra but then it feels
as if I’m not striving towards what I want, or that I’m setting myself up for
future regret about not putting in the effort where it needed to be. My mind
runs through permutations of events, “someone probably got 3 As, they’re
the ones who are going to receive your university offer” I feel myself
fretting. I shouldn’t fret, but I do. I know people who failed they’re exams
and they have to repeat a year of their life, they would kill to be in my
situation. There are also people who seem like demigods to me who always get
perfect scores along with having elaborate and incredible side projects. To
some my worries will seem preposterous, to others I will seem I don’t know how
lucky I am. Perhaps I’m both these things and perhaps I’m neither.&lt;/p&gt;
&lt;p&gt;But I’m not in their situation, I’m in my situation and can only act within
the context of it. I want to achieve the best possible results I can, and I
didn’t. I wasn’t far off; in fact, I was damn close but it doesn’t matter the distance.
Out of the 216 combinations, I have satisfied 215, and the person inside me
that wanted that last one remains dissatisfied.&lt;/p&gt;
&lt;p&gt;Will 1 mark affect whether I get an offer from my preferred university?
Probably not. &lt;em&gt;Probably&lt;/em&gt; not. Probably is the most terrifying
word in the English language. There are no certainties in life, everything can
be prefixed with the word probably. Yet we feel the need to stick it
before only a few things, I presume this is to deliberately remind us of the
very large improbability of the task we about to undertake and then
what is the point of even specifying a chance in the first place? Perhaps a
wandering mind is a good sign. I’m not struggling to finance my education
through a side job or agonizing over planning to resist a year, I have a
supportive family and am grateful to my past self for not screwing everything
up terrible.&lt;/p&gt;
&lt;p&gt;So. Is everything fine?&lt;/p&gt;
&lt;p&gt;Probably.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 17 Aug 2019 20:49:25 +0000</pubDate>
    </item>
    <item>
      <title>Inspection &amp; Dissection: Dice-Jack
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-dice-jack</link>
      <description>&lt;img class='post-hero' src='static/postimages/10/dicejack1.png' alt='&lt;div&gt;Inspection &amp; Dissection: Dice-Jack&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: Dice-Jack&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As part of a course we had to make a game in 2 days that involved random dice and be made as a Windows forms application with Visual Basic. So we had to make a game in something that was the furthest you could get from a game engine with a language I had never used before. But hey, &lt;a href="https://en.wikipedia.org/wiki/Rogue_%28video_game%29"&gt;Rogue&lt;/a&gt; was made in 1980 and the graphics had to be ASCII so it could be worse.&lt;/p&gt;
&lt;p&gt;The rest of the class generally stuck to the brief with 3 dice that you rolled and you got points for each dot.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack2.png" alt="dicejack 2" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, its rather simple. Theres 4 picture boxes, 4 labels, 2 buttons and a listbox. Dice are rolled, the dots are added up and the score is added to the listbox. After 5 rolls the game ends and the player is given their total score. But to know how I added further features we need to look at how this prototype was made.&lt;/p&gt;
&lt;a name='behind-the-prototype'&gt;&lt;/a&gt;&lt;h1&gt;Behind the prototype&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So we have our variables declared in the convoluted VB way. Die1, Die2, and Die3 and the scores for the corresponding dice. DicePoints is the total of those 3 scores and rollcount keeps track of how many times the dice were rolled. Random is just an object we use to generate random numbers&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tmrTimer_Tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Handles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tick&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Increments the load bar every tick&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;New&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Sets dice to random number when the timer ticks before the load is full&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On the board is a timer (inventfully called tmrTimer), it tick every 0.1s. Each tick it adds a bit onto the load bar at the bottom and randomizes the images on the dice. MatchImage is my own subroutine but all it does is take an integer and applies the correct face for it to whichever picture box I pass it.&lt;/p&gt;
&lt;p&gt;Once the bar gets to 100, the fun begins.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Adds the necessary points on the random dice when the load bar &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;reaches 100&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We stop the timer ticking, we empty the load bar and we increment our roll counter before adding up all the spots on the dice, pretty simple.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Adds Score to list&lt;/span&gt;
&lt;span class="n"&gt;lstScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Roll &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;
&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Almost done, we add our points to the listbox with some formatting. Add the points to the total score for the game and then set it back to 0.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MsgBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Your game score was &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Game Over&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btnStart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;False&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btnReset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we check whether they have reached the magic 5 rolls, if so we tell them their score and let them reset the game&lt;/p&gt;
&lt;p&gt;There is also some initialisation code that assigns images and there are event handlers that make the buttons work but this is the main logic. If you would like to see how that stuff works, you can find it at the &lt;a href="https://github.com/LukeBriggsDev/Dice-Alpha"&gt;github repo&lt;/a&gt;&lt;/p&gt;
&lt;a name='the-evolution'&gt;&lt;/a&gt;&lt;h1&gt;The Evolution&lt;/h1&gt;
&lt;p&gt;The following won’t include too many code snippets since it is slightly more extensive (the rushed deadline also means it resembles a tin of Heinz spaghetti in a tumble dryer but we’ll keep that between us)&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack1.png" alt="dicejack 1" /&gt;&lt;/p&gt;
&lt;p&gt;Lets break this down.&lt;/p&gt;
&lt;p&gt;First we have a background that was shamelessly made in powerpoint.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack3.png" alt="dicejack 3" /&gt;&lt;/p&gt;
&lt;p&gt;The rules, scores, and title are all labels. The bar on the right is made up of the same button and listbox items as before but with its properties edited to change colour, font and border style.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Rules have been changed to the following:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The goal is to get as close to 21 points without going over&lt;/li&gt;
&lt;li&gt;There is a Player and a Dealer&lt;/li&gt;
&lt;li&gt;Each contestant has 2 dice&lt;/li&gt;
&lt;li&gt;The player goes first&lt;/li&gt;
&lt;li&gt;Each dice spot is worth 2 points&lt;/li&gt;
&lt;li&gt;If either the player or dealer goes over 21, they lose the game&lt;/li&gt;
&lt;li&gt;After the first roll, if the player has not gone bust, they can choose to ‘stand’ or ‘hit’&lt;/li&gt;
&lt;li&gt;If they ‘hit’, the dice are rolled again and the player can choose to add the points of either die or the total of both dice&lt;/li&gt;
&lt;li&gt;The player must add a score after hitting, even if it means they will go ‘bust’&lt;/li&gt;
&lt;li&gt;In the event of a tie, the game goes to the dealer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rules are based on those by &lt;a href="http://www.chessandpoker.com/dice_blackjack.html"&gt;James Yates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Instead of a big chunk of code I’m going to show you the process of a turn through our good old friend the flow chart. They can be intimidating but I’ve tried to make it in a way that is easy to follow and you should be ale to get a grasp of what the code is doing behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/flowchart.png" alt="flowchart" /&gt;&lt;/p&gt;
&lt;p&gt;There you go, who needs a hundred lines of bolognese when you can have pastel shapes?&lt;/p&gt;
&lt;p&gt;Those who played the game may also notice this is the first time I’ve included a computer-controlled opponent, ‘The Dealer’. The dealer is like the player but has the advantages of being able to go second and win in the result of a draw. The dealer’s choice code is as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;

&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Dealer goes bust if no options are available&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerStand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tmrDealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Dealer stands if their score is more than the player&amp;#39;s&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerStand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerRoll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before this code I run checks that see which options are available after a dealer rolls (these are the DealerCanChoose variables). Here there is a series of conditionals that look at the options and picks the best one for the dealer.&lt;/p&gt;
&lt;p&gt;If there is only one option available, then the dealer will pick that one. If there is more than one option available then the dealer will pick whichever will get them the highest score that turn. If there are no options available then the dealer is bust and they will stand. The dealer will also stand if they have a score higher than that of the player. The dealer will continue to roll as long as they are lower than the player and their current score is under 17.&lt;/p&gt;
&lt;p&gt;And thats the game! The quickest project I’ve ever done and although its rough around the edges the gameplay is solid and I got to grips with windows form’s implementation of an event-driven program. You can find the full source code &lt;a href="https://github.com/LukeBriggsDev/Dice-Jack"&gt;here&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/10/dicejack1.png' alt='&lt;div&gt;Inspection &amp; Dissection: Dice-Jack&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: Dice-Jack&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As part of a course we had to make a game in 2 days that involved random dice and be made as a Windows forms application with Visual Basic. So we had to make a game in something that was the furthest you could get from a game engine with a language I had never used before. But hey, &lt;a href="https://en.wikipedia.org/wiki/Rogue_%28video_game%29"&gt;Rogue&lt;/a&gt; was made in 1980 and the graphics had to be ASCII so it could be worse.&lt;/p&gt;
&lt;p&gt;The rest of the class generally stuck to the brief with 3 dice that you rolled and you got points for each dot.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack2.png" alt="dicejack 2" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, its rather simple. Theres 4 picture boxes, 4 labels, 2 buttons and a listbox. Dice are rolled, the dots are added up and the score is added to the listbox. After 5 rolls the game ends and the player is given their total score. But to know how I added further features we need to look at how this prototype was made.&lt;/p&gt;
&lt;a name='behind-the-prototype'&gt;&lt;/a&gt;&lt;h1&gt;Behind the prototype&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;
&lt;span class="k"&gt;Dim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So we have our variables declared in the convoluted VB way. Die1, Die2, and Die3 and the scores for the corresponding dice. DicePoints is the total of those 3 scores and rollcount keeps track of how many times the dice were rolled. Random is just an object we use to generate random numbers&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tmrTimer_Tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Handles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tick&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Increments the load bar every tick&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;New&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Sets dice to random number when the timer ticks before the load is full&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&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 class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MatchImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pbxDie3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On the board is a timer (inventfully called tmrTimer), it tick every 0.1s. Each tick it adds a bit onto the load bar at the bottom and randomizes the images on the dice. MatchImage is my own subroutine but all it does is take an integer and applies the correct face for it to whichever picture box I pass it.&lt;/p&gt;
&lt;p&gt;Once the bar gets to 100, the fun begins.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Adds the necessary points on the random dice when the load bar &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;reaches 100&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;prbLoad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We stop the timer ticking, we empty the load bar and we increment our roll counter before adding up all the spots on the dice, pretty simple.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Adds Score to list&lt;/span&gt;
&lt;span class="n"&gt;lstScore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Roll &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DicePoints&lt;/span&gt;
&lt;span class="n"&gt;DicePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Almost done, we add our points to the listbox with some formatting. Add the points to the total score for the game and then set it back to 0.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RollCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;MsgBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Your game score was &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Game Over&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tmrTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btnStart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;False&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btnReset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we check whether they have reached the magic 5 rolls, if so we tell them their score and let them reset the game&lt;/p&gt;
&lt;p&gt;There is also some initialisation code that assigns images and there are event handlers that make the buttons work but this is the main logic. If you would like to see how that stuff works, you can find it at the &lt;a href="https://github.com/LukeBriggsDev/Dice-Alpha"&gt;github repo&lt;/a&gt;&lt;/p&gt;
&lt;a name='the-evolution'&gt;&lt;/a&gt;&lt;h1&gt;The Evolution&lt;/h1&gt;
&lt;p&gt;The following won’t include too many code snippets since it is slightly more extensive (the rushed deadline also means it resembles a tin of Heinz spaghetti in a tumble dryer but we’ll keep that between us)&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack1.png" alt="dicejack 1" /&gt;&lt;/p&gt;
&lt;p&gt;Lets break this down.&lt;/p&gt;
&lt;p&gt;First we have a background that was shamelessly made in powerpoint.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/dicejack3.png" alt="dicejack 3" /&gt;&lt;/p&gt;
&lt;p&gt;The rules, scores, and title are all labels. The bar on the right is made up of the same button and listbox items as before but with its properties edited to change colour, font and border style.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Rules have been changed to the following:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The goal is to get as close to 21 points without going over&lt;/li&gt;
&lt;li&gt;There is a Player and a Dealer&lt;/li&gt;
&lt;li&gt;Each contestant has 2 dice&lt;/li&gt;
&lt;li&gt;The player goes first&lt;/li&gt;
&lt;li&gt;Each dice spot is worth 2 points&lt;/li&gt;
&lt;li&gt;If either the player or dealer goes over 21, they lose the game&lt;/li&gt;
&lt;li&gt;After the first roll, if the player has not gone bust, they can choose to ‘stand’ or ‘hit’&lt;/li&gt;
&lt;li&gt;If they ‘hit’, the dice are rolled again and the player can choose to add the points of either die or the total of both dice&lt;/li&gt;
&lt;li&gt;The player must add a score after hitting, even if it means they will go ‘bust’&lt;/li&gt;
&lt;li&gt;In the event of a tie, the game goes to the dealer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rules are based on those by &lt;a href="http://www.chessandpoker.com/dice_blackjack.html"&gt;James Yates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Instead of a big chunk of code I’m going to show you the process of a turn through our good old friend the flow chart. They can be intimidating but I’ve tried to make it in a way that is easy to follow and you should be ale to get a grasp of what the code is doing behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/10/flowchart.png" alt="flowchart" /&gt;&lt;/p&gt;
&lt;p&gt;There you go, who needs a hundred lines of bolognese when you can have pastel shapes?&lt;/p&gt;
&lt;p&gt;Those who played the game may also notice this is the first time I’ve included a computer-controlled opponent, ‘The Dealer’. The dealer is like the player but has the advantages of being able to go second and win in the result of a draw. The dealer’s choice code is as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;And&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;

&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChoose2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerCanChooseBoth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Dealer goes bust if no options are available&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Die2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerStand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tmrDealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;ElseIf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DealerScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameScore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;&amp;#39;Dealer stands if their score is more than the player&amp;#39;s&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerStand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;Else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DealerRoll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;End&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before this code I run checks that see which options are available after a dealer rolls (these are the DealerCanChoose variables). Here there is a series of conditionals that look at the options and picks the best one for the dealer.&lt;/p&gt;
&lt;p&gt;If there is only one option available, then the dealer will pick that one. If there is more than one option available then the dealer will pick whichever will get them the highest score that turn. If there are no options available then the dealer is bust and they will stand. The dealer will also stand if they have a score higher than that of the player. The dealer will continue to roll as long as they are lower than the player and their current score is under 17.&lt;/p&gt;
&lt;p&gt;And thats the game! The quickest project I’ve ever done and although its rough around the edges the gameplay is solid and I got to grips with windows form’s implementation of an event-driven program. You can find the full source code &lt;a href="https://github.com/LukeBriggsDev/Dice-Jack"&gt;here&lt;/a&gt;&lt;/p&gt;
</content:encoded>
      <pubDate>Tue, 24 Sep 2019 21:06:18 +0000</pubDate>
    </item>
    <item>
      <title>The Layperson’s Guide to LaTeX
</title>
      <link>https://lukebriggs.dev/posts/the-laypersons-guide-to-latex</link>
      <description>&lt;img class='post-hero' src='static/postimages/11/rainbow.jpg' alt='&lt;div&gt;The Layperson’s Guide to LaTeX&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;The Layperson’s Guide to LaTeX&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As part of my degree I will have to write many words into many documents and submit them all as part of assignments.&lt;/p&gt;
&lt;p&gt;There was a time when we were young, stupid and thought that the peak of document formatting was WordArt, a drop shadow, and rainbow II. We would stick borders on our .pub files and feel superior if our PowerPoints had a dissolve transition. As we age past primary school we begin to conform to the world’s sensibilities that Comic Sans is not an adequate typeface and having every colour on the spectrum is a way to actually guarantee some of your text will be unreadable.&lt;/p&gt;
&lt;p&gt;Since we are forced to conform, we might as well do it to perfection, and you can only go so far in a tool that still thinks that word processors need a background ‘water droplet’ texture fill.&lt;/p&gt;
&lt;a name='what-is-this-latex-and-why-is-it-not-pronounced-like-that?'&gt;&lt;/a&gt;&lt;h1&gt;What is this LaTeX and Why is it Not Pronounced Like That?&lt;/h1&gt;
&lt;p&gt;If you want a tool that focuses on the nicest looking documents without caving into the design requirements of 7 year olds, you have to go back to a time before texture fills. Actually you have to go back to a time before computers could even show pictures. Nice looking documents (i.e had legible fonts) had to be obtained using specialised typesetters that cost as much as a house, either that or you’d use a literal printing press – this was the time in which TeX was created. LaTeX is built on TeX and is its more approachable step-son. LaTeX uses a mark-up language to design its document with the idea being that you focus on the content while the engine works out the best formatting.&lt;/p&gt;
&lt;a name='isn’t-this-a-bit-of-a-faff?'&gt;&lt;/a&gt;&lt;h1&gt;Isn’t This a Bit of a Faff?&lt;/h1&gt;
&lt;p&gt;It depends on your personality. If you are happy with documents that are only adequate, then continue in your mediocrity. But for those of us who seek perfection and see neuroplasticity as a fundamental attribute, LaTeX offers a sterling reward for your efforts.&lt;/p&gt;
&lt;a name='how-good-does-it-look?'&gt;&lt;/a&gt;&lt;h1&gt;How Good Does it Look?&lt;/h1&gt;
&lt;p&gt;In the days when people weren’t made of pixels, I spent the time making my own word template. It had wonderful serif headings, all the styles used Word’s tools so it did as much of the heavy lifting as possible, and all the font sizes were made just right.&lt;/p&gt;
&lt;p&gt;The results from Word are as follows:
&lt;img src="static/postimages/11/full.png" alt="full word document" /&gt;&lt;/p&gt;
&lt;p&gt;It looks &lt;em&gt;okay&lt;/em&gt;. It looks far better than what some people create in Word. Even creating something okay looking feels like a hack though. Having nice paragraph spacing underneath headings required me to individually change all the line spacing options by hand. Anyone who has ever tried to implement code into a word document also knows that it will require you to sacrifice your firstborn.&lt;/p&gt;
&lt;p&gt;Now, for a LaTeX document:
&lt;img src="static/postimages/11/fulllatex.png" alt="full latex" /&gt;&lt;/p&gt;
&lt;p&gt;No time spent messing with templates, no changing font sizes, and it probably took me less time to make a document that looks even better. The best thing about LaTeX is that because everything is done programmatically, it can have an integration that is mind boggling. For instance, if you want to insert a segment of a python script in your document you dont actually need to copy and paste bits into your .tex file. You can just tell it where the script is, give it the line numbers and it will display and format it all for you.&lt;/p&gt;
&lt;a name='where-do-i-begin?'&gt;&lt;/a&gt;&lt;h1&gt;Where Do I Begin?&lt;/h1&gt;
&lt;p&gt;This is for those of a Windows disposition&lt;/p&gt;
&lt;p&gt;First install a distribution of LaTeX called &lt;a href="https://miktex.org/download"&gt;MiKTeX&lt;/a&gt;. MiKTeX has everything you need and will make the whole experience as easy as possible.&lt;/p&gt;
&lt;p&gt;Our code editor is called TeXworks, so open that up and lets write some LaTeX.&lt;/p&gt;
&lt;p&gt;LaTeX follows a syntax of \command[option]{parameter} and we start a document off by selecting the type of document we want to create, and then starting and ending said document. There are a number of &lt;a href="https://en.wikibooks.org/wiki/LaTeX/Document_Structure#Document_classes"&gt;document classes&lt;/a&gt; but article is the one recommended for most documents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
I&amp;#39;m so pretty
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we get:
&lt;img src="static/postimages/11/empty.png" alt="empty latex" /&gt;&lt;/p&gt;
&lt;p&gt;Currently it looks like a note left by a serial killer with access to a typewriter so lets stick our name on it.&lt;/p&gt;
&lt;p&gt;The title, date, and author of your document all have dedicated tags in LaTeX. They are \title \date and \author. We then tell LaTeX to show all these on the screen by using \maketitle&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\title&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;My Pretty Document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\author&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;J. Smith&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\date&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;23 November 1963&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\maketitle&lt;/span&gt;

&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:
&lt;img src="static/postimages/11/title.png" alt="title page" /&gt;&lt;/p&gt;
&lt;p&gt;You can hear groups of your preferred gender(s) running to throw themselves at you as we speak.&lt;/p&gt;
&lt;p&gt;Now for some content. Once again there are various different types of &lt;a href="https://en.wikibooks.org/wiki/LaTeX/Document_Structure#Sectioning_commands"&gt;sectioning&lt;/a&gt; you can use but we will use the pretty straight forward \section&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\title&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;My Pretty Document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\author&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;J. Smith&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\date&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;23 November 1963&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\maketitle&lt;/span&gt;

&lt;span class="k"&gt;\section&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;This is a subtitle&lt;span class="nb"&gt;}&lt;/span&gt;
I can just write text under the section tag and it will all be made nice

&lt;span class="k"&gt;\section&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;This is my second subtitle&lt;span class="nb"&gt;}&lt;/span&gt;
I just add another section tag and it will become the second section in the document. Pretty cool!

&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/11/content.png" alt="content" /&gt;&lt;/p&gt;
&lt;p&gt;Positive gasps emanate from the crowd at the sight of such serifs. You will notice that LaTex automatically added heading numbers and changed the weight, face, and size of the type to better suit a heading. &lt;a href="https://en.wikibooks.org/wiki/LaTeX"&gt;There are all sorts of things you can do&lt;/a&gt; that I haven’t covered like how it can do bibliographies for you and organise images and figures correctly. There are also things that are beyond my knowledge like drawing your own 3d graphics within source. All of it can be taken one step at a time. If you don’t know something, look it up, learn how to do it, and implement it – it’s all pretty approachable.&lt;/p&gt;
&lt;p&gt;LaTeX isn’t perfect in its implementation, only its possible output. For instance, the answer to the question ‘how do I insert an svg’ is ‘use a pdf instead’ but I hope I have given you a taste of a better alternative to Word, even if it does introduce the possibility that your reports can have syntax errors.&lt;/p&gt;
&lt;a name='further-notes'&gt;&lt;/a&gt;&lt;h1&gt;Further Notes&lt;/h1&gt;
&lt;p&gt;If you are writing your reports in LaTeX like me then you will need the correct bibliography formatting. LaTeX offers a few styles by default but I have learned there is no such thing as a standard and my University (Newcastle) uses &lt;a href="https://libguides.ncl.ac.uk/managing/harvard"&gt;its own guidelines&lt;/a&gt;. The process for creating your own style involves both a command line tool and further tweaking using a bespoke programming language using REVERSE POLISH NOTATION, which is what happens if Christopher Nolan got his hands on a compiler. To save my fellow students time, I created a style for Newcastle’s bibliography style and &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX"&gt;it is hosted on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/11/rainbow.jpg' alt='&lt;div&gt;The Layperson’s Guide to LaTeX&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;The Layperson’s Guide to LaTeX&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As part of my degree I will have to write many words into many documents and submit them all as part of assignments.&lt;/p&gt;
&lt;p&gt;There was a time when we were young, stupid and thought that the peak of document formatting was WordArt, a drop shadow, and rainbow II. We would stick borders on our .pub files and feel superior if our PowerPoints had a dissolve transition. As we age past primary school we begin to conform to the world’s sensibilities that Comic Sans is not an adequate typeface and having every colour on the spectrum is a way to actually guarantee some of your text will be unreadable.&lt;/p&gt;
&lt;p&gt;Since we are forced to conform, we might as well do it to perfection, and you can only go so far in a tool that still thinks that word processors need a background ‘water droplet’ texture fill.&lt;/p&gt;
&lt;a name='what-is-this-latex-and-why-is-it-not-pronounced-like-that?'&gt;&lt;/a&gt;&lt;h1&gt;What is this LaTeX and Why is it Not Pronounced Like That?&lt;/h1&gt;
&lt;p&gt;If you want a tool that focuses on the nicest looking documents without caving into the design requirements of 7 year olds, you have to go back to a time before texture fills. Actually you have to go back to a time before computers could even show pictures. Nice looking documents (i.e had legible fonts) had to be obtained using specialised typesetters that cost as much as a house, either that or you’d use a literal printing press – this was the time in which TeX was created. LaTeX is built on TeX and is its more approachable step-son. LaTeX uses a mark-up language to design its document with the idea being that you focus on the content while the engine works out the best formatting.&lt;/p&gt;
&lt;a name='isn’t-this-a-bit-of-a-faff?'&gt;&lt;/a&gt;&lt;h1&gt;Isn’t This a Bit of a Faff?&lt;/h1&gt;
&lt;p&gt;It depends on your personality. If you are happy with documents that are only adequate, then continue in your mediocrity. But for those of us who seek perfection and see neuroplasticity as a fundamental attribute, LaTeX offers a sterling reward for your efforts.&lt;/p&gt;
&lt;a name='how-good-does-it-look?'&gt;&lt;/a&gt;&lt;h1&gt;How Good Does it Look?&lt;/h1&gt;
&lt;p&gt;In the days when people weren’t made of pixels, I spent the time making my own word template. It had wonderful serif headings, all the styles used Word’s tools so it did as much of the heavy lifting as possible, and all the font sizes were made just right.&lt;/p&gt;
&lt;p&gt;The results from Word are as follows:
&lt;img src="static/postimages/11/full.png" alt="full word document" /&gt;&lt;/p&gt;
&lt;p&gt;It looks &lt;em&gt;okay&lt;/em&gt;. It looks far better than what some people create in Word. Even creating something okay looking feels like a hack though. Having nice paragraph spacing underneath headings required me to individually change all the line spacing options by hand. Anyone who has ever tried to implement code into a word document also knows that it will require you to sacrifice your firstborn.&lt;/p&gt;
&lt;p&gt;Now, for a LaTeX document:
&lt;img src="static/postimages/11/fulllatex.png" alt="full latex" /&gt;&lt;/p&gt;
&lt;p&gt;No time spent messing with templates, no changing font sizes, and it probably took me less time to make a document that looks even better. The best thing about LaTeX is that because everything is done programmatically, it can have an integration that is mind boggling. For instance, if you want to insert a segment of a python script in your document you dont actually need to copy and paste bits into your .tex file. You can just tell it where the script is, give it the line numbers and it will display and format it all for you.&lt;/p&gt;
&lt;a name='where-do-i-begin?'&gt;&lt;/a&gt;&lt;h1&gt;Where Do I Begin?&lt;/h1&gt;
&lt;p&gt;This is for those of a Windows disposition&lt;/p&gt;
&lt;p&gt;First install a distribution of LaTeX called &lt;a href="https://miktex.org/download"&gt;MiKTeX&lt;/a&gt;. MiKTeX has everything you need and will make the whole experience as easy as possible.&lt;/p&gt;
&lt;p&gt;Our code editor is called TeXworks, so open that up and lets write some LaTeX.&lt;/p&gt;
&lt;p&gt;LaTeX follows a syntax of \command[option]{parameter} and we start a document off by selecting the type of document we want to create, and then starting and ending said document. There are a number of &lt;a href="https://en.wikibooks.org/wiki/LaTeX/Document_Structure#Document_classes"&gt;document classes&lt;/a&gt; but article is the one recommended for most documents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
I&amp;#39;m so pretty
&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we get:
&lt;img src="static/postimages/11/empty.png" alt="empty latex" /&gt;&lt;/p&gt;
&lt;p&gt;Currently it looks like a note left by a serial killer with access to a typewriter so lets stick our name on it.&lt;/p&gt;
&lt;p&gt;The title, date, and author of your document all have dedicated tags in LaTeX. They are \title \date and \author. We then tell LaTeX to show all these on the screen by using \maketitle&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\title&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;My Pretty Document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\author&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;J. Smith&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\date&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;23 November 1963&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\maketitle&lt;/span&gt;

&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:
&lt;img src="static/postimages/11/title.png" alt="title page" /&gt;&lt;/p&gt;
&lt;p&gt;You can hear groups of your preferred gender(s) running to throw themselves at you as we speak.&lt;/p&gt;
&lt;p&gt;Now for some content. Once again there are various different types of &lt;a href="https://en.wikibooks.org/wiki/LaTeX/Document_Structure#Sectioning_commands"&gt;sectioning&lt;/a&gt; you can use but we will use the pretty straight forward \section&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;% Start of Document (Comments are denoted by a percentage at the start of the line)&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;article&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\begin&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\title&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;My Pretty Document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\author&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;J. Smith&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\date&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;23 November 1963&lt;span class="nb"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;\maketitle&lt;/span&gt;

&lt;span class="k"&gt;\section&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;This is a subtitle&lt;span class="nb"&gt;}&lt;/span&gt;
I can just write text under the section tag and it will all be made nice

&lt;span class="k"&gt;\section&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;This is my second subtitle&lt;span class="nb"&gt;}&lt;/span&gt;
I just add another section tag and it will become the second section in the document. Pretty cool!

&lt;span class="k"&gt;\end&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;document&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/11/content.png" alt="content" /&gt;&lt;/p&gt;
&lt;p&gt;Positive gasps emanate from the crowd at the sight of such serifs. You will notice that LaTex automatically added heading numbers and changed the weight, face, and size of the type to better suit a heading. &lt;a href="https://en.wikibooks.org/wiki/LaTeX"&gt;There are all sorts of things you can do&lt;/a&gt; that I haven’t covered like how it can do bibliographies for you and organise images and figures correctly. There are also things that are beyond my knowledge like drawing your own 3d graphics within source. All of it can be taken one step at a time. If you don’t know something, look it up, learn how to do it, and implement it – it’s all pretty approachable.&lt;/p&gt;
&lt;p&gt;LaTeX isn’t perfect in its implementation, only its possible output. For instance, the answer to the question ‘how do I insert an svg’ is ‘use a pdf instead’ but I hope I have given you a taste of a better alternative to Word, even if it does introduce the possibility that your reports can have syntax errors.&lt;/p&gt;
&lt;a name='further-notes'&gt;&lt;/a&gt;&lt;h1&gt;Further Notes&lt;/h1&gt;
&lt;p&gt;If you are writing your reports in LaTeX like me then you will need the correct bibliography formatting. LaTeX offers a few styles by default but I have learned there is no such thing as a standard and my University (Newcastle) uses &lt;a href="https://libguides.ncl.ac.uk/managing/harvard"&gt;its own guidelines&lt;/a&gt;. The process for creating your own style involves both a command line tool and further tweaking using a bespoke programming language using REVERSE POLISH NOTATION, which is what happens if Christopher Nolan got his hands on a compiler. To save my fellow students time, I created a style for Newcastle’s bibliography style and &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX"&gt;it is hosted on GitHub&lt;/a&gt;.&lt;/p&gt;
</content:encoded>
      <pubDate>Wed, 06 Jan 2021 22:06:22 +0000</pubDate>
    </item>
    <item>
      <title>Inspection &amp; Dissection: This Site!
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-this-site</link>
      <description>&lt;img class='post-hero' src='static/postimages/12/index.png' alt='&lt;div&gt;Inspection &amp; Dissection: This Site!&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: This Site!&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;Look at me with a fancy website. We're about to get meta as we discuss how this site you're exploring right now came to be.&lt;/p&gt;
&lt;a name='why-have-a-website?'&gt;&lt;/a&gt;&lt;h1&gt;Why have a website?&lt;/h1&gt;
&lt;p&gt;I want something to point to when someone asks 'so what have you done?'. I also need it for when I ask myself the same thing. Sometimes I wonder how much I have actually done in my spare time, and a site like this helps me to remember that I haven't wasted &lt;em&gt;all&lt;/em&gt; of my spare time on Minecraft.&lt;/p&gt;
&lt;a name='why-make-your-own-website?'&gt;&lt;/a&gt;&lt;h1&gt;Why make your own website?&lt;/h1&gt;
&lt;p&gt;Here in Computer Science land: men are real men, women are real women, and small furry creatures from Alpha Centauri are real small furry creatures from Alpha Centauri; thanks to these huge revelations in the field of existentialism we take it upon ourselves to walk the road already taken.&lt;/p&gt;
&lt;p&gt;The real reason is I ought to have side-projects, more than I used to. I have more time, not just because of COVID but also because Computer Science is now the only academic subject I have to pay attention to, whereas most of my time in Sixth Form was spent on Maths and Further Maths. It made reasonable sense for the first project to be a platform for my other projects and this is that platform.&lt;/p&gt;
&lt;a name='where-did-you-start?'&gt;&lt;/a&gt;&lt;h1&gt;Where did you start?&lt;/h1&gt;
&lt;p&gt;I knew I wanted to make a website with a Flask back end for 2 reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I wanted a back-end that could enable things like logging in and writing blog posts all within the site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I vehemently hate JavaScript and would prefer to do as much with python as possible. In fact this whole site doesn't have any JavaScript. You can inspect element and see that everything front end is done through CSS and HTML; this is certain to change but I will hold out for as long as I can.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the uninitiated, websites have 2 parts: A front end and a back end. In a simple form, the front end is everything you see (HTML, CSS, JS) and the backend is everything you don't (Databases, Form requests, etc). Flask is a python framework that allows the said language to be used to serve all your requests.&lt;/p&gt;
&lt;p&gt;I had used Flask in the past whilst following the &lt;a href="https://cs50.harvard.edu/x/2021/"&gt;Harvard CS50x&lt;/a&gt; course back in 2019 to make a fake stocks app (💎👐). This time round, to re-familiarise myself I followed &lt;a href="https://flask.palletsprojects.com/en/1.1.x/tutorial/"&gt;this excellent tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After you are let loose on your own (especially in web dev) I found you have to have goals and a purpose to what you are doing otherwise it'll never happened. I persevered through the trial-and-error process that is CSS&lt;/p&gt;
&lt;p&gt;I used a couple of sites for reference when I was making the design for the sight. These were the sights of: my new friend &lt;a href="https://gwood.dev"&gt;George Wood&lt;/a&gt;, the blog of &lt;a href="https://www.caseyliss.com/"&gt;Casey Liss&lt;/a&gt;, the blog of &lt;a href="https://marco.org"&gt;Marco Arment&lt;/a&gt;, and &lt;a href="https://hypercritical.co"&gt;Hypercritical&lt;/a&gt; (No prizes for guessing which podcast I listen to).&lt;/p&gt;
&lt;a name='what-extra-things-have-you-done?'&gt;&lt;/a&gt;&lt;h1&gt;What extra things have you done?&lt;/h1&gt;
&lt;p&gt;I'm honoured at your presumption that I go above and beyond in the call of duty. The main thing I have done is make all my posts in markdown. Yes, all my posts are entirely written in markdown which makes me able to write nicely structured documents quickly. The raw text of the markdown is stored as a regular text field in the sqlite database but at the stage when the backend grabs the field from the database, jinja parses it as html using the python module &lt;a href="https://mistune.readthedocs.io/en/latest/intro.html"&gt;mistune&lt;/a&gt;. To spice the formatting up even further, since I will be probably be using code snippets, I added the syntax highlighter &lt;a href="https://pygments.org/"&gt;pygments&lt;/a&gt;. In fact here is the code for the highlight renderer being rendered in it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mistune&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments.lexers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_lexer_by_name&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments.formatters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HighlightRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mistune&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;block_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;lexer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_lexer_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stripall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HtmlFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;monokai&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noclasses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mistune&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It goes without saying that this website will continue to be updated as I change my mind on a few things and wish to add more functionality. On my list of todos are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A switch between light mode and dark mode&lt;/li&gt;
&lt;li&gt;A way for people to follow the blog (maybe through RSS)&lt;/li&gt;
&lt;li&gt;A way to better list out blog posts (currently all are listed on one page which will probably become cumbersome when they grow in number)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the meantime I hope you come back and see if I can offer you any informative content.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/12/index.png' alt='&lt;div&gt;Inspection &amp; Dissection: This Site!&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection &amp; Dissection: This Site!&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;Look at me with a fancy website. We're about to get meta as we discuss how this site you're exploring right now came to be.&lt;/p&gt;
&lt;a name='why-have-a-website?'&gt;&lt;/a&gt;&lt;h1&gt;Why have a website?&lt;/h1&gt;
&lt;p&gt;I want something to point to when someone asks 'so what have you done?'. I also need it for when I ask myself the same thing. Sometimes I wonder how much I have actually done in my spare time, and a site like this helps me to remember that I haven't wasted &lt;em&gt;all&lt;/em&gt; of my spare time on Minecraft.&lt;/p&gt;
&lt;a name='why-make-your-own-website?'&gt;&lt;/a&gt;&lt;h1&gt;Why make your own website?&lt;/h1&gt;
&lt;p&gt;Here in Computer Science land: men are real men, women are real women, and small furry creatures from Alpha Centauri are real small furry creatures from Alpha Centauri; thanks to these huge revelations in the field of existentialism we take it upon ourselves to walk the road already taken.&lt;/p&gt;
&lt;p&gt;The real reason is I ought to have side-projects, more than I used to. I have more time, not just because of COVID but also because Computer Science is now the only academic subject I have to pay attention to, whereas most of my time in Sixth Form was spent on Maths and Further Maths. It made reasonable sense for the first project to be a platform for my other projects and this is that platform.&lt;/p&gt;
&lt;a name='where-did-you-start?'&gt;&lt;/a&gt;&lt;h1&gt;Where did you start?&lt;/h1&gt;
&lt;p&gt;I knew I wanted to make a website with a Flask back end for 2 reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I wanted a back-end that could enable things like logging in and writing blog posts all within the site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I vehemently hate JavaScript and would prefer to do as much with python as possible. In fact this whole site doesn't have any JavaScript. You can inspect element and see that everything front end is done through CSS and HTML; this is certain to change but I will hold out for as long as I can.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the uninitiated, websites have 2 parts: A front end and a back end. In a simple form, the front end is everything you see (HTML, CSS, JS) and the backend is everything you don't (Databases, Form requests, etc). Flask is a python framework that allows the said language to be used to serve all your requests.&lt;/p&gt;
&lt;p&gt;I had used Flask in the past whilst following the &lt;a href="https://cs50.harvard.edu/x/2021/"&gt;Harvard CS50x&lt;/a&gt; course back in 2019 to make a fake stocks app (💎👐). This time round, to re-familiarise myself I followed &lt;a href="https://flask.palletsprojects.com/en/1.1.x/tutorial/"&gt;this excellent tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After you are let loose on your own (especially in web dev) I found you have to have goals and a purpose to what you are doing otherwise it'll never happened. I persevered through the trial-and-error process that is CSS&lt;/p&gt;
&lt;p&gt;I used a couple of sites for reference when I was making the design for the sight. These were the sights of: my new friend &lt;a href="https://gwood.dev"&gt;George Wood&lt;/a&gt;, the blog of &lt;a href="https://www.caseyliss.com/"&gt;Casey Liss&lt;/a&gt;, the blog of &lt;a href="https://marco.org"&gt;Marco Arment&lt;/a&gt;, and &lt;a href="https://hypercritical.co"&gt;Hypercritical&lt;/a&gt; (No prizes for guessing which podcast I listen to).&lt;/p&gt;
&lt;a name='what-extra-things-have-you-done?'&gt;&lt;/a&gt;&lt;h1&gt;What extra things have you done?&lt;/h1&gt;
&lt;p&gt;I'm honoured at your presumption that I go above and beyond in the call of duty. The main thing I have done is make all my posts in markdown. Yes, all my posts are entirely written in markdown which makes me able to write nicely structured documents quickly. The raw text of the markdown is stored as a regular text field in the sqlite database but at the stage when the backend grabs the field from the database, jinja parses it as html using the python module &lt;a href="https://mistune.readthedocs.io/en/latest/intro.html"&gt;mistune&lt;/a&gt;. To spice the formatting up even further, since I will be probably be using code snippets, I added the syntax highlighter &lt;a href="https://pygments.org/"&gt;pygments&lt;/a&gt;. In fact here is the code for the highlight renderer being rendered in it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mistune&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments.lexers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_lexer_by_name&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pygments.formatters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HighlightRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mistune&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;block_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;lexer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_lexer_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stripall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HtmlFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;monokai&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noclasses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mistune&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It goes without saying that this website will continue to be updated as I change my mind on a few things and wish to add more functionality. On my list of todos are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A switch between light mode and dark mode&lt;/li&gt;
&lt;li&gt;A way for people to follow the blog (maybe through RSS)&lt;/li&gt;
&lt;li&gt;A way to better list out blog posts (currently all are listed on one page which will probably become cumbersome when they grow in number)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the meantime I hope you come back and see if I can offer you any informative content.&lt;/p&gt;
</content:encoded>
      <pubDate>Wed, 03 Feb 2021 16:39:25 +0000</pubDate>
    </item>
    <item>
      <title>Goodbye Windows, I Hardly GNU ya
</title>
      <link>https://lukebriggs.dev/posts/goodbye-windows-i-hardly-gnu-ya</link>
      <description>&lt;img class='post-hero' src='static/postimages/13/desktop.png' alt='&lt;div&gt;Goodbye Windows, I Hardly GNU ya&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Goodbye Windows, I Hardly GNU ya&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;Preface: I should state that this is not an evangelical sermon, Linux isn't for everyone but it is for me. This is merely a detailing of why I have chosen to switch Operating System&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have, over the course of the past year, consumed pretty much every interpretation and adaptation of Sherlock Holmes out there, from the original works to tangentially linked shows such as the excellent House MD; one thing I have come to understand is that you can only deduce correctly if your initial assumptions are correct. Logic is useless if its underlying axioms are unstable.&lt;/p&gt;
&lt;p&gt;So we turn to my current assumption when I use computers &amp;quot;Everything must be done in Windows&amp;quot;. I have used Windows all my life, all the software I need is on Windows, and all other operating systems are either anaemic in their UX and feature set or are incapable of running on my hardware. It just stands to reason, or does it?&lt;/p&gt;
&lt;p&gt;Lets look at that first point, 'I have used Windows all my life'. That is not a very good reason, and the weakest of all. It is indeed true but it shouldn't have any bearing on choice of Operating System, it is an unquestioned ideology rather than any valid argument.&lt;/p&gt;
&lt;p&gt;The second axiom, 'all the software I need is on windows', was probably true for quite a long time. For instance, if I wanted to play any windows games I would have been bang out of luck in days gone by, but tools such as &lt;a href="https://lutris.net/"&gt;Lutris&lt;/a&gt; and the strides made in &lt;a href="https://www.winehq.org/"&gt;WINE&lt;/a&gt; have made that side of things perfectly capable for my needs. Needless to say Mac is straying further away at this point with their move to ARM so the assumption still holds true for them. Outside of gaming, all the apps I &lt;em&gt;need&lt;/em&gt; are actually available on Linux. My academic work in Computer Science lends itself perfectly to Linux. All the IDEs I use (the JetBrains suite) are available and the terminal is actually more conducive to my studies compared to the limited Unix-like aliases in the Windows Powershell. The only notable exception on Linux is the lack of the Microsoft Office Suite, but I was quite staggered when I realised that I don't actually have any need for it. My long form writing is now done in LaTeX (&lt;a href="posts/the-laypersons-guide-to-latex"&gt;see my reasons for that here&lt;/a&gt;), and I don't use Excel or PowerPoint. Should the need ever arise, there is the native &lt;a href="https://www.libreoffice.org/"&gt;LibreOffice&lt;/a&gt; suite, and the cross platform &lt;a href="https://docs.google.com"&gt;Google Docs&lt;/a&gt;. And if compatibility is a necessity then Microsoft also now offers a web app version of the suite.&lt;/p&gt;
&lt;p&gt;The second point links to the third, that other operating systems have terrible UX. The king of UX is obviously MacOS, but that obviously doesn't support my hardware or the ability to run the occasional windows game. I had always perceived Linux as having terrible UX because I always just viewed through the lens of someone who has used Windows their whole life. I always just assumed (once again question your assumptions) that how a Linux distro shipped was how it was. I thought I would have to be stuck with the bland, Ubuntu default GNOME desktop and icons with their washed out colours and pre-iOS 6 style realism. I was completely wrong about this and now we are going to look at where Linux, my new Operating System, is actually better for my needs.&lt;/p&gt;
&lt;a name='the-linux-way-of-thinking'&gt;&lt;/a&gt;&lt;h1&gt;The Linux way of thinking&lt;/h1&gt;
&lt;p&gt;Linux is about what Computers were built to do, and it is about the things that us Computer people love. GNU/Linux is a whole software ecosystem that is far greater than what Windows could ever hope for and only rivaled by what Apple has cultivated on its platforms. Unlike Apple, however, GNU/Linux also offers the user complete freedom in every aspect, and there are levels to this. Yes there are demigods that are compiling their own kernels but because there is such a community driven approach, other people have performed every possible layer of abstraction. Over the decades other people have been putting rungs at all levels of the ladder for other people to step on. Because Linux is built for the community by the community, it doesn't fight me.&lt;/p&gt;
&lt;p&gt;If I wanted to change the interface on windows, I would need to install several third party apps, each using their own design language and frameworks all while eating up huge amounts of RAM as they do so. In Linux its as easy as choosing an overall desktop environment you like and customisation is welcomed with open arms as a basic human right. Surprisingly, Linux also has an incredibly consistent design language because of how its built. In Windows you have all sorts of frameworks from many decades that all conflict. You'll go from a UWP app with its tile based design ideas, and then open a WPF app that has a reasonable flat aesthetic and some okay ideas, before finally finding one of your applications uses WinForms with all of its tabs and ugly green loading bars. Almost everything on Linux using either the Gtk or Qt GUI libraries, and because of this everything looks consistent. Most Desktop Environments also let you either make or download your own themes for these graphics libraries. As a result you can make all the colours, buttons and menus in the ENTIRE Linux ecosystem look how you want.&lt;/p&gt;
&lt;p&gt;The Linux way is for people who care about these things. If you care about things like the same apps using the same frameworks, or the fact that you can use package managers to allow apps to auto-update and avoid redundant dependencies, or how you have a whole community of people who's only incentive is to make good software.&lt;/p&gt;
&lt;a name='technical-details'&gt;&lt;/a&gt;&lt;h1&gt;Technical Details&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Distribution&lt;/strong&gt;: &lt;a href="https://manjaro.org/"&gt;Manjaro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desktop Environment&lt;/strong&gt;: &lt;a href="https://kde.org/plasma-desktop/"&gt;KDE Plasma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Theme&lt;/strong&gt;: Breeze Dark&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Icon Set&lt;/strong&gt;: &lt;a href="https://github.com/yeyushengfan258/Reversal-icon-theme"&gt;Reversal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: (&lt;a href="https://i.imgur.com/DUXXqM2.jpg"&gt;Imgur&lt;/a&gt;) (&lt;a href="static/postimages/13/themagichour.png"&gt;Mirror&lt;/a&gt;)&lt;/p&gt;
&lt;a name='why-manjaro?'&gt;&lt;/a&gt;&lt;h2&gt;Why Manjaro?&lt;/h2&gt;
&lt;p&gt;I chose Manjaro, at first by design and then retroactively I realised that I would have had to go with something like it anyway. I wanted a distribution that didn't come with the usual GNOME look, something that either looked excellent at first glance or had extensive customisation capabilities, and something that was pretty light on what it came with. I ended up narrowing it down to &lt;a href="https://manjaro.org/"&gt;Manjaro&lt;/a&gt; and &lt;a href="https://elementary.io/"&gt;Elementary OS&lt;/a&gt;. In the end I chose Manjaro between the two because Elementary seemed slightly far behind in its update cycle compared to the Ubuntu it is based off and its never fun to start off with something knowing there is a major version incredibly close. It turned out in the end that Manjaro was really my best choice between the two anyway thanks to its easy switching between Kernels. I currently need to be running the latest experimental kernel for my touch pad to work.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/13/desktop.png' alt='&lt;div&gt;Goodbye Windows, I Hardly GNU ya&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Goodbye Windows, I Hardly GNU ya&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;Preface: I should state that this is not an evangelical sermon, Linux isn't for everyone but it is for me. This is merely a detailing of why I have chosen to switch Operating System&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have, over the course of the past year, consumed pretty much every interpretation and adaptation of Sherlock Holmes out there, from the original works to tangentially linked shows such as the excellent House MD; one thing I have come to understand is that you can only deduce correctly if your initial assumptions are correct. Logic is useless if its underlying axioms are unstable.&lt;/p&gt;
&lt;p&gt;So we turn to my current assumption when I use computers &amp;quot;Everything must be done in Windows&amp;quot;. I have used Windows all my life, all the software I need is on Windows, and all other operating systems are either anaemic in their UX and feature set or are incapable of running on my hardware. It just stands to reason, or does it?&lt;/p&gt;
&lt;p&gt;Lets look at that first point, 'I have used Windows all my life'. That is not a very good reason, and the weakest of all. It is indeed true but it shouldn't have any bearing on choice of Operating System, it is an unquestioned ideology rather than any valid argument.&lt;/p&gt;
&lt;p&gt;The second axiom, 'all the software I need is on windows', was probably true for quite a long time. For instance, if I wanted to play any windows games I would have been bang out of luck in days gone by, but tools such as &lt;a href="https://lutris.net/"&gt;Lutris&lt;/a&gt; and the strides made in &lt;a href="https://www.winehq.org/"&gt;WINE&lt;/a&gt; have made that side of things perfectly capable for my needs. Needless to say Mac is straying further away at this point with their move to ARM so the assumption still holds true for them. Outside of gaming, all the apps I &lt;em&gt;need&lt;/em&gt; are actually available on Linux. My academic work in Computer Science lends itself perfectly to Linux. All the IDEs I use (the JetBrains suite) are available and the terminal is actually more conducive to my studies compared to the limited Unix-like aliases in the Windows Powershell. The only notable exception on Linux is the lack of the Microsoft Office Suite, but I was quite staggered when I realised that I don't actually have any need for it. My long form writing is now done in LaTeX (&lt;a href="posts/the-laypersons-guide-to-latex"&gt;see my reasons for that here&lt;/a&gt;), and I don't use Excel or PowerPoint. Should the need ever arise, there is the native &lt;a href="https://www.libreoffice.org/"&gt;LibreOffice&lt;/a&gt; suite, and the cross platform &lt;a href="https://docs.google.com"&gt;Google Docs&lt;/a&gt;. And if compatibility is a necessity then Microsoft also now offers a web app version of the suite.&lt;/p&gt;
&lt;p&gt;The second point links to the third, that other operating systems have terrible UX. The king of UX is obviously MacOS, but that obviously doesn't support my hardware or the ability to run the occasional windows game. I had always perceived Linux as having terrible UX because I always just viewed through the lens of someone who has used Windows their whole life. I always just assumed (once again question your assumptions) that how a Linux distro shipped was how it was. I thought I would have to be stuck with the bland, Ubuntu default GNOME desktop and icons with their washed out colours and pre-iOS 6 style realism. I was completely wrong about this and now we are going to look at where Linux, my new Operating System, is actually better for my needs.&lt;/p&gt;
&lt;a name='the-linux-way-of-thinking'&gt;&lt;/a&gt;&lt;h1&gt;The Linux way of thinking&lt;/h1&gt;
&lt;p&gt;Linux is about what Computers were built to do, and it is about the things that us Computer people love. GNU/Linux is a whole software ecosystem that is far greater than what Windows could ever hope for and only rivaled by what Apple has cultivated on its platforms. Unlike Apple, however, GNU/Linux also offers the user complete freedom in every aspect, and there are levels to this. Yes there are demigods that are compiling their own kernels but because there is such a community driven approach, other people have performed every possible layer of abstraction. Over the decades other people have been putting rungs at all levels of the ladder for other people to step on. Because Linux is built for the community by the community, it doesn't fight me.&lt;/p&gt;
&lt;p&gt;If I wanted to change the interface on windows, I would need to install several third party apps, each using their own design language and frameworks all while eating up huge amounts of RAM as they do so. In Linux its as easy as choosing an overall desktop environment you like and customisation is welcomed with open arms as a basic human right. Surprisingly, Linux also has an incredibly consistent design language because of how its built. In Windows you have all sorts of frameworks from many decades that all conflict. You'll go from a UWP app with its tile based design ideas, and then open a WPF app that has a reasonable flat aesthetic and some okay ideas, before finally finding one of your applications uses WinForms with all of its tabs and ugly green loading bars. Almost everything on Linux using either the Gtk or Qt GUI libraries, and because of this everything looks consistent. Most Desktop Environments also let you either make or download your own themes for these graphics libraries. As a result you can make all the colours, buttons and menus in the ENTIRE Linux ecosystem look how you want.&lt;/p&gt;
&lt;p&gt;The Linux way is for people who care about these things. If you care about things like the same apps using the same frameworks, or the fact that you can use package managers to allow apps to auto-update and avoid redundant dependencies, or how you have a whole community of people who's only incentive is to make good software.&lt;/p&gt;
&lt;a name='technical-details'&gt;&lt;/a&gt;&lt;h1&gt;Technical Details&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Distribution&lt;/strong&gt;: &lt;a href="https://manjaro.org/"&gt;Manjaro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desktop Environment&lt;/strong&gt;: &lt;a href="https://kde.org/plasma-desktop/"&gt;KDE Plasma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Theme&lt;/strong&gt;: Breeze Dark&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Icon Set&lt;/strong&gt;: &lt;a href="https://github.com/yeyushengfan258/Reversal-icon-theme"&gt;Reversal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: (&lt;a href="https://i.imgur.com/DUXXqM2.jpg"&gt;Imgur&lt;/a&gt;) (&lt;a href="static/postimages/13/themagichour.png"&gt;Mirror&lt;/a&gt;)&lt;/p&gt;
&lt;a name='why-manjaro?'&gt;&lt;/a&gt;&lt;h2&gt;Why Manjaro?&lt;/h2&gt;
&lt;p&gt;I chose Manjaro, at first by design and then retroactively I realised that I would have had to go with something like it anyway. I wanted a distribution that didn't come with the usual GNOME look, something that either looked excellent at first glance or had extensive customisation capabilities, and something that was pretty light on what it came with. I ended up narrowing it down to &lt;a href="https://manjaro.org/"&gt;Manjaro&lt;/a&gt; and &lt;a href="https://elementary.io/"&gt;Elementary OS&lt;/a&gt;. In the end I chose Manjaro between the two because Elementary seemed slightly far behind in its update cycle compared to the Ubuntu it is based off and its never fun to start off with something knowing there is a major version incredibly close. It turned out in the end that Manjaro was really my best choice between the two anyway thanks to its easy switching between Kernels. I currently need to be running the latest experimental kernel for my touch pad to work.&lt;/p&gt;
</content:encoded>
      <pubDate>Sun, 07 Feb 2021 21:12:30 +0000</pubDate>
    </item>
    <item>
      <title>You Can Now Follow Me on RSS!
</title>
      <link>https://lukebriggs.dev/posts/you-can-now-follow-me-on-rss</link>
      <description>&lt;h1 class='post-title'&gt;&lt;div&gt;You Can Now Follow Me on RSS!&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I had a bit of time today and I wanted to do something so here we are. 
Thanks to the incredible &lt;a href="https://feedgen.kiesow.be/"&gt;FeedGen&lt;/a&gt; python library, you can now point your RSS reader to &lt;a href="index.xml"&gt;here&lt;/a&gt; and get updates on when I write a new post.&lt;/p&gt;
</description>
      <content:encoded>&lt;h1 class='post-title'&gt;&lt;div&gt;You Can Now Follow Me on RSS!&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I had a bit of time today and I wanted to do something so here we are. 
Thanks to the incredible &lt;a href="https://feedgen.kiesow.be/"&gt;FeedGen&lt;/a&gt; python library, you can now point your RSS reader to &lt;a href="index.xml"&gt;here&lt;/a&gt; and get updates on when I write a new post.&lt;/p&gt;
</content:encoded>
      <pubDate>Thu, 18 Feb 2021 20:52:00 +0000</pubDate>
    </item>
    <item>
      <title>Inspection and Dissection: Type or Die
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-type-or-die</link>
      <description>&lt;img class='post-hero' src='static/postimages/21/cover.png' alt='&lt;div&gt;Inspection and Dissection: Type or Die&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Type or Die&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://lukebriggs.itch.io/type-or-die"&gt;Itch.io Link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the past 5 days I have done what I have failed to do many times before,
complete the process of making a game.&lt;/p&gt;
&lt;p&gt;The game was for the NUCATS Game Jam. NUCATS is the Newcastle University Computing
and Technology Society. It was made in Unity (with great help from &lt;a href="https://www.youtube.com/channel/UCYbK_tjZ2OrIZFBvU6CCMiA"&gt;Brackeys&lt;/a&gt;),
and it was really the first reasonably sized game I've made. The only other thing I've ever made in Unity was &lt;a href="projects/ping"&gt;Ping&lt;/a&gt;
which, as the name suggests, was a pong clone.&lt;/p&gt;
&lt;p&gt;Type or Die is a top-down zombie shooter where it is not about how good
your aim is, but how fast you can type. Waves of zombies come at you in all directions, with the direction
they come from determining what key to press to shoot at them (e.g a zombie coming from the top right would be shot at
using the 'p' key).&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/21/fight.png" alt="Type or Die game image" /&gt;&lt;/p&gt;
&lt;p&gt;The game jam has come in a time between some pretty busy weeks so I have surprised myself by actually getting a
finished game out. I even contemplated not taking part at all after the first day because I felt I just wouldn't be able to do it.
I started off (as optimistic idiots often do) full of goals with zero plans. Every step of the way I was decreasing scope
to match my skill and enthusiasm, and its where those paths crossed that the game was made. I knew that the most complex
thing I could make in the time with limited skill was a 2d, single-screen game. Guns are an easy way to make the mundane exciting,
so the game became a shooter, and wanting to have the computer do all the work for you meant that it became a wave shooter for
replayability.&lt;/p&gt;
&lt;p&gt;Every waking moment from Monday to Thursday was spent either watching &lt;a href="https://www.imdb.com/title/tt1632701/?ref_=fn_al_tt_1"&gt;Suits&lt;/a&gt;
or making this game, and the sheer intensity of such an endeavour in the middle of some pretty hectic University team projects
made me realise one thing, I will probably not make another game for a very long time. If you have a gander at my &lt;a href="projects"&gt;projects&lt;/a&gt; page
you will see that all of them are games, so you may think that I really enjoy game-making. But in retrospect I think I only made games as
an outlet for programming rather than an outlet for artistic ideas. Creation is a painful process, so you have to see the purpose in it.
As much as I am proud of what I achieved with each of the games I made, I can't see them as providing a service.&lt;/p&gt;
&lt;p&gt;My perspective on games has completely changed in the past year, I place a huge value on the incredible narrative experiences offered by the likes of 'God of War' or
'The Beginners Guide', these are games made by people with something to say and the skill to say it. There is certainly a place for arcade
shooters, but if I don't feel passionate about the things I create then I will never see them as worth the time I put into them.&lt;/p&gt;
&lt;p&gt;Type or Die marks the end of the 4-year-long adventure that started this whole blog off, I suppose it is fitting that it should end with another
top down arcade shooter. The game is pretty fun, the zombie death animations are my favourite part (also an original theme made by my musically inept hand).&lt;/p&gt;
&lt;p&gt;More projects lie on the horizon, and the times they are a changin'.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/21/cover.png' alt='&lt;div&gt;Inspection and Dissection: Type or Die&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Type or Die&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://lukebriggs.itch.io/type-or-die"&gt;Itch.io Link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the past 5 days I have done what I have failed to do many times before,
complete the process of making a game.&lt;/p&gt;
&lt;p&gt;The game was for the NUCATS Game Jam. NUCATS is the Newcastle University Computing
and Technology Society. It was made in Unity (with great help from &lt;a href="https://www.youtube.com/channel/UCYbK_tjZ2OrIZFBvU6CCMiA"&gt;Brackeys&lt;/a&gt;),
and it was really the first reasonably sized game I've made. The only other thing I've ever made in Unity was &lt;a href="projects/ping"&gt;Ping&lt;/a&gt;
which, as the name suggests, was a pong clone.&lt;/p&gt;
&lt;p&gt;Type or Die is a top-down zombie shooter where it is not about how good
your aim is, but how fast you can type. Waves of zombies come at you in all directions, with the direction
they come from determining what key to press to shoot at them (e.g a zombie coming from the top right would be shot at
using the 'p' key).&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/21/fight.png" alt="Type or Die game image" /&gt;&lt;/p&gt;
&lt;p&gt;The game jam has come in a time between some pretty busy weeks so I have surprised myself by actually getting a
finished game out. I even contemplated not taking part at all after the first day because I felt I just wouldn't be able to do it.
I started off (as optimistic idiots often do) full of goals with zero plans. Every step of the way I was decreasing scope
to match my skill and enthusiasm, and its where those paths crossed that the game was made. I knew that the most complex
thing I could make in the time with limited skill was a 2d, single-screen game. Guns are an easy way to make the mundane exciting,
so the game became a shooter, and wanting to have the computer do all the work for you meant that it became a wave shooter for
replayability.&lt;/p&gt;
&lt;p&gt;Every waking moment from Monday to Thursday was spent either watching &lt;a href="https://www.imdb.com/title/tt1632701/?ref_=fn_al_tt_1"&gt;Suits&lt;/a&gt;
or making this game, and the sheer intensity of such an endeavour in the middle of some pretty hectic University team projects
made me realise one thing, I will probably not make another game for a very long time. If you have a gander at my &lt;a href="projects"&gt;projects&lt;/a&gt; page
you will see that all of them are games, so you may think that I really enjoy game-making. But in retrospect I think I only made games as
an outlet for programming rather than an outlet for artistic ideas. Creation is a painful process, so you have to see the purpose in it.
As much as I am proud of what I achieved with each of the games I made, I can't see them as providing a service.&lt;/p&gt;
&lt;p&gt;My perspective on games has completely changed in the past year, I place a huge value on the incredible narrative experiences offered by the likes of 'God of War' or
'The Beginners Guide', these are games made by people with something to say and the skill to say it. There is certainly a place for arcade
shooters, but if I don't feel passionate about the things I create then I will never see them as worth the time I put into them.&lt;/p&gt;
&lt;p&gt;Type or Die marks the end of the 4-year-long adventure that started this whole blog off, I suppose it is fitting that it should end with another
top down arcade shooter. The game is pretty fun, the zombie death animations are my favourite part (also an original theme made by my musically inept hand).&lt;/p&gt;
&lt;p&gt;More projects lie on the horizon, and the times they are a changin'.&lt;/p&gt;
</content:encoded>
      <pubDate>Fri, 05 Mar 2021 12:11:40 +0000</pubDate>
    </item>
    <item>
      <title>Where Hugo I Go
</title>
      <link>https://lukebriggs.dev/posts/where-hugo-i-go</link>
      <description>&lt;img class='post-hero' src='static/postimages/where-hugo-i-go/banner.png' alt='&lt;div&gt;Where Hugo I Go&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Where Hugo I Go&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As you are probably aware, I have redecorated. I said in a &lt;a href="posts/inspection-and-dissection-this-site"&gt;previous post&lt;/a&gt; that my reason for making my own site in the first place was as a central hub to point people to all the things that I do. Despite the fact that from the outside it looks like I haven't done a whole lot since, behind the scenes I have my biggest project yet in development (check out my &lt;a href="https://github.com/lukebriggsdev"&gt;GitHub&lt;/a&gt; if you want a sneak preview of that). It was while working on my project that I realised that I shouldn't have a site that requires my to ssh into a VPS and pull a git repository every time I want to add a post.&lt;/p&gt;
&lt;a name='technology'&gt;&lt;/a&gt;&lt;h2&gt;Technology&lt;/h2&gt;
&lt;p&gt;Behind the scenes, the site is hosted on GitHub Pages. The site is generated using a static site generator called &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; with a &lt;em&gt;slightly&lt;/em&gt; tweaked version of the &lt;a href="https://themes.gohugo.io/loveit/"&gt;LoveIt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With a static site I can remove server costs completely, have a better looking site, and make it easier to add new posts.&lt;/p&gt;
&lt;p&gt;Because each post is now a document rather than a database field, you can also stick &lt;code&gt;index.md&lt;/code&gt; at the end of any post to get the raw markdown for that post. You are also able to view the source for the site at &lt;a href="https://github.com/lukebriggsdev/lukebriggsdev.github.io"&gt;my GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='new-logo'&gt;&lt;/a&gt;&lt;h2&gt;New Logo&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/where-hugo-i-go/ComputerLogoAnim.png" alt="New Logo" /&gt;&lt;/p&gt;
&lt;p&gt;Along with the revamped site, I have created a new logo to go with it; it is probably the best looking thing I have ever drawn. The logo takes inspiration from the IBM PCJr with a few more rounded corners, thinner bezels, and a more minimalist feel.&lt;/p&gt;
&lt;p&gt;It was made in &lt;a href="https://inkscape.org"&gt;Inkscape&lt;/a&gt; with the basic shapes and the font is Roboto Mono.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/where-hugo-i-go/banner.png' alt='&lt;div&gt;Where Hugo I Go&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Where Hugo I Go&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;As you are probably aware, I have redecorated. I said in a &lt;a href="posts/inspection-and-dissection-this-site"&gt;previous post&lt;/a&gt; that my reason for making my own site in the first place was as a central hub to point people to all the things that I do. Despite the fact that from the outside it looks like I haven't done a whole lot since, behind the scenes I have my biggest project yet in development (check out my &lt;a href="https://github.com/lukebriggsdev"&gt;GitHub&lt;/a&gt; if you want a sneak preview of that). It was while working on my project that I realised that I shouldn't have a site that requires my to ssh into a VPS and pull a git repository every time I want to add a post.&lt;/p&gt;
&lt;a name='technology'&gt;&lt;/a&gt;&lt;h2&gt;Technology&lt;/h2&gt;
&lt;p&gt;Behind the scenes, the site is hosted on GitHub Pages. The site is generated using a static site generator called &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; with a &lt;em&gt;slightly&lt;/em&gt; tweaked version of the &lt;a href="https://themes.gohugo.io/loveit/"&gt;LoveIt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With a static site I can remove server costs completely, have a better looking site, and make it easier to add new posts.&lt;/p&gt;
&lt;p&gt;Because each post is now a document rather than a database field, you can also stick &lt;code&gt;index.md&lt;/code&gt; at the end of any post to get the raw markdown for that post. You are also able to view the source for the site at &lt;a href="https://github.com/lukebriggsdev/lukebriggsdev.github.io"&gt;my GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='new-logo'&gt;&lt;/a&gt;&lt;h2&gt;New Logo&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/where-hugo-i-go/ComputerLogoAnim.png" alt="New Logo" /&gt;&lt;/p&gt;
&lt;p&gt;Along with the revamped site, I have created a new logo to go with it; it is probably the best looking thing I have ever drawn. The logo takes inspiration from the IBM PCJr with a few more rounded corners, thinner bezels, and a more minimalist feel.&lt;/p&gt;
&lt;p&gt;It was made in &lt;a href="https://inkscape.org"&gt;Inkscape&lt;/a&gt; with the basic shapes and the font is Roboto Mono.&lt;/p&gt;
</content:encoded>
      <pubDate>Mon, 03 May 2021 20:06:07 +0000</pubDate>
    </item>
    <item>
      <title>Flatpak: Instructions Not Included
</title>
      <link>https://lukebriggs.dev/posts/flatpak-instructions-not-included</link>
      <description>&lt;img class='post-hero' src='static/postimages/flatpak-instructions-not-included/flatpak.png' alt='&lt;div&gt;Flatpak: Instructions Not Included&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Flatpak: Instructions Not Included&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;There is a very peculiar thing I have found in software development, it is incredibly difficult to actually get software on other people's machines. Even compiled languages can have difficulty.&lt;/p&gt;
&lt;a name='context'&gt;&lt;/a&gt;&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;I am elbow deep in a very large personal project at the moment (all will be revealed soon) that has so far taken a month. The project is getting to a stage now where deployment methods have to be evaluated. From the beginning I wanted the project to be fully cross platform across Windows, Linux, Mac with a singular codebase. Because of these specific requirements, I went with the &lt;a href="https://www.qt.io/product/framework"&gt;Qt GUI framework&lt;/a&gt;, it is cross platform, runs natively on each platform, and has bindings for Python (my preferred language).&lt;/p&gt;
&lt;p&gt;Because nothing is ever easy, there are actually two different python bindings for Qt. There is &lt;a href="https://en.wikipedia.org/wiki/PySide"&gt;PySide&lt;/a&gt; which was created by the Qt Company themselves. It has a less restrictive license, but seems to have less of a community around it due to it being the newer of the two bindings. The other binding is called &lt;a href="https://en.wikipedia.org/wiki/PyQt"&gt;PyQt&lt;/a&gt; and came first, even being called &lt;code&gt;python3-qt&lt;/code&gt; in the fedora package manager. When it comes down to coding, there is pretty much no difference between them since they are all just pythonic fronts for the same C++ back-end. For the whole project up until recently I was using PySide since it is the same in every way except for a better license.&lt;/p&gt;
&lt;a name='python-deployment'&gt;&lt;/a&gt;&lt;h2&gt;Python Deployment&lt;/h2&gt;
&lt;p&gt;Python, as it is shipped as CPython, does not (by default) compile to machine code. You'll notice a parenthetical and a subordinate clause in the previous sentence, that's how windy this road goes.&lt;/p&gt;
&lt;p&gt;There are systems that will turn your python code into binary executables, I was using &lt;a href="https://www.pyinstaller.org/"&gt;PyInstaller&lt;/a&gt; to get the job done for me. I'd run it on Linux, Windows, MacOS and all my code would be packaged in to binary form; there was the issue of non-python dependencies I had but I could find ways around that. So there I was with all my binaries in a row and feeling confident about how I'm going to deploy my application.&lt;/p&gt;
&lt;a name='linux-binary-woes'&gt;&lt;/a&gt;&lt;h2&gt;Linux Binary Woes&lt;/h2&gt;
&lt;p&gt;My current main machine runs Fedora Linux, this is a distribution that is kept reasonably up to date and, at the time of writing, has a new desktop environment and newer kernel than other non-Arch distros. All of this meant that when I tried to run my Linux compiled program on Ubuntu (A major distro I want to support), I get thrown an error that Ubuntu doesn't have the correct version of glibc (the dynamically linked C libraries). Sticking with the standard glibc versions that come with each distro, GNU/Linux is backwards compatible but not forwards compatible. That is to say that a program compiled on an older distro will run on a newer distro but not vice-versa. The solution to this seems straightforward doesn't it? Compile the program on an older version. So I loaded up an Ubuntu LTS VM, compile the program, works like a charm. I try to run that same executable on my main Fedora machine and I get an error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Settings schema 'org.gnome.settings-daemon.plugins.xsettings'
does not contain a key named 'antialiasing'
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The program does not run. This is without doubt a bug in Gnome 40. But it is a bug that happens 100% of the time, it may get fixed, it may not. My application is either incompatible with anything other than my own machine, or compatible with everything &lt;em&gt;except&lt;/em&gt; my own machine. Of course I could have two separate binaries, but that would be a bit of a hassle to maintain. In comes what I thought would be my saviour, Flatpak.&lt;/p&gt;
&lt;a name='build-systems'&gt;&lt;/a&gt;&lt;h3&gt;Build Systems&lt;/h3&gt;
&lt;p&gt;Linux has 3 main methods of deploying applications. Shipping binaries, making per distribution packages, and containers (of which flatpak is one). Binaries are, as we've seen, version dependent, packages are distribution dependent, and containers run across all machines but have extra bulk since they package there own dependencies rather than relying on system libraries.&lt;/p&gt;
&lt;p&gt;Throughout my exploration of deployment options, I have made all three. I have documented my results of binaries, and I also went on to make an RPM package (the packaging system that Fedora uses).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Name:&lt;span class="w"&gt;           &lt;/span&gt;Pepys
Version:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.3.0
Release:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;?dist&lt;span class="o"&gt;}&lt;/span&gt;
Summary:&lt;span class="w"&gt;        &lt;/span&gt;A&lt;span class="w"&gt; &lt;/span&gt;straightforward&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;journal

License:&lt;span class="w"&gt;        &lt;/span&gt;GPLv3
URL:&lt;span class="w"&gt;            &lt;/span&gt;https://www.lukebriggs.dev/pepys
Source0:&lt;span class="w"&gt;        &lt;/span&gt;pepys.tar.gz

Requires:&lt;span class="w"&gt;       &lt;/span&gt;python3,&lt;span class="w"&gt; &lt;/span&gt;python3-wheel,&lt;span class="w"&gt; &lt;/span&gt;python3-pip,&lt;span class="w"&gt; &lt;/span&gt;pandoc,&lt;span class="w"&gt; &lt;/span&gt;enchant,&lt;span class="w"&gt; &lt;/span&gt;wkhtmltopdf,&lt;span class="w"&gt; &lt;/span&gt;python3-qt5,&lt;span class="w"&gt; &lt;/span&gt;python3-qt5-webengine,&lt;span class="w"&gt; &lt;/span&gt;python3-regex,&lt;span class="w"&gt; &lt;/span&gt;python3-num2words,&lt;span class="w"&gt; &lt;/span&gt;python3-pypandoc,&lt;span class="w"&gt; &lt;/span&gt;python3-enchant,&lt;span class="w"&gt; &lt;/span&gt;python3-setproctitle,&lt;span class="w"&gt; &lt;/span&gt;texlive-mdwtools
BuildRequires:&lt;span class="w"&gt;  &lt;/span&gt;python3-pip
%description

%build
&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;buildroot&lt;span class="o"&gt;}&lt;/span&gt;/usr/share/pepys
&lt;span class="nv"&gt;APP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;buildroot&lt;span class="o"&gt;}&lt;/span&gt;/usr/local/share/applications
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

tar&lt;span class="w"&gt; &lt;/span&gt;-xzvf&lt;span class="w"&gt; &lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;SOURCE0&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/config.json&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/config.json
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/wordlist.txt&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/wordlist.txt&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

cp&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp


&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[Desktop Entry]\n \&lt;/span&gt;
&lt;span class="s2"&gt;Type=Application\n \&lt;/span&gt;
&lt;span class="s2"&gt;Name=Pepys\n \&lt;/span&gt;
&lt;span class="s2"&gt;Categories=Office;\n \&lt;/span&gt;
&lt;span class="s2"&gt;X-GNOME-FullName=Pepys\n \&lt;/span&gt;
&lt;span class="s2"&gt;Comment=A straightforward markdown journal\n \&lt;/span&gt;
&lt;span class="s2"&gt;Icon=%s/src/main/resources/base/icons/appicons/icon.svg\n \&lt;/span&gt;
&lt;span class="s2"&gt;NoDisplay=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;Exec= python3 %s/src/main/python/main.py\n \&lt;/span&gt;
&lt;span class="s2"&gt;Path=\n \&lt;/span&gt;
&lt;span class="s2"&gt;Terminal=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;X-GNOME-UsesNotifications=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;StartupWMClass=Pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$APP_DIR&lt;/span&gt;/Pepys.desktop
pip3&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;PyPDF4


%files
/*

%post
chmod&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;777&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/share/pepys

&lt;span class="c1"&gt;#%license add-license-file-here&lt;/span&gt;
&lt;span class="c1"&gt;#%doc add-docs-here&lt;/span&gt;



%changelog
*&lt;span class="w"&gt; &lt;/span&gt;Sat&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Luke&lt;span class="w"&gt; &lt;/span&gt;Briggs&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;lukebriggs02@gmail.com&amp;gt;
-
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;NOTICE: The above is a script used for testing, it is mostly functional but don't use it as a guide for how to do things properly&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The above is a script you feed into &lt;code&gt;rpmbuild&lt;/code&gt; and it will generate a .rpm file which Fedora users can use to install your software. You can see that all it really is is some metadata listing app information, dependencies (these dependencies are ones that are inside the fedora packaging system), and a shell script to say what gets installed and how. Because all the dependencies are listed, and are all from the the distros package manager, the file size of an rpm only consists of the files that you supply. In my case it was some python source files and some vector icons, totalling 1.2MB. Of course the full size of the app still needs to be downloaded but the other 150MB or so come in the form of system libraries that other apps can also use. This is the classic Linux method of software deployment, it is lean, and ensures compatibility with a particular distro. The problem comes when looking at other distributions. Some distributions also use RPM (CentOS, RHEL, OpenSUSE) but have different packages, and so need special cases in the file. Other distributions use a different package management system, Debian and derivatives use .deb files for instance.&lt;/p&gt;
&lt;a name='flatpak'&gt;&lt;/a&gt;&lt;h3&gt;Flatpak&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Flatpak"&gt;Flatpak&lt;/a&gt; and it's rival &lt;a href="https://en.wikipedia.org/wiki/Snap_(package_manager)"&gt;Snap&lt;/a&gt; aim to solve the dependency hell by shipping everything together in one big package. You avoid incompatibility at the cost of redundancy. The cover image of this post is my flatpak spec file that gets fed into &lt;code&gt;flatpak-builder&lt;/code&gt;. And you may notice that it works in a similar way to a distribution's own package manager.&lt;/p&gt;
&lt;p&gt;We have metadata along with base dependencies&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;app-id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;dev.lukebriggs.pepys&lt;/span&gt;
&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;org.kde.Platform&lt;/span&gt;
&lt;span class="nt"&gt;runtime-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;5.15&amp;#39;&lt;/span&gt;
&lt;span class="nt"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;org.kde.Sdk&lt;/span&gt;
&lt;span class="nt"&gt;add-extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;org.freedesktop.Sdk.Extension.texlive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;texlive&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;subdirectories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;autodelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;20.08&amp;#39;&lt;/span&gt;
&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;runner.sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because everything is in a sandbox, we have to declare what parts of the host system we have to use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;finish-args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--share=ipc&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=x11&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=wayland&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=pulseaudio&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--device=dri&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--filesystem=home&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--share=network&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--env=PATH=/usr/bin:/app/bin:/app/texlive/bin:/app/texlive/bin/x86_64-linux:/app/texlive/bin/aarch64-linux&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then comes the rest of our dependencies which have to be files we supply, along with the build script we use to actually do what we want with the files.&lt;/p&gt;
&lt;a name='the-trouble-with-python,-qt-and-flatpak'&gt;&lt;/a&gt;&lt;h4&gt;The Trouble with Python, Qt and Flatpak&lt;/h4&gt;
&lt;p&gt;All was going swimmingly until I had to get my Qt app in flatpak.
2 of my app dependencies are installed by effectively copying the prebuild binaries into the flatpak sandbox.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;pandoc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;buildsystem&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;build-commands&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ls&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;install -D bin/pandoc /app/bin/pandoc&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="w w-Error"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;archive&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://github.com/jgm/pandoc/releases/download/2.13/pandoc-2.13-linux-amd64.tar.gz&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;7404aa88a6eb9fbb99d9803b80170a3a546f51959230cc529c66a2ce6b950d4c&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;wkhtmltopdf&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;buildsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;build-commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;cp -r local/* /app/&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ls lib&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;archive&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.centos8.x86_64.rpm&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;5cc267d54fe3f144729f31432a165e028b689583c53cfee0a01d52644ab280d9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One of my dependencies is actually built and compiled within the flatpak container. (Given no &lt;code&gt;buildsystem&lt;/code&gt; option on archives with makefiles in them, flatpak will automatically compile and install them)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  - name: enchant
    sources:
      - type: archive
        url: https://github.com/AbiWord/enchant/releases/download/v2.2.15/enchant-2.2.15.tar.gz
        sha256: 3b0f2215578115f28e2a6aa549b35128600394304bd79d6f28b0d3b3d6f46c03
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we are back to the dilemma of using source files or prebuilt binaries, you'll see later that the solution is a mix of both.&lt;/p&gt;
&lt;p&gt;One option is just shipping a compiled version of my program in a flatpak. The issue is that flatpak's glibc is once again older than my main machine so &lt;em&gt;all&lt;/em&gt; flatpak builds would have to be done in an Ubuntu VM, not ideal. Next up comes building from source in the flatpak. My plan for the process was this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get python and resource files in the flatpak&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip install&lt;/code&gt; all dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sounds simple enough, but flatpak didn't like me communicating with the internet while installing (I tried &lt;code&gt;share=network&lt;/code&gt; on individual modules and it didn't work)
So, each python library had to be down as it's own python module with a link to the tar balls on pypi. Flatpak has a tool for such an occasion called &lt;a href="https://github.com/flatpak/flatpak-builder-tools/tree/master/pip"&gt;flatpak-pip-generator&lt;/a&gt;
so the line in the flatpak yml&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;python3-requirements.json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is a pointer to a file actually containing all pip dependencies&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-requirements&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;modules&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-regex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;regex\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/38/3f/4c42a98c9ad7d08c16e7d23b2194a0e4f3b2914662da8bc88986e4e6de1f/regex-2021.4.4.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-num2words&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;num2words\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/33/db/76f1151a1b0cfad532d41021b77cd231495bf72c47618166f92dcdff2ebe/num2words-0.5.10.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;37cd4f60678f7e1045cdc3adf6acf93c8b41bf732da860f97d301f04e611cc57&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-pypandoc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;wheel\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;pypandoc\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/ed/46/e298a50dde405e1c202e316fa6a3015ff9288423661d7ea5e8f22f589071/wheel-0.36.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/d6/b7/5050dc1769c8a93d3ec7c4bd55be161991c94b8b235f88bf7c764449e708/pypandoc-1.5.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;14a49977ab1fbc9b14ef3087dcb101f336851837fca55ca79cf33846cc4976ff&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-pyenchant&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;pyenchant\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/1f/d4/52869fe4ed24e373694c116adc00c82e5d92c747be4cbc97b24af43807f6/pyenchant-3.2.0.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;6b97e9a9f132fa7c9029a6635d821ccad67d4980e68186d02c765b4256b6f152&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-PyPDF4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;PyPDF4\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/4f/1f/509b44850c475c101aa5b5c9b81755cedd363389d6fbb5c53be6fa915a61/PyPDF4-1.27.0.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7c932441146d205572f96254d53c79ea2c30c9e11df55a5cf87e056c7b3d7f89&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-setproctitle&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;setproctitle\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/a1/7f/a1d4f4c7b66f0fc02f35dc5c85f45a8b4e4a7988357a29e61c14e725ef86/setproctitle-1.2.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7dfb472c8852403d34007e01d6e3c68c57eb66433fb8a5c77b13b89a160d97df&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You'll notice that there is no mention of PySide or Qt. The &lt;em&gt;key&lt;/em&gt; module that the app depends so heavily is not there, why? Well because both Qt python dependencies are not available as source files from pip. Pip hosts source files and wheels. All the above are source files. These are tar balls that pip will compile and build from source. Wheels are, once again, pre-built binaries. Flatpak doesn't include wheels by default since it wants everything to be as cross platform and cross architecture as possible.&lt;/p&gt;
&lt;p&gt;I also wanted to be as platform agnostic as possible so I attempted to build my python bindings from source in the flatpak. Flatpak did not like this. Neither PySide nor PyQt would build and each threw different error during the compilation process. My best guess would by the sandbox does not contain some required system libraries but I am at a loss to know which ones. And C compilers are not the most helpful thing as your only point of reference for a system error.&lt;/p&gt;
&lt;a name='lasers-to-the-rescue'&gt;&lt;/a&gt;&lt;h3&gt;Lasers to the rescue&lt;/h3&gt;
&lt;p&gt;At this stage, I didn't actually know what python wheels were, I just assumed everything had to be built from source. I was desperate for answers after 3 days of debugging and staring at config files. I did something I very rarely do, I used the GitHub search function. To my amazement I found a solution.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.physics.hu-berlin.de/en/qom"&gt;Optical Metrology Group&lt;/a&gt; in the Physics department of Humboldt University Berlin &lt;a href="https://github.com/hermitdemschoenenleben/linien"&gt;created a Linux application for locking onto spectroscopy lines&lt;/a&gt;. Guess what, they made a flatpak!&lt;/p&gt;
&lt;p&gt;I looked at there yaml, and I knew then and there that they had found a solution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# we used to build pyqt on our own here, but this build caused trouble with the pyqtgraph widget being transparent on some systems.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Therefore, we just use the x86_64 wheel here...&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;pyqt-x86_64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;buildsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;file&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://files.pythonhosted.org/packages/4c/bb/7fce18fbe0275d7a3e069a306d8f4662c77eda30ec6780634fd4a7ee50ce/PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;b1ea7e82004dc7b311d1e29df2f276461016e2d180e10c73805ace4376125ed9&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;file&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://files.pythonhosted.org/packages/31/24/f887203677955ba4d5d4efe9176ac7ed2bf84efce8c243ab91e63183ad9e/PyQt5_sip-12.8.1-cp37-cp37m-manylinux1_x86_64.whl&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;a1b8ef013086e224b8e86c93f880f776d01b59195bdfa2a8e0b23f0480678fec&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;build-commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;pip3 install PyQt*.whl --target=/app/lib/python3.7/site-packages&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;They had obviously also faced similar Qt-based problems. Their YAML led to me finding out about python wheels, how I could get PyQt in a flatpak, and how I could tell pip the right directory for a python installation (I had no idea what &lt;code&gt;--target&lt;/code&gt; would do before this).&lt;/p&gt;
&lt;p&gt;Thanks to some German physicists, my next project is back on track. Beady eyed people may notice some information in some of the config files I've posted that hint to what it could be. I did try and use PySide using the same wheel method but I got into some strange cyclical versioning thing since it required PySide an Shiboken2 to be installed at the same time. All that means is that my application will be open source out of a legal obligation, as well as an civil one.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;SIDE:&lt;/em&gt; kerberos is also a requirement for PyQt to work in a flatpak, I have no idea why but it may have something to do with certain networking modules.&lt;/p&gt;
&lt;a name='further-reading'&gt;&lt;/a&gt;&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;Here are some useful sources of information I turned to while interacting with packaging systems on Linux&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.loganasherjones.com/2018/05/using-flatpak-with-python/"&gt;https://www.loganasherjones.com/2018/05/using-flatpak-with-python/&lt;/a&gt; 
:	An excellent and succinct guide that covers making non-qt python apps work in a flatpak&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.flatpak.org/en/latest/getting-started.html"&gt;https://docs.flatpak.org/en/latest/getting-started.html&lt;/a&gt;
:	Information on what a flatpak is and what its parts consist of.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html"&gt;https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html&lt;/a&gt;
:	A good reference for what commands can be used in flatpak YAML&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/flathub/io.github.hermitdemschoenenleben.linien/blob/8d89b1c7193602f0696f134e92ac1eba39986303/io.github.hermitdemschoenenleben.linien.yml#L18"&gt;https://github.com/flathub/io.github.hermitdemschoenenleben.linien/blob/8d89b1c7193602f0696f134e92ac1eba39986303/io.github.hermitdemschoenenleben.linien.yml#L18&lt;/a&gt;
: 	The Humboldt University Berlin YAML&lt;/p&gt;
&lt;p&gt;&lt;a href="https://opensource.com/article/18/9/how-build-rpm-packages"&gt;https://opensource.com/article/18/9/how-build-rpm-packages&lt;/a&gt;
:	A straightforward guide on how to make RPM packages&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/flatpak-instructions-not-included/flatpak.png' alt='&lt;div&gt;Flatpak: Instructions Not Included&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Flatpak: Instructions Not Included&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;There is a very peculiar thing I have found in software development, it is incredibly difficult to actually get software on other people's machines. Even compiled languages can have difficulty.&lt;/p&gt;
&lt;a name='context'&gt;&lt;/a&gt;&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;I am elbow deep in a very large personal project at the moment (all will be revealed soon) that has so far taken a month. The project is getting to a stage now where deployment methods have to be evaluated. From the beginning I wanted the project to be fully cross platform across Windows, Linux, Mac with a singular codebase. Because of these specific requirements, I went with the &lt;a href="https://www.qt.io/product/framework"&gt;Qt GUI framework&lt;/a&gt;, it is cross platform, runs natively on each platform, and has bindings for Python (my preferred language).&lt;/p&gt;
&lt;p&gt;Because nothing is ever easy, there are actually two different python bindings for Qt. There is &lt;a href="https://en.wikipedia.org/wiki/PySide"&gt;PySide&lt;/a&gt; which was created by the Qt Company themselves. It has a less restrictive license, but seems to have less of a community around it due to it being the newer of the two bindings. The other binding is called &lt;a href="https://en.wikipedia.org/wiki/PyQt"&gt;PyQt&lt;/a&gt; and came first, even being called &lt;code&gt;python3-qt&lt;/code&gt; in the fedora package manager. When it comes down to coding, there is pretty much no difference between them since they are all just pythonic fronts for the same C++ back-end. For the whole project up until recently I was using PySide since it is the same in every way except for a better license.&lt;/p&gt;
&lt;a name='python-deployment'&gt;&lt;/a&gt;&lt;h2&gt;Python Deployment&lt;/h2&gt;
&lt;p&gt;Python, as it is shipped as CPython, does not (by default) compile to machine code. You'll notice a parenthetical and a subordinate clause in the previous sentence, that's how windy this road goes.&lt;/p&gt;
&lt;p&gt;There are systems that will turn your python code into binary executables, I was using &lt;a href="https://www.pyinstaller.org/"&gt;PyInstaller&lt;/a&gt; to get the job done for me. I'd run it on Linux, Windows, MacOS and all my code would be packaged in to binary form; there was the issue of non-python dependencies I had but I could find ways around that. So there I was with all my binaries in a row and feeling confident about how I'm going to deploy my application.&lt;/p&gt;
&lt;a name='linux-binary-woes'&gt;&lt;/a&gt;&lt;h2&gt;Linux Binary Woes&lt;/h2&gt;
&lt;p&gt;My current main machine runs Fedora Linux, this is a distribution that is kept reasonably up to date and, at the time of writing, has a new desktop environment and newer kernel than other non-Arch distros. All of this meant that when I tried to run my Linux compiled program on Ubuntu (A major distro I want to support), I get thrown an error that Ubuntu doesn't have the correct version of glibc (the dynamically linked C libraries). Sticking with the standard glibc versions that come with each distro, GNU/Linux is backwards compatible but not forwards compatible. That is to say that a program compiled on an older distro will run on a newer distro but not vice-versa. The solution to this seems straightforward doesn't it? Compile the program on an older version. So I loaded up an Ubuntu LTS VM, compile the program, works like a charm. I try to run that same executable on my main Fedora machine and I get an error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Settings schema 'org.gnome.settings-daemon.plugins.xsettings'
does not contain a key named 'antialiasing'
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The program does not run. This is without doubt a bug in Gnome 40. But it is a bug that happens 100% of the time, it may get fixed, it may not. My application is either incompatible with anything other than my own machine, or compatible with everything &lt;em&gt;except&lt;/em&gt; my own machine. Of course I could have two separate binaries, but that would be a bit of a hassle to maintain. In comes what I thought would be my saviour, Flatpak.&lt;/p&gt;
&lt;a name='build-systems'&gt;&lt;/a&gt;&lt;h3&gt;Build Systems&lt;/h3&gt;
&lt;p&gt;Linux has 3 main methods of deploying applications. Shipping binaries, making per distribution packages, and containers (of which flatpak is one). Binaries are, as we've seen, version dependent, packages are distribution dependent, and containers run across all machines but have extra bulk since they package there own dependencies rather than relying on system libraries.&lt;/p&gt;
&lt;p&gt;Throughout my exploration of deployment options, I have made all three. I have documented my results of binaries, and I also went on to make an RPM package (the packaging system that Fedora uses).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Name:&lt;span class="w"&gt;           &lt;/span&gt;Pepys
Version:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.3.0
Release:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;?dist&lt;span class="o"&gt;}&lt;/span&gt;
Summary:&lt;span class="w"&gt;        &lt;/span&gt;A&lt;span class="w"&gt; &lt;/span&gt;straightforward&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;journal

License:&lt;span class="w"&gt;        &lt;/span&gt;GPLv3
URL:&lt;span class="w"&gt;            &lt;/span&gt;https://www.lukebriggs.dev/pepys
Source0:&lt;span class="w"&gt;        &lt;/span&gt;pepys.tar.gz

Requires:&lt;span class="w"&gt;       &lt;/span&gt;python3,&lt;span class="w"&gt; &lt;/span&gt;python3-wheel,&lt;span class="w"&gt; &lt;/span&gt;python3-pip,&lt;span class="w"&gt; &lt;/span&gt;pandoc,&lt;span class="w"&gt; &lt;/span&gt;enchant,&lt;span class="w"&gt; &lt;/span&gt;wkhtmltopdf,&lt;span class="w"&gt; &lt;/span&gt;python3-qt5,&lt;span class="w"&gt; &lt;/span&gt;python3-qt5-webengine,&lt;span class="w"&gt; &lt;/span&gt;python3-regex,&lt;span class="w"&gt; &lt;/span&gt;python3-num2words,&lt;span class="w"&gt; &lt;/span&gt;python3-pypandoc,&lt;span class="w"&gt; &lt;/span&gt;python3-enchant,&lt;span class="w"&gt; &lt;/span&gt;python3-setproctitle,&lt;span class="w"&gt; &lt;/span&gt;texlive-mdwtools
BuildRequires:&lt;span class="w"&gt;  &lt;/span&gt;python3-pip
%description

%build
&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;buildroot&lt;span class="o"&gt;}&lt;/span&gt;/usr/share/pepys
&lt;span class="nv"&gt;APP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;buildroot&lt;span class="o"&gt;}&lt;/span&gt;/usr/local/share/applications
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

tar&lt;span class="w"&gt; &lt;/span&gt;-xzvf&lt;span class="w"&gt; &lt;/span&gt;%&lt;span class="o"&gt;{&lt;/span&gt;SOURCE0&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/config.json&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/config.json
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/wordlist.txt&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/src/resources/base/wordlist.txt&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

cp&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp/*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAIN_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/temp


&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[Desktop Entry]\n \&lt;/span&gt;
&lt;span class="s2"&gt;Type=Application\n \&lt;/span&gt;
&lt;span class="s2"&gt;Name=Pepys\n \&lt;/span&gt;
&lt;span class="s2"&gt;Categories=Office;\n \&lt;/span&gt;
&lt;span class="s2"&gt;X-GNOME-FullName=Pepys\n \&lt;/span&gt;
&lt;span class="s2"&gt;Comment=A straightforward markdown journal\n \&lt;/span&gt;
&lt;span class="s2"&gt;Icon=%s/src/main/resources/base/icons/appicons/icon.svg\n \&lt;/span&gt;
&lt;span class="s2"&gt;NoDisplay=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;Exec= python3 %s/src/main/python/main.py\n \&lt;/span&gt;
&lt;span class="s2"&gt;Path=\n \&lt;/span&gt;
&lt;span class="s2"&gt;Terminal=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;X-GNOME-UsesNotifications=false\n \&lt;/span&gt;
&lt;span class="s2"&gt;StartupWMClass=Pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/share/pepys&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$APP_DIR&lt;/span&gt;/Pepys.desktop
pip3&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;PyPDF4


%files
/*

%post
chmod&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;777&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/share/pepys

&lt;span class="c1"&gt;#%license add-license-file-here&lt;/span&gt;
&lt;span class="c1"&gt;#%doc add-docs-here&lt;/span&gt;



%changelog
*&lt;span class="w"&gt; &lt;/span&gt;Sat&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Luke&lt;span class="w"&gt; &lt;/span&gt;Briggs&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;lukebriggs02@gmail.com&amp;gt;
-
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;NOTICE: The above is a script used for testing, it is mostly functional but don't use it as a guide for how to do things properly&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The above is a script you feed into &lt;code&gt;rpmbuild&lt;/code&gt; and it will generate a .rpm file which Fedora users can use to install your software. You can see that all it really is is some metadata listing app information, dependencies (these dependencies are ones that are inside the fedora packaging system), and a shell script to say what gets installed and how. Because all the dependencies are listed, and are all from the the distros package manager, the file size of an rpm only consists of the files that you supply. In my case it was some python source files and some vector icons, totalling 1.2MB. Of course the full size of the app still needs to be downloaded but the other 150MB or so come in the form of system libraries that other apps can also use. This is the classic Linux method of software deployment, it is lean, and ensures compatibility with a particular distro. The problem comes when looking at other distributions. Some distributions also use RPM (CentOS, RHEL, OpenSUSE) but have different packages, and so need special cases in the file. Other distributions use a different package management system, Debian and derivatives use .deb files for instance.&lt;/p&gt;
&lt;a name='flatpak'&gt;&lt;/a&gt;&lt;h3&gt;Flatpak&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Flatpak"&gt;Flatpak&lt;/a&gt; and it's rival &lt;a href="https://en.wikipedia.org/wiki/Snap_(package_manager)"&gt;Snap&lt;/a&gt; aim to solve the dependency hell by shipping everything together in one big package. You avoid incompatibility at the cost of redundancy. The cover image of this post is my flatpak spec file that gets fed into &lt;code&gt;flatpak-builder&lt;/code&gt;. And you may notice that it works in a similar way to a distribution's own package manager.&lt;/p&gt;
&lt;p&gt;We have metadata along with base dependencies&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;app-id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;dev.lukebriggs.pepys&lt;/span&gt;
&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;org.kde.Platform&lt;/span&gt;
&lt;span class="nt"&gt;runtime-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;5.15&amp;#39;&lt;/span&gt;
&lt;span class="nt"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;org.kde.Sdk&lt;/span&gt;
&lt;span class="nt"&gt;add-extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;org.freedesktop.Sdk.Extension.texlive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;texlive&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;subdirectories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;autodelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;20.08&amp;#39;&lt;/span&gt;
&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;runner.sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because everything is in a sandbox, we have to declare what parts of the host system we have to use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;finish-args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--share=ipc&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=x11&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=wayland&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--socket=pulseaudio&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--device=dri&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--filesystem=home&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--share=network&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;--env=PATH=/usr/bin:/app/bin:/app/texlive/bin:/app/texlive/bin/x86_64-linux:/app/texlive/bin/aarch64-linux&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then comes the rest of our dependencies which have to be files we supply, along with the build script we use to actually do what we want with the files.&lt;/p&gt;
&lt;a name='the-trouble-with-python,-qt-and-flatpak'&gt;&lt;/a&gt;&lt;h4&gt;The Trouble with Python, Qt and Flatpak&lt;/h4&gt;
&lt;p&gt;All was going swimmingly until I had to get my Qt app in flatpak.
2 of my app dependencies are installed by effectively copying the prebuild binaries into the flatpak sandbox.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;pandoc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;buildsystem&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;build-commands&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ls&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;install -D bin/pandoc /app/bin/pandoc&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="w w-Error"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;archive&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://github.com/jgm/pandoc/releases/download/2.13/pandoc-2.13-linux-amd64.tar.gz&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;7404aa88a6eb9fbb99d9803b80170a3a546f51959230cc529c66a2ce6b950d4c&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;wkhtmltopdf&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;buildsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;build-commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;cp -r local/* /app/&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ls lib&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;archive&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.centos8.x86_64.rpm&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;5cc267d54fe3f144729f31432a165e028b689583c53cfee0a01d52644ab280d9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One of my dependencies is actually built and compiled within the flatpak container. (Given no &lt;code&gt;buildsystem&lt;/code&gt; option on archives with makefiles in them, flatpak will automatically compile and install them)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  - name: enchant
    sources:
      - type: archive
        url: https://github.com/AbiWord/enchant/releases/download/v2.2.15/enchant-2.2.15.tar.gz
        sha256: 3b0f2215578115f28e2a6aa549b35128600394304bd79d6f28b0d3b3d6f46c03
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we are back to the dilemma of using source files or prebuilt binaries, you'll see later that the solution is a mix of both.&lt;/p&gt;
&lt;p&gt;One option is just shipping a compiled version of my program in a flatpak. The issue is that flatpak's glibc is once again older than my main machine so &lt;em&gt;all&lt;/em&gt; flatpak builds would have to be done in an Ubuntu VM, not ideal. Next up comes building from source in the flatpak. My plan for the process was this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get python and resource files in the flatpak&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip install&lt;/code&gt; all dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sounds simple enough, but flatpak didn't like me communicating with the internet while installing (I tried &lt;code&gt;share=network&lt;/code&gt; on individual modules and it didn't work)
So, each python library had to be down as it's own python module with a link to the tar balls on pypi. Flatpak has a tool for such an occasion called &lt;a href="https://github.com/flatpak/flatpak-builder-tools/tree/master/pip"&gt;flatpak-pip-generator&lt;/a&gt;
so the line in the flatpak yml&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;python3-requirements.json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is a pointer to a file actually containing all pip dependencies&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-requirements&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;modules&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-regex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;regex\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/38/3f/4c42a98c9ad7d08c16e7d23b2194a0e4f3b2914662da8bc88986e4e6de1f/regex-2021.4.4.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-num2words&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;num2words\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/33/db/76f1151a1b0cfad532d41021b77cd231495bf72c47618166f92dcdff2ebe/num2words-0.5.10.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;37cd4f60678f7e1045cdc3adf6acf93c8b41bf732da860f97d301f04e611cc57&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-pypandoc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;wheel\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;pypandoc\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/ed/46/e298a50dde405e1c202e316fa6a3015ff9288423661d7ea5e8f22f589071/wheel-0.36.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/d6/b7/5050dc1769c8a93d3ec7c4bd55be161991c94b8b235f88bf7c764449e708/pypandoc-1.5.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;14a49977ab1fbc9b14ef3087dcb101f336851837fca55ca79cf33846cc4976ff&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-pyenchant&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;pyenchant\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/1f/d4/52869fe4ed24e373694c116adc00c82e5d92c747be4cbc97b24af43807f6/pyenchant-3.2.0.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;6b97e9a9f132fa7c9029a6635d821ccad67d4980e68186d02c765b4256b6f152&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-PyPDF4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;PyPDF4\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/4f/1f/509b44850c475c101aa5b5c9b81755cedd363389d6fbb5c53be6fa915a61/PyPDF4-1.27.0.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7c932441146d205572f96254d53c79ea2c30c9e11df55a5cf87e056c7b3d7f89&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-setproctitle&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;buildsystem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;build-commands&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pip3 install --verbose --exists-action=i --no-index --find-links=\&amp;quot;file://${PWD}\&amp;quot; --prefix=${FLATPAK_DEST} \&amp;quot;setproctitle\&amp;quot; --no-build-isolation&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sources&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://files.pythonhosted.org/packages/a1/7f/a1d4f4c7b66f0fc02f35dc5c85f45a8b4e4a7988357a29e61c14e725ef86/setproctitle-1.2.2.tar.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;sha256&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7dfb472c8852403d34007e01d6e3c68c57eb66433fb8a5c77b13b89a160d97df&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You'll notice that there is no mention of PySide or Qt. The &lt;em&gt;key&lt;/em&gt; module that the app depends so heavily is not there, why? Well because both Qt python dependencies are not available as source files from pip. Pip hosts source files and wheels. All the above are source files. These are tar balls that pip will compile and build from source. Wheels are, once again, pre-built binaries. Flatpak doesn't include wheels by default since it wants everything to be as cross platform and cross architecture as possible.&lt;/p&gt;
&lt;p&gt;I also wanted to be as platform agnostic as possible so I attempted to build my python bindings from source in the flatpak. Flatpak did not like this. Neither PySide nor PyQt would build and each threw different error during the compilation process. My best guess would by the sandbox does not contain some required system libraries but I am at a loss to know which ones. And C compilers are not the most helpful thing as your only point of reference for a system error.&lt;/p&gt;
&lt;a name='lasers-to-the-rescue'&gt;&lt;/a&gt;&lt;h3&gt;Lasers to the rescue&lt;/h3&gt;
&lt;p&gt;At this stage, I didn't actually know what python wheels were, I just assumed everything had to be built from source. I was desperate for answers after 3 days of debugging and staring at config files. I did something I very rarely do, I used the GitHub search function. To my amazement I found a solution.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.physics.hu-berlin.de/en/qom"&gt;Optical Metrology Group&lt;/a&gt; in the Physics department of Humboldt University Berlin &lt;a href="https://github.com/hermitdemschoenenleben/linien"&gt;created a Linux application for locking onto spectroscopy lines&lt;/a&gt;. Guess what, they made a flatpak!&lt;/p&gt;
&lt;p&gt;I looked at there yaml, and I knew then and there that they had found a solution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# we used to build pyqt on our own here, but this build caused trouble with the pyqtgraph widget being transparent on some systems.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Therefore, we just use the x86_64 wheel here...&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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 l-Scalar l-Scalar-Plain"&gt;pyqt-x86_64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;buildsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;simple&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;file&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://files.pythonhosted.org/packages/4c/bb/7fce18fbe0275d7a3e069a306d8f4662c77eda30ec6780634fd4a7ee50ce/PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;b1ea7e82004dc7b311d1e29df2f276461016e2d180e10c73805ace4376125ed9&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;file&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://files.pythonhosted.org/packages/31/24/f887203677955ba4d5d4efe9176ac7ed2bf84efce8c243ab91e63183ad9e/PyQt5_sip-12.8.1-cp37-cp37m-manylinux1_x86_64.whl&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;a1b8ef013086e224b8e86c93f880f776d01b59195bdfa2a8e0b23f0480678fec&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;build-commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;pip3 install PyQt*.whl --target=/app/lib/python3.7/site-packages&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;They had obviously also faced similar Qt-based problems. Their YAML led to me finding out about python wheels, how I could get PyQt in a flatpak, and how I could tell pip the right directory for a python installation (I had no idea what &lt;code&gt;--target&lt;/code&gt; would do before this).&lt;/p&gt;
&lt;p&gt;Thanks to some German physicists, my next project is back on track. Beady eyed people may notice some information in some of the config files I've posted that hint to what it could be. I did try and use PySide using the same wheel method but I got into some strange cyclical versioning thing since it required PySide an Shiboken2 to be installed at the same time. All that means is that my application will be open source out of a legal obligation, as well as an civil one.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;SIDE:&lt;/em&gt; kerberos is also a requirement for PyQt to work in a flatpak, I have no idea why but it may have something to do with certain networking modules.&lt;/p&gt;
&lt;a name='further-reading'&gt;&lt;/a&gt;&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;Here are some useful sources of information I turned to while interacting with packaging systems on Linux&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.loganasherjones.com/2018/05/using-flatpak-with-python/"&gt;https://www.loganasherjones.com/2018/05/using-flatpak-with-python/&lt;/a&gt; 
:	An excellent and succinct guide that covers making non-qt python apps work in a flatpak&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.flatpak.org/en/latest/getting-started.html"&gt;https://docs.flatpak.org/en/latest/getting-started.html&lt;/a&gt;
:	Information on what a flatpak is and what its parts consist of.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html"&gt;https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html&lt;/a&gt;
:	A good reference for what commands can be used in flatpak YAML&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/flathub/io.github.hermitdemschoenenleben.linien/blob/8d89b1c7193602f0696f134e92ac1eba39986303/io.github.hermitdemschoenenleben.linien.yml#L18"&gt;https://github.com/flathub/io.github.hermitdemschoenenleben.linien/blob/8d89b1c7193602f0696f134e92ac1eba39986303/io.github.hermitdemschoenenleben.linien.yml#L18&lt;/a&gt;
: 	The Humboldt University Berlin YAML&lt;/p&gt;
&lt;p&gt;&lt;a href="https://opensource.com/article/18/9/how-build-rpm-packages"&gt;https://opensource.com/article/18/9/how-build-rpm-packages&lt;/a&gt;
:	A straightforward guide on how to make RPM packages&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 22 May 2021 19:08:56 +0000</pubDate>
    </item>
    <item>
      <title>Inspection and Dissection: Pepys - A Straightforward Markdown Editor
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-pepys</link>
      <description>&lt;img class='post-hero' src='static/postimages/inspection-and-dissection-pepys/BookLogoLargeWhite.svg' alt='&lt;div&gt;Inspection and Dissection: Pepys - A Straightforward Markdown Editor&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Pepys - A Straightforward Markdown Editor&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;The product page is available &lt;a href="projects/pepys"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;Pepys is a GUI journaling application built using Python bindings for the Qt framework.
It is available as an installer for Windows and a Flatpak on Linux.&lt;/p&gt;
&lt;a name='background'&gt;&lt;/a&gt;&lt;h1&gt;Background&lt;/h1&gt;
&lt;p&gt;I started journaling around February last year, it was probably the most prescient thing I have ever done.
It wasn't long before we all went into self-imposed isolation and journaling provided a good way to express my thoughts.&lt;/p&gt;
&lt;p&gt;My first posts were made in one big Word document.
Journals need to be as future-proof as possible, and I thought at the time that since entire governments are probably reliant on MS Word that it won't be going away any time soon.
It wasn't a good experience though. 
Having to type the date each time was tiresome, and I thought it would be a formatting mess should I use an Operating System without MS Word (something which would later happen when I spent several months using Linux).&lt;/p&gt;
&lt;p&gt;I next moved on to &lt;a href="https://notion.so"&gt;Notion&lt;/a&gt;.
An excellent productivity application that can be used to do all sorts from notes to spreadsheets to databases.
It's template, tagging and calendar features made it a great prospect for writing my journal in. 
The entries were made in Markdown so would be viewable on any computer for as long as we still used ASCII and Unicode, seems pretty future proof.
The trouble was, it made journal writing a chore.
To write an entry I'd have to open up this electron application that took an &lt;em&gt;age&lt;/em&gt; to open and slowly click through web links, waiting for pages to load, before I could get to writing entries.
I wanted a native application that would allow me to write journal entries in markdown, with a date-based file chooser.
I found no application that fitted all this criteria that worked on Linux and Windows, they all seemed Mac only (I am envious of the great ecosystem Apple cultivates among its development community).
So I took it upon myself to write my own.&lt;/p&gt;
&lt;a name='a-rocky-start'&gt;&lt;/a&gt;&lt;h1&gt;A Rocky Start&lt;/h1&gt;
&lt;p&gt;The first idea for a Journal application first came to me in June 2020 but it would take nearly a year before I would find the time and the courage to actually start it.&lt;/p&gt;
&lt;p&gt;My only experience with a GUI application that wasn't made in a dedicated game engine was &lt;a href="posts/inspection-and-dissection-dice-jack"&gt;Dice-Jack&lt;/a&gt; which was a version of blackjack that used Dice instead of cards and was made over a few days for an assignment as part of my Sixth Form Computing course.
I knew I couldn't use dotNet since I wanted it to be able to run on Linux as well as Windows.
My next thought was Java, since that was the language I was learning at University at the time and seemed to fit all my requirements.&lt;/p&gt;
&lt;p&gt;I managed to get a very early text editor working in Java.
At that point, the idea was to have all the styling done in real time as you typed.
For example, if I typed a &lt;code&gt;#&lt;/code&gt; then I would set the font size you type in to that of a title.&lt;/p&gt;
&lt;p&gt;I was running into issues that were perfectly fixable but I was never truly comfortable in Java.
I will absolutely use Java in the future but it just didn't seem right with this project. 
With Java I had the choice between the ancient swing and JavaFX.
I have never got to grasps with the whole split GUI framework where some bits are in code and some bits are in XML files.
All the GUI frameworks are going this way so I will have to get my head around it eventually but this was not the project for this.&lt;/p&gt;
&lt;a name='a-walk-in-the-dark'&gt;&lt;/a&gt;&lt;h1&gt;A Walk in the Dark&lt;/h1&gt;
&lt;p&gt;After bouncing of Java frameworks I had to go with what I know, Python.
Python was the first language I learned and I've been using it for coming up 4 years now.
The big players in the Python GUI game is Gtk, Qt, wxWidgets, and Tkinter. 
Tkinter and wxWidgets are the more simple of the four with the majority of applications being built in either Gtk or Qt.
In the end I settled with Qt because it seemed to have better look and feel across different systems, and Gtk seemed to want me to use build systems that I was unfamiliar with.
I first broke ground with the first &lt;a href="https://github.com/LukeBriggsDev/Pepys/commit/66f42549e53db7a43224d317be2191b2000e0d94"&gt;git commit&lt;/a&gt; being pushed at 20:29 BST on April 1st.
This was the first commit to the repo that would become the final release, this came at the end of several weeks of the aforementioned bouncing around.&lt;/p&gt;
&lt;a name='syntax-highlighting'&gt;&lt;/a&gt;&lt;h2&gt;Syntax Highlighting&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="An early version of the edit pane" src="static/postimages/inspection-and-dissection-pepys/pepys-april7-2021.png"&gt;
&lt;figcaption&gt;An early version of the edit pane&lt;/figcaption&gt;
&lt;/figure&gt;
My primary focus was in getting markdown source highlighting in the text window.
Things like bold, italic, and strike-through came rather quickly but became incredibly slow with large amounts of text.
My initial solution to the syntax highlighting was a naive one.
I would be performing regex searches and applying text character formatting across the document on each key press.
The approach was okay on small documents, but the larger the document the more text would be searched through and it would become impossible to type.
The first breakthrough came when I discovered a Qt widget called QSyntaxHighlighter which provided methods that would allow text to be broken up into 'blocks'.
I put all my regular expressions into a QSyntaxHighlighter and used its blocking mechanism to allow for typing to not be slowed down on large documents.
&lt;a name='html-preview'&gt;&lt;/a&gt;&lt;h2&gt;HTML Preview&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="An early version of the view pane - note the switch from menu bar to tool bar" src="static/postimages/inspection-and-dissection-pepys/pepys-april9-2021.png"&gt;
&lt;figcaption&gt;An early version of the view pane&lt;/figcaption&gt;
&lt;/figure&gt;
Alot of the early work went into refining my markdown regular expressions, making sure they formatted the correct parts and matched the output reasonably.
It wasn't long before I had to turn my attention to the HTML preview.
The preview pane was initially just a QTextBrowser that supported a limited subset of HTML.
When the preview button was clicked the markdown would be converted to html using [mistune](https://mistune.readthedocs.io/en/latest/).
I had used mistune previously on the [first iteration of this website](projects/inspection-and-dissection-this-site) so a lot of that could be copied and pasted from my work there.
&lt;p&gt;The fact that only a subset of HTML was supported soon became an issue and I had to switch the preview to a full on web engine (the reason why the application is so large).
The web engine was such a double edged sword.
Without it: previews wouldn't match exports, math equations wouldn't be supported, many markdown elements couldn't be rendered properly (tables, inline html).
But with it, the application swells in size to over 100MB download and even larger when fully installed.
I wish I could resolve this alas I am too tired and too unskilled to be able to implement a solution.&lt;/p&gt;
&lt;a name='the-killer-feature'&gt;&lt;/a&gt;&lt;h2&gt;The Killer Feature&lt;/h2&gt;
&lt;p&gt;It was around this time that I went into exploring &lt;a href="https://pandoc.org/"&gt;pandoc&lt;/a&gt;.
I was amazed by its power and I will undoubtedly utilise it in many future projects.
Pandoc is a program written in haskell that uses its own flavour of markdown to provide a &lt;em&gt;huge&lt;/em&gt; amount of outputs for document conversion.
I knew I had to implement this in some way to provide some way of providing a wide range of export option.
Then I will have truly realised my need of having entries been in a future proof format, why have 1 future proof format when you can have every format under the Sun?&lt;/p&gt;
&lt;a name='calendar-file-selector'&gt;&lt;/a&gt;&lt;h2&gt;Calendar File Selector&lt;/h2&gt;
&lt;p&gt;I knew that my main method of interacting with files should be through a calendar.
Qt provides a reasonably good calendar widget that saved alot of time.
The way I keep track of the files in a user's journal is by having a very rigid folder structure which Pepys gets pointed to.
The journal directory has a structure of &lt;code&gt;YYYY\MM\DD\YYYY-MM-DD\YYYY-MM-DD.md&lt;/code&gt; This makes it very easy to search for all the entries by date.&lt;/p&gt;
&lt;a name='release'&gt;&lt;/a&gt;&lt;h2&gt;Release&lt;/h2&gt;
&lt;figure&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;img alt="Very Old logo" src="static/postimages/inspection-and-dissection-pepys/pepysoldlock.png" width="256px"&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;img alt="Old logo" src="static/postimages/inspection-and-dissection-pepys/pepysold.png" width="256px"&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;img alt="New logo" src="static/postimages/inspection-and-dissection-pepys/pepysnew.png" width="256px"&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;figcaption&gt;A comparison of different logos I went through&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have went into my woes over releasing software &lt;a href="projects/flatpak-instructions-not-included"&gt;here&lt;/a&gt; but it is safe to say that this is an are where I learned an awful lot.
In the end Pepys was released on Linux via flatpak and on Windows via an NSIS installer &lt;a href="https://github.com/LukeBriggsDev/Pepys/releases/"&gt;available to download on GitHub&lt;/a&gt;.
There was no Mac release because I do not own a Mac no have sufficient experience with Macs to be comfortable with creating installers and sufficiently testing them for correctness.&lt;/p&gt;
&lt;a name='a-retrospective'&gt;&lt;/a&gt;&lt;h1&gt;A Retrospective&lt;/h1&gt;
&lt;p&gt;This whole process has been the longest I have ever spent on a project, it was probably the largest project I have ever made, and there were alot of firsts.
It was the first application I made that wasn't a game, it was the first proper GUI application I have made, and it was the first time I had to make installers by hand.
The process was arduous at times and I felt like giving up at some points.&lt;/p&gt;
&lt;p&gt;I sit here now after releasing it and I think &amp;quot;if I'd only done this&amp;quot; or &amp;quot;it would be so much better if...&amp;quot; but I can't think like that.
If I had spent as long as possible on each feature till it was perfect then the software would never be released.
I have learned that software development is an iterative process in 2 ways.
The first way is in relation to an individual piece of software.
You develop the software over time, slowly improving and adding until a finished product stumbles over the finish line.
The second way is at a macroscopic level.
Each huge project your begin, each journey you embark on, brings a new iteration on what went before.
The next GUI project I make &lt;em&gt;will&lt;/em&gt; be better.
The next installer I make &lt;em&gt;will&lt;/em&gt; be better.
And this excites me.&lt;/p&gt;
&lt;p&gt;I suppose it has taken me until the end of my first year of University to understand what learning is really about.
Learning isn't about passing tests, although schools may tell you otherwise. 
Learning isn't even about knowing stuff, that is just a by-product.
Learning is about being better, about knowing you &lt;em&gt;will&lt;/em&gt; be better, and about being excited about that.
I am excited about what I will create next, how I will iterate on what I have learned, and how I can surprise myself.&lt;/p&gt;
&lt;a name='special-thanks'&gt;&lt;/a&gt;&lt;h1&gt;Special Thanks&lt;/h1&gt;
&lt;p&gt;All of this took an awful lot of effort so I would like to give special thanks to the following people and projects for there valuable insights.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gitlab.gnome.org/World/apostrophe"&gt;Apostrophe&lt;/a&gt;
: An excellent markdown editor that shows how to make a properly good writing experience and led me down the Pandoc path. Also inspired some of the regex used.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/hermitdemschoenenleben/linien"&gt;Humboldt University Optical Metrology Group&lt;/a&gt;
: Without whom I'd still be wrestling with compilers in Flatpak&lt;/p&gt;
&lt;p&gt;&lt;a href="https://akaru.me/"&gt;Lucy Marsden&lt;/a&gt; (&lt;a href="https://github.com/noneuclideanmotion"&gt;Github&lt;/a&gt;)
: Who provided a second set of eyes and motivated me to actually get stuff done.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FedoraQt/adwaita-qt"&gt;Jan Grulich&lt;/a&gt;
: For showing how to implement Adwaita colours in Qt&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/inspection-and-dissection-pepys/BookLogoLargeWhite.svg' alt='&lt;div&gt;Inspection and Dissection: Pepys - A Straightforward Markdown Editor&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Pepys - A Straightforward Markdown Editor&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;The product page is available &lt;a href="projects/pepys"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;Pepys is a GUI journaling application built using Python bindings for the Qt framework.
It is available as an installer for Windows and a Flatpak on Linux.&lt;/p&gt;
&lt;a name='background'&gt;&lt;/a&gt;&lt;h1&gt;Background&lt;/h1&gt;
&lt;p&gt;I started journaling around February last year, it was probably the most prescient thing I have ever done.
It wasn't long before we all went into self-imposed isolation and journaling provided a good way to express my thoughts.&lt;/p&gt;
&lt;p&gt;My first posts were made in one big Word document.
Journals need to be as future-proof as possible, and I thought at the time that since entire governments are probably reliant on MS Word that it won't be going away any time soon.
It wasn't a good experience though. 
Having to type the date each time was tiresome, and I thought it would be a formatting mess should I use an Operating System without MS Word (something which would later happen when I spent several months using Linux).&lt;/p&gt;
&lt;p&gt;I next moved on to &lt;a href="https://notion.so"&gt;Notion&lt;/a&gt;.
An excellent productivity application that can be used to do all sorts from notes to spreadsheets to databases.
It's template, tagging and calendar features made it a great prospect for writing my journal in. 
The entries were made in Markdown so would be viewable on any computer for as long as we still used ASCII and Unicode, seems pretty future proof.
The trouble was, it made journal writing a chore.
To write an entry I'd have to open up this electron application that took an &lt;em&gt;age&lt;/em&gt; to open and slowly click through web links, waiting for pages to load, before I could get to writing entries.
I wanted a native application that would allow me to write journal entries in markdown, with a date-based file chooser.
I found no application that fitted all this criteria that worked on Linux and Windows, they all seemed Mac only (I am envious of the great ecosystem Apple cultivates among its development community).
So I took it upon myself to write my own.&lt;/p&gt;
&lt;a name='a-rocky-start'&gt;&lt;/a&gt;&lt;h1&gt;A Rocky Start&lt;/h1&gt;
&lt;p&gt;The first idea for a Journal application first came to me in June 2020 but it would take nearly a year before I would find the time and the courage to actually start it.&lt;/p&gt;
&lt;p&gt;My only experience with a GUI application that wasn't made in a dedicated game engine was &lt;a href="posts/inspection-and-dissection-dice-jack"&gt;Dice-Jack&lt;/a&gt; which was a version of blackjack that used Dice instead of cards and was made over a few days for an assignment as part of my Sixth Form Computing course.
I knew I couldn't use dotNet since I wanted it to be able to run on Linux as well as Windows.
My next thought was Java, since that was the language I was learning at University at the time and seemed to fit all my requirements.&lt;/p&gt;
&lt;p&gt;I managed to get a very early text editor working in Java.
At that point, the idea was to have all the styling done in real time as you typed.
For example, if I typed a &lt;code&gt;#&lt;/code&gt; then I would set the font size you type in to that of a title.&lt;/p&gt;
&lt;p&gt;I was running into issues that were perfectly fixable but I was never truly comfortable in Java.
I will absolutely use Java in the future but it just didn't seem right with this project. 
With Java I had the choice between the ancient swing and JavaFX.
I have never got to grasps with the whole split GUI framework where some bits are in code and some bits are in XML files.
All the GUI frameworks are going this way so I will have to get my head around it eventually but this was not the project for this.&lt;/p&gt;
&lt;a name='a-walk-in-the-dark'&gt;&lt;/a&gt;&lt;h1&gt;A Walk in the Dark&lt;/h1&gt;
&lt;p&gt;After bouncing of Java frameworks I had to go with what I know, Python.
Python was the first language I learned and I've been using it for coming up 4 years now.
The big players in the Python GUI game is Gtk, Qt, wxWidgets, and Tkinter. 
Tkinter and wxWidgets are the more simple of the four with the majority of applications being built in either Gtk or Qt.
In the end I settled with Qt because it seemed to have better look and feel across different systems, and Gtk seemed to want me to use build systems that I was unfamiliar with.
I first broke ground with the first &lt;a href="https://github.com/LukeBriggsDev/Pepys/commit/66f42549e53db7a43224d317be2191b2000e0d94"&gt;git commit&lt;/a&gt; being pushed at 20:29 BST on April 1st.
This was the first commit to the repo that would become the final release, this came at the end of several weeks of the aforementioned bouncing around.&lt;/p&gt;
&lt;a name='syntax-highlighting'&gt;&lt;/a&gt;&lt;h2&gt;Syntax Highlighting&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="An early version of the edit pane" src="static/postimages/inspection-and-dissection-pepys/pepys-april7-2021.png"&gt;
&lt;figcaption&gt;An early version of the edit pane&lt;/figcaption&gt;
&lt;/figure&gt;
My primary focus was in getting markdown source highlighting in the text window.
Things like bold, italic, and strike-through came rather quickly but became incredibly slow with large amounts of text.
My initial solution to the syntax highlighting was a naive one.
I would be performing regex searches and applying text character formatting across the document on each key press.
The approach was okay on small documents, but the larger the document the more text would be searched through and it would become impossible to type.
The first breakthrough came when I discovered a Qt widget called QSyntaxHighlighter which provided methods that would allow text to be broken up into 'blocks'.
I put all my regular expressions into a QSyntaxHighlighter and used its blocking mechanism to allow for typing to not be slowed down on large documents.
&lt;a name='html-preview'&gt;&lt;/a&gt;&lt;h2&gt;HTML Preview&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="An early version of the view pane - note the switch from menu bar to tool bar" src="static/postimages/inspection-and-dissection-pepys/pepys-april9-2021.png"&gt;
&lt;figcaption&gt;An early version of the view pane&lt;/figcaption&gt;
&lt;/figure&gt;
Alot of the early work went into refining my markdown regular expressions, making sure they formatted the correct parts and matched the output reasonably.
It wasn't long before I had to turn my attention to the HTML preview.
The preview pane was initially just a QTextBrowser that supported a limited subset of HTML.
When the preview button was clicked the markdown would be converted to html using [mistune](https://mistune.readthedocs.io/en/latest/).
I had used mistune previously on the [first iteration of this website](projects/inspection-and-dissection-this-site) so a lot of that could be copied and pasted from my work there.
&lt;p&gt;The fact that only a subset of HTML was supported soon became an issue and I had to switch the preview to a full on web engine (the reason why the application is so large).
The web engine was such a double edged sword.
Without it: previews wouldn't match exports, math equations wouldn't be supported, many markdown elements couldn't be rendered properly (tables, inline html).
But with it, the application swells in size to over 100MB download and even larger when fully installed.
I wish I could resolve this alas I am too tired and too unskilled to be able to implement a solution.&lt;/p&gt;
&lt;a name='the-killer-feature'&gt;&lt;/a&gt;&lt;h2&gt;The Killer Feature&lt;/h2&gt;
&lt;p&gt;It was around this time that I went into exploring &lt;a href="https://pandoc.org/"&gt;pandoc&lt;/a&gt;.
I was amazed by its power and I will undoubtedly utilise it in many future projects.
Pandoc is a program written in haskell that uses its own flavour of markdown to provide a &lt;em&gt;huge&lt;/em&gt; amount of outputs for document conversion.
I knew I had to implement this in some way to provide some way of providing a wide range of export option.
Then I will have truly realised my need of having entries been in a future proof format, why have 1 future proof format when you can have every format under the Sun?&lt;/p&gt;
&lt;a name='calendar-file-selector'&gt;&lt;/a&gt;&lt;h2&gt;Calendar File Selector&lt;/h2&gt;
&lt;p&gt;I knew that my main method of interacting with files should be through a calendar.
Qt provides a reasonably good calendar widget that saved alot of time.
The way I keep track of the files in a user's journal is by having a very rigid folder structure which Pepys gets pointed to.
The journal directory has a structure of &lt;code&gt;YYYY\MM\DD\YYYY-MM-DD\YYYY-MM-DD.md&lt;/code&gt; This makes it very easy to search for all the entries by date.&lt;/p&gt;
&lt;a name='release'&gt;&lt;/a&gt;&lt;h2&gt;Release&lt;/h2&gt;
&lt;figure&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;img alt="Very Old logo" src="static/postimages/inspection-and-dissection-pepys/pepysoldlock.png" width="256px"&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;img alt="Old logo" src="static/postimages/inspection-and-dissection-pepys/pepysold.png" width="256px"&gt;
&lt;/th&gt;
&lt;th&gt;
&lt;img alt="New logo" src="static/postimages/inspection-and-dissection-pepys/pepysnew.png" width="256px"&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;figcaption&gt;A comparison of different logos I went through&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have went into my woes over releasing software &lt;a href="projects/flatpak-instructions-not-included"&gt;here&lt;/a&gt; but it is safe to say that this is an are where I learned an awful lot.
In the end Pepys was released on Linux via flatpak and on Windows via an NSIS installer &lt;a href="https://github.com/LukeBriggsDev/Pepys/releases/"&gt;available to download on GitHub&lt;/a&gt;.
There was no Mac release because I do not own a Mac no have sufficient experience with Macs to be comfortable with creating installers and sufficiently testing them for correctness.&lt;/p&gt;
&lt;a name='a-retrospective'&gt;&lt;/a&gt;&lt;h1&gt;A Retrospective&lt;/h1&gt;
&lt;p&gt;This whole process has been the longest I have ever spent on a project, it was probably the largest project I have ever made, and there were alot of firsts.
It was the first application I made that wasn't a game, it was the first proper GUI application I have made, and it was the first time I had to make installers by hand.
The process was arduous at times and I felt like giving up at some points.&lt;/p&gt;
&lt;p&gt;I sit here now after releasing it and I think &amp;quot;if I'd only done this&amp;quot; or &amp;quot;it would be so much better if...&amp;quot; but I can't think like that.
If I had spent as long as possible on each feature till it was perfect then the software would never be released.
I have learned that software development is an iterative process in 2 ways.
The first way is in relation to an individual piece of software.
You develop the software over time, slowly improving and adding until a finished product stumbles over the finish line.
The second way is at a macroscopic level.
Each huge project your begin, each journey you embark on, brings a new iteration on what went before.
The next GUI project I make &lt;em&gt;will&lt;/em&gt; be better.
The next installer I make &lt;em&gt;will&lt;/em&gt; be better.
And this excites me.&lt;/p&gt;
&lt;p&gt;I suppose it has taken me until the end of my first year of University to understand what learning is really about.
Learning isn't about passing tests, although schools may tell you otherwise. 
Learning isn't even about knowing stuff, that is just a by-product.
Learning is about being better, about knowing you &lt;em&gt;will&lt;/em&gt; be better, and about being excited about that.
I am excited about what I will create next, how I will iterate on what I have learned, and how I can surprise myself.&lt;/p&gt;
&lt;a name='special-thanks'&gt;&lt;/a&gt;&lt;h1&gt;Special Thanks&lt;/h1&gt;
&lt;p&gt;All of this took an awful lot of effort so I would like to give special thanks to the following people and projects for there valuable insights.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gitlab.gnome.org/World/apostrophe"&gt;Apostrophe&lt;/a&gt;
: An excellent markdown editor that shows how to make a properly good writing experience and led me down the Pandoc path. Also inspired some of the regex used.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/hermitdemschoenenleben/linien"&gt;Humboldt University Optical Metrology Group&lt;/a&gt;
: Without whom I'd still be wrestling with compilers in Flatpak&lt;/p&gt;
&lt;p&gt;&lt;a href="https://akaru.me/"&gt;Lucy Marsden&lt;/a&gt; (&lt;a href="https://github.com/noneuclideanmotion"&gt;Github&lt;/a&gt;)
: Who provided a second set of eyes and motivated me to actually get stuff done.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FedoraQt/adwaita-qt"&gt;Jan Grulich&lt;/a&gt;
: For showing how to implement Adwaita colours in Qt&lt;/p&gt;
</content:encoded>
      <pubDate>Mon, 31 May 2021 16:47:38 +0000</pubDate>
    </item>
    <item>
      <title>Full Release: newcastle-bst - Harvard referencing style as recommended by Newcastle University
</title>
      <link>https://lukebriggs.dev/posts/full-release-newcastle-bst</link>
      <description>&lt;img class='post-hero' src='static/postimages/full-release-newcastle-bst/bibtex.png' alt='&lt;div&gt;Full Release: newcastle-bst - Harvard referencing style as recommended by Newcastle University&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Full Release: newcastle-bst - Harvard referencing style as recommended by Newcastle University&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;A couple of months ago I released &lt;a href="posts/the-laypersons-guide-to-latex"&gt;a blog post about LateX&lt;/a&gt;.
At the bottom of the post I made quick reference to a BibTeX style I had created for the referencing used by Newcastle University.
The style had a few bugs and was quite hard to find it but it was left dormant while I made some other software and focused on work.&lt;/p&gt;
&lt;p&gt;I am now pleased to say that I have spent some work polishing it up, fixing some issues, and giving it a proper release.
It's even on &lt;a href="https://ctan.org/pkg/newcastle-bst"&gt;CTAN!&lt;/a&gt;.
If you are a student and notice any issues, please report them on &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX/issues"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='release-notes'&gt;&lt;/a&gt;&lt;h1&gt;Release Notes&lt;/h1&gt;
&lt;a name='newcastle-bst:-harvard-referencing-style-as-recommended-by-newcastle-university'&gt;&lt;/a&gt;&lt;h2&gt;newcastle-bst: Harvard referencing style as recommended by Newcastle University&lt;/h2&gt;
&lt;p&gt;This package provides a &lt;a href="https://ctan.org/pkg/BibTeX"&gt;BibTeX&lt;/a&gt; style to format reference lists in the &lt;a href="https://libguides.ncl.ac.uk/managing/harvard"&gt;Harvard at Newcastle&lt;/a&gt; style recommended by Newcastle University. It should be used alongside &lt;a href="https://ctan.org/pkg/natbib"&gt;natbib&lt;/a&gt; for citations.&lt;/p&gt;
&lt;a name='installation'&gt;&lt;/a&gt;&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;The required style file is available from &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX"&gt;GitHub&lt;/a&gt; and &lt;a href="https://ctan.org/pkg/newcastle-bst"&gt;CTAN&lt;/a&gt;. You can use the style by copying it into your working directory containing your &lt;code&gt;.tex&lt;/code&gt; file. You can also add it to your bst directory in your tex path to use it without having to copy it over each time.&lt;/p&gt;
&lt;a name='using-the-style'&gt;&lt;/a&gt;&lt;h3&gt;Using the style&lt;/h3&gt;
&lt;p&gt;To use the style include this in your preamble:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;natbib&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="na"&gt;[UKenglish]&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;isodate&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\bibliographystyle&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;newcastle&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also remember to specify your &lt;code&gt;.bib&lt;/code&gt; file at the end of the document:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;\bibliography&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;file&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The easiest way to create .bib files for this style is through exporting entries from a reference manager such as &lt;a href="https://www.mendeley.com/"&gt;Mendeley&lt;/a&gt;.
However, some parts are not available through this (such as titleaddon for computer programs).
If you notice any discrepancies between generated references and the recommended styles then please raise this on &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX/issues"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='license'&gt;&lt;/a&gt;&lt;h3&gt;License&lt;/h3&gt;
&lt;p&gt;Copyright 2021 Luke Briggs
This work consists of the documented &lt;code&gt;newcastle.bst&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The text files contained in this work may be distributed and/or modified under the conditions of the LATEX Project Public License (LPPL), either version 1.3c of this license or (at your option) any later version.&lt;/p&gt;
&lt;p&gt;This work has had no input from Newcastle University and is done entirely in order to help other students create bibliography quicker.&lt;/p&gt;
&lt;p&gt;This work is ‘maintained’ (as per LPPL maintenance status) by Luke Briggs.&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/full-release-newcastle-bst/bibtex.png' alt='&lt;div&gt;Full Release: newcastle-bst - Harvard referencing style as recommended by Newcastle University&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Full Release: newcastle-bst - Harvard referencing style as recommended by Newcastle University&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;A couple of months ago I released &lt;a href="posts/the-laypersons-guide-to-latex"&gt;a blog post about LateX&lt;/a&gt;.
At the bottom of the post I made quick reference to a BibTeX style I had created for the referencing used by Newcastle University.
The style had a few bugs and was quite hard to find it but it was left dormant while I made some other software and focused on work.&lt;/p&gt;
&lt;p&gt;I am now pleased to say that I have spent some work polishing it up, fixing some issues, and giving it a proper release.
It's even on &lt;a href="https://ctan.org/pkg/newcastle-bst"&gt;CTAN!&lt;/a&gt;.
If you are a student and notice any issues, please report them on &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX/issues"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='release-notes'&gt;&lt;/a&gt;&lt;h1&gt;Release Notes&lt;/h1&gt;
&lt;a name='newcastle-bst:-harvard-referencing-style-as-recommended-by-newcastle-university'&gt;&lt;/a&gt;&lt;h2&gt;newcastle-bst: Harvard referencing style as recommended by Newcastle University&lt;/h2&gt;
&lt;p&gt;This package provides a &lt;a href="https://ctan.org/pkg/BibTeX"&gt;BibTeX&lt;/a&gt; style to format reference lists in the &lt;a href="https://libguides.ncl.ac.uk/managing/harvard"&gt;Harvard at Newcastle&lt;/a&gt; style recommended by Newcastle University. It should be used alongside &lt;a href="https://ctan.org/pkg/natbib"&gt;natbib&lt;/a&gt; for citations.&lt;/p&gt;
&lt;a name='installation'&gt;&lt;/a&gt;&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;The required style file is available from &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX"&gt;GitHub&lt;/a&gt; and &lt;a href="https://ctan.org/pkg/newcastle-bst"&gt;CTAN&lt;/a&gt;. You can use the style by copying it into your working directory containing your &lt;code&gt;.tex&lt;/code&gt; file. You can also add it to your bst directory in your tex path to use it without having to copy it over each time.&lt;/p&gt;
&lt;a name='using-the-style'&gt;&lt;/a&gt;&lt;h3&gt;Using the style&lt;/h3&gt;
&lt;p&gt;To use the style include this in your preamble:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;natbib&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="na"&gt;[UKenglish]&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;isodate&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\bibliographystyle&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;newcastle&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also remember to specify your &lt;code&gt;.bib&lt;/code&gt; file at the end of the document:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;\bibliography&lt;/span&gt;&lt;span class="nb"&gt;{&lt;/span&gt;file&lt;span class="nb"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The easiest way to create .bib files for this style is through exporting entries from a reference manager such as &lt;a href="https://www.mendeley.com/"&gt;Mendeley&lt;/a&gt;.
However, some parts are not available through this (such as titleaddon for computer programs).
If you notice any discrepancies between generated references and the recommended styles then please raise this on &lt;a href="https://github.com/LukeBriggsDev/Newcastle-BibTeX/issues"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;a name='license'&gt;&lt;/a&gt;&lt;h3&gt;License&lt;/h3&gt;
&lt;p&gt;Copyright 2021 Luke Briggs
This work consists of the documented &lt;code&gt;newcastle.bst&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The text files contained in this work may be distributed and/or modified under the conditions of the LATEX Project Public License (LPPL), either version 1.3c of this license or (at your option) any later version.&lt;/p&gt;
&lt;p&gt;This work has had no input from Newcastle University and is done entirely in order to help other students create bibliography quicker.&lt;/p&gt;
&lt;p&gt;This work is ‘maintained’ (as per LPPL maintenance status) by Luke Briggs.&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 10 Jul 2021 10:33:04 +0000</pubDate>
    </item>
    <item>
      <title>Inspection and Dissection: Calmer Internet - My First Web Extension
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-calmer-internet</link>
      <description>&lt;img class='post-hero' src='static/calmer-internet/banner.svg' alt='&lt;div&gt;Inspection and Dissection: Calmer Internet - My First Web Extension&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Calmer Internet - My First Web Extension&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;The product page is available &lt;a href="projects/calmer-internet"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Calmer Internet&lt;/em&gt; is a web extension for Chrome, Firefox, and Edge that makes the internet a less infuriating place to be.
It removes comments, recommended content and various trending pages from Twitter, YouTube, and Instagram to try and relieve that doom-scrolling.&lt;/p&gt;
&lt;a name='rationale'&gt;&lt;/a&gt;&lt;h1&gt;Rationale&lt;/h1&gt;
&lt;p&gt;Since I finished stage 1 of University in June, I had a considerable amount of time off.
A lot of that time was spent in a state of not quite working and not quite relaxing.
I was stuck in a cycle of following the YouTube sidebar of bland content before going to Twitter and scrolling down the trending hashtags and comments, getting annoyed at every step.&lt;/p&gt;
&lt;p&gt;Many social media platforms just throw various things at you in an attempt to just keep scrolling and clicking and engaging, before you know it you've spent an hour of your life on a soul-sucking site.&lt;/p&gt;
&lt;p&gt;I didn't want to quit these sites entirely. 
There are truly incredible and insightful people on there like &lt;a href="https://www.youtube.com/user/enyay"&gt;Tom Scott&lt;/a&gt;, &lt;a href="https://www.youtube.com/c/Exurb1a"&gt;exurb1a&lt;/a&gt;, and &lt;a href="https://www.youtube.com/channel/UCE1jXbVAGJQEORz9nZqb5bQ"&gt;Ahoy&lt;/a&gt;.
Twitter is also good as a micro-blog feed for people I want to follow in the tech sector. 
The conclusion I came to is that I need to take control of what I see. 
I should only be consuming things I have actively sought out, because those are the things that I enjoy the most.
It also means that I can't just keep scrolling and watching forever, I will run out of content because I only see what I have subscribed to.
There is no 'one more click'&lt;/p&gt;
&lt;p&gt;My initial solution was to have everything go to an RSS reader but most social media platforms don't play nicely with rss feeds and feed readers don't really play nicely with conveying threads, retweets and video content.
As a result, I turned to editing the sites themselves to provide a more focused experience.&lt;/p&gt;
&lt;a name='how-it's-made'&gt;&lt;/a&gt;&lt;h1&gt;How it's made&lt;/h1&gt;
&lt;p&gt;This extension didn't start out as an extension. It started out as a set of rules for my ad-blocker. 
I'd use the eyedropper tool to select the &lt;em&gt;Trending&lt;/em&gt; bar on Twitter just so I wouldn't be tempted to click it.
I did similar things with the trending tab on YouTube.
It then got to a point where I wanted to do more like remove the recommended sidebar and the video-wall end screens, so I decided I needed a web extension.&lt;/p&gt;
&lt;p&gt;I have never made a web extension before, but I do have some experience in HTML and JavaScript so it wasn't too troublesome to get used to.
Most of what my extension does takes place in a 'content script'.
This is a javascript file that just loaded alongside the current page at load time.
The file then looks at the current URL and checks the page for any elements I've told it to remove.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Adding Twitter elements to a list of elements to remove&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;twitter.com&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mobile.twitter.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterTrendingBar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;trendingBar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;div[aria-label=&amp;#39;Timeline: Trending now&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterExploreLinks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;exploreLinks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a[href=&amp;#39;/explore&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterWhoToFollow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;miscStyling&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;css-1dbjc4n r-1867qdf r-1phboty r-rs99b7 r-1ifxtd0 r-1bro5k0 r-1udh08x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;whoToFollow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aside[aria-label=&amp;#39;Who to follow&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterTopics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;topics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;div[aria-label=&amp;#39;Timeline: &amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The script then attaches a listener that causes new checks every time the webpage is updated&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observeBodyRemove&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Select the node that will be observed for mutations&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Options for the observer (which mutations to observe)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;childList&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;subtree&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Callback function to execute when mutations are observed&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutationsList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getElementsToRemove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Create an observer instance linked to the callback function&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MutationObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Start observing the target node for configured mutations&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only other JavaScript in the extension is in a 'background script'.
Whereas 'content scripts' are loaded alongside a webpage, background scripts are persistent and always run whenever the extension is loaded.
This means they are useful for doing things before a page is loaded. 
One feature of the extension is you can redirect any links to YouTube.com to youtube.com/feed/subscriptions, so you aren't bombarded by useless recommendations.
I initially had the redirect in a content script but that required the whole page to be loaded before redirecting away from it.&lt;/p&gt;
&lt;p&gt;My current solution uses the WebRequest API to intercept a page request and load a new one instead.
This is also done be setting up a listener, such as this one:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// YouTube&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onBeforeRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YTHomeRedirect&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://youtube.com/feed/subscriptions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main_frame&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sub_frame&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;script&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;xmlhttprequest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;other&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;blocking&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, all that was left was to create a manifest.
I have great experience with manifests since &lt;a href="https://github.com/LukeBriggsDev/Pepys"&gt;Pepys recently received builds for rpm, .deb, and PKGBUILD&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;manifest_version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Calmer Internet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;browser_specific_settings&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;gecko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;calmerinternet@lukebriggs.dev&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;browser_action&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;default_icon&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;16&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/16.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;24&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/24.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/32.png&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;default_title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Calmer Internet&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;icons&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/48.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;96&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/96.png&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;content_scripts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;matches&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.instagram.com/*&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;calmer.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;background.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;permissions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.instagram.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;storage&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;webRequest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;webRequestBlocking&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Provides a calmer internet experience. Removes comments and various recommendation elements from Twitter, YouTube, Instagram.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;options_ui&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;options.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='deployment'&gt;&lt;/a&gt;&lt;h1&gt;Deployment&lt;/h1&gt;
&lt;p&gt;The extension is available on the Chrome Web Store, the Firefox Add-on Store, and the Microsoft Store.
WebExtensions are now pretty cross-compatible, so I use the exact same code-base across all browsers.
It would even support Safari as of Big Sur, but I do not have a Mac to upload it, nor do I want to fork out the $99 price of an Apple Developer account.&lt;/p&gt;
&lt;p&gt;As ever, the project is also available in full on my &lt;a href="https://github.com/LukeBriggsDev/calmer-internet"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/calmer-internet/banner.svg' alt='&lt;div&gt;Inspection and Dissection: Calmer Internet - My First Web Extension&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Calmer Internet - My First Web Extension&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;The product page is available &lt;a href="projects/calmer-internet"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Calmer Internet&lt;/em&gt; is a web extension for Chrome, Firefox, and Edge that makes the internet a less infuriating place to be.
It removes comments, recommended content and various trending pages from Twitter, YouTube, and Instagram to try and relieve that doom-scrolling.&lt;/p&gt;
&lt;a name='rationale'&gt;&lt;/a&gt;&lt;h1&gt;Rationale&lt;/h1&gt;
&lt;p&gt;Since I finished stage 1 of University in June, I had a considerable amount of time off.
A lot of that time was spent in a state of not quite working and not quite relaxing.
I was stuck in a cycle of following the YouTube sidebar of bland content before going to Twitter and scrolling down the trending hashtags and comments, getting annoyed at every step.&lt;/p&gt;
&lt;p&gt;Many social media platforms just throw various things at you in an attempt to just keep scrolling and clicking and engaging, before you know it you've spent an hour of your life on a soul-sucking site.&lt;/p&gt;
&lt;p&gt;I didn't want to quit these sites entirely. 
There are truly incredible and insightful people on there like &lt;a href="https://www.youtube.com/user/enyay"&gt;Tom Scott&lt;/a&gt;, &lt;a href="https://www.youtube.com/c/Exurb1a"&gt;exurb1a&lt;/a&gt;, and &lt;a href="https://www.youtube.com/channel/UCE1jXbVAGJQEORz9nZqb5bQ"&gt;Ahoy&lt;/a&gt;.
Twitter is also good as a micro-blog feed for people I want to follow in the tech sector. 
The conclusion I came to is that I need to take control of what I see. 
I should only be consuming things I have actively sought out, because those are the things that I enjoy the most.
It also means that I can't just keep scrolling and watching forever, I will run out of content because I only see what I have subscribed to.
There is no 'one more click'&lt;/p&gt;
&lt;p&gt;My initial solution was to have everything go to an RSS reader but most social media platforms don't play nicely with rss feeds and feed readers don't really play nicely with conveying threads, retweets and video content.
As a result, I turned to editing the sites themselves to provide a more focused experience.&lt;/p&gt;
&lt;a name='how-it's-made'&gt;&lt;/a&gt;&lt;h1&gt;How it's made&lt;/h1&gt;
&lt;p&gt;This extension didn't start out as an extension. It started out as a set of rules for my ad-blocker. 
I'd use the eyedropper tool to select the &lt;em&gt;Trending&lt;/em&gt; bar on Twitter just so I wouldn't be tempted to click it.
I did similar things with the trending tab on YouTube.
It then got to a point where I wanted to do more like remove the recommended sidebar and the video-wall end screens, so I decided I needed a web extension.&lt;/p&gt;
&lt;p&gt;I have never made a web extension before, but I do have some experience in HTML and JavaScript so it wasn't too troublesome to get used to.
Most of what my extension does takes place in a 'content script'.
This is a javascript file that just loaded alongside the current page at load time.
The file then looks at the current URL and checks the page for any elements I've told it to remove.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Adding Twitter elements to a list of elements to remove&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;twitter.com&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;mobile.twitter.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterTrendingBar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;trendingBar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;div[aria-label=&amp;#39;Timeline: Trending now&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterExploreLinks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;exploreLinks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a[href=&amp;#39;/explore&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterWhoToFollow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;miscStyling&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;css-1dbjc4n r-1867qdf r-1phboty r-rs99b7 r-1ifxtd0 r-1bro5k0 r-1udh08x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;whoToFollow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aside[aria-label=&amp;#39;Who to follow&amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TwitterTopics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;topics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;div[aria-label=&amp;#39;Timeline: &amp;#39;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The script then attaches a listener that causes new checks every time the webpage is updated&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observeBodyRemove&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Select the node that will be observed for mutations&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetNode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Options for the observer (which mutations to observe)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;childList&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;subtree&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Callback function to execute when mutations are observed&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutationsList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getElementsToRemove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elementsToRemove&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Create an observer instance linked to the callback function&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MutationObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Start observing the target node for configured mutations&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only other JavaScript in the extension is in a 'background script'.
Whereas 'content scripts' are loaded alongside a webpage, background scripts are persistent and always run whenever the extension is loaded.
This means they are useful for doing things before a page is loaded. 
One feature of the extension is you can redirect any links to YouTube.com to youtube.com/feed/subscriptions, so you aren't bombarded by useless recommendations.
I initially had the redirect in a content script but that required the whole page to be loaded before redirecting away from it.&lt;/p&gt;
&lt;p&gt;My current solution uses the WebRequest API to intercept a page request and load a new one instead.
This is also done be setting up a listener, such as this one:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// YouTube&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onBeforeRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YTHomeRedirect&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://youtube.com/feed/subscriptions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main_frame&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sub_frame&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;script&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;xmlhttprequest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;other&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;blocking&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, all that was left was to create a manifest.
I have great experience with manifests since &lt;a href="https://github.com/LukeBriggsDev/Pepys"&gt;Pepys recently received builds for rpm, .deb, and PKGBUILD&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;manifest_version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Calmer Internet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;browser_specific_settings&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;gecko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;calmerinternet@lukebriggs.dev&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;browser_action&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;default_icon&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;16&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/16.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;24&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/24.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/32.png&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;default_title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Calmer Internet&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;icons&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/48.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;96&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;icons/96.png&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;content_scripts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;matches&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.instagram.com/*&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;calmer.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;background.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;permissions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.youtube.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*://*.instagram.com/*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;storage&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;webRequest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;webRequestBlocking&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Provides a calmer internet experience. Removes comments and various recommendation elements from Twitter, YouTube, Instagram.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;options_ui&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;options.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='deployment'&gt;&lt;/a&gt;&lt;h1&gt;Deployment&lt;/h1&gt;
&lt;p&gt;The extension is available on the Chrome Web Store, the Firefox Add-on Store, and the Microsoft Store.
WebExtensions are now pretty cross-compatible, so I use the exact same code-base across all browsers.
It would even support Safari as of Big Sur, but I do not have a Mac to upload it, nor do I want to fork out the $99 price of an Apple Developer account.&lt;/p&gt;
&lt;p&gt;As ever, the project is also available in full on my &lt;a href="https://github.com/LukeBriggsDev/calmer-internet"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content:encoded>
      <pubDate>Wed, 18 Aug 2021 15:18:16 +0000</pubDate>
    </item>
    <item>
      <title>Inspection and Dissection: Sounds2Spotify
</title>
      <link>https://lukebriggs.dev/posts/inspection-and-dissection-sounds2spotify</link>
      <description>&lt;img class='post-hero' src='static/projects/sounds2spotify_banner.svg' alt='&lt;div&gt;Inspection and Dissection: Sounds2&lt;wbr&gt;Spotify&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Sounds2&lt;wbr&gt;Spotify&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;Available on &lt;a href="https://github.com/LukeBriggsDev/Sounds2Spotify"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;Sounds2Spotify is a web extension for firefox and chrome that converts the tracklists that appear on &lt;a href="https://bbc.co.uk/sounds"&gt;BBC Sounds&lt;/a&gt; programme pages to be converted into Spotify playlists.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a href="projectscalmer-internet"&gt;Calmer-Internet&lt;/a&gt; this extension can only be installed by following the instructions on &lt;a href="https://github.com/LukeBriggsDev/Sounds2Spotify"&gt;Github&lt;/a&gt; due to its use of API keys.&lt;/p&gt;
&lt;a name='impetus'&gt;&lt;/a&gt;&lt;h1&gt;Impetus&lt;/h1&gt;
&lt;p&gt;One of my pleasures in life is listening to Music.
My favourite tracks are stored locally and also in Spotify playlists for when I'm using a device without my collection.
Most of the time, however, I'm not listening to my favourite tracks, I'm listening to the &lt;a href="https://www.bbc.co.uk/sounds/play/live:bbc_6music"&gt;BBC 6Music&lt;/a&gt;.
More specifically, I'm listening to the &lt;a href="https://www.bbc.co.uk/programmes/b00c000j"&gt;Lauren Laverne Breakfast Show&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Due to licensing reasons the BBC can only have its music programming available on its own BBC Sounds app for a limited time.
This is fine when I'm using my computer or phone, but quite often I want to listen to music in the background when using my PlayStation, which only allows music to be played through Spotify.&lt;/p&gt;
&lt;p&gt;The goal: to convert the music played on BBC Sounds to Spotify playlists.&lt;/p&gt;
&lt;a name='code-walkthrough'&gt;&lt;/a&gt;&lt;h1&gt;Code Walkthrough&lt;/h1&gt;
&lt;a name='part-1:-getting-the-music'&gt;&lt;/a&gt;&lt;h2&gt;Part 1: Getting the Music&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/inspection-and-dissection-sounds2spotify/tracklist.png" alt="BBC Sounds Tracklist" /&gt;&lt;/p&gt;
&lt;hr style="border: 1px solid black"&gt;
&lt;p&gt;&lt;img src="static/postimages/inspection-and-dissection-sounds2spotify/track_popup.png" alt="Track popup" /&gt;&lt;/p&gt;
&lt;p&gt;Thankfully, underneath every music programme, the BBC provides a track list of all the music played throughout the programme as well as a popover menu providing links to external sources.&lt;/p&gt;
&lt;p&gt;So the first job my extension had to do was to scrape this information.
There are no APIs or direct links to this information so the only way to get this information is by clicking on each button and grabbing the Spotify link.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// List of buttons that bring up track popover&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[id^=&amp;quot;track-&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;episodeDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sc-c-episode__metadata__data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;lastChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each menu button has the HTML ID of &amp;quot;track-x&amp;quot; where x is its position in the tracklist.
So a query for all these IDs will yield a list of button elements.&lt;/p&gt;
&lt;p&gt;The date the episode aired is also quite useful when it comes to naming the eventual playlist, so I grab that as well.&lt;/p&gt;
&lt;p&gt;I also initialise the tracklist here. Eventually I want a list of the Spotify links for the tracks.&lt;/p&gt;
&lt;p&gt;The IDs and element classes were obtained by hand by scouring the HTML source of the page.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;scrollIntoView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// t = 200ms&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[href^=&amp;quot;https://open.spotify.com/track/&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackMetadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data-bbc-metadata&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TID&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;trackTitle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// No links found&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I loop through all the button elements, scroll to the element and click it. There is a 200ms delay between each track as render differences can lead to buttons not being clicked.&lt;/p&gt;
&lt;p&gt;When a track is clicked, single popover appears containing a Spotify track link if it exists. As a result, by querying for a Spotify track URL on the page, I will get the link, if it exists.&lt;/p&gt;
&lt;p&gt;The popover also includes some metadata for the track in the form of JSON. So I use the track title as the key in a dictionary of tracks, just to make debugging easier. 
The value in the dictionary is the corresponding link.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tracklist&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track_list&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;episodeDate&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;farewell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All this data is then wrapped up into a message and sent off to be picked up by a background script.&lt;/p&gt;
&lt;p&gt;I mention background scripts in more detail on my &lt;a href="posts/inspection-and-dissection-calmer-internet/"&gt;Inspection and Dissection on Calmer-Internet&lt;/a&gt;&lt;/p&gt;
&lt;a name='part-2:-promises,-async,-apis'&gt;&lt;/a&gt;&lt;h2&gt;Part 2: Promises, Async, APIs&lt;/h2&gt;
&lt;p&gt;Now for the complicated part.
Using the list of Spotify links I have to create a playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Base URL&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://accounts.spotify.com/authorize?&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`client_id=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;`&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;response_type=code&amp;amp;&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`redirect_uri=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;`&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;scope=playlist-modify-public&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first thing I need to do is get authorisation from the user to allow the extension to modify public playlists.
This is done by pointing a request to a specific url containing certain information.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;client_id: this is and id associated with a &lt;a href="https://developer.spotify.com/dashboard/applications"&gt;Spotify app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;response_type: there are various ways to authenticate, the way I are doing it is through a 'code' flow&lt;/li&gt;
&lt;li&gt;redirect_uri: the url Spotify should redirect to when done.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Web extensions require this to be a single link unique to the extension which is obtained through the method above&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;scope: which permissions I require&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tracklist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;farewell&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;recieved tracklist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track_list&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Authenticate and make playlist&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launchWebAuthFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;interactive&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authenticateSpotify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a listener that responds to my message containing a tracklist.
All the listener does is store the information in global variables (I know it can be bad practice but this is a small program with a specific purpose) and launch an authentication flow with my link.&lt;/p&gt;
&lt;p&gt;Once this is done, I then call the &lt;code&gt;authenticateSpotify&lt;/code&gt; method.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authenticateSpotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Get parameters from response&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;urlParams&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My WebAuthFlow passes a response in the form of a URL containing a parameter with an authorisation code (or a rejection).
I isolate these parameters by stripping off My redirect url and calling &lt;code&gt;URLSearchParams&lt;/code&gt; on it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// POST request for access token&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://accounts.spotify.com/api/token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application/x-www-form-urlencoded;charset=UTF-8&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grant_type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization_code&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;urlParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;redirect_uri&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;client_id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;client_secret&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_secret&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then construct a POST request to Spotify by exchanging my authorisation code, and client details for an access token.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Create playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;createPlaylist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then send this POST request, receive a response, parse the JSON response and send the access token to the &lt;code&gt;createPlaylist&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSpotifyID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;userRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://api.spotify.com/v1/me&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To know which account I'm working with I ask for the profile ID.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createPlaylist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Add create Spotify URIs from track links&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://open.spotify.com/track/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;spotify:track:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Spotify API does not want the tracks in the form of a link it wants a uri in the form &lt;code&gt;spotify:track:trackid&lt;/code&gt;.
So for each link in our track list I replace the link part with &lt;code&gt;spotify:track:&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Create new playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`https://api.spotify.com/v1/users/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/playlists`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="sb"&gt;`{&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;name&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tracklist_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; | &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tracklist_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;quot;,&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;description&amp;quot;: &amp;quot;Made using Sounds2Spotify&amp;quot;&lt;/span&gt;
&lt;span class="sb"&gt;}`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before I can add to a playlist, I need to create one first, so I construct a request to do just that using the authorisation token, and the user ID.
I use the page name, and date from the BBC Sounds page as the title of the playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Add tracklist songs to newly created playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`https://api.spotify.com/v1/playlists/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playlistID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/tracks`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="sb"&gt;`{&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;uris&amp;quot;: [&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;]&lt;/span&gt;
&lt;span class="sb"&gt;}`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The response of my request contains the playlist ID which I then feed into our next request to add my list of tracks to the playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Open tab to new playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`https://open.spotify.com/playlist/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playlistID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, I open up the playlist in a new tab.&lt;/p&gt;
&lt;a name='retrospective'&gt;&lt;/a&gt;&lt;h1&gt;Retrospective&lt;/h1&gt;
&lt;p&gt;Overall, I am very pleased with what I managed to achieve. 
I have very limited experience in using JavaScript to interact with REST APIs, but I managed to pick it up reasonably quickly.&lt;/p&gt;
&lt;p&gt;The code I think is relatively clean for a first attempt.
Obviously if any of the request throw an error then there is not much in the way of handling a response, but JavaScript tends to be pretty robust with errors and this isn't a product that is going to be released on any web store or anything.&lt;/p&gt;
&lt;a name='reason-for-installation-procedure'&gt;&lt;/a&gt;&lt;h1&gt;Reason for Installation Procedure&lt;/h1&gt;
&lt;p&gt;The reason why this project is not going to be released on a web store is for security reasons.
A part of the process requires sending Spotify secret API keys for the corresponding Spotify app.
This would mean that my secret keys would have to be in the client-side code, and therefore be freely accessible.&lt;/p&gt;
&lt;p&gt;It would therefore be possible for someone to pose as my extension and start making requests as my app to users.&lt;/p&gt;
&lt;p&gt;The installation process isn't so cumbersome to be impossible to install, but it isn't as plug and play as I would like it to be&lt;/p&gt;
&lt;a name='sources-of-information'&gt;&lt;/a&gt;&lt;h1&gt;Sources of Information&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Spotify API Docs - &lt;a href="https://developer.spotify.com/documentation/web-api/"&gt;https://developer.spotify.com/documentation/web-api/&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.spotify.com/console/playlists/"&gt;Playlists&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chrome extension API Docs - &lt;a href="https://developer.chrome.com/docs/extensions/reference/"&gt;https://developer.chrome.com/docs/extensions/reference/&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/identity/#method-getRedirectURL"&gt;identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/mv2/messaging/"&gt;Message Passing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mozilla Web API Docs - &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API"&gt;https://developer.mozilla.org/en-US/docs/Web/API&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch"&gt;fetch()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Response"&gt;Response&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;Promise&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/projects/sounds2spotify_banner.svg' alt='&lt;div&gt;Inspection and Dissection: Sounds2&lt;wbr&gt;Spotify&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Inspection and Dissection: Sounds2&lt;wbr&gt;Spotify&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;Available on &lt;a href="https://github.com/LukeBriggsDev/Sounds2Spotify"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='brief-description'&gt;&lt;/a&gt;&lt;h1&gt;Brief Description&lt;/h1&gt;
&lt;p&gt;Sounds2Spotify is a web extension for firefox and chrome that converts the tracklists that appear on &lt;a href="https://bbc.co.uk/sounds"&gt;BBC Sounds&lt;/a&gt; programme pages to be converted into Spotify playlists.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a href="projectscalmer-internet"&gt;Calmer-Internet&lt;/a&gt; this extension can only be installed by following the instructions on &lt;a href="https://github.com/LukeBriggsDev/Sounds2Spotify"&gt;Github&lt;/a&gt; due to its use of API keys.&lt;/p&gt;
&lt;a name='impetus'&gt;&lt;/a&gt;&lt;h1&gt;Impetus&lt;/h1&gt;
&lt;p&gt;One of my pleasures in life is listening to Music.
My favourite tracks are stored locally and also in Spotify playlists for when I'm using a device without my collection.
Most of the time, however, I'm not listening to my favourite tracks, I'm listening to the &lt;a href="https://www.bbc.co.uk/sounds/play/live:bbc_6music"&gt;BBC 6Music&lt;/a&gt;.
More specifically, I'm listening to the &lt;a href="https://www.bbc.co.uk/programmes/b00c000j"&gt;Lauren Laverne Breakfast Show&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Due to licensing reasons the BBC can only have its music programming available on its own BBC Sounds app for a limited time.
This is fine when I'm using my computer or phone, but quite often I want to listen to music in the background when using my PlayStation, which only allows music to be played through Spotify.&lt;/p&gt;
&lt;p&gt;The goal: to convert the music played on BBC Sounds to Spotify playlists.&lt;/p&gt;
&lt;a name='code-walkthrough'&gt;&lt;/a&gt;&lt;h1&gt;Code Walkthrough&lt;/h1&gt;
&lt;a name='part-1:-getting-the-music'&gt;&lt;/a&gt;&lt;h2&gt;Part 1: Getting the Music&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/inspection-and-dissection-sounds2spotify/tracklist.png" alt="BBC Sounds Tracklist" /&gt;&lt;/p&gt;
&lt;hr style="border: 1px solid black"&gt;
&lt;p&gt;&lt;img src="static/postimages/inspection-and-dissection-sounds2spotify/track_popup.png" alt="Track popup" /&gt;&lt;/p&gt;
&lt;p&gt;Thankfully, underneath every music programme, the BBC provides a track list of all the music played throughout the programme as well as a popover menu providing links to external sources.&lt;/p&gt;
&lt;p&gt;So the first job my extension had to do was to scrape this information.
There are no APIs or direct links to this information so the only way to get this information is by clicking on each button and grabbing the Spotify link.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// List of buttons that bring up track popover&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[id^=&amp;quot;track-&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;episodeDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByClassName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sc-c-episode__metadata__data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;lastChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each menu button has the HTML ID of &amp;quot;track-x&amp;quot; where x is its position in the tracklist.
So a query for all these IDs will yield a list of button elements.&lt;/p&gt;
&lt;p&gt;The date the episode aired is also quite useful when it comes to naming the eventual playlist, so I grab that as well.&lt;/p&gt;
&lt;p&gt;I also initialise the tracklist here. Eventually I want a list of the Spotify links for the tracks.&lt;/p&gt;
&lt;p&gt;The IDs and element classes were obtained by hand by scouring the HTML source of the page.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;scrollIntoView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// t = 200ms&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[href^=&amp;quot;https://open.spotify.com/track/&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackMetadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data-bbc-metadata&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackTitle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TID&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;trackTitle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// No links found&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I loop through all the button elements, scroll to the element and click it. There is a 200ms delay between each track as render differences can lead to buttons not being clicked.&lt;/p&gt;
&lt;p&gt;When a track is clicked, single popover appears containing a Spotify track link if it exists. As a result, by querying for a Spotify track URL on the page, I will get the link, if it exists.&lt;/p&gt;
&lt;p&gt;The popover also includes some metadata for the track in the form of JSON. So I use the track title as the key in a dictionary of tracks, just to make debugging easier. 
The value in the dictionary is the corresponding link.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tracklist&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track_list&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;episodeDate&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;farewell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All this data is then wrapped up into a message and sent off to be picked up by a background script.&lt;/p&gt;
&lt;p&gt;I mention background scripts in more detail on my &lt;a href="posts/inspection-and-dissection-calmer-internet/"&gt;Inspection and Dissection on Calmer-Internet&lt;/a&gt;&lt;/p&gt;
&lt;a name='part-2:-promises,-async,-apis'&gt;&lt;/a&gt;&lt;h2&gt;Part 2: Promises, Async, APIs&lt;/h2&gt;
&lt;p&gt;Now for the complicated part.
Using the list of Spotify links I have to create a playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Base URL&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://accounts.spotify.com/authorize?&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`client_id=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;`&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;response_type=code&amp;amp;&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`redirect_uri=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;amp;`&lt;/span&gt;
&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;scope=playlist-modify-public&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first thing I need to do is get authorisation from the user to allow the extension to modify public playlists.
This is done by pointing a request to a specific url containing certain information.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;client_id: this is and id associated with a &lt;a href="https://developer.spotify.com/dashboard/applications"&gt;Spotify app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;response_type: there are various ways to authenticate, the way I are doing it is through a 'code' flow&lt;/li&gt;
&lt;li&gt;redirect_uri: the url Spotify should redirect to when done.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Web extensions require this to be a single link unique to the extension which is obtained through the method above&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;scope: which permissions I require&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tracklist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;farewell&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;recieved tracklist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track_list&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tracklist_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Authenticate and make playlist&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launchWebAuthFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;get_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;interactive&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authenticateSpotify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a listener that responds to my message containing a tracklist.
All the listener does is store the information in global variables (I know it can be bad practice but this is a small program with a specific purpose) and launch an authentication flow with my link.&lt;/p&gt;
&lt;p&gt;Once this is done, I then call the &lt;code&gt;authenticateSpotify&lt;/code&gt; method.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authenticateSpotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Get parameters from response&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;urlParams&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My WebAuthFlow passes a response in the form of a URL containing a parameter with an authorisation code (or a rejection).
I isolate these parameters by stripping off My redirect url and calling &lt;code&gt;URLSearchParams&lt;/code&gt; on it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// POST request for access token&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;authRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://accounts.spotify.com/api/token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application/x-www-form-urlencoded;charset=UTF-8&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grant_type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization_code&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;urlParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;redirect_uri&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRedirectURL&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;client_id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;client_secret&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;client_secret&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then construct a POST request to Spotify by exchanging my authorisation code, and client details for an access token.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Create playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authRequest&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;createPlaylist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then send this POST request, receive a response, parse the JSON response and send the access token to the &lt;code&gt;createPlaylist&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSpotifyID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;userRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://api.spotify.com/v1/me&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To know which account I'm working with I ask for the profile ID.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createPlaylist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Add create Spotify URIs from track links&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tracklist&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://open.spotify.com/track/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;spotify:track:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Spotify API does not want the tracks in the form of a link it wants a uri in the form &lt;code&gt;spotify:track:trackid&lt;/code&gt;.
So for each link in our track list I replace the link part with &lt;code&gt;spotify:track:&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Create new playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`https://api.spotify.com/v1/users/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/playlists`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="sb"&gt;`{&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;name&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tracklist_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; | &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tracklist_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;&amp;quot;,&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;description&amp;quot;: &amp;quot;Made using Sounds2Spotify&amp;quot;&lt;/span&gt;
&lt;span class="sb"&gt;}`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before I can add to a playlist, I need to create one first, so I construct a request to do just that using the authorisation token, and the user ID.
I use the page name, and date from the BBC Sounds page as the title of the playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Add tracklist songs to newly created playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`https://api.spotify.com/v1/playlists/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playlistID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/tracks`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="sb"&gt;`{&lt;/span&gt;
&lt;span class="sb"&gt;    &amp;quot;uris&amp;quot;: [&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;trackURIS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;]&lt;/span&gt;
&lt;span class="sb"&gt;}`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The response of my request contains the playlist ID which I then feed into our next request to add my list of tracks to the playlist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Open tab to new playlist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`https://open.spotify.com/playlist/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playlistID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, I open up the playlist in a new tab.&lt;/p&gt;
&lt;a name='retrospective'&gt;&lt;/a&gt;&lt;h1&gt;Retrospective&lt;/h1&gt;
&lt;p&gt;Overall, I am very pleased with what I managed to achieve. 
I have very limited experience in using JavaScript to interact with REST APIs, but I managed to pick it up reasonably quickly.&lt;/p&gt;
&lt;p&gt;The code I think is relatively clean for a first attempt.
Obviously if any of the request throw an error then there is not much in the way of handling a response, but JavaScript tends to be pretty robust with errors and this isn't a product that is going to be released on any web store or anything.&lt;/p&gt;
&lt;a name='reason-for-installation-procedure'&gt;&lt;/a&gt;&lt;h1&gt;Reason for Installation Procedure&lt;/h1&gt;
&lt;p&gt;The reason why this project is not going to be released on a web store is for security reasons.
A part of the process requires sending Spotify secret API keys for the corresponding Spotify app.
This would mean that my secret keys would have to be in the client-side code, and therefore be freely accessible.&lt;/p&gt;
&lt;p&gt;It would therefore be possible for someone to pose as my extension and start making requests as my app to users.&lt;/p&gt;
&lt;p&gt;The installation process isn't so cumbersome to be impossible to install, but it isn't as plug and play as I would like it to be&lt;/p&gt;
&lt;a name='sources-of-information'&gt;&lt;/a&gt;&lt;h1&gt;Sources of Information&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Spotify API Docs - &lt;a href="https://developer.spotify.com/documentation/web-api/"&gt;https://developer.spotify.com/documentation/web-api/&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.spotify.com/console/playlists/"&gt;Playlists&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chrome extension API Docs - &lt;a href="https://developer.chrome.com/docs/extensions/reference/"&gt;https://developer.chrome.com/docs/extensions/reference/&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/reference/identity/#method-getRedirectURL"&gt;identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/extensions/mv2/messaging/"&gt;Message Passing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mozilla Web API Docs - &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API"&gt;https://developer.mozilla.org/en-US/docs/Web/API&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch"&gt;fetch()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Response"&gt;Response&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;Promise&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
      <pubDate>Thu, 16 Sep 2021 15:07:04 +0000</pubDate>
    </item>
    <item>
      <title>Shiny New Things
</title>
      <link>https://lukebriggs.dev/posts/shiny-new-things</link>
      <description>&lt;img class='post-hero' src='static/postimages/shiny-new-things/mac_desktop.jpg' alt='&lt;div&gt;Shiny New Things&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Shiny New Things&lt;/div&gt;
&lt;/h1&gt;&lt;a name='new-hardware'&gt;&lt;/a&gt;&lt;h2&gt;New Hardware&lt;/h2&gt;
&lt;p&gt;The RISC revolution claims a new victim.
On October 25th I became the owner of my first Apple computer, my first non-x86 desktop, and what is already the best computer I have ever used.&lt;/p&gt;
&lt;a name='past-devices'&gt;&lt;/a&gt;&lt;h3&gt;Past devices&lt;/h3&gt;
&lt;p&gt;I &lt;a href="posts/goodbye-windows-i-hardly-gnu-ya/"&gt;moved away from Windows about 9 months ago&lt;/a&gt; and I really haven't looked back.
A few things changed in that gestation period.
Firstly, I settled on Fedora 34 as my final distro: GNOME 40 made some changes I liked and also my bluetooth audio devices worked better.
Secondly, and more importantly, my priorities shifted.
September saw the return of in-person University lecturing and some changes had to be made.&lt;/p&gt;
&lt;figure&gt;
&lt;img src="static/postimages/shiny-new-things/legion5.jpg" alt="Lenovo Legion 5"&gt;&lt;/a&gt;
&lt;figcaption&gt;&amp;copy; &lt;a href="https://www.trustedreviews.com/"&gt;Trusted Reviews&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My previous computer was a Lenovo Legion 5, it had a efficient (but still power hungry) Ryzen 5 4600h, and a dedicated Nvidia GPU.
The laptop was 15.6&amp;quot;, weighed 2.4kg and would require obnoxious fans to spin up if it even thought you might do something demanding.
The laptop was a symptom of being purchased at the beginning of stay-at-home orders by someone who overestimated the amount of games they would be playing.&lt;/p&gt;
&lt;p&gt;When it came to in-person teaching, it also was a bit cumbersome to use the machines on-site.
At the beginning of the term, the University decided move away from using local software to having Azure Virtual Desktops instead, with the PCs acting as thin clients.
Even with gigabit networking and decent hardware, virtual desktops still have a strange smell to them.
The main issue was the fact that they are still in the teething phase and IT departments are not quick to react.
Not every virtual desktop has exactly the same software, and there is no way to know which desktop you are going to get.
One day I logged onto a virtual desktop and it had all the software I needed except git.
My only solution was installing a portable version of git &lt;em&gt;into&lt;/em&gt; my OneDrive so I could guarantee a git install on each machine.
Virtual desktops also made python virtual environments a hassle since every time I would do work on my personal machine, all the symlinks from the AVD would be broke and I'd have too recreate it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So here were my new requirement:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A CPU at least as powerful as my previous laptop&lt;/li&gt;
&lt;li&gt;16GB RAM (8GB was too little when doing development alongside local virtual machines)&lt;/li&gt;
&lt;li&gt;No dGPU (the weight, battery, and noise overhead is just awful)&lt;/li&gt;
&lt;li&gt;Screen larger than 13&amp;quot;, ideally 14.5 - 15&amp;quot;&lt;/li&gt;
&lt;li&gt;Portable, ideally around 1.5kg&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;Like-to-haves:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;120Hz screen (Legion 5 had it and it made things very nice)&lt;/li&gt;
&lt;li&gt;512GB hard drive (Legion 5 had 256GB and I was pushing up against it)&lt;/li&gt;
&lt;li&gt;A iGPU good enough to play basic 3d games at full speed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There was a selection of PC laptops that met some of my requirements. 
However, a lot of them put the higher RAM behind the models with a dGPU, which is an instant turn-off.&lt;/p&gt;
&lt;p&gt;The incredible performance of last year's M1 chips got my head pointed towards Cupertino.
They were efficient, quiet, had a strong GPU, blazing CPU and were bundled with a first-party Unix OS.
Last year's MacBooks did not meet my requirements for the case however. A 13&amp;quot; screen is too small to be doing comfortable development work on.&lt;/p&gt;
&lt;p&gt;So I sat eagerly awaiting the November Apple Event, hoping that rumors of a more powerful 14&amp;quot; MacBook Pro was on the horizon.&lt;/p&gt;
&lt;p&gt;The announced computers met every single one of my criteria, the price was steeper than I had been anticipating but I had some disposable income and I had fallen slightly in love.&lt;/p&gt;
&lt;a name='the-mac-factor'&gt;&lt;/a&gt;&lt;h3&gt;The Mac Factor&lt;/h3&gt;
&lt;p&gt;I took delivery of my base-model 14-inch MacBook Pro (M1 Pro 8/14) on day one, and have used it every day in the 2 weeks since.
The true reason why I went slightly over-budget is due to the fact that these computers are the first in a while to be truly exciting to me.
A whole new instruction set platform in the desktop space is not something that has happened in my computing lifetime and it just awakens the computer nerd inside of me.
Speed &lt;em&gt;and&lt;/em&gt; battery life, graphics &lt;em&gt;and&lt;/em&gt; little fan noise, to mention nothing of the fact that Apple devices have the most high-quality feel of any laptop.&lt;/p&gt;
&lt;p&gt;The software enthusiast inside me also loves the idea of being one of the first on a new platform.
Not all the open source apps I use have been compiled for ARM yet, I could be the one to do it!
Heck, I have my own apps to port!&lt;/p&gt;
&lt;a name='new-site'&gt;&lt;/a&gt;&lt;h2&gt;New Site&lt;/h2&gt;
&lt;p&gt;If you have a look around you may also notice a slight redecoration.
This is iteration ⅠⅠⅠ of my site.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first was a &lt;a href="posts/inspection-and-dissection-this-site"&gt;dynamic site served through my own flask web server&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;The second was a &lt;a href="/posts/where-hugo-i-go/"&gt;static site generated through Hugo&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;This iteration is a &lt;a href="https://github.com/LukeBriggsDev/VictorSSG"&gt;static site generator of my own devising&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I made the change because my last site looked pretty cluttered (and I felt that my design skills have improved since my first attempt).
I also wanted a nicer way to list my projects.&lt;/p&gt;
&lt;p&gt;The process of developing a static site generator in python was much more straightforward than I thought.
It only took around 4 days to get to a point where everything looked nice on the outside.
The codebase needs some cleanup, and it isn't entirely ready for anyone other than me to use it, but it works.&lt;/p&gt;
&lt;p&gt;The program on initialisation creates a few directories to place stuff (&lt;code&gt;content&lt;/code&gt;, &lt;code&gt;projects&lt;/code&gt;, &lt;code&gt;static&lt;/code&gt;, etc) as well as a config file for certain things like the navigation bar.
The built website gets put into a &lt;code&gt;public&lt;/code&gt; directory.
The building process itself starts by copying the static directory tree into the public directory.
A python library called &lt;a href="https://pypi.org/project/mistune/"&gt;mistune&lt;/a&gt; converts the markdown files in &lt;code&gt;content&lt;/code&gt; (along with YAML metadata headers) to HTML, &lt;a href="https://pypi.org/project/Pygments/"&gt;pygments&lt;/a&gt; is also used for syntax highlighting. 
The converted html posts are then passed to my custom &lt;a href="https://pypi.org/project/Jinja2/"&gt;jinja2&lt;/a&gt; templates that have all the styling and base markup.
There are a couple of other things like auto-generated social links on the homepage and a so-basic-its-almost-broken built-in HTTP server for viewing webpages locally.&lt;/p&gt;
&lt;p&gt;I will probably tweak a few things over time, but I think I've settled on the principle design, at least for a while.&lt;/p&gt;
&lt;p&gt;The SSG is named Victor as a tongue-in-cheek nod to Hugo, I also quite like that it is also the name of Mr. Freeze which kind of makes sense for a static site generator.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/LukeBriggsDev/VictorSSG"&gt;The source code is available on GitHub&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/shiny-new-things/mac_desktop.jpg' alt='&lt;div&gt;Shiny New Things&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Shiny New Things&lt;/div&gt;
&lt;/h1&gt;&lt;a name='new-hardware'&gt;&lt;/a&gt;&lt;h2&gt;New Hardware&lt;/h2&gt;
&lt;p&gt;The RISC revolution claims a new victim.
On October 25th I became the owner of my first Apple computer, my first non-x86 desktop, and what is already the best computer I have ever used.&lt;/p&gt;
&lt;a name='past-devices'&gt;&lt;/a&gt;&lt;h3&gt;Past devices&lt;/h3&gt;
&lt;p&gt;I &lt;a href="posts/goodbye-windows-i-hardly-gnu-ya/"&gt;moved away from Windows about 9 months ago&lt;/a&gt; and I really haven't looked back.
A few things changed in that gestation period.
Firstly, I settled on Fedora 34 as my final distro: GNOME 40 made some changes I liked and also my bluetooth audio devices worked better.
Secondly, and more importantly, my priorities shifted.
September saw the return of in-person University lecturing and some changes had to be made.&lt;/p&gt;
&lt;figure&gt;
&lt;img src="static/postimages/shiny-new-things/legion5.jpg" alt="Lenovo Legion 5"&gt;&lt;/a&gt;
&lt;figcaption&gt;&amp;copy; &lt;a href="https://www.trustedreviews.com/"&gt;Trusted Reviews&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My previous computer was a Lenovo Legion 5, it had a efficient (but still power hungry) Ryzen 5 4600h, and a dedicated Nvidia GPU.
The laptop was 15.6&amp;quot;, weighed 2.4kg and would require obnoxious fans to spin up if it even thought you might do something demanding.
The laptop was a symptom of being purchased at the beginning of stay-at-home orders by someone who overestimated the amount of games they would be playing.&lt;/p&gt;
&lt;p&gt;When it came to in-person teaching, it also was a bit cumbersome to use the machines on-site.
At the beginning of the term, the University decided move away from using local software to having Azure Virtual Desktops instead, with the PCs acting as thin clients.
Even with gigabit networking and decent hardware, virtual desktops still have a strange smell to them.
The main issue was the fact that they are still in the teething phase and IT departments are not quick to react.
Not every virtual desktop has exactly the same software, and there is no way to know which desktop you are going to get.
One day I logged onto a virtual desktop and it had all the software I needed except git.
My only solution was installing a portable version of git &lt;em&gt;into&lt;/em&gt; my OneDrive so I could guarantee a git install on each machine.
Virtual desktops also made python virtual environments a hassle since every time I would do work on my personal machine, all the symlinks from the AVD would be broke and I'd have too recreate it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So here were my new requirement:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A CPU at least as powerful as my previous laptop&lt;/li&gt;
&lt;li&gt;16GB RAM (8GB was too little when doing development alongside local virtual machines)&lt;/li&gt;
&lt;li&gt;No dGPU (the weight, battery, and noise overhead is just awful)&lt;/li&gt;
&lt;li&gt;Screen larger than 13&amp;quot;, ideally 14.5 - 15&amp;quot;&lt;/li&gt;
&lt;li&gt;Portable, ideally around 1.5kg&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;Like-to-haves:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;120Hz screen (Legion 5 had it and it made things very nice)&lt;/li&gt;
&lt;li&gt;512GB hard drive (Legion 5 had 256GB and I was pushing up against it)&lt;/li&gt;
&lt;li&gt;A iGPU good enough to play basic 3d games at full speed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There was a selection of PC laptops that met some of my requirements. 
However, a lot of them put the higher RAM behind the models with a dGPU, which is an instant turn-off.&lt;/p&gt;
&lt;p&gt;The incredible performance of last year's M1 chips got my head pointed towards Cupertino.
They were efficient, quiet, had a strong GPU, blazing CPU and were bundled with a first-party Unix OS.
Last year's MacBooks did not meet my requirements for the case however. A 13&amp;quot; screen is too small to be doing comfortable development work on.&lt;/p&gt;
&lt;p&gt;So I sat eagerly awaiting the November Apple Event, hoping that rumors of a more powerful 14&amp;quot; MacBook Pro was on the horizon.&lt;/p&gt;
&lt;p&gt;The announced computers met every single one of my criteria, the price was steeper than I had been anticipating but I had some disposable income and I had fallen slightly in love.&lt;/p&gt;
&lt;a name='the-mac-factor'&gt;&lt;/a&gt;&lt;h3&gt;The Mac Factor&lt;/h3&gt;
&lt;p&gt;I took delivery of my base-model 14-inch MacBook Pro (M1 Pro 8/14) on day one, and have used it every day in the 2 weeks since.
The true reason why I went slightly over-budget is due to the fact that these computers are the first in a while to be truly exciting to me.
A whole new instruction set platform in the desktop space is not something that has happened in my computing lifetime and it just awakens the computer nerd inside of me.
Speed &lt;em&gt;and&lt;/em&gt; battery life, graphics &lt;em&gt;and&lt;/em&gt; little fan noise, to mention nothing of the fact that Apple devices have the most high-quality feel of any laptop.&lt;/p&gt;
&lt;p&gt;The software enthusiast inside me also loves the idea of being one of the first on a new platform.
Not all the open source apps I use have been compiled for ARM yet, I could be the one to do it!
Heck, I have my own apps to port!&lt;/p&gt;
&lt;a name='new-site'&gt;&lt;/a&gt;&lt;h2&gt;New Site&lt;/h2&gt;
&lt;p&gt;If you have a look around you may also notice a slight redecoration.
This is iteration ⅠⅠⅠ of my site.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first was a &lt;a href="posts/inspection-and-dissection-this-site"&gt;dynamic site served through my own flask web server&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;The second was a &lt;a href="/posts/where-hugo-i-go/"&gt;static site generated through Hugo&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;This iteration is a &lt;a href="https://github.com/LukeBriggsDev/VictorSSG"&gt;static site generator of my own devising&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I made the change because my last site looked pretty cluttered (and I felt that my design skills have improved since my first attempt).
I also wanted a nicer way to list my projects.&lt;/p&gt;
&lt;p&gt;The process of developing a static site generator in python was much more straightforward than I thought.
It only took around 4 days to get to a point where everything looked nice on the outside.
The codebase needs some cleanup, and it isn't entirely ready for anyone other than me to use it, but it works.&lt;/p&gt;
&lt;p&gt;The program on initialisation creates a few directories to place stuff (&lt;code&gt;content&lt;/code&gt;, &lt;code&gt;projects&lt;/code&gt;, &lt;code&gt;static&lt;/code&gt;, etc) as well as a config file for certain things like the navigation bar.
The built website gets put into a &lt;code&gt;public&lt;/code&gt; directory.
The building process itself starts by copying the static directory tree into the public directory.
A python library called &lt;a href="https://pypi.org/project/mistune/"&gt;mistune&lt;/a&gt; converts the markdown files in &lt;code&gt;content&lt;/code&gt; (along with YAML metadata headers) to HTML, &lt;a href="https://pypi.org/project/Pygments/"&gt;pygments&lt;/a&gt; is also used for syntax highlighting. 
The converted html posts are then passed to my custom &lt;a href="https://pypi.org/project/Jinja2/"&gt;jinja2&lt;/a&gt; templates that have all the styling and base markup.
There are a couple of other things like auto-generated social links on the homepage and a so-basic-its-almost-broken built-in HTTP server for viewing webpages locally.&lt;/p&gt;
&lt;p&gt;I will probably tweak a few things over time, but I think I've settled on the principle design, at least for a while.&lt;/p&gt;
&lt;p&gt;The SSG is named Victor as a tongue-in-cheek nod to Hugo, I also quite like that it is also the name of Mr. Freeze which kind of makes sense for a static site generator.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/LukeBriggsDev/VictorSSG"&gt;The source code is available on GitHub&lt;/a&gt;&lt;/p&gt;
</content:encoded>
      <pubDate>Thu, 11 Nov 2021 15:48:20 +0000</pubDate>
    </item>
    <item>
      <title>Memory in Assembly - How different areas of memory are treated at the metal
</title>
      <link>https://lukebriggs.dev/posts/memory-in-assembly</link>
      <description>&lt;img class='post-hero' src='/static/postimages/memory-in-assembly/ghidra.png' alt='&lt;div&gt;Memory in Assembly - How different areas of memory are treated at the metal&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Memory in Assembly - How different areas of memory are treated at the metal&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I thought it might make for an interesting learning exercise to see how memory in different areas is treated at the assembly level.
The program itself is simple, but I hope it will provide some insight.&lt;/p&gt;
&lt;a name='c-program'&gt;&lt;/a&gt;&lt;h2&gt;C Program&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xc07&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57a71c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57ac3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc&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 class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;malloc_int&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="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xa1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='armv8-assembly'&gt;&lt;/a&gt;&lt;h2&gt;ARMv8 Assembly&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;stp         x29,x30,[sp, #local_20]!                &lt;/span&gt;
&lt;span class="x"&gt;mov         x29,sp                                  &lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0x7ac3                              &lt;/span&gt;
&lt;span class="x"&gt;movk        w0,#0x5, LSL #16                        &lt;/span&gt;
&lt;span class="x"&gt;str         w0,[sp, #stack_int+0x20]                &lt;/span&gt;
&lt;span class="x"&gt;mov         x0,#0x1                                 &lt;/span&gt;
&lt;span class="x"&gt;bl          __stubs:__stubs::_malloc                ;void * _malloc(size_t param_1)&lt;/span&gt;
&lt;span class="x"&gt;str         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;mov         w1,#0xa1                                &lt;/span&gt;
&lt;span class="x"&gt;str         w1,[x0]                                 &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[sp, #stack_int+0x20]                &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]                                 &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;adrp        x0,0x100008000                          &lt;/span&gt;
&lt;span class="x"&gt;add         x0,x0,#0x0                              &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]=&amp;gt;__data:main::static_int        ;= 57A71Ch&lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0xc07                               &lt;/span&gt;
&lt;span class="x"&gt;bl          func_const                              ;void func_const(int x)&lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0x0                                 &lt;/span&gt;
&lt;span class="x"&gt;ldp         x29=&amp;gt;local_20,x30,[sp], #0x20           &lt;/span&gt;
&lt;span class="x"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='static-integer'&gt;&lt;/a&gt;&lt;h2&gt;Static Integer&lt;/h2&gt;
&lt;p&gt;You may notice that our static (0x57a71c) variable is not declared in the assembly. 
This is because everything you see above is in the TEXT segment. The part of the assembly that is read only. 
Text segment is labelled as such with an assembly directive.&lt;/p&gt;
&lt;p&gt;Static variables exist for the lifetime of the program but can change their value and so shouldn't be loaded into the text segment. 
Instead, values that can be edited but are static and initialised are loaded into the data segment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;// __data&lt;/span&gt;
&lt;span class="x"&gt;// __DATA&lt;/span&gt;
&lt;span class="x"&gt;// ram:100008000-ram:100008003&lt;/span&gt;
&lt;span class="x"&gt;//&lt;/span&gt;

&lt;span class="x"&gt;_static_int.0&lt;/span&gt;
&lt;span class="x"&gt;main::static int&lt;/span&gt;
&lt;span class="x"&gt;    int     57A71Ch&lt;/span&gt;
&lt;span class="x"&gt;//&lt;/span&gt;
&lt;span class="x"&gt;//__DATA&lt;/span&gt;
&lt;span class="x"&gt;//__DATA&lt;/span&gt;
&lt;span class="x"&gt;// ram:100008004-ram:10000bfff&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With Ghidra we can see that our file contains a directive to load our static variable into the data segment at launch. 
We also have a label to this static variable that somewhat matches our C code.&lt;/p&gt;
&lt;a name='stack-integer'&gt;&lt;/a&gt;&lt;h2&gt;Stack Integer&lt;/h2&gt;
&lt;p&gt;This works by moving our value into a register, then storing the contents of that register into an area of memory offset from the stack pointer. 
The stack pointer is a special register that the CPU uses to tell us where our stack is. 
Because everything we store on the stack is a known size, the compiler works out the offsets and knows where things should be stored in relation to each other.&lt;/p&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57ac3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         w0,#0x7ac3               ; move integer into register 0                             &lt;/span&gt;
&lt;span class="x"&gt;movk        w0,#0x5, LSL #16                        &lt;/span&gt;
&lt;span class="x"&gt;str         w0,[sp, #stack_int+0x20] ; store integer into RAM address pointed to by&lt;/span&gt;
&lt;span class="x"&gt;                                     ; stack pointer (sp) + an offset based on number&lt;/span&gt;
&lt;span class="x"&gt;                                     ; size. Our number is now in stack memory&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='heap-integer'&gt;&lt;/a&gt;&lt;h2&gt;Heap Integer&lt;/h2&gt;
&lt;p&gt;This works by asking for a given amount of memory to be allocated, the kernel allocates the new memory in our address space then hands us back a pointer to it. 
The address we get back is stored on the stack, and we can load values into this address to store on the heap.&lt;/p&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;malloc_int&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="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xa1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         x0,#0x1                     ; Set first parameter of malloc to 1 (number of &lt;/span&gt;
&lt;span class="x"&gt;                                        ; bytes to allocate)                        &lt;/span&gt;
&lt;span class="x"&gt;bl          __stubs:__stubs::_malloc    ; call malloc&lt;/span&gt;
&lt;span class="x"&gt;str         x0,[sp, #malloc_int+0x20]   ; Store return value of malloc (register 0)&lt;/span&gt;
&lt;span class="x"&gt;                                        ; onto the stack (sp + offset)&lt;/span&gt;




&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]   ; Load heap address (which is stored on stack)&lt;/span&gt;
&lt;span class="x"&gt;                                        ; into register              &lt;/span&gt;
&lt;span class="x"&gt;mov         w1,#0xa1                    ; move our integer into register 1              &lt;/span&gt;
&lt;span class="x"&gt;str         w1,[x0]                     ; Store our integer into the heap address &lt;/span&gt;
&lt;span class="x"&gt;                                        ; (integer is now on the heap)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Notice how the bottom two lines are effectively the same as what we did on the stack, everything else is all the extra overhead of using the heap, this is one of the reasons why it's easier to use the stack to store local variables (another obvious one is we don't have to free things on the stack whereas in a real program we would also have to remember to free this memory)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='calling-a-function-with-a-stack-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a stack variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;ldr         w0,[sp, #stack_int+0x20] ; Set parameter 0 to value stored in the &lt;/span&gt;
&lt;span class="x"&gt;                                     ;  address pointed to by stack_int                &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                 ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-heap-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a heap variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20] ; load the value stored at the malloc_int variable (our&lt;/span&gt;
&lt;span class="x"&gt;                                      ; heap pointer) into register 0&lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]                   ; load the value at our heap address (the actual number) &lt;/span&gt;
&lt;span class="x"&gt;                                      ; into register 0 as the parameter to our function.                         &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                  ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-static-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a static variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;adrp        x0,0x100008000   ; Since static variables are in the data section,&lt;/span&gt;
&lt;span class="x"&gt;                             ; we know the precise address (relative to our &lt;/span&gt;
&lt;span class="x"&gt;                             ; program) of them, and so we don&amp;#39;t need to use the &lt;/span&gt;
&lt;span class="x"&gt;                             ; stack pointer, just the program counter which adrp &lt;/span&gt;
&lt;span class="x"&gt;                             ; does by default                        &lt;/span&gt;
&lt;span class="x"&gt;add         x0,x0,#0x0                                    &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]          ; load the value at the data address from memory &lt;/span&gt;
&lt;span class="x"&gt;                             ; into register 0 (our function parameter)&lt;/span&gt;
&lt;span class="x"&gt;bl          func_int         ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-constant-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a constant variable&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         w0,#0xc07   ; A constant variable never changes so we don&amp;#39;t need to &lt;/span&gt;
&lt;span class="x"&gt;                        ; use addresses, the constant is here in the text section &lt;/span&gt;
&lt;span class="x"&gt;                        ; with the code and is loaded by value into register 0&lt;/span&gt;
&lt;span class="x"&gt;bl          func_const. ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='recap'&gt;&lt;/a&gt;&lt;h2&gt;Recap&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Using stack variables, we load everything relative to the stack pointer.&lt;/li&gt;
&lt;li&gt;With heap variables we first load the address we have on the stack, then load the value from this address&lt;/li&gt;
&lt;li&gt;With a static variable we load everything from a known location relative to the program counter (in the data segment)&lt;/li&gt;
&lt;li&gt;With a constant variable we can just use the values as is which is stored in the text of the assembly itself.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='/static/postimages/memory-in-assembly/ghidra.png' alt='&lt;div&gt;Memory in Assembly - How different areas of memory are treated at the metal&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Memory in Assembly - How different areas of memory are treated at the metal&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I thought it might make for an interesting learning exercise to see how memory in different areas is treated at the assembly level.
The program itself is simple, but I hope it will provide some insight.&lt;/p&gt;
&lt;a name='c-program'&gt;&lt;/a&gt;&lt;h2&gt;C Program&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xc07&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57a71c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57ac3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc&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 class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;malloc_int&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="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xa1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;func_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='armv8-assembly'&gt;&lt;/a&gt;&lt;h2&gt;ARMv8 Assembly&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;stp         x29,x30,[sp, #local_20]!                &lt;/span&gt;
&lt;span class="x"&gt;mov         x29,sp                                  &lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0x7ac3                              &lt;/span&gt;
&lt;span class="x"&gt;movk        w0,#0x5, LSL #16                        &lt;/span&gt;
&lt;span class="x"&gt;str         w0,[sp, #stack_int+0x20]                &lt;/span&gt;
&lt;span class="x"&gt;mov         x0,#0x1                                 &lt;/span&gt;
&lt;span class="x"&gt;bl          __stubs:__stubs::_malloc                ;void * _malloc(size_t param_1)&lt;/span&gt;
&lt;span class="x"&gt;str         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;mov         w1,#0xa1                                &lt;/span&gt;
&lt;span class="x"&gt;str         w1,[x0]                                 &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[sp, #stack_int+0x20]                &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]               &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]                                 &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;adrp        x0,0x100008000                          &lt;/span&gt;
&lt;span class="x"&gt;add         x0,x0,#0x0                              &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]=&amp;gt;__data:main::static_int        ;= 57A71Ch&lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                                ;void func_int(int x)&lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0xc07                               &lt;/span&gt;
&lt;span class="x"&gt;bl          func_const                              ;void func_const(int x)&lt;/span&gt;
&lt;span class="x"&gt;mov         w0,#0x0                                 &lt;/span&gt;
&lt;span class="x"&gt;ldp         x29=&amp;gt;local_20,x30,[sp], #0x20           &lt;/span&gt;
&lt;span class="x"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='static-integer'&gt;&lt;/a&gt;&lt;h2&gt;Static Integer&lt;/h2&gt;
&lt;p&gt;You may notice that our static (0x57a71c) variable is not declared in the assembly. 
This is because everything you see above is in the TEXT segment. The part of the assembly that is read only. 
Text segment is labelled as such with an assembly directive.&lt;/p&gt;
&lt;p&gt;Static variables exist for the lifetime of the program but can change their value and so shouldn't be loaded into the text segment. 
Instead, values that can be edited but are static and initialised are loaded into the data segment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;// __data&lt;/span&gt;
&lt;span class="x"&gt;// __DATA&lt;/span&gt;
&lt;span class="x"&gt;// ram:100008000-ram:100008003&lt;/span&gt;
&lt;span class="x"&gt;//&lt;/span&gt;

&lt;span class="x"&gt;_static_int.0&lt;/span&gt;
&lt;span class="x"&gt;main::static int&lt;/span&gt;
&lt;span class="x"&gt;    int     57A71Ch&lt;/span&gt;
&lt;span class="x"&gt;//&lt;/span&gt;
&lt;span class="x"&gt;//__DATA&lt;/span&gt;
&lt;span class="x"&gt;//__DATA&lt;/span&gt;
&lt;span class="x"&gt;// ram:100008004-ram:10000bfff&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With Ghidra we can see that our file contains a directive to load our static variable into the data segment at launch. 
We also have a label to this static variable that somewhat matches our C code.&lt;/p&gt;
&lt;a name='stack-integer'&gt;&lt;/a&gt;&lt;h2&gt;Stack Integer&lt;/h2&gt;
&lt;p&gt;This works by moving our value into a register, then storing the contents of that register into an area of memory offset from the stack pointer. 
The stack pointer is a special register that the CPU uses to tell us where our stack is. 
Because everything we store on the stack is a known size, the compiler works out the offsets and knows where things should be stored in relation to each other.&lt;/p&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x57ac3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         w0,#0x7ac3               ; move integer into register 0                             &lt;/span&gt;
&lt;span class="x"&gt;movk        w0,#0x5, LSL #16                        &lt;/span&gt;
&lt;span class="x"&gt;str         w0,[sp, #stack_int+0x20] ; store integer into RAM address pointed to by&lt;/span&gt;
&lt;span class="x"&gt;                                     ; stack pointer (sp) + an offset based on number&lt;/span&gt;
&lt;span class="x"&gt;                                     ; size. Our number is now in stack memory&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='heap-integer'&gt;&lt;/a&gt;&lt;h2&gt;Heap Integer&lt;/h2&gt;
&lt;p&gt;This works by asking for a given amount of memory to be allocated, the kernel allocates the new memory in our address space then hands us back a pointer to it. 
The address we get back is stored on the stack, and we can load values into this address to store on the heap.&lt;/p&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;malloc_int&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="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xa1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         x0,#0x1                     ; Set first parameter of malloc to 1 (number of &lt;/span&gt;
&lt;span class="x"&gt;                                        ; bytes to allocate)                        &lt;/span&gt;
&lt;span class="x"&gt;bl          __stubs:__stubs::_malloc    ; call malloc&lt;/span&gt;
&lt;span class="x"&gt;str         x0,[sp, #malloc_int+0x20]   ; Store return value of malloc (register 0)&lt;/span&gt;
&lt;span class="x"&gt;                                        ; onto the stack (sp + offset)&lt;/span&gt;




&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20]   ; Load heap address (which is stored on stack)&lt;/span&gt;
&lt;span class="x"&gt;                                        ; into register              &lt;/span&gt;
&lt;span class="x"&gt;mov         w1,#0xa1                    ; move our integer into register 1              &lt;/span&gt;
&lt;span class="x"&gt;str         w1,[x0]                     ; Store our integer into the heap address &lt;/span&gt;
&lt;span class="x"&gt;                                        ; (integer is now on the heap)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Notice how the bottom two lines are effectively the same as what we did on the stack, everything else is all the extra overhead of using the heap, this is one of the reasons why it's easier to use the stack to store local variables (another obvious one is we don't have to free things on the stack whereas in a real program we would also have to remember to free this memory)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a name='calling-a-function-with-a-stack-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a stack variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;ldr         w0,[sp, #stack_int+0x20] ; Set parameter 0 to value stored in the &lt;/span&gt;
&lt;span class="x"&gt;                                     ;  address pointed to by stack_int                &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                 ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-heap-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a heap variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;malloc_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;ldr         x0,[sp, #malloc_int+0x20] ; load the value stored at the malloc_int variable (our&lt;/span&gt;
&lt;span class="x"&gt;                                      ; heap pointer) into register 0&lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]                   ; load the value at our heap address (the actual number) &lt;/span&gt;
&lt;span class="x"&gt;                                      ; into register 0 as the parameter to our function.                         &lt;/span&gt;
&lt;span class="x"&gt;bl          func_int                  ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-static-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a static variable&lt;/h2&gt;
&lt;a name='c'&gt;&lt;/a&gt;&lt;h3&gt;C&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;static_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='assembly'&gt;&lt;/a&gt;&lt;h3&gt;Assembly&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;adrp        x0,0x100008000   ; Since static variables are in the data section,&lt;/span&gt;
&lt;span class="x"&gt;                             ; we know the precise address (relative to our &lt;/span&gt;
&lt;span class="x"&gt;                             ; program) of them, and so we don&amp;#39;t need to use the &lt;/span&gt;
&lt;span class="x"&gt;                             ; stack pointer, just the program counter which adrp &lt;/span&gt;
&lt;span class="x"&gt;                             ; does by default                        &lt;/span&gt;
&lt;span class="x"&gt;add         x0,x0,#0x0                                    &lt;/span&gt;
&lt;span class="x"&gt;ldr         w0,[x0]          ; load the value at the data address from memory &lt;/span&gt;
&lt;span class="x"&gt;                             ; into register 0 (our function parameter)&lt;/span&gt;
&lt;span class="x"&gt;bl          func_int         ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='calling-a-function-with-a-constant-variable'&gt;&lt;/a&gt;&lt;h2&gt;Calling a function with a constant variable&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;func_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constant_int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="x"&gt;mov         w0,#0xc07   ; A constant variable never changes so we don&amp;#39;t need to &lt;/span&gt;
&lt;span class="x"&gt;                        ; use addresses, the constant is here in the text section &lt;/span&gt;
&lt;span class="x"&gt;                        ; with the code and is loaded by value into register 0&lt;/span&gt;
&lt;span class="x"&gt;bl          func_const. ; call function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='recap'&gt;&lt;/a&gt;&lt;h2&gt;Recap&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Using stack variables, we load everything relative to the stack pointer.&lt;/li&gt;
&lt;li&gt;With heap variables we first load the address we have on the stack, then load the value from this address&lt;/li&gt;
&lt;li&gt;With a static variable we load everything from a known location relative to the program counter (in the data segment)&lt;/li&gt;
&lt;li&gt;With a constant variable we can just use the values as is which is stored in the text of the assembly itself.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
      <pubDate>Fri, 20 May 2022 17:57:44 +0000</pubDate>
    </item>
    <item>
      <title>Painting by the Numbers: An exploration into evolutionary algorithms
</title>
      <link>https://lukebriggs.dev/posts/painting-by-the-numbers</link>
      <description>&lt;img class='post-hero' src='static/postimages/painting-by-the-numbers/header.png' alt='&lt;div&gt;Painting by the Numbers: An exploration into evolutionary algorithms&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Painting by the Numbers: An exploration into evolutionary algorithms&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;In a recent second year University project, I was tasked with developing an &lt;a href="https://en.wikipedia.org/wiki/Evolutionary_algorithm"&gt;evolutionary algorithm&lt;/a&gt; for reproducing images using a limited number of semi-transparent polygons. I spent so much time above and beyond what I needed to that I thought it was worth writing a post about how I went about my work and challenges along the way.&lt;/p&gt;
&lt;a name='what-are-evolutionary-algorithms?'&gt;&lt;/a&gt;&lt;h2&gt;What are evolutionary algorithms?&lt;/h2&gt;
&lt;p&gt;The basic premise of an evolutionary algorithm is: you have a population of solutions; this population goes through some sort of mutation, reproduction, or mating; the individuals in the population are then evaluated according to a particular &lt;em&gt;fitness function&lt;/em&gt; and the fittest survive. The idea with evolutionary algorithms, as with evolution of biological species, is that given sufficient time, variation, and evolutionary pressure, it is possible for individuals to emerge that solve the particular problem you have placed upon it.&lt;/p&gt;
&lt;p&gt;Just as when faced with the problem of getting food from land, some fish became amphibious, and eventually exclusively land creatures. Given the problem of wanting to look like the Mona Lisa, a population of shapes will emerge that solve this problem.&lt;/p&gt;
&lt;a name='the-brief'&gt;&lt;/a&gt;&lt;h2&gt;The brief&lt;/h2&gt;
&lt;p&gt;The brief was inspired by &lt;a href="https://rogerjohansson.blog/2008/12/07/genetic-programming-evolution-of-mona-lisa/"&gt;Roger Alsing's blog post&lt;/a&gt; where he did a similar thing.
His algorithm was quite simplistic in what sort of mutations it offered and it was therefore felt we could make some improvement on this.&lt;/p&gt;
&lt;p&gt;The final submission for the project was written in Python using the &lt;a href="https://deap.readthedocs.io/en/master/"&gt;DEAP&lt;/a&gt; library, however, I fancied a speed-up.
And using a compiled solution like &lt;a href="https://www.pypy.org"&gt;PyPy&lt;/a&gt; was not cooperative and so I rewrote the program in Go.
Because of various hoops and hurdles in releasing University coursework submissions, the original python implementation is not available.
My Go rewrite, however, is available at my &lt;a href="https://github.com/LukeBriggsDev/EARP"&gt;GitHub&lt;/a&gt;.
I am not as experienced in developing in Go as with python but I feel I have made (mostly) sane, if not idiomatic, choices.&lt;/p&gt;
&lt;a name='the-program'&gt;&lt;/a&gt;&lt;h2&gt;The Program&lt;/h2&gt;
&lt;a name='making-the-population'&gt;&lt;/a&gt;&lt;h3&gt;Making the population&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makeIndividual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAX_POLYGONS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I start off by making the population of Individuals.
In this case I make 256 individuals with each individual consisting of 100 polygons.&lt;/p&gt;
&lt;p&gt;Our Polygon and Point structs looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rgba&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make a polygon I simply create instances of these classes with various random starting values in order to provide a diverse population from which a solution can emerge.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makePolygon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Create colour&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;sides&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Create vertices&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sides&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Arrange vertices such that they don&amp;#39;t create a shape that self intersects if a polygon has more than 3 initial sides&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeSelfIntersect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See &lt;a href="javascript:;" onclick="document.location.hash='non-self-intersecting-polygons';"&gt;This section&lt;/a&gt; for more details on how I made sure polygons didn't self-intersect.&lt;/p&gt;
&lt;p&gt;The polygons then go on to form an individual:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makeIndividual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makePolygon&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Individuals are initialised with a fitness of -1, which means that fitness is invalid and needs to be re-calculated.
In order to prevent doing more processing than necessary, I will reset the fitness back to -1 whenever a change is made to that individuals polygons.
Doing this means that I can guarantee that if a fitness is not -1, the polygons haven't change and I can skip that individual's evaluation.&lt;/p&gt;
&lt;a name='generating-offspring'&gt;&lt;/a&gt;&lt;h3&gt;Generating offspring&lt;/h3&gt;
&lt;p&gt;Every generation, new offspring are created from our current population.
The strategy I went with (varOr) leads to each child being either a copy of a parent, a mutation of a parent, or a mating between two parents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;varOr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mating involves getting a taking a random point in the list of polygons as a pivot point, then swapping everything after the pivot point with the same set of points from the other parent.
Leaving a child where the first half(ish) of the polygons are from one parent, and the other half(ish) are from the second parent.
Any children from this process are also given an initial fitness of -1, as the parent fitness is no longer valid due to half the polygons being different.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Get pivot&lt;/span&gt;
&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// Swap ends&lt;/span&gt;
&lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// return children&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Reproduction involves a simple copying of one individual across generations, as such the fitness does not have to be invalidated to -1 because it is a perfect copy of an Individual with valid fitness.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Choose individual&lt;/span&gt;
&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// Clone individual&amp;#39;s polygons&lt;/span&gt;
&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clonePolygonSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Add new individual with same polygons to offspring&lt;/span&gt;
&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mutation is where a large amount of the uniqueness of this implementation comes in, and where a lot of the improvement was made during development.
The following mutations can occur to an individual:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change colour of polygon&lt;/li&gt;
&lt;li&gt;Change transparency of polygon&lt;/li&gt;
&lt;li&gt;Add a polygon to an individual (within 100 limits)&lt;/li&gt;
&lt;li&gt;Remove polygon from an individual (within 20-100 limits)&lt;/li&gt;
&lt;li&gt;Add a point to a polygon (requires removing self intersect)&lt;/li&gt;
&lt;li&gt;Re-order how polygons are stacked&lt;/li&gt;
&lt;li&gt;Change position of a single point&lt;/li&gt;
&lt;li&gt;Change position of all points at once&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The mutations were picked through a process of 1% inspiration, 99% calculation.
With many trial and error runs of various mutations and algorithm choices before settling on the current set with their current probabilities of occurrence.&lt;/p&gt;
&lt;a name='offspring-evaluation'&gt;&lt;/a&gt;&lt;h3&gt;Offspring evaluation&lt;/h3&gt;
&lt;p&gt;Once we've got our children, we need to see how good they are.
It is at this point that Go slightly comes into its own.
Evolutionary algorithms, particularly the evaluation, are incredibly well suited to multithreading.
Each evaluation is entirely independent and, as such, each one can run in its own thread, speeding up things significantly on multi-core systems.&lt;/p&gt;
&lt;p&gt;It is also in this aspect where Go also comes into its own, as Go has first-class support for multithreading.
If you have a thread-safe function, then spinning it up in a new thread is as easy as putting the keyword &lt;code&gt;go&lt;/code&gt; before it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WaitGroup&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&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 class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this instance, we loop through all the offspring, and if the fitness is invalid (like it is the result of a mutation or mating) we evaluate the fitness of the Individuals polygons.
All the &lt;code&gt;WaitGroup&lt;/code&gt; stuff around it just holds a counter of how many routines are left to finish until we can carry on with the program.
This allows us to utilise all the physical cores on our machine during the evaluation stage.&lt;/p&gt;
&lt;p&gt;The evaluation itself is quite straightforward.
We draw the individual out onto a canvas, convert it and the target image into greyscale, and then go pixel by pixel to calculate how different the image is.
The individual with the smallest difference between its greyscale and the target greyscale is determined to have the highest fitness.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;drawSolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ImageDifference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MaxUint16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='offspring-selection'&gt;&lt;/a&gt;&lt;h3&gt;Offspring selection&lt;/h3&gt;
&lt;p&gt;After we have our children, we must pit them against each other to the death.
The selection method I chose was tournament selection, this works be getting a random sample from the population and carrying the best from that sample into the future generation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TournSel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tournsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tournsize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;))])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BestSel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then draw out the best child each generation just so I can see the progress as it goes on.
Apart from that, our generation is over and the cycle starts over again.&lt;/p&gt;
&lt;a name='the-results'&gt;&lt;/a&gt;&lt;h2&gt;The results&lt;/h2&gt;
&lt;iframe width="300" height="300" src="https://www.youtube.com/embed/-eObA3jZh7g" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Even though we never do anything other than random, indiscriminate changes, after about 250,000 generations we can get pretty good images made up of very few polygons.&lt;/p&gt;
&lt;span style="margin-left: auto; margin-right:auto"&gt;
&lt;img alt="Darwin reference" src="/static/postimages/painting-by-the-numbers/darwin.png"&gt;
&lt;img alt="Darwin 96.87% fitness" src="/static/postimages/painting-by-the-numbers/darwin96.87.png"&gt;
&lt;/span&gt;
&lt;span style="margin-left: auto; margin-right:auto"&gt;
&lt;img alt="Mona Lisa reference" src="/static/postimages/painting-by-the-numbers/monalisa.png"&gt;
&lt;img alt="Mona Lisa 96.65% fitness" src="/static/postimages/painting-by-the-numbers/monalisa96.65.png"&gt;
&lt;/span&gt;
&lt;a name='appendix'&gt;&lt;/a&gt;&lt;h2&gt;Appendix&lt;/h2&gt;
&lt;a name='non-self-intersecting-polygons'&gt;&lt;/a&gt;&lt;h3&gt;Non self-intersecting polygons&lt;/h3&gt;
&lt;p&gt;When it comes to the vertices of a polygon, you can't just start drawing lines between them and hope for the best.&lt;/p&gt;
&lt;p&gt;If I have 4 points that are going to make up my square:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-1.svg" alt="4 points plotted in a square" /&gt;&lt;/p&gt;
&lt;p&gt;And then I start drawing lines between the points in any order:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-2.svg" alt="A self-intersecting square" /&gt;&lt;/p&gt;
&lt;p&gt;That ain't no square chief.
So, how can we tell which order we should connect the points?
One way to do it is with the power of vectors and angles.
First we start out with a base vector, which we just use to be the vector between the center of the polygon and the first point:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-3.svg" alt="Vector between first and center point" /&gt;&lt;/p&gt;
&lt;p&gt;We then get vectors between the center and each point in the shape:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-4.svg" alt="All vectors between points and the center" /&gt;&lt;/p&gt;
&lt;p&gt;If we then get the angle between the base vector and all of those vectors, we notice a pattern:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-5.svg" alt="All angles between vectors and base vector" /&gt;&lt;/p&gt;
&lt;p&gt;The order in which we wan't to connect the dots in, also make increasingly large angles with the base vector.
Therefore, if we get our points and sort them by the angle their vector makes with the base vector, they will be in the order in which we can draw them.&lt;/p&gt;
&lt;p&gt;The code for the mathematics itself can be found in &lt;a href="https://github.com/LukeBriggsDev/EARP/blob/715bd60cab714bcadee6e1d27525ad7cfa070bef/polygon.go#L49"&gt;&lt;code&gt;polygon.go&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/painting-by-the-numbers/header.png' alt='&lt;div&gt;Painting by the Numbers: An exploration into evolutionary algorithms&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Painting by the Numbers: An exploration into evolutionary algorithms&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;In a recent second year University project, I was tasked with developing an &lt;a href="https://en.wikipedia.org/wiki/Evolutionary_algorithm"&gt;evolutionary algorithm&lt;/a&gt; for reproducing images using a limited number of semi-transparent polygons. I spent so much time above and beyond what I needed to that I thought it was worth writing a post about how I went about my work and challenges along the way.&lt;/p&gt;
&lt;a name='what-are-evolutionary-algorithms?'&gt;&lt;/a&gt;&lt;h2&gt;What are evolutionary algorithms?&lt;/h2&gt;
&lt;p&gt;The basic premise of an evolutionary algorithm is: you have a population of solutions; this population goes through some sort of mutation, reproduction, or mating; the individuals in the population are then evaluated according to a particular &lt;em&gt;fitness function&lt;/em&gt; and the fittest survive. The idea with evolutionary algorithms, as with evolution of biological species, is that given sufficient time, variation, and evolutionary pressure, it is possible for individuals to emerge that solve the particular problem you have placed upon it.&lt;/p&gt;
&lt;p&gt;Just as when faced with the problem of getting food from land, some fish became amphibious, and eventually exclusively land creatures. Given the problem of wanting to look like the Mona Lisa, a population of shapes will emerge that solve this problem.&lt;/p&gt;
&lt;a name='the-brief'&gt;&lt;/a&gt;&lt;h2&gt;The brief&lt;/h2&gt;
&lt;p&gt;The brief was inspired by &lt;a href="https://rogerjohansson.blog/2008/12/07/genetic-programming-evolution-of-mona-lisa/"&gt;Roger Alsing's blog post&lt;/a&gt; where he did a similar thing.
His algorithm was quite simplistic in what sort of mutations it offered and it was therefore felt we could make some improvement on this.&lt;/p&gt;
&lt;p&gt;The final submission for the project was written in Python using the &lt;a href="https://deap.readthedocs.io/en/master/"&gt;DEAP&lt;/a&gt; library, however, I fancied a speed-up.
And using a compiled solution like &lt;a href="https://www.pypy.org"&gt;PyPy&lt;/a&gt; was not cooperative and so I rewrote the program in Go.
Because of various hoops and hurdles in releasing University coursework submissions, the original python implementation is not available.
My Go rewrite, however, is available at my &lt;a href="https://github.com/LukeBriggsDev/EARP"&gt;GitHub&lt;/a&gt;.
I am not as experienced in developing in Go as with python but I feel I have made (mostly) sane, if not idiomatic, choices.&lt;/p&gt;
&lt;a name='the-program'&gt;&lt;/a&gt;&lt;h2&gt;The Program&lt;/h2&gt;
&lt;a name='making-the-population'&gt;&lt;/a&gt;&lt;h3&gt;Making the population&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makeIndividual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAX_POLYGONS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I start off by making the population of Individuals.
In this case I make 256 individuals with each individual consisting of 100 polygons.&lt;/p&gt;
&lt;p&gt;Our Polygon and Point structs looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rgba&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make a polygon I simply create instances of these classes with various random starting values in order to provide a diverse population from which a solution can emerge.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makePolygon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Create colour&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;sides&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Create vertices&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sides&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Arrange vertices such that they don&amp;#39;t create a shape that self intersects if a polygon has more than 3 initial sides&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeSelfIntersect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygon&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See &lt;a href="javascript:;" onclick="document.location.hash='non-self-intersecting-polygons';"&gt;This section&lt;/a&gt; for more details on how I made sure polygons didn't self-intersect.&lt;/p&gt;
&lt;p&gt;The polygons then go on to form an individual:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makeIndividual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;makePolygon&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polygons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Individuals are initialised with a fitness of -1, which means that fitness is invalid and needs to be re-calculated.
In order to prevent doing more processing than necessary, I will reset the fitness back to -1 whenever a change is made to that individuals polygons.
Doing this means that I can guarantee that if a fitness is not -1, the polygons haven't change and I can skip that individual's evaluation.&lt;/p&gt;
&lt;a name='generating-offspring'&gt;&lt;/a&gt;&lt;h3&gt;Generating offspring&lt;/h3&gt;
&lt;p&gt;Every generation, new offspring are created from our current population.
The strategy I went with (varOr) leads to each child being either a copy of a parent, a mutation of a parent, or a mating between two parents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;varOr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mating involves getting a taking a random point in the list of polygons as a pivot point, then swapping everything after the pivot point with the same set of points from the other parent.
Leaving a child where the first half(ish) of the polygons are from one parent, and the other half(ish) are from the second parent.
Any children from this process are also given an initial fitness of -1, as the parent fitness is no longer valid due to half the polygons being different.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Get pivot&lt;/span&gt;
&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// Swap ends&lt;/span&gt;
&lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;cxpoint&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// return children&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Reproduction involves a simple copying of one individual across generations, as such the fitness does not have to be invalidated to -1 because it is a perfect copy of an Individual with valid fitness.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Choose individual&lt;/span&gt;
&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// Clone individual&amp;#39;s polygons&lt;/span&gt;
&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clonePolygonSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Add new individual with same polygons to offspring&lt;/span&gt;
&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;population&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mutation is where a large amount of the uniqueness of this implementation comes in, and where a lot of the improvement was made during development.
The following mutations can occur to an individual:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change colour of polygon&lt;/li&gt;
&lt;li&gt;Change transparency of polygon&lt;/li&gt;
&lt;li&gt;Add a polygon to an individual (within 100 limits)&lt;/li&gt;
&lt;li&gt;Remove polygon from an individual (within 20-100 limits)&lt;/li&gt;
&lt;li&gt;Add a point to a polygon (requires removing self intersect)&lt;/li&gt;
&lt;li&gt;Re-order how polygons are stacked&lt;/li&gt;
&lt;li&gt;Change position of a single point&lt;/li&gt;
&lt;li&gt;Change position of all points at once&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The mutations were picked through a process of 1% inspiration, 99% calculation.
With many trial and error runs of various mutations and algorithm choices before settling on the current set with their current probabilities of occurrence.&lt;/p&gt;
&lt;a name='offspring-evaluation'&gt;&lt;/a&gt;&lt;h3&gt;Offspring evaluation&lt;/h3&gt;
&lt;p&gt;Once we've got our children, we need to see how good they are.
It is at this point that Go slightly comes into its own.
Evolutionary algorithms, particularly the evaluation, are incredibly well suited to multithreading.
Each evaluation is entirely independent and, as such, each one can run in its own thread, speeding up things significantly on multi-core systems.&lt;/p&gt;
&lt;p&gt;It is also in this aspect where Go also comes into its own, as Go has first-class support for multithreading.
If you have a thread-safe function, then spinning it up in a new thread is as easy as putting the keyword &lt;code&gt;go&lt;/code&gt; before it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WaitGroup&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&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 class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fitness&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offspring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="nx"&gt;offIdx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;waitGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this instance, we loop through all the offspring, and if the fitness is invalid (like it is the result of a mutation or mating) we evaluate the fitness of the Individuals polygons.
All the &lt;code&gt;WaitGroup&lt;/code&gt; stuff around it just holds a counter of how many routines are left to finish until we can carry on with the program.
This allows us to utilise all the physical cores on our machine during the evaluation stage.&lt;/p&gt;
&lt;p&gt;The evaluation itself is quite straightforward.
We draw the individual out onto a canvas, convert it and the target image into greyscale, and then go pixel by pixel to calculate how different the image is.
The individual with the smallest difference between its greyscale and the target greyscale is determined to have the highest fitness.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Polygon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;drawSolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ImageDifference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MaxUint16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MAX&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;a name='offspring-selection'&gt;&lt;/a&gt;&lt;h3&gt;Offspring selection&lt;/h3&gt;
&lt;p&gt;After we have our children, we must pit them against each other to the death.
The selection method I chose was tournament selection, this works be getting a random sample from the population and carrying the best from that sample into the future generation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TournSel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tournsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Individual&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tournsize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;individuals&lt;/span&gt;&lt;span class="p"&gt;))])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BestSel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aspirant&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chosen&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then draw out the best child each generation just so I can see the progress as it goes on.
Apart from that, our generation is over and the cycle starts over again.&lt;/p&gt;
&lt;a name='the-results'&gt;&lt;/a&gt;&lt;h2&gt;The results&lt;/h2&gt;
&lt;iframe width="300" height="300" src="https://www.youtube.com/embed/-eObA3jZh7g" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Even though we never do anything other than random, indiscriminate changes, after about 250,000 generations we can get pretty good images made up of very few polygons.&lt;/p&gt;
&lt;span style="margin-left: auto; margin-right:auto"&gt;
&lt;img alt="Darwin reference" src="/static/postimages/painting-by-the-numbers/darwin.png"&gt;
&lt;img alt="Darwin 96.87% fitness" src="/static/postimages/painting-by-the-numbers/darwin96.87.png"&gt;
&lt;/span&gt;
&lt;span style="margin-left: auto; margin-right:auto"&gt;
&lt;img alt="Mona Lisa reference" src="/static/postimages/painting-by-the-numbers/monalisa.png"&gt;
&lt;img alt="Mona Lisa 96.65% fitness" src="/static/postimages/painting-by-the-numbers/monalisa96.65.png"&gt;
&lt;/span&gt;
&lt;a name='appendix'&gt;&lt;/a&gt;&lt;h2&gt;Appendix&lt;/h2&gt;
&lt;a name='non-self-intersecting-polygons'&gt;&lt;/a&gt;&lt;h3&gt;Non self-intersecting polygons&lt;/h3&gt;
&lt;p&gt;When it comes to the vertices of a polygon, you can't just start drawing lines between them and hope for the best.&lt;/p&gt;
&lt;p&gt;If I have 4 points that are going to make up my square:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-1.svg" alt="4 points plotted in a square" /&gt;&lt;/p&gt;
&lt;p&gt;And then I start drawing lines between the points in any order:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-2.svg" alt="A self-intersecting square" /&gt;&lt;/p&gt;
&lt;p&gt;That ain't no square chief.
So, how can we tell which order we should connect the points?
One way to do it is with the power of vectors and angles.
First we start out with a base vector, which we just use to be the vector between the center of the polygon and the first point:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-3.svg" alt="Vector between first and center point" /&gt;&lt;/p&gt;
&lt;p&gt;We then get vectors between the center and each point in the shape:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-4.svg" alt="All vectors between points and the center" /&gt;&lt;/p&gt;
&lt;p&gt;If we then get the angle between the base vector and all of those vectors, we notice a pattern:&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/painting-by-the-numbers/self-intersect-5.svg" alt="All angles between vectors and base vector" /&gt;&lt;/p&gt;
&lt;p&gt;The order in which we wan't to connect the dots in, also make increasingly large angles with the base vector.
Therefore, if we get our points and sort them by the angle their vector makes with the base vector, they will be in the order in which we can draw them.&lt;/p&gt;
&lt;p&gt;The code for the mathematics itself can be found in &lt;a href="https://github.com/LukeBriggsDev/EARP/blob/715bd60cab714bcadee6e1d27525ad7cfa070bef/polygon.go#L49"&gt;&lt;code&gt;polygon.go&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
</content:encoded>
      <pubDate>Sat, 28 May 2022 17:05:11 +0000</pubDate>
    </item>
    <item>
      <title>Playing Soldiers: An Exploration into Wartime Ciphers - Enigma and Lorenz
</title>
      <link>https://lukebriggs.dev/posts/playing-soldiers-enigma-and-lorenz</link>
      <description>&lt;img class='post-hero' src='static/postimages/playing-soldiers-enigma-and-lorenz/Encrypt.svg' alt='&lt;div&gt;Playing Soldiers: An Exploration into Wartime Ciphers - Enigma and Lorenz&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Playing Soldiers: An Exploration into Wartime Ciphers - Enigma and Lorenz&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I had a bit of time over the Summer, and thought I would do something that I have been meaning to do for a long time.
Create a software implementation of an Enigma and a Lorenz machine. 
While I was at it, I thought that I might as well take a look at how the machines could be broken.&lt;/p&gt;
&lt;p&gt;For the programs themselves, head over to the &lt;a href="/projects/enigma-lorenz"&gt;project page&lt;/a&gt;.
The rest of this post is an explanation of how the machines work and the low-hanging fruit when it comes to vulnerabilities.&lt;/p&gt;
&lt;a name='preface'&gt;&lt;/a&gt;&lt;h1&gt;Preface&lt;/h1&gt;
&lt;p&gt;Enigma and Lorenz are two series of electromechanical cipher machines that saw extensive use by the Axis powers during World War II. 
Enigma was primarily used by the German Navy, Air Force, and Army as a method to encrypt communications. 
Lorenz machines were used from 1940 onwards and were the preferred encryption method for communications between German High Command. 
The Enigma and Lorenz machines formed the vast majority of traffic decrypted at the British Government Code and Ciphers School (GC&amp;amp;CS) in Bletchley Park.&lt;/p&gt;
&lt;a name='enigma'&gt;&lt;/a&gt;&lt;h1&gt;Enigma&lt;/h1&gt;
&lt;p&gt;Enigma was the most widely used of the two machines, and the largest share traffic flowing through Bletchley Park was encrypted by Enigma. 
With over 40,000 machines constructed (compared to the approximately 200 Lorenz machines), Enigma was the priority of Allied codebreakers, especially during the early stages of the war.&lt;/p&gt;
&lt;a name='workings'&gt;&lt;/a&gt;&lt;h2&gt;Workings&lt;/h2&gt;
&lt;p&gt;German military Enigma machines are made up of three distinct parts: the rotors, the reflector and the plugboard.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Enigma.svg" alt="Data flow through Enigma machine" /&gt;&lt;/p&gt;
&lt;a name='the-plugboard'&gt;&lt;/a&gt;&lt;h3&gt;The Plugboard&lt;/h3&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Plugboard.svg" alt="Enigma plugboard" /&gt;&lt;/p&gt;
&lt;p&gt;The plugboard is the simplest part of the encryption process but is what separates military Enigma from the commercial variant used before the war. 
The plugboard is a grid of contacts with each contact relating to a letter. 
Two ends of a plug would be inserted into two of the letters to electronically connect them. 
The connections on the plugboard would cause letters to be swapped before and after encryption. 
Each Enigma machine came with 13 plugs, with only up to 10 ever used at one time.&lt;/p&gt;
&lt;a name='the-rotors'&gt;&lt;/a&gt;&lt;h3&gt;The Rotors&lt;/h3&gt;
&lt;p&gt;The rotors are the most distinctive element of the Enigma machine. 
All German military Enigma machines featured three conventional rotors. 
A later Enigma model, the M4, is often referred to as having four rotors however this ‘fourth’ rotor behaves more like a reflector than a conventional rotor.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Rotor.svg" alt="Enigma rotor" /&gt;&lt;/p&gt;
&lt;p&gt;A rotor is very straightforward electronically: it maps a single input on one side, to an output on another side, through a wire. 
There were 26 mappings on each rotor, one for each letter of the alphabet, and each mapping was marked with either a number from 1 to 26 or the letters A to Z. 
The topmost marking could be seen through a small window on the machine, and this was used for setting an initial configuration. 
An Enigma rotor also has a “ring setting”. 
The markings on the rotor can be twisted independent of the rotor itself and so the mapping represented by “A” on ring setting 0 would be represented by a “Z” on ring setting 1. 
It effectively offsets the outer casing and notch from the inner wiring. 
The ring setting is set at the beginning of the message and remains the same throughout.&lt;/p&gt;
&lt;p&gt;On each keypress the rightmost rotor is rotated towards the operator by a single step. 
Each rotor also has one or two small notches aligned with one or two of the steps. 
Usually, when the right rotor turns it blocks the other two rotors from spinning. 
However, if the rotor is in a position where the notch aligns with the mechanism, the rotor to the left of it can rotate one step. 
The same is true for the middle and left rotors. 
The effect is similar to something like the odometer on a car: at a certain point in the rotation of the right rotor, the middle rotor is increased by one, and at a certain point in the rotation of the middle rotor, the left rotor is increased by one.&lt;/p&gt;
&lt;a name='note-on-double-stepping'&gt;&lt;/a&gt;&lt;h4&gt;Note on Double Stepping&lt;/h4&gt;
&lt;p&gt;There is a quirk with the mechanism of German Enigma machines which means the middle rotor will also rotate if it is at its notch position even if the rotor to the right of it is not.&lt;/p&gt;
&lt;a name='the-reflector'&gt;&lt;/a&gt;&lt;h3&gt;The Reflector&lt;/h3&gt;
&lt;p&gt;The reflector is electronically similar to a rotor in that it has a series of input and output contacts that are mapped with wiring, however there is no rotation of a reflector during transmission of the message. 
A reflector is set at the beginning of a message and remains static throughout. 
The ‘fourth’ rotor of Enigma M4 also remains static throughout the message and therefore it somewhat of a misnomer to call it a ‘fourth’ rotor. 
In fact, using the ‘beta’ wheel as the fourth rotor and the UKW-b wheel as the reflector in M4 Enigma is logically identical to the UKW-B reflector of three-wheel Enigma.&lt;/p&gt;
&lt;a name='stages-of-encryption'&gt;&lt;/a&gt;&lt;h2&gt;Stages of Encryption&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Encrypt.svg" alt="Enigma encryption process" /&gt;&lt;/p&gt;
&lt;p&gt;To fully understand the stages of Enigma encryption, it is best to show a worked example. 
In this example we are going to encrypt the character ‘A’ with rotors III, II, and I in default position, with A mapped to T on the plugboard, and with the ring setting of rotor I set to 2. 
To run this configuration in the provided simulator the command would be:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;enigma -m &amp;quot;A&amp;quot; -l &amp;quot;III 1 0&amp;quot; -c &amp;quot;II 1 0&amp;quot; -r &amp;quot;I 1 2&amp;quot; -ukw &amp;quot;B&amp;quot; -plugs &amp;quot;A:T&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;a name='character-'a'-pressed'&gt;&lt;/a&gt;&lt;h3&gt;Character 'A' Pressed&lt;/h3&gt;
&lt;p&gt;When character A is pressed, the right most rotor rotates forward by one. 
The right rotor was not at its notch position, so it is the only rotor that moves. 
An electrical signal is then sent through the machine.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first stage is the plugboard. Our plugboard maps A to a T so our electrical signal comes out of contact T of the plugboard.&lt;/li&gt;
&lt;li&gt;Because rotor I has been shifted by one, output T of the plugboard actually goes into input U of rotor I. The input contact U maps to the output contact U and so this receives the electrical signal.&lt;/li&gt;
&lt;li&gt;Rotor I’s contact U is connected to Rotor II’s input contact T so this is the input point of the rotor. T is wired to N in this rotor, so a signal is outputted on this contact.&lt;/li&gt;
&lt;li&gt;Rotor II’s contact N is connected to Rotor III’s input contact N so this receives the signal. Input N is wired to output N so electricity is passed out at this contact.&lt;/li&gt;
&lt;li&gt;Output N goes into the reflector’s input N, travels to the mapped output point K and then travels back through all previous 3 rotor along whichever wirings are available in that direction.&lt;/li&gt;
&lt;li&gt;K is mapped to U so Rotor III feeds electricity to the contact U on Rotor II’s left hand side.&lt;/li&gt;
&lt;li&gt;U is mapped to H so Rotor II feeds electricity to its output contact H.&lt;/li&gt;
&lt;li&gt;Because Rotor I is rotated by 1 step, Rotor II’s right contact H is touching Rotor I’s left contact I so this is the input point. I maps to H so electricity is fed to this output contact.&lt;/li&gt;
&lt;li&gt;Once again, because I is rotated by I, contact H is actually in connected to the G contact on the plugboard. Because we have no mapping for G, it passes through unchanged, and the G lamp lights ups. G becomes our ciphertext.&lt;/li&gt;
&lt;/ol&gt;
&lt;a name='methods-of-decryption'&gt;&lt;/a&gt;&lt;h2&gt;Methods of Decryption&lt;/h2&gt;
&lt;a name='brute-force'&gt;&lt;/a&gt;&lt;h3&gt;Brute Force&lt;/h3&gt;
&lt;p&gt;The most naïve of decryption methods would be to brute force the initial settings. 
This would be incredibly difficult, even on a modern machine, due to the large number of possibilities:&lt;/p&gt;
&lt;p&gt;Possible Rotor Combinations = 5×4×3=60 (Picking 3 rotors from 5)&lt;/p&gt;
&lt;p&gt;Possible Rotor Settings = 26×26×26=17,576 (26 settings for each of the 3 rotors)&lt;/p&gt;
&lt;p&gt;Possible Plugboard Settings = 26!/(6!10!2^10)=150,738,274,937,250 (26 letters, order of 10 pairs does not matter, 6 letters go unused, mappings are bi-directional)&lt;/p&gt;
&lt;p&gt;Total Combinations = 158,962,555,217,826,360,000&lt;/p&gt;
&lt;p&gt;This is only using a three rotor Enigma machine where three rotors are chosen from five. 
The Navy could choose three rotors from eight, and the M4 Enigma had even more combinations with its two reflectors.&lt;/p&gt;
&lt;p&gt;Brute forcing Enigma was impossible at the time and is still infeasible as a method of decryption on modern machines in a reasonable period.&lt;/p&gt;
&lt;a name='analytical-methods'&gt;&lt;/a&gt;&lt;h3&gt;Analytical Methods&lt;/h3&gt;
&lt;p&gt;Because of the infeasibility of brute force methods, cryptanalysis had to be performed to reduce the search space to something reasonable.&lt;/p&gt;
&lt;a name='known-plaintext-attacks'&gt;&lt;/a&gt;&lt;h4&gt;Known-plaintext Attacks&lt;/h4&gt;
&lt;p&gt;One of the key flaws in Enigma’s encryption process was that, due to the nature of the reflector, a letter in plaintext could never map to the same letter in the ciphertext. 
The primary method of utilising this flaw came in using either known plaintext or guessed plaintext. 
If a message was sent with partially known content in a guessable format, then you could use the flaw to work out where certain words may appear in the ciphertext and then reverse engineer the settings from that.&lt;/p&gt;
&lt;p&gt;An example of this might be a weather report. 
A weather report is likely to contain the German word for ‘weather report’, ‘wetterbericht’. 
You could see where ‘wetterbericht’ would plausibly fit in the message (no plaintext letters match ciphertext letters) and only go through combinations where that outcome is possible. 
A piece of known plaintext such as this was known as a ‘crib’.&lt;/p&gt;
&lt;p&gt;Cribs could also be used to identify plugboard combinations. 
By going through the crib, we could make certain assumptions and develop trees of possible plugboard settings. 
If one of our assumptions is contradicted along the tree, then we can rule out that whole branch of plugboard settings without ever needing to try them. 
Techniques like plugboard checking can help to reduce the search space significantly. 
The search space became small enough that even in the 40s it was possible to use these techniques to reduce the problem electromechanically using devices known as Bombes.&lt;/p&gt;
&lt;a name='ciphertext-only-attack'&gt;&lt;/a&gt;&lt;h4&gt;Ciphertext-only Attack&lt;/h4&gt;
&lt;p&gt;All successful cryptanalysis on Enigma during the war focused on known-plaintext attack methods. 
Modern computing power combined with statistical methods allows for certain plaintext-only methods of decryption. 
On such plaintext-only attack involves calculating the index of coincidence. 
Index of coincidence (IoC) is a measure of how likely to it is to draw two letters from a piece of text, and for those two letters to be the same. 
Index of coincidence is useful in decrypting because the distribution of letters in a language is different to that of random characters (A piece of random text has an average IoC of 1.0 whereas German text has an average IoC of 2.05). 
Enigma is vulnerable to the use of IoC as a method of decryption since if one of either the rotors, ring settings, or plugboard are correct, the message will be slightly closer to the plaintext and therefore have a slightly higher IoC.&lt;/p&gt;
&lt;p&gt;If you were to run all possible rotor combinations with default ring settings, no plugboard, and the message was sufficiently long, the IoC of the correct rotor combination would be slightly higher than random. 
Being able to solve, or at least narrow, the problem in individual elements removes the multiplicative element of brute force and makes the problem more computationally feasible. 
Likewise, having one of the plugboard settings correct will produce a better IoC than having none of them correct.&lt;/p&gt;
&lt;p&gt;IoC is only useful when you have enough text to become statistically significant, with Enigma this would be somewhere between 600-1500 characters depending on plugboard settings. 
The German military purposely kept Enigma messages short for this very reason, as IoC was known at the time. 
There were, however, occasions where operational mistakes or multiple messages using the same settings would result in long strings of characters enciphered the same.&lt;/p&gt;
&lt;p&gt;It is likely that IoC could be used in conjunction with known-plaintext attacks to create a much more efficient method of decryption since both use alternative ways to narrow the search-space.&lt;/p&gt;
&lt;a name='lorenz'&gt;&lt;/a&gt;&lt;h1&gt;Lorenz&lt;/h1&gt;
&lt;p&gt;As previously mentioned, The Lorenz machine was used to encipher the most secret intelligence between Hitler and his generals. 
The nature of the traffic meant that the cryptanalysts at Bletchley Park had much fewer messages to try and decrypt, and the lack of machines meant that it was less likely for them to get a physical machine to test with. 
In fact, almost all cryptanalysis on Lorenz was done without any access to the physical hardware as the first machine was only captured by the allies late in the war as Europe was being liberated. 
However, messages did tend to be longer due to the fact the Lorenz machine was much easier to use.&lt;/p&gt;
&lt;a name='workings'&gt;&lt;/a&gt;&lt;h2&gt;Workings&lt;/h2&gt;
&lt;p&gt;Unlike Enigma, which was sent by morse, the Lorenz machine used teleprinter code which was automatically ciphered and deciphered. 
An operator would type their message in plaintext and the receiver would see the incoming message in plaintext with decryption only occurring for transmission.&lt;/p&gt;
&lt;p&gt;Lorenz signals used, what would now be referred to as, a 5-bit encoding scheme known as ITA2. 
Plaintext characters would be represented as 5 dots or spaces on 5-hole paper tape, and this is what would be enciphered. 
The encipherment is logically straightforward, the plaintext ITA2 stream would have a bitwise XOR operation performed on it with a pseudorandom keystream. 
It is the cracking of how the keystream was generated that would be vital in uncovering the message.&lt;/p&gt;
&lt;p&gt;For UX reasons, the ITA scheme used by the Lorenz simulator is slightly different to the standard ITA2 schema.
The simulator uses the following mapping:&lt;/p&gt;
&lt;div style="line-height: 1.1rem; margin-left: auto; margin-right: auto"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Binary Code&lt;/strong&gt;&lt;/th&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Letter Shift&lt;/strong&gt;&lt;/th&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Figure Shift&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;±&lt;/td&gt;
  &lt;td style="text-align:center"&gt;±&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;T&lt;/td&gt;
  &lt;td style="text-align:center"&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;_&lt;/td&gt;
  &lt;td style="text-align:center"&gt;_&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;O&lt;/td&gt;
  &lt;td style="text-align:center"&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;SPACE&lt;/td&gt;
  &lt;td style="text-align:center"&gt;!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;H&lt;/td&gt;
  &lt;td style="text-align:center"&gt;£&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;N&lt;/td&gt;
  &lt;td style="text-align:center"&gt;,&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;M&lt;/td&gt;
  &lt;td style="text-align:center"&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;|&lt;/td&gt;
  &lt;td style="text-align:center"&gt;|&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;L&lt;/td&gt;
  &lt;td style="text-align:center"&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;R&lt;/td&gt;
  &lt;td style="text-align:center"&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;G&lt;/td&gt;
  &lt;td style="text-align:center"&gt;&amp;amp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;I&lt;/td&gt;
  &lt;td style="text-align:center"&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;P&lt;/td&gt;
  &lt;td style="text-align:center"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;C&lt;/td&gt;
  &lt;td style="text-align:center"&gt;:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;V&lt;/td&gt;
  &lt;td style="text-align:center"&gt;=&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;E&lt;/td&gt;
  &lt;td style="text-align:center"&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Z&lt;/td&gt;
  &lt;td style="text-align:center"&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;D&lt;/td&gt;
  &lt;td style="text-align:center"&gt;#&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;B&lt;/td&gt;
  &lt;td style="text-align:center"&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;S&lt;/td&gt;
  &lt;td style="text-align:center"&gt;\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Y&lt;/td&gt;
  &lt;td style="text-align:center"&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;F&lt;/td&gt;
  &lt;td style="text-align:center"&gt;%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;X&lt;/td&gt;
  &lt;td style="text-align:center"&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;A&lt;/td&gt;
  &lt;td style="text-align:center"&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;W&lt;/td&gt;
  &lt;td style="text-align:center"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;J&lt;/td&gt;
  &lt;td style="text-align:center"&gt;$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;^ (Figure Shift)&lt;/td&gt;
  &lt;td style="text-align:center"&gt;^ (Figure Shift)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;U&lt;/td&gt;
  &lt;td style="text-align:center"&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Q&lt;/td&gt;
  &lt;td style="text-align:center"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;K&lt;/td&gt;
  &lt;td style="text-align:center"&gt;(&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;* (Letter Shift)&lt;/td&gt;
  &lt;td style="text-align:center"&gt;* (Letter Shift)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;a name='keystream-generation'&gt;&lt;/a&gt;&lt;h3&gt;Keystream Generation&lt;/h3&gt;
&lt;p&gt;Like Enigma, the Lorenz machine used rotors, however there were 12 rather than the 3 found in Enigma. 
The rotors can be divided into three sets: the ψ wheels, the χ wheels, and the μ wheels.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Lorenz.svg" alt="Lorenz encryption process" /&gt;&lt;/p&gt;
&lt;p&gt;Each rotor has a number of pins across its circumference. The number of pins on a rotor is co-prime with the number of pins on the other rotors, giving a very long period before a key sequence is repeated. The pins on the rotor can be set to either on or off (equivalent to 1 or 0 on a bit pattern).&lt;/p&gt;
&lt;p&gt;When a key is pressed, the 5-bit input is XORed with the bit pattern across the χ wheels, then again with the bit pattern across the ψ wheels. The wheels are then stepped depending on the position of the other wheels.&lt;/p&gt;
&lt;a name='rotor-stepping'&gt;&lt;/a&gt;&lt;h4&gt;Rotor Stepping&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;After the XORing, all χ rotors step forward by one.&lt;/li&gt;
&lt;li&gt;The ψ wheels only step forward by one if μ2 is in a ‘on’ positions&lt;/li&gt;
&lt;li&gt;Then, μ1 will always step forward by one&lt;/li&gt;
&lt;li&gt;If μ1 is in an ‘on’ position then μ2 will also step forward by one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later models of the Lorenz machine had further limitations placed on when a rotor would step forward.&lt;/p&gt;
&lt;a name='methods-of-decryption'&gt;&lt;/a&gt;&lt;h2&gt;Methods of Decryption&lt;/h2&gt;
&lt;p&gt;As with Enigma, Lorenz machines were far too complex to have any hope of using brute force techniques to acquire the initial settings.&lt;/p&gt;
&lt;a name='depths'&gt;&lt;/a&gt;&lt;h3&gt;Depths&lt;/h3&gt;
&lt;p&gt;As with Enigma, having credible guesses of what parts of the plaintext might be can go a long way into decrypting the whole message. If two messages share the same key then it becomes a much easier task.&lt;/p&gt;
&lt;p&gt;Consider the following, where C1 and C2 are two cipher texts, P1 and P2 are two plaintexts, and K is a key they have in common.&lt;/p&gt;
&lt;p&gt;$$C_1=P_1\oplus K$$
$$C_2=P_2\oplus K$$
$$C_1\oplus C_2=P_1{\oplus P}_2\oplus K\oplus K$$
$$\mathrm{Since\ }K\oplus K=0:$$
$$C_1\oplus C_2=P_1{\oplus P}_2$$
$$\mathrm{let\ }F=C_1\oplus C_2$$&lt;/p&gt;
&lt;p&gt;As can be seen, by having two messages that use the same key, you can achieve a combination (F) of the two plaintexts by XORing the two ciphertexts. The resulting amalgamation contains no part of the keystream.&lt;/p&gt;
&lt;p&gt;The result of this is, if we can guess a part of one plaintext, and XOR it with F, then we will get a part of the other piece of plaintext. One powerful instance of this weakness proving useful came when a German officer sent two long messages using the same key with slightly different content. First a message was sent, then the receiver requested the message be sent again due to a failure on their end, the sender sent the message again but, because they were more impatient the second time around, started using abbreviations in their message.&lt;/p&gt;
&lt;a name='worked-example'&gt;&lt;/a&gt;&lt;h4&gt;Worked Example&lt;/h4&gt;
&lt;p&gt;Say we have the message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Plaintext:      REGIMENT NUMBER 5 WILL ATTACK WEST POINT AT DAWN
Ciphertext:     Z_ZFINNOV_YQM*PL*_JL^6?-1!::9=|+,(2(:1.$,1-1*OKVIL
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then our operator comes back to us and asks us to repeat the message. We might send back:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Plaintext:      REGIMENT NO 5 WILL ATK W POINT AT DAWN
Ciphertext:     Z_ZFINNOV_RKVCALQVI NT^=1£&amp;amp;_-03'^%8^-|13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we XOR our two cipher text messages we get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this particular ITA alphabet, ± is the null character and so we know that the characters in those positions are the same in both messages.&lt;/p&gt;
&lt;p&gt;Let us suppose that we know that a message is going to start with a regiment number, but we don’t know where they will attack. We can XOR our crib with F to see if we can get some of the other message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER
F XOR CRIB:     REGIMENT NO ^5*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that be XORing our crib against the message, we get the contents of the other message. Since they are messages with the same intent, we can take a guess that our first message will also refer to regiment 5, this can form the basis of a new crib:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5*
F XOR Crib:     REGIMENT NO ^5* WI
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we have gathered two more letters. We can keep feeding cribs into each other to read out the entire message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WI
F XOR Crib:     REGIMENT NO ^5* WILL A
Crib:           REGIMENT NUMBER ^5* WILL A
F XOR Crib:     R REGIMENT NO ^5* WILL ATK W
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At points like this we can see another likely deviation in the messages. We have found out that the second message uses the phrase ATK, one assumption we could make is that they used the full word ATTACK in the original message.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WILL ATTACK
F XOR Crib:     REGIMENT NO ^5* WILL ATK W POIN
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Likewise, a cryptanalyst might also assume that W could mean WEST. Realistically cryptanalysts would try various combinations to see which one creates reasonable plaintext.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WILL ATTACK WEST POI
F XOR Crib:     REGIMENT NO ^5* WILL ATK W POINT AT DAWN
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have both messages in the clear without ever needing to know what the settings were of the Lorenz machine or what the key stream was. The only outright guess we needed to make was that the message would start with the phrase “REGIMENT NUMBER”, and from that we found out which regiment it was, what they were doing, and when they were doing it.&lt;/p&gt;
&lt;p&gt;This was not the only technique used in the breaking of Lorenz traffic, but it is one of the most potent. Such an attack also highlights how operational failures can severely jeopardise the use of a system that is quite secure from a cryptographic standpoint.&lt;/p&gt;
&lt;a name='bibliography'&gt;&lt;/a&gt;&lt;h1&gt;Bibliography&lt;/h1&gt;
&lt;p&gt;Computerphile. (2014, December 9). Tackling Enigma (Turing's Enigma Problem Part 2) - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=kj_7Jc1mS9k"&gt;https://www.youtube.com/watch?v=kj_7Jc1mS9k&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2014, November 28). Turing's Enigma Problem (Part 1) - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=d2NWPG2gB_A"&gt;https://www.youtube.com/watch?v=d2NWPG2gB_A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2015, July 1). Fishy Codes: Bletchley's Other Secret - Computerphile. Retrieved from YouTube: &lt;a href="https://youtu.be/Ou_9ntYRzzw"&gt;https://youtu.be/Ou_9ntYRzzw&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2015, September 16). Zig Zag Decryption - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=yxx3Bkmv3ck"&gt;https://www.youtube.com/watch?v=yxx3Bkmv3ck&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2018, September 5). Exploiting the Tiltman Break - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=-hrNWRtDr7Y"&gt;https://www.youtube.com/watch?v=-hrNWRtDr7Y&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2021, April 21). Cracking Enigma in 2021 - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=RzWB5jL5RX0"&gt;https://www.youtube.com/watch?v=RzWB5jL5RX0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Good, J., Michie, D., &amp;amp; Timms, G. (1945). General Report on Tunny.&lt;/p&gt;
&lt;p&gt;Jackson, J. (2022, August 15). The National Museum of Computing. Retrieved from The Enigma Machine: &lt;a href="https://www.tnmoc.org/bh-2-the-enigma-machine"&gt;https://www.tnmoc.org/bh-2-the-enigma-machine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Numberphile. (2013, January 10). 158,962,555,217,826,360,000 (Enigma Machine) - Numberphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=G2_Q9FoD-oQ"&gt;https://www.youtube.com/watch?v=G2_Q9FoD-oQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Numberphile. (2013, January 14). Flaw in the Enigma Code - Numberphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=V4V2bpZlqx8"&gt;https://www.youtube.com/watch?v=V4V2bpZlqx8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Owen, J. (2021, December 11). How did the Enigma machine work? Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=ybkkiGtJmkM"&gt;https://www.youtube.com/watch?v=ybkkiGtJmkM&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Stichting Cryptomuseum. (2022, August 12). Retrieved from Crypto Museum: &lt;a href="https://www.cryptomuseum.com/index.htm"&gt;https://www.cryptomuseum.com/index.htm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thaophialuang, L. (2019, January 24). Enigma Simulator. Retrieved from Enigma Cipher: &lt;a href="https://piotte13.github.io/enigma-cipher/"&gt;https://piotte13.github.io/enigma-cipher/&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='static/postimages/playing-soldiers-enigma-and-lorenz/Encrypt.svg' alt='&lt;div&gt;Playing Soldiers: An Exploration into Wartime Ciphers - Enigma and Lorenz&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;Playing Soldiers: An Exploration into Wartime Ciphers - Enigma and Lorenz&lt;/div&gt;
&lt;/h1&gt;&lt;p&gt;I had a bit of time over the Summer, and thought I would do something that I have been meaning to do for a long time.
Create a software implementation of an Enigma and a Lorenz machine. 
While I was at it, I thought that I might as well take a look at how the machines could be broken.&lt;/p&gt;
&lt;p&gt;For the programs themselves, head over to the &lt;a href="/projects/enigma-lorenz"&gt;project page&lt;/a&gt;.
The rest of this post is an explanation of how the machines work and the low-hanging fruit when it comes to vulnerabilities.&lt;/p&gt;
&lt;a name='preface'&gt;&lt;/a&gt;&lt;h1&gt;Preface&lt;/h1&gt;
&lt;p&gt;Enigma and Lorenz are two series of electromechanical cipher machines that saw extensive use by the Axis powers during World War II. 
Enigma was primarily used by the German Navy, Air Force, and Army as a method to encrypt communications. 
Lorenz machines were used from 1940 onwards and were the preferred encryption method for communications between German High Command. 
The Enigma and Lorenz machines formed the vast majority of traffic decrypted at the British Government Code and Ciphers School (GC&amp;amp;CS) in Bletchley Park.&lt;/p&gt;
&lt;a name='enigma'&gt;&lt;/a&gt;&lt;h1&gt;Enigma&lt;/h1&gt;
&lt;p&gt;Enigma was the most widely used of the two machines, and the largest share traffic flowing through Bletchley Park was encrypted by Enigma. 
With over 40,000 machines constructed (compared to the approximately 200 Lorenz machines), Enigma was the priority of Allied codebreakers, especially during the early stages of the war.&lt;/p&gt;
&lt;a name='workings'&gt;&lt;/a&gt;&lt;h2&gt;Workings&lt;/h2&gt;
&lt;p&gt;German military Enigma machines are made up of three distinct parts: the rotors, the reflector and the plugboard.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Enigma.svg" alt="Data flow through Enigma machine" /&gt;&lt;/p&gt;
&lt;a name='the-plugboard'&gt;&lt;/a&gt;&lt;h3&gt;The Plugboard&lt;/h3&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Plugboard.svg" alt="Enigma plugboard" /&gt;&lt;/p&gt;
&lt;p&gt;The plugboard is the simplest part of the encryption process but is what separates military Enigma from the commercial variant used before the war. 
The plugboard is a grid of contacts with each contact relating to a letter. 
Two ends of a plug would be inserted into two of the letters to electronically connect them. 
The connections on the plugboard would cause letters to be swapped before and after encryption. 
Each Enigma machine came with 13 plugs, with only up to 10 ever used at one time.&lt;/p&gt;
&lt;a name='the-rotors'&gt;&lt;/a&gt;&lt;h3&gt;The Rotors&lt;/h3&gt;
&lt;p&gt;The rotors are the most distinctive element of the Enigma machine. 
All German military Enigma machines featured three conventional rotors. 
A later Enigma model, the M4, is often referred to as having four rotors however this ‘fourth’ rotor behaves more like a reflector than a conventional rotor.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Rotor.svg" alt="Enigma rotor" /&gt;&lt;/p&gt;
&lt;p&gt;A rotor is very straightforward electronically: it maps a single input on one side, to an output on another side, through a wire. 
There were 26 mappings on each rotor, one for each letter of the alphabet, and each mapping was marked with either a number from 1 to 26 or the letters A to Z. 
The topmost marking could be seen through a small window on the machine, and this was used for setting an initial configuration. 
An Enigma rotor also has a “ring setting”. 
The markings on the rotor can be twisted independent of the rotor itself and so the mapping represented by “A” on ring setting 0 would be represented by a “Z” on ring setting 1. 
It effectively offsets the outer casing and notch from the inner wiring. 
The ring setting is set at the beginning of the message and remains the same throughout.&lt;/p&gt;
&lt;p&gt;On each keypress the rightmost rotor is rotated towards the operator by a single step. 
Each rotor also has one or two small notches aligned with one or two of the steps. 
Usually, when the right rotor turns it blocks the other two rotors from spinning. 
However, if the rotor is in a position where the notch aligns with the mechanism, the rotor to the left of it can rotate one step. 
The same is true for the middle and left rotors. 
The effect is similar to something like the odometer on a car: at a certain point in the rotation of the right rotor, the middle rotor is increased by one, and at a certain point in the rotation of the middle rotor, the left rotor is increased by one.&lt;/p&gt;
&lt;a name='note-on-double-stepping'&gt;&lt;/a&gt;&lt;h4&gt;Note on Double Stepping&lt;/h4&gt;
&lt;p&gt;There is a quirk with the mechanism of German Enigma machines which means the middle rotor will also rotate if it is at its notch position even if the rotor to the right of it is not.&lt;/p&gt;
&lt;a name='the-reflector'&gt;&lt;/a&gt;&lt;h3&gt;The Reflector&lt;/h3&gt;
&lt;p&gt;The reflector is electronically similar to a rotor in that it has a series of input and output contacts that are mapped with wiring, however there is no rotation of a reflector during transmission of the message. 
A reflector is set at the beginning of a message and remains static throughout. 
The ‘fourth’ rotor of Enigma M4 also remains static throughout the message and therefore it somewhat of a misnomer to call it a ‘fourth’ rotor. 
In fact, using the ‘beta’ wheel as the fourth rotor and the UKW-b wheel as the reflector in M4 Enigma is logically identical to the UKW-B reflector of three-wheel Enigma.&lt;/p&gt;
&lt;a name='stages-of-encryption'&gt;&lt;/a&gt;&lt;h2&gt;Stages of Encryption&lt;/h2&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Encrypt.svg" alt="Enigma encryption process" /&gt;&lt;/p&gt;
&lt;p&gt;To fully understand the stages of Enigma encryption, it is best to show a worked example. 
In this example we are going to encrypt the character ‘A’ with rotors III, II, and I in default position, with A mapped to T on the plugboard, and with the ring setting of rotor I set to 2. 
To run this configuration in the provided simulator the command would be:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;enigma -m &amp;quot;A&amp;quot; -l &amp;quot;III 1 0&amp;quot; -c &amp;quot;II 1 0&amp;quot; -r &amp;quot;I 1 2&amp;quot; -ukw &amp;quot;B&amp;quot; -plugs &amp;quot;A:T&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;a name='character-'a'-pressed'&gt;&lt;/a&gt;&lt;h3&gt;Character 'A' Pressed&lt;/h3&gt;
&lt;p&gt;When character A is pressed, the right most rotor rotates forward by one. 
The right rotor was not at its notch position, so it is the only rotor that moves. 
An electrical signal is then sent through the machine.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first stage is the plugboard. Our plugboard maps A to a T so our electrical signal comes out of contact T of the plugboard.&lt;/li&gt;
&lt;li&gt;Because rotor I has been shifted by one, output T of the plugboard actually goes into input U of rotor I. The input contact U maps to the output contact U and so this receives the electrical signal.&lt;/li&gt;
&lt;li&gt;Rotor I’s contact U is connected to Rotor II’s input contact T so this is the input point of the rotor. T is wired to N in this rotor, so a signal is outputted on this contact.&lt;/li&gt;
&lt;li&gt;Rotor II’s contact N is connected to Rotor III’s input contact N so this receives the signal. Input N is wired to output N so electricity is passed out at this contact.&lt;/li&gt;
&lt;li&gt;Output N goes into the reflector’s input N, travels to the mapped output point K and then travels back through all previous 3 rotor along whichever wirings are available in that direction.&lt;/li&gt;
&lt;li&gt;K is mapped to U so Rotor III feeds electricity to the contact U on Rotor II’s left hand side.&lt;/li&gt;
&lt;li&gt;U is mapped to H so Rotor II feeds electricity to its output contact H.&lt;/li&gt;
&lt;li&gt;Because Rotor I is rotated by 1 step, Rotor II’s right contact H is touching Rotor I’s left contact I so this is the input point. I maps to H so electricity is fed to this output contact.&lt;/li&gt;
&lt;li&gt;Once again, because I is rotated by I, contact H is actually in connected to the G contact on the plugboard. Because we have no mapping for G, it passes through unchanged, and the G lamp lights ups. G becomes our ciphertext.&lt;/li&gt;
&lt;/ol&gt;
&lt;a name='methods-of-decryption'&gt;&lt;/a&gt;&lt;h2&gt;Methods of Decryption&lt;/h2&gt;
&lt;a name='brute-force'&gt;&lt;/a&gt;&lt;h3&gt;Brute Force&lt;/h3&gt;
&lt;p&gt;The most naïve of decryption methods would be to brute force the initial settings. 
This would be incredibly difficult, even on a modern machine, due to the large number of possibilities:&lt;/p&gt;
&lt;p&gt;Possible Rotor Combinations = 5×4×3=60 (Picking 3 rotors from 5)&lt;/p&gt;
&lt;p&gt;Possible Rotor Settings = 26×26×26=17,576 (26 settings for each of the 3 rotors)&lt;/p&gt;
&lt;p&gt;Possible Plugboard Settings = 26!/(6!10!2^10)=150,738,274,937,250 (26 letters, order of 10 pairs does not matter, 6 letters go unused, mappings are bi-directional)&lt;/p&gt;
&lt;p&gt;Total Combinations = 158,962,555,217,826,360,000&lt;/p&gt;
&lt;p&gt;This is only using a three rotor Enigma machine where three rotors are chosen from five. 
The Navy could choose three rotors from eight, and the M4 Enigma had even more combinations with its two reflectors.&lt;/p&gt;
&lt;p&gt;Brute forcing Enigma was impossible at the time and is still infeasible as a method of decryption on modern machines in a reasonable period.&lt;/p&gt;
&lt;a name='analytical-methods'&gt;&lt;/a&gt;&lt;h3&gt;Analytical Methods&lt;/h3&gt;
&lt;p&gt;Because of the infeasibility of brute force methods, cryptanalysis had to be performed to reduce the search space to something reasonable.&lt;/p&gt;
&lt;a name='known-plaintext-attacks'&gt;&lt;/a&gt;&lt;h4&gt;Known-plaintext Attacks&lt;/h4&gt;
&lt;p&gt;One of the key flaws in Enigma’s encryption process was that, due to the nature of the reflector, a letter in plaintext could never map to the same letter in the ciphertext. 
The primary method of utilising this flaw came in using either known plaintext or guessed plaintext. 
If a message was sent with partially known content in a guessable format, then you could use the flaw to work out where certain words may appear in the ciphertext and then reverse engineer the settings from that.&lt;/p&gt;
&lt;p&gt;An example of this might be a weather report. 
A weather report is likely to contain the German word for ‘weather report’, ‘wetterbericht’. 
You could see where ‘wetterbericht’ would plausibly fit in the message (no plaintext letters match ciphertext letters) and only go through combinations where that outcome is possible. 
A piece of known plaintext such as this was known as a ‘crib’.&lt;/p&gt;
&lt;p&gt;Cribs could also be used to identify plugboard combinations. 
By going through the crib, we could make certain assumptions and develop trees of possible plugboard settings. 
If one of our assumptions is contradicted along the tree, then we can rule out that whole branch of plugboard settings without ever needing to try them. 
Techniques like plugboard checking can help to reduce the search space significantly. 
The search space became small enough that even in the 40s it was possible to use these techniques to reduce the problem electromechanically using devices known as Bombes.&lt;/p&gt;
&lt;a name='ciphertext-only-attack'&gt;&lt;/a&gt;&lt;h4&gt;Ciphertext-only Attack&lt;/h4&gt;
&lt;p&gt;All successful cryptanalysis on Enigma during the war focused on known-plaintext attack methods. 
Modern computing power combined with statistical methods allows for certain plaintext-only methods of decryption. 
On such plaintext-only attack involves calculating the index of coincidence. 
Index of coincidence (IoC) is a measure of how likely to it is to draw two letters from a piece of text, and for those two letters to be the same. 
Index of coincidence is useful in decrypting because the distribution of letters in a language is different to that of random characters (A piece of random text has an average IoC of 1.0 whereas German text has an average IoC of 2.05). 
Enigma is vulnerable to the use of IoC as a method of decryption since if one of either the rotors, ring settings, or plugboard are correct, the message will be slightly closer to the plaintext and therefore have a slightly higher IoC.&lt;/p&gt;
&lt;p&gt;If you were to run all possible rotor combinations with default ring settings, no plugboard, and the message was sufficiently long, the IoC of the correct rotor combination would be slightly higher than random. 
Being able to solve, or at least narrow, the problem in individual elements removes the multiplicative element of brute force and makes the problem more computationally feasible. 
Likewise, having one of the plugboard settings correct will produce a better IoC than having none of them correct.&lt;/p&gt;
&lt;p&gt;IoC is only useful when you have enough text to become statistically significant, with Enigma this would be somewhere between 600-1500 characters depending on plugboard settings. 
The German military purposely kept Enigma messages short for this very reason, as IoC was known at the time. 
There were, however, occasions where operational mistakes or multiple messages using the same settings would result in long strings of characters enciphered the same.&lt;/p&gt;
&lt;p&gt;It is likely that IoC could be used in conjunction with known-plaintext attacks to create a much more efficient method of decryption since both use alternative ways to narrow the search-space.&lt;/p&gt;
&lt;a name='lorenz'&gt;&lt;/a&gt;&lt;h1&gt;Lorenz&lt;/h1&gt;
&lt;p&gt;As previously mentioned, The Lorenz machine was used to encipher the most secret intelligence between Hitler and his generals. 
The nature of the traffic meant that the cryptanalysts at Bletchley Park had much fewer messages to try and decrypt, and the lack of machines meant that it was less likely for them to get a physical machine to test with. 
In fact, almost all cryptanalysis on Lorenz was done without any access to the physical hardware as the first machine was only captured by the allies late in the war as Europe was being liberated. 
However, messages did tend to be longer due to the fact the Lorenz machine was much easier to use.&lt;/p&gt;
&lt;a name='workings'&gt;&lt;/a&gt;&lt;h2&gt;Workings&lt;/h2&gt;
&lt;p&gt;Unlike Enigma, which was sent by morse, the Lorenz machine used teleprinter code which was automatically ciphered and deciphered. 
An operator would type their message in plaintext and the receiver would see the incoming message in plaintext with decryption only occurring for transmission.&lt;/p&gt;
&lt;p&gt;Lorenz signals used, what would now be referred to as, a 5-bit encoding scheme known as ITA2. 
Plaintext characters would be represented as 5 dots or spaces on 5-hole paper tape, and this is what would be enciphered. 
The encipherment is logically straightforward, the plaintext ITA2 stream would have a bitwise XOR operation performed on it with a pseudorandom keystream. 
It is the cracking of how the keystream was generated that would be vital in uncovering the message.&lt;/p&gt;
&lt;p&gt;For UX reasons, the ITA scheme used by the Lorenz simulator is slightly different to the standard ITA2 schema.
The simulator uses the following mapping:&lt;/p&gt;
&lt;div style="line-height: 1.1rem; margin-left: auto; margin-right: auto"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Binary Code&lt;/strong&gt;&lt;/th&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Letter Shift&lt;/strong&gt;&lt;/th&gt;
  &lt;th style="text-align:center"&gt;&lt;strong&gt;Figure Shift&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;±&lt;/td&gt;
  &lt;td style="text-align:center"&gt;±&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;T&lt;/td&gt;
  &lt;td style="text-align:center"&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;_&lt;/td&gt;
  &lt;td style="text-align:center"&gt;_&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;O&lt;/td&gt;
  &lt;td style="text-align:center"&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;SPACE&lt;/td&gt;
  &lt;td style="text-align:center"&gt;!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;H&lt;/td&gt;
  &lt;td style="text-align:center"&gt;£&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;N&lt;/td&gt;
  &lt;td style="text-align:center"&gt;,&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;00111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;M&lt;/td&gt;
  &lt;td style="text-align:center"&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;|&lt;/td&gt;
  &lt;td style="text-align:center"&gt;|&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;L&lt;/td&gt;
  &lt;td style="text-align:center"&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;R&lt;/td&gt;
  &lt;td style="text-align:center"&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;G&lt;/td&gt;
  &lt;td style="text-align:center"&gt;&amp;amp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;I&lt;/td&gt;
  &lt;td style="text-align:center"&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;P&lt;/td&gt;
  &lt;td style="text-align:center"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;C&lt;/td&gt;
  &lt;td style="text-align:center"&gt;:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;01111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;V&lt;/td&gt;
  &lt;td style="text-align:center"&gt;=&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;E&lt;/td&gt;
  &lt;td style="text-align:center"&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Z&lt;/td&gt;
  &lt;td style="text-align:center"&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;D&lt;/td&gt;
  &lt;td style="text-align:center"&gt;#&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;B&lt;/td&gt;
  &lt;td style="text-align:center"&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;S&lt;/td&gt;
  &lt;td style="text-align:center"&gt;\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Y&lt;/td&gt;
  &lt;td style="text-align:center"&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;F&lt;/td&gt;
  &lt;td style="text-align:center"&gt;%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;10111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;X&lt;/td&gt;
  &lt;td style="text-align:center"&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11000&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;A&lt;/td&gt;
  &lt;td style="text-align:center"&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11001&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;W&lt;/td&gt;
  &lt;td style="text-align:center"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11010&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;J&lt;/td&gt;
  &lt;td style="text-align:center"&gt;$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11011&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;^ (Figure Shift)&lt;/td&gt;
  &lt;td style="text-align:center"&gt;^ (Figure Shift)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11100&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;U&lt;/td&gt;
  &lt;td style="text-align:center"&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11101&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;Q&lt;/td&gt;
  &lt;td style="text-align:center"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11110&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;K&lt;/td&gt;
  &lt;td style="text-align:center"&gt;(&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td style="text-align:center"&gt;&lt;code&gt;11111&lt;/code&gt;&lt;/td&gt;
  &lt;td style="text-align:center"&gt;* (Letter Shift)&lt;/td&gt;
  &lt;td style="text-align:center"&gt;* (Letter Shift)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;a name='keystream-generation'&gt;&lt;/a&gt;&lt;h3&gt;Keystream Generation&lt;/h3&gt;
&lt;p&gt;Like Enigma, the Lorenz machine used rotors, however there were 12 rather than the 3 found in Enigma. 
The rotors can be divided into three sets: the ψ wheels, the χ wheels, and the μ wheels.&lt;/p&gt;
&lt;p&gt;&lt;img src="static/postimages/playing-soldiers-enigma-and-lorenz/Lorenz.svg" alt="Lorenz encryption process" /&gt;&lt;/p&gt;
&lt;p&gt;Each rotor has a number of pins across its circumference. The number of pins on a rotor is co-prime with the number of pins on the other rotors, giving a very long period before a key sequence is repeated. The pins on the rotor can be set to either on or off (equivalent to 1 or 0 on a bit pattern).&lt;/p&gt;
&lt;p&gt;When a key is pressed, the 5-bit input is XORed with the bit pattern across the χ wheels, then again with the bit pattern across the ψ wheels. The wheels are then stepped depending on the position of the other wheels.&lt;/p&gt;
&lt;a name='rotor-stepping'&gt;&lt;/a&gt;&lt;h4&gt;Rotor Stepping&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;After the XORing, all χ rotors step forward by one.&lt;/li&gt;
&lt;li&gt;The ψ wheels only step forward by one if μ2 is in a ‘on’ positions&lt;/li&gt;
&lt;li&gt;Then, μ1 will always step forward by one&lt;/li&gt;
&lt;li&gt;If μ1 is in an ‘on’ position then μ2 will also step forward by one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later models of the Lorenz machine had further limitations placed on when a rotor would step forward.&lt;/p&gt;
&lt;a name='methods-of-decryption'&gt;&lt;/a&gt;&lt;h2&gt;Methods of Decryption&lt;/h2&gt;
&lt;p&gt;As with Enigma, Lorenz machines were far too complex to have any hope of using brute force techniques to acquire the initial settings.&lt;/p&gt;
&lt;a name='depths'&gt;&lt;/a&gt;&lt;h3&gt;Depths&lt;/h3&gt;
&lt;p&gt;As with Enigma, having credible guesses of what parts of the plaintext might be can go a long way into decrypting the whole message. If two messages share the same key then it becomes a much easier task.&lt;/p&gt;
&lt;p&gt;Consider the following, where C1 and C2 are two cipher texts, P1 and P2 are two plaintexts, and K is a key they have in common.&lt;/p&gt;
&lt;p&gt;$$C_1=P_1\oplus K$$
$$C_2=P_2\oplus K$$
$$C_1\oplus C_2=P_1{\oplus P}_2\oplus K\oplus K$$
$$\mathrm{Since\ }K\oplus K=0:$$
$$C_1\oplus C_2=P_1{\oplus P}_2$$
$$\mathrm{let\ }F=C_1\oplus C_2$$&lt;/p&gt;
&lt;p&gt;As can be seen, by having two messages that use the same key, you can achieve a combination (F) of the two plaintexts by XORing the two ciphertexts. The resulting amalgamation contains no part of the keystream.&lt;/p&gt;
&lt;p&gt;The result of this is, if we can guess a part of one plaintext, and XOR it with F, then we will get a part of the other piece of plaintext. One powerful instance of this weakness proving useful came when a German officer sent two long messages using the same key with slightly different content. First a message was sent, then the receiver requested the message be sent again due to a failure on their end, the sender sent the message again but, because they were more impatient the second time around, started using abbreviations in their message.&lt;/p&gt;
&lt;a name='worked-example'&gt;&lt;/a&gt;&lt;h4&gt;Worked Example&lt;/h4&gt;
&lt;p&gt;Say we have the message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Plaintext:      REGIMENT NUMBER 5 WILL ATTACK WEST POINT AT DAWN
Ciphertext:     Z_ZFINNOV_YQM*PL*_JL^6?-1!::9=|+,(2(:1.$,1-1*OKVIL
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then our operator comes back to us and asks us to repeat the message. We might send back:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Plaintext:      REGIMENT NO 5 WILL ATK W POINT AT DAWN
Ciphertext:     Z_ZFINNOV_RKVCALQVI NT^=1£&amp;amp;_-03'^%8^-|13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we XOR our two cipher text messages we get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this particular ITA alphabet, ± is the null character and so we know that the characters in those positions are the same in both messages.&lt;/p&gt;
&lt;p&gt;Let us suppose that we know that a message is going to start with a regiment number, but we don’t know where they will attack. We can XOR our crib with F to see if we can get some of the other message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER
F XOR CRIB:     REGIMENT NO ^5*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that be XORing our crib against the message, we get the contents of the other message. Since they are messages with the same intent, we can take a guess that our first message will also refer to regiment 5, this can form the basis of a new crib:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5*
F XOR Crib:     REGIMENT NO ^5* WI
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we have gathered two more letters. We can keep feeding cribs into each other to read out the entire message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WI
F XOR Crib:     REGIMENT NO ^5* WILL A
Crib:           REGIMENT NUMBER ^5* WILL A
F XOR Crib:     R REGIMENT NO ^5* WILL ATK W
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At points like this we can see another likely deviation in the messages. We have found out that the second message uses the phrase ATK, one assumption we could make is that they used the full word ATTACK in the original message.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WILL ATTACK
F XOR Crib:     REGIMENT NO ^5* WILL ATK W POIN
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Likewise, a cryptanalyst might also assume that W could mean WEST. Realistically cryptanalysts would try various combinations to see which one creates reasonable plaintext.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;F:              ±±±±±±±±±±*O|ZY±_PFPQS|X±THI^_-£1|6£%6$4
Crib:           REGIMENT NUMBER ^5* WILL ATTACK WEST POI
F XOR Crib:     REGIMENT NO ^5* WILL ATK W POINT AT DAWN
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have both messages in the clear without ever needing to know what the settings were of the Lorenz machine or what the key stream was. The only outright guess we needed to make was that the message would start with the phrase “REGIMENT NUMBER”, and from that we found out which regiment it was, what they were doing, and when they were doing it.&lt;/p&gt;
&lt;p&gt;This was not the only technique used in the breaking of Lorenz traffic, but it is one of the most potent. Such an attack also highlights how operational failures can severely jeopardise the use of a system that is quite secure from a cryptographic standpoint.&lt;/p&gt;
&lt;a name='bibliography'&gt;&lt;/a&gt;&lt;h1&gt;Bibliography&lt;/h1&gt;
&lt;p&gt;Computerphile. (2014, December 9). Tackling Enigma (Turing's Enigma Problem Part 2) - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=kj_7Jc1mS9k"&gt;https://www.youtube.com/watch?v=kj_7Jc1mS9k&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2014, November 28). Turing's Enigma Problem (Part 1) - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=d2NWPG2gB_A"&gt;https://www.youtube.com/watch?v=d2NWPG2gB_A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2015, July 1). Fishy Codes: Bletchley's Other Secret - Computerphile. Retrieved from YouTube: &lt;a href="https://youtu.be/Ou_9ntYRzzw"&gt;https://youtu.be/Ou_9ntYRzzw&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2015, September 16). Zig Zag Decryption - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=yxx3Bkmv3ck"&gt;https://www.youtube.com/watch?v=yxx3Bkmv3ck&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2018, September 5). Exploiting the Tiltman Break - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=-hrNWRtDr7Y"&gt;https://www.youtube.com/watch?v=-hrNWRtDr7Y&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Computerphile. (2021, April 21). Cracking Enigma in 2021 - Computerphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=RzWB5jL5RX0"&gt;https://www.youtube.com/watch?v=RzWB5jL5RX0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Good, J., Michie, D., &amp;amp; Timms, G. (1945). General Report on Tunny.&lt;/p&gt;
&lt;p&gt;Jackson, J. (2022, August 15). The National Museum of Computing. Retrieved from The Enigma Machine: &lt;a href="https://www.tnmoc.org/bh-2-the-enigma-machine"&gt;https://www.tnmoc.org/bh-2-the-enigma-machine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Numberphile. (2013, January 10). 158,962,555,217,826,360,000 (Enigma Machine) - Numberphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=G2_Q9FoD-oQ"&gt;https://www.youtube.com/watch?v=G2_Q9FoD-oQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Numberphile. (2013, January 14). Flaw in the Enigma Code - Numberphile. Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=V4V2bpZlqx8"&gt;https://www.youtube.com/watch?v=V4V2bpZlqx8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Owen, J. (2021, December 11). How did the Enigma machine work? Retrieved from YouTube: &lt;a href="https://www.youtube.com/watch?v=ybkkiGtJmkM"&gt;https://www.youtube.com/watch?v=ybkkiGtJmkM&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Stichting Cryptomuseum. (2022, August 12). Retrieved from Crypto Museum: &lt;a href="https://www.cryptomuseum.com/index.htm"&gt;https://www.cryptomuseum.com/index.htm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thaophialuang, L. (2019, January 24). Enigma Simulator. Retrieved from Enigma Cipher: &lt;a href="https://piotte13.github.io/enigma-cipher/"&gt;https://piotte13.github.io/enigma-cipher/&lt;/a&gt;&lt;/p&gt;
</content:encoded>
      <pubDate>Mon, 29 Aug 2022 15:27:07 +0000</pubDate>
    </item>
    <item>
      <title>For Fonts in My Life
</title>
      <link>https://lukebriggs.dev/posts/for-fonts-in-my-life</link>
      <description>&lt;img class='post-hero' src='/static/postimages/for-fonts-in-my-life/header.png' alt='&lt;div&gt;For Fonts in My Life&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;For Fonts in My Life&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;Header image by &lt;a href="https://awright.dev"&gt;Andrew Wright&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is dissertation writing season at University, and this means one thing, document creation.
There are a few schools of thought when it comes to document creation.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-office-clerk&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The Office Clerk&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;A person who will use 12pt &lt;a href="https://en.wikipedia.org/wiki/Calibri"&gt;Calibri&lt;/a&gt;, have headings in 'Blue, Accent 1', and submit it as a &lt;code&gt;.docx&lt;/code&gt; file if they can.
Likely records videos in portrait.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-wysiwyg-wizards&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The WYSIWYG Wizards&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;Someone who still uses Microsoft Office but will change font, margins, bullet styles, and may even go as far as designing a custom template.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-typesetters&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The Typesetters&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;Someone who uses dedicated document preparation software.
Will spend hours searching for the correct typeface.
They spend more time on formatting than on writing.
Do not mention Arial in the company of this person.&lt;/p&gt;
&lt;p&gt;You will fall somewhere along this spectrum.
Most likely somewhere between the first and second.
I am here as a counterbalance.
To show you why you should care about your documents.
But mainly I'm here to gush about typefaces.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning, unqualified pretentious font talk ahead!&lt;/strong&gt;&lt;/p&gt;
&lt;a name='words-count'&gt;&lt;/a&gt;&lt;h1&gt;Words Count&lt;/h1&gt;
&lt;p&gt;A good typeface can elevate a document to something more than the sum of its parts.
A typeface has one purpose, to present text on a page for it to be read.
But it is the way in which it achieves this purpose where there is space.
Space for creativity, for expression, for sentiment.
When I make a document that I want to present, I want that document to say something about me.&lt;/p&gt;
&lt;p&gt;The written word is a decidedly constrictive medium for visual creativity.
Especially when those words are part of a dull report, or distinctly verbose thesis.
The writing itself is the star of the show of course, but that show should be presented in as grand a theatre as possible.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/calibri-times-orwell.svg" alt="Calibri against Times New Roman" /&gt;&lt;/p&gt;
&lt;p&gt;Here I have the same line in the two stalwarts of Microsoft Office, &lt;a href="https://en.wikipedia.org/wiki/Times_New_Roman"&gt;Times New Roman&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Calibri"&gt;Calibri&lt;/a&gt;.
These typefaces lay at opposite ends of design language. One is a traditional Roman style serif designed for a newspaper in the '30s, but inspired by the likes of &lt;a href="https://en.wikipedia.org/wiki/Baskerville"&gt;Baskerville&lt;/a&gt; from the 18th century.
The other is a humanist sans-serif, designed for digital displays, with edges smooth enough to leave near small children.
Each of these have their place (probably), but it is inarguable that Times gives a more powerful presentation of the words of &lt;a href="https://en.wikipedia.org/wiki/Nineteen_Eighty-Four"&gt;INGSOC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a rather extreme example.
Typefaces, like any art, mostly boil down to taste and personal preference.
As much as I dislike Calibri, I respect someone's choice to use it.
The problem is, people very rarely &lt;em&gt;choose&lt;/em&gt; it.
They use it because they didn't make a choice, and apathy is the fashion of the meek.
If there is one thing I want you to get from this article, it is to make a choice.
Let every part of your document's aesthetic be a conscious decision, own your typography.&lt;/p&gt;
&lt;a name='ibm-plex-sans'&gt;&lt;/a&gt;&lt;h1&gt;IBM Plex Sans&lt;/h1&gt;
&lt;p&gt;As an example of a conscious font choice, I present my use of &lt;a href="https://fonts.google.com/specimen/IBM+Plex+Sans"&gt;IBM Plex Sans&lt;/a&gt; in bold as something I commonly use as a heading font.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/IBM-Plex.svg" alt="IBM Plex Sans" /&gt;&lt;/p&gt;
&lt;p&gt;I adore the era of computing when teletypes reigned supreme and graphics were optional.
I wouldn't like to live then, you understand.
Much in the same way that people idolise the wild west, when in reality it was organised crime mixed with dysentery.
I just like the smell I get in my ears when I look at the photographs.&lt;/p&gt;
&lt;p&gt;Four of the biggest players in computing during this era were &lt;a href="https://en.wikipedia.org/wiki/IBM"&gt;IBM&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Digital_Equipment_Corporation"&gt;DEC&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Bell_Labs"&gt;Bell Labs&lt;/a&gt; (owned by &lt;a href="https://en.wikipedia.org/wiki/AT%26T"&gt;AT&amp;amp;T&lt;/a&gt;), and &lt;a href="https://en.wikipedia.org/wiki/General_Electric"&gt;General Electric&lt;/a&gt;. 
IBM were the largest, they developed the first mainframe computers that could be sold in large (for the time) numbers.&lt;/p&gt;
&lt;p&gt;Bell Labs were the research powerhouse of the industry. 
The shear importance of Bell Labs in the history of science and computing cannot be overstated. 
The transistor, the cosmic microwave background radiation, the laser, the CCD, the concept of bits, C, C++, Unix, nine Nobel Prizes, five turing awards...
The list of achievements is astounding and is worthy of several documentaries.&lt;/p&gt;
&lt;p&gt;The GE computing division (later sold to &lt;a href="https://en.wikipedia.org/wiki/Honeywell"&gt;Honeywell&lt;/a&gt;) and DEC were not as large as IBM but still formed two of &lt;a href="https://en.wikipedia.org/wiki/BUNCH"&gt;DeBUNCH&lt;/a&gt; of IBM competitors.&lt;/p&gt;
&lt;p&gt;By &lt;a href="https://money.cnn.com/magazines/fortune/fortune500_archive/full/1988/index.html"&gt;1988&lt;/a&gt;, the 5 of them would represent the 4th, 6th, 8th, 28th, and 38th largest companies in America.
They were by far the largest technology companies of their day and represented the dawn of the information age.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/ibm-bell-labs.png" alt="IBM System/360 manual and the Bell System Technical Journal" /&gt;&lt;/p&gt;
&lt;p&gt;This duality of being the cutting edge modernity and being multinational corporations came through in their typography.
Above are excerpts from the &lt;a href="https://ieeexplore.ieee.org/document/6770689"&gt;Bell System Technical Journal of December 1979&lt;/a&gt;, the &lt;a href="http://bitsavers.trailing-edge.com/pdf/ibm/360/princOps/A22-6821-0_360PrincOps.pdf"&gt;IBM System/360 user manual&lt;/a&gt;, the &lt;a href="http://bitsavers.org/pdf/ge/GE-645/LSB0468_GE-645_System_Manual_Jan1968.pdf"&gt;GE-645 system manual&lt;/a&gt;, and the &lt;a href="http://www.bitsavers.org/pdf/dec/pdp11/handbooks/PDP-11_Processor_Handbook_1981.pdf"&gt;PDP-11 Processor handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bell and DEC are using the &lt;a href="https://fonts.google.com/knowledge/glossary/grotesque_neo_grotesque"&gt;Neo-Grotesque&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Helvetica"&gt;Helvetica&lt;/a&gt;, with IBM and G.E using the &lt;a href="https://fonts.google.com/knowledge/glossary/geometric"&gt;Geometric&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Futura_(typeface)"&gt;Futura&lt;/a&gt;.&lt;/p&gt;
&lt;a name='helvetica'&gt;&lt;/a&gt;&lt;h2&gt;Helvetica&lt;/h2&gt;
&lt;p&gt;Helvetica is a typeface that is both lauded and besmirched.
Its design is heralded, but it's use as the symbol of modern corporate America meant it hit a level of saturation that has left a sour taste in the mouth of those from a prior generation.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/helvetica.svg" alt="Uses of Helvetica" /&gt;&lt;/p&gt;
&lt;p&gt;And they are perfectly correct of course.
Helvetica found an audience in the large companies of the 80s and 90s.
It is non-confrontational, it has no outlandish flair.
And the absence of serifs along with its Swiss modernism moves it away from the archaic &lt;a href="https://en.wikipedia.org/wiki/Garamond"&gt;Garamonds&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Caslon"&gt;Caslons&lt;/a&gt; of the world.
But I think that its use amongst the billion-dollar conglomerates of yesteryear should not be a reason to dismiss this typeface.&lt;/p&gt;
&lt;p&gt;For a start, the saturation of Helvetica means that brands have began to move away from it.
&lt;a href="https://www.dezeen.com/2013/01/21/american-airlines-debuts-new-logo-and-livery/"&gt;American Airlines&lt;/a&gt; changed its font in 2013.
And today's major companies (Google, Tesla, Microsoft) no longer see it as representing modernity.
So perhaps it's reasonable to look at why Helvetica was used in the first place.&lt;/p&gt;
&lt;img src="/static/postimages/for-fonts-in-my-life/porsche.jpg" alt="Porsche poster" height="400px"&gt;
&lt;p&gt;The strength of helvetica is in the way it can hold its own on a page.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/helvetica-gill-porsche.svg" alt="Helvetica against Gill Sans" /&gt;&lt;/p&gt;
&lt;p&gt;If we compare it against the &lt;a href="https://fonts.google.com/knowledge/glossary/humanist_old_style"&gt;Humanist&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Gill_Sans"&gt;Gill Sans&lt;/a&gt;, I just feel it sits so much better.
It brings an air of German functionalist efficiency that Gill Sans doesn't.&lt;/p&gt;
&lt;p&gt;The stand-out character in Helvetica is the capital R.
Helvetica feels placed, in position, structurally sound.
One of the reasons for this is the way all of its terminals are either perfectly vertical or horizontal.
Look at the way the C opposes itself, the tail of the y facing left, and the s finishing straight up and straight down.
Helvetica locks itself into place with these, it grabs the page.&lt;/p&gt;
&lt;p&gt;On the other hand, Gill Sans, and a lot of humanist typefaces, feel like they're ever so slightly about to fall over.
They seem to me like they always need one more letter next to it just to support the previous one.
Of course, this run-on nature makes them wonderful for &lt;a href="https://en.wikipedia.org/wiki/Body_text"&gt;body text&lt;/a&gt;.
They allow text to flow easily, whereas the rigid nature of helvetica is slightly too uniform to make it nice to read in large chunks.
For header text though, Helvetica can reign supreme.&lt;/p&gt;
&lt;a name='futura'&gt;&lt;/a&gt;&lt;h2&gt;Futura&lt;/h2&gt;
&lt;p&gt;Speaking of &lt;a href="https://en.wikipedia.org/wiki/Supreme_(brand)"&gt;Supreme&lt;/a&gt;, Futura.
It is what is known as a geometric typeface, it's characters are formed from circles and straight lines.
It's foundations in geometry make it a perennial staple in anything wanting to convey as modern or futuristic.
&lt;a href="https://www.pixartprinting.co.uk/blog/wes-andersons-fonts/"&gt;Wes Anderson&lt;/a&gt;, &lt;a href="https://typographica.org/on-typography/stanley-kubrick-fan-of-futura/"&gt;Stanley Kubrick&lt;/a&gt;, and &lt;a href="https://www.wired.co.uk/gallery/futura-font-on-the-moon-christopher-burke-book"&gt;NASA&lt;/a&gt; have all made extensive use of its sharp angles and perfect curves.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/futura.svg" alt="Futura" /&gt;&lt;/p&gt;
&lt;p&gt;It's easy to see why it is so popular.
It just screams technology.
It's abstract characters redefine type in terms of mathematics and the result is something notably artificial.&lt;/p&gt;
&lt;a name='man-and-machine'&gt;&lt;/a&gt;&lt;h2&gt;Man and Machine&lt;/h2&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/font-comparison.svg" alt="IBM Plex Sans" /&gt;
IBM Plex falls into the category of &lt;a href="https://fonts.google.com/knowledge/glossary/grotesque_neo_grotesque"&gt;Grotesque&lt;/a&gt; fonts.
It shares quite a few similarities with Helvetica and its predecessor &lt;a href="https://en.wikipedia.org/wiki/Akzidenz-Grotesk"&gt;Akzidenz-Grotesque&lt;/a&gt;.
The main similarity it has with Akzidenz and Futura over Helvetica is its more gothic R with a diagonal leg.&lt;/p&gt;
&lt;p&gt;Although it does not share any letter forms with Futura, IBM plex still has a distinct geometric machined quality.
Its &lt;a href="https://fonts.google.com/knowledge/glossary/counter"&gt;counters&lt;/a&gt; are not perfect circles, but they're not the ovals of more Humanist or Grotesque typefaces either.
Characters like C, G, O, and Q all have a stadium shaped counter. 
Not an elemental shape but still with foundations in geometry.
The central &amp;quot;pipe&amp;quot; like leg also has an artificial quality but once again has its roots in machinery rather than formal design.
The only real Humanist design choice is the &lt;a href="https://en.wikipedia.org/wiki/G#/media/File:LowercaseG.svg"&gt;double-storey&lt;/a&gt; g.
A strange decision thematically, but I think it's little pipe ear is quite charming.&lt;/p&gt;
&lt;p&gt;IBM have created a typeface that harks back to the pre-digital age.
Just like IBM, the grotesque typeface was born out of the Industrial era and found its greatest success between the 50s and 90s (with Helvetica).
It's machined nature doesn't distract either.
It manages to be contemporary without being sleek.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/porsche-plex.svg" alt="IBM Plex Sans Nobody's Perfect" /&gt;&lt;/p&gt;
&lt;a name='charter'&gt;&lt;/a&gt;&lt;h1&gt;Charter&lt;/h1&gt;
&lt;p&gt;Into the realm of &lt;a href="https://fonts.google.com/knowledge/glossary/serif"&gt;serifs&lt;/a&gt;, more specifically serif body typefaces.
I'm more of a fan of using a serif for the main text of a document.
Some people say it is more readable, I just feel it fits with my more classic, timeless aesthetic.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/serif-comparison.svg" alt="IBM Plex Sans Nobody's Perfect" /&gt;
Serifs can get a bit tricky to get right because it depends on the context.
Something like &lt;a href="https://en.wikipedia.org/wiki/Baskerville"&gt;Baskerville&lt;/a&gt; looks quite beautiful in print.
Its serifs taper thin, and it has a very high &lt;a href="https://fonts.google.com/knowledge/glossary/contrast"&gt;stroke contrast&lt;/a&gt; that shines on the page of a book.
To see what I mean, look at the capital A.
The left hand side is much thinner than the right.&lt;/p&gt;
&lt;p&gt;The problem with these older typefaces, designed to look great on paper, is they don't transfer to the digital screen very well.
At the lower detail densities of screens, these thin strokes can become hard to read and harm legibility.
You will notice that modern serif typefaces designed for screens or home laser printers will have much lower stroke contrast.
They also tend to have a slightly higher &lt;a href="https://en.wikipedia.org/wiki/X-height"&gt;x-height&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The obvious pairing for IBM Plex Sans should be &lt;a href="https://fonts.google.com/specimen/IBM+Plex+Serif"&gt;IBM Plex Serif&lt;/a&gt;, right?
Well it left me feeling a bit cold.
I can imagine using it for UI, but overall I can't gel with its modernism.
Its &lt;a href="https://en.wikipedia.org/wiki/Bodoni"&gt;Bodoni-style&lt;/a&gt; sharp, rectangle serifs feel a bit too geometric for me.
It also has a reasonably tall x-height, moving away from the traditional look that I want.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Bitstream_Charter"&gt;Charter&lt;/a&gt; strikes a good middle-ground.
Its x-height is a bit shorter, it's serifs tapered (but not excessively), and a slightly thinner average stroke width from something like &lt;a href="https://en.wikipedia.org/wiki/Georgia_(typeface)"&gt;Georgia&lt;/a&gt; (Also by Matthew Carter).&lt;/p&gt;
&lt;p&gt;Of course, I'll chop and change things depending on what a document should look like, but I hope I've given you enough of an introduction into typefaces that you may dip your toe into something other than the default.
If you want more guidance on things other than typography then I can't recommend &lt;a href="https://practicaltypography.com"&gt;Butterick's Practical Typography&lt;/a&gt; enough.&lt;/p&gt;
&lt;p&gt;And just for the sake of it, here are some more honorable font mentions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serif&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Source+Serif+Pro"&gt;Adobe Source Serif Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Lora?category=Serif"&gt;Lora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Century_type_family"&gt;Century Schoolbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fontsquirrel.com/fonts/latin-modern-roman"&gt;Latin Modern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sans-serif&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Source+Sans+Pro"&gt;Source Sans Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Inter"&gt;Inter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Josefin+Sans"&gt;Josefin Sans&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded>&lt;img class='post-hero' src='/static/postimages/for-fonts-in-my-life/header.png' alt='&lt;div&gt;For Fonts in My Life&lt;/div&gt;
'/&gt;&lt;h1 class='post-title'&gt;&lt;div&gt;For Fonts in My Life&lt;/div&gt;
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;Header image by &lt;a href="https://awright.dev"&gt;Andrew Wright&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is dissertation writing season at University, and this means one thing, document creation.
There are a few schools of thought when it comes to document creation.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-office-clerk&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The Office Clerk&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;A person who will use 12pt &lt;a href="https://en.wikipedia.org/wiki/Calibri"&gt;Calibri&lt;/a&gt;, have headings in 'Blue, Accent 1', and submit it as a &lt;code&gt;.docx&lt;/code&gt; file if they can.
Likely records videos in portrait.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-wysiwyg-wizards&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The WYSIWYG Wizards&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;Someone who still uses Microsoft Office but will change font, margins, bullet styles, and may even go as far as designing a custom template.&lt;/p&gt;
&lt;a name='&lt;em&gt;the-typesetters&lt;/em&gt;'&gt;&lt;/a&gt;&lt;h4&gt;&lt;em&gt;The Typesetters&lt;/em&gt;&lt;/h4&gt;
&lt;p&gt;Someone who uses dedicated document preparation software.
Will spend hours searching for the correct typeface.
They spend more time on formatting than on writing.
Do not mention Arial in the company of this person.&lt;/p&gt;
&lt;p&gt;You will fall somewhere along this spectrum.
Most likely somewhere between the first and second.
I am here as a counterbalance.
To show you why you should care about your documents.
But mainly I'm here to gush about typefaces.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning, unqualified pretentious font talk ahead!&lt;/strong&gt;&lt;/p&gt;
&lt;a name='words-count'&gt;&lt;/a&gt;&lt;h1&gt;Words Count&lt;/h1&gt;
&lt;p&gt;A good typeface can elevate a document to something more than the sum of its parts.
A typeface has one purpose, to present text on a page for it to be read.
But it is the way in which it achieves this purpose where there is space.
Space for creativity, for expression, for sentiment.
When I make a document that I want to present, I want that document to say something about me.&lt;/p&gt;
&lt;p&gt;The written word is a decidedly constrictive medium for visual creativity.
Especially when those words are part of a dull report, or distinctly verbose thesis.
The writing itself is the star of the show of course, but that show should be presented in as grand a theatre as possible.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/calibri-times-orwell.svg" alt="Calibri against Times New Roman" /&gt;&lt;/p&gt;
&lt;p&gt;Here I have the same line in the two stalwarts of Microsoft Office, &lt;a href="https://en.wikipedia.org/wiki/Times_New_Roman"&gt;Times New Roman&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Calibri"&gt;Calibri&lt;/a&gt;.
These typefaces lay at opposite ends of design language. One is a traditional Roman style serif designed for a newspaper in the '30s, but inspired by the likes of &lt;a href="https://en.wikipedia.org/wiki/Baskerville"&gt;Baskerville&lt;/a&gt; from the 18th century.
The other is a humanist sans-serif, designed for digital displays, with edges smooth enough to leave near small children.
Each of these have their place (probably), but it is inarguable that Times gives a more powerful presentation of the words of &lt;a href="https://en.wikipedia.org/wiki/Nineteen_Eighty-Four"&gt;INGSOC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a rather extreme example.
Typefaces, like any art, mostly boil down to taste and personal preference.
As much as I dislike Calibri, I respect someone's choice to use it.
The problem is, people very rarely &lt;em&gt;choose&lt;/em&gt; it.
They use it because they didn't make a choice, and apathy is the fashion of the meek.
If there is one thing I want you to get from this article, it is to make a choice.
Let every part of your document's aesthetic be a conscious decision, own your typography.&lt;/p&gt;
&lt;a name='ibm-plex-sans'&gt;&lt;/a&gt;&lt;h1&gt;IBM Plex Sans&lt;/h1&gt;
&lt;p&gt;As an example of a conscious font choice, I present my use of &lt;a href="https://fonts.google.com/specimen/IBM+Plex+Sans"&gt;IBM Plex Sans&lt;/a&gt; in bold as something I commonly use as a heading font.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/IBM-Plex.svg" alt="IBM Plex Sans" /&gt;&lt;/p&gt;
&lt;p&gt;I adore the era of computing when teletypes reigned supreme and graphics were optional.
I wouldn't like to live then, you understand.
Much in the same way that people idolise the wild west, when in reality it was organised crime mixed with dysentery.
I just like the smell I get in my ears when I look at the photographs.&lt;/p&gt;
&lt;p&gt;Four of the biggest players in computing during this era were &lt;a href="https://en.wikipedia.org/wiki/IBM"&gt;IBM&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Digital_Equipment_Corporation"&gt;DEC&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Bell_Labs"&gt;Bell Labs&lt;/a&gt; (owned by &lt;a href="https://en.wikipedia.org/wiki/AT%26T"&gt;AT&amp;amp;T&lt;/a&gt;), and &lt;a href="https://en.wikipedia.org/wiki/General_Electric"&gt;General Electric&lt;/a&gt;. 
IBM were the largest, they developed the first mainframe computers that could be sold in large (for the time) numbers.&lt;/p&gt;
&lt;p&gt;Bell Labs were the research powerhouse of the industry. 
The shear importance of Bell Labs in the history of science and computing cannot be overstated. 
The transistor, the cosmic microwave background radiation, the laser, the CCD, the concept of bits, C, C++, Unix, nine Nobel Prizes, five turing awards...
The list of achievements is astounding and is worthy of several documentaries.&lt;/p&gt;
&lt;p&gt;The GE computing division (later sold to &lt;a href="https://en.wikipedia.org/wiki/Honeywell"&gt;Honeywell&lt;/a&gt;) and DEC were not as large as IBM but still formed two of &lt;a href="https://en.wikipedia.org/wiki/BUNCH"&gt;DeBUNCH&lt;/a&gt; of IBM competitors.&lt;/p&gt;
&lt;p&gt;By &lt;a href="https://money.cnn.com/magazines/fortune/fortune500_archive/full/1988/index.html"&gt;1988&lt;/a&gt;, the 5 of them would represent the 4th, 6th, 8th, 28th, and 38th largest companies in America.
They were by far the largest technology companies of their day and represented the dawn of the information age.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/ibm-bell-labs.png" alt="IBM System/360 manual and the Bell System Technical Journal" /&gt;&lt;/p&gt;
&lt;p&gt;This duality of being the cutting edge modernity and being multinational corporations came through in their typography.
Above are excerpts from the &lt;a href="https://ieeexplore.ieee.org/document/6770689"&gt;Bell System Technical Journal of December 1979&lt;/a&gt;, the &lt;a href="http://bitsavers.trailing-edge.com/pdf/ibm/360/princOps/A22-6821-0_360PrincOps.pdf"&gt;IBM System/360 user manual&lt;/a&gt;, the &lt;a href="http://bitsavers.org/pdf/ge/GE-645/LSB0468_GE-645_System_Manual_Jan1968.pdf"&gt;GE-645 system manual&lt;/a&gt;, and the &lt;a href="http://www.bitsavers.org/pdf/dec/pdp11/handbooks/PDP-11_Processor_Handbook_1981.pdf"&gt;PDP-11 Processor handbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bell and DEC are using the &lt;a href="https://fonts.google.com/knowledge/glossary/grotesque_neo_grotesque"&gt;Neo-Grotesque&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Helvetica"&gt;Helvetica&lt;/a&gt;, with IBM and G.E using the &lt;a href="https://fonts.google.com/knowledge/glossary/geometric"&gt;Geometric&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Futura_(typeface)"&gt;Futura&lt;/a&gt;.&lt;/p&gt;
&lt;a name='helvetica'&gt;&lt;/a&gt;&lt;h2&gt;Helvetica&lt;/h2&gt;
&lt;p&gt;Helvetica is a typeface that is both lauded and besmirched.
Its design is heralded, but it's use as the symbol of modern corporate America meant it hit a level of saturation that has left a sour taste in the mouth of those from a prior generation.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/helvetica.svg" alt="Uses of Helvetica" /&gt;&lt;/p&gt;
&lt;p&gt;And they are perfectly correct of course.
Helvetica found an audience in the large companies of the 80s and 90s.
It is non-confrontational, it has no outlandish flair.
And the absence of serifs along with its Swiss modernism moves it away from the archaic &lt;a href="https://en.wikipedia.org/wiki/Garamond"&gt;Garamonds&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Caslon"&gt;Caslons&lt;/a&gt; of the world.
But I think that its use amongst the billion-dollar conglomerates of yesteryear should not be a reason to dismiss this typeface.&lt;/p&gt;
&lt;p&gt;For a start, the saturation of Helvetica means that brands have began to move away from it.
&lt;a href="https://www.dezeen.com/2013/01/21/american-airlines-debuts-new-logo-and-livery/"&gt;American Airlines&lt;/a&gt; changed its font in 2013.
And today's major companies (Google, Tesla, Microsoft) no longer see it as representing modernity.
So perhaps it's reasonable to look at why Helvetica was used in the first place.&lt;/p&gt;
&lt;img src="/static/postimages/for-fonts-in-my-life/porsche.jpg" alt="Porsche poster" height="400px"&gt;
&lt;p&gt;The strength of helvetica is in the way it can hold its own on a page.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/helvetica-gill-porsche.svg" alt="Helvetica against Gill Sans" /&gt;&lt;/p&gt;
&lt;p&gt;If we compare it against the &lt;a href="https://fonts.google.com/knowledge/glossary/humanist_old_style"&gt;Humanist&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Gill_Sans"&gt;Gill Sans&lt;/a&gt;, I just feel it sits so much better.
It brings an air of German functionalist efficiency that Gill Sans doesn't.&lt;/p&gt;
&lt;p&gt;The stand-out character in Helvetica is the capital R.
Helvetica feels placed, in position, structurally sound.
One of the reasons for this is the way all of its terminals are either perfectly vertical or horizontal.
Look at the way the C opposes itself, the tail of the y facing left, and the s finishing straight up and straight down.
Helvetica locks itself into place with these, it grabs the page.&lt;/p&gt;
&lt;p&gt;On the other hand, Gill Sans, and a lot of humanist typefaces, feel like they're ever so slightly about to fall over.
They seem to me like they always need one more letter next to it just to support the previous one.
Of course, this run-on nature makes them wonderful for &lt;a href="https://en.wikipedia.org/wiki/Body_text"&gt;body text&lt;/a&gt;.
They allow text to flow easily, whereas the rigid nature of helvetica is slightly too uniform to make it nice to read in large chunks.
For header text though, Helvetica can reign supreme.&lt;/p&gt;
&lt;a name='futura'&gt;&lt;/a&gt;&lt;h2&gt;Futura&lt;/h2&gt;
&lt;p&gt;Speaking of &lt;a href="https://en.wikipedia.org/wiki/Supreme_(brand)"&gt;Supreme&lt;/a&gt;, Futura.
It is what is known as a geometric typeface, it's characters are formed from circles and straight lines.
It's foundations in geometry make it a perennial staple in anything wanting to convey as modern or futuristic.
&lt;a href="https://www.pixartprinting.co.uk/blog/wes-andersons-fonts/"&gt;Wes Anderson&lt;/a&gt;, &lt;a href="https://typographica.org/on-typography/stanley-kubrick-fan-of-futura/"&gt;Stanley Kubrick&lt;/a&gt;, and &lt;a href="https://www.wired.co.uk/gallery/futura-font-on-the-moon-christopher-burke-book"&gt;NASA&lt;/a&gt; have all made extensive use of its sharp angles and perfect curves.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/futura.svg" alt="Futura" /&gt;&lt;/p&gt;
&lt;p&gt;It's easy to see why it is so popular.
It just screams technology.
It's abstract characters redefine type in terms of mathematics and the result is something notably artificial.&lt;/p&gt;
&lt;a name='man-and-machine'&gt;&lt;/a&gt;&lt;h2&gt;Man and Machine&lt;/h2&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/font-comparison.svg" alt="IBM Plex Sans" /&gt;
IBM Plex falls into the category of &lt;a href="https://fonts.google.com/knowledge/glossary/grotesque_neo_grotesque"&gt;Grotesque&lt;/a&gt; fonts.
It shares quite a few similarities with Helvetica and its predecessor &lt;a href="https://en.wikipedia.org/wiki/Akzidenz-Grotesk"&gt;Akzidenz-Grotesque&lt;/a&gt;.
The main similarity it has with Akzidenz and Futura over Helvetica is its more gothic R with a diagonal leg.&lt;/p&gt;
&lt;p&gt;Although it does not share any letter forms with Futura, IBM plex still has a distinct geometric machined quality.
Its &lt;a href="https://fonts.google.com/knowledge/glossary/counter"&gt;counters&lt;/a&gt; are not perfect circles, but they're not the ovals of more Humanist or Grotesque typefaces either.
Characters like C, G, O, and Q all have a stadium shaped counter. 
Not an elemental shape but still with foundations in geometry.
The central &amp;quot;pipe&amp;quot; like leg also has an artificial quality but once again has its roots in machinery rather than formal design.
The only real Humanist design choice is the &lt;a href="https://en.wikipedia.org/wiki/G#/media/File:LowercaseG.svg"&gt;double-storey&lt;/a&gt; g.
A strange decision thematically, but I think it's little pipe ear is quite charming.&lt;/p&gt;
&lt;p&gt;IBM have created a typeface that harks back to the pre-digital age.
Just like IBM, the grotesque typeface was born out of the Industrial era and found its greatest success between the 50s and 90s (with Helvetica).
It's machined nature doesn't distract either.
It manages to be contemporary without being sleek.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/porsche-plex.svg" alt="IBM Plex Sans Nobody's Perfect" /&gt;&lt;/p&gt;
&lt;a name='charter'&gt;&lt;/a&gt;&lt;h1&gt;Charter&lt;/h1&gt;
&lt;p&gt;Into the realm of &lt;a href="https://fonts.google.com/knowledge/glossary/serif"&gt;serifs&lt;/a&gt;, more specifically serif body typefaces.
I'm more of a fan of using a serif for the main text of a document.
Some people say it is more readable, I just feel it fits with my more classic, timeless aesthetic.&lt;/p&gt;
&lt;p&gt;&lt;img src="/static/postimages/for-fonts-in-my-life/serif-comparison.svg" alt="IBM Plex Sans Nobody's Perfect" /&gt;
Serifs can get a bit tricky to get right because it depends on the context.
Something like &lt;a href="https://en.wikipedia.org/wiki/Baskerville"&gt;Baskerville&lt;/a&gt; looks quite beautiful in print.
Its serifs taper thin, and it has a very high &lt;a href="https://fonts.google.com/knowledge/glossary/contrast"&gt;stroke contrast&lt;/a&gt; that shines on the page of a book.
To see what I mean, look at the capital A.
The left hand side is much thinner than the right.&lt;/p&gt;
&lt;p&gt;The problem with these older typefaces, designed to look great on paper, is they don't transfer to the digital screen very well.
At the lower detail densities of screens, these thin strokes can become hard to read and harm legibility.
You will notice that modern serif typefaces designed for screens or home laser printers will have much lower stroke contrast.
They also tend to have a slightly higher &lt;a href="https://en.wikipedia.org/wiki/X-height"&gt;x-height&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The obvious pairing for IBM Plex Sans should be &lt;a href="https://fonts.google.com/specimen/IBM+Plex+Serif"&gt;IBM Plex Serif&lt;/a&gt;, right?
Well it left me feeling a bit cold.
I can imagine using it for UI, but overall I can't gel with its modernism.
Its &lt;a href="https://en.wikipedia.org/wiki/Bodoni"&gt;Bodoni-style&lt;/a&gt; sharp, rectangle serifs feel a bit too geometric for me.
It also has a reasonably tall x-height, moving away from the traditional look that I want.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Bitstream_Charter"&gt;Charter&lt;/a&gt; strikes a good middle-ground.
Its x-height is a bit shorter, it's serifs tapered (but not excessively), and a slightly thinner average stroke width from something like &lt;a href="https://en.wikipedia.org/wiki/Georgia_(typeface)"&gt;Georgia&lt;/a&gt; (Also by Matthew Carter).&lt;/p&gt;
&lt;p&gt;Of course, I'll chop and change things depending on what a document should look like, but I hope I've given you enough of an introduction into typefaces that you may dip your toe into something other than the default.
If you want more guidance on things other than typography then I can't recommend &lt;a href="https://practicaltypography.com"&gt;Butterick's Practical Typography&lt;/a&gt; enough.&lt;/p&gt;
&lt;p&gt;And just for the sake of it, here are some more honorable font mentions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serif&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Source+Serif+Pro"&gt;Adobe Source Serif Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Lora?category=Serif"&gt;Lora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Century_type_family"&gt;Century Schoolbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fontsquirrel.com/fonts/latin-modern-roman"&gt;Latin Modern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sans-serif&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Source+Sans+Pro"&gt;Source Sans Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Inter"&gt;Inter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Josefin+Sans"&gt;Josefin Sans&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
      <pubDate>Sat, 11 Mar 2023 16:39:17 +0000</pubDate>
    </item>
  </channel>
</rss>
