Tinkering Tobias I'm Tobias Skarhed. This is my blog. I do some software development and is generally interested in learning things. 2023-04-10T00:00:00Z https://blog.skarhed.com Tobias Skarhed Using an Eleventy starter 2020-08-19T00:00:00Z https://blog.skarhed.com/using-an-eleventy-starter/ <p>For a long time I've wanted a blog that doesn't require any form of maintenance hosting-wise. I hate hosting stuff. Spinning up a VPS or something similar just to get a blog started is just not worth it. And it isn't free. I scrolled through some options and found Eleventy (11ty) as an alternative.</p> <p>The concept is that it supports a ton of template languages etc. which means a couple of things:</p> <ul> <li>You are the direct owner of the content. (Hinting a bit at Medium here).</li> <li>It is easy to transition to if you used anything other previously.</li> <li>It is future proof.</li> </ul> <h2 id="using-a-starter">Using a starter<a class="tdbc-anchor" href="https://blog.skarhed.com/using-an-eleventy-starter/#using-a-starter">#</a></h2> <p>I need to be honest with you - the documentation is way too technical when trying to get started with Eleventy. That's why I used a <a href="https://www.11ty.dev/docs/starter/">starter</a>.</p> <p>I chose a beautiful starter made by Stephanie Eckles, called <a href="https://github.com/5t3ph/11ty-netlify-jumpstart">11ty-netlify-jumpstart</a>. It has a very good &quot;getting started&quot; section.</p> <h2 id="making-it-my-own">Making it my own<a class="tdbc-anchor" href="https://blog.skarhed.com/using-an-eleventy-starter/#making-it-my-own">#</a></h2> <p>This starter is more of a static website type of deal, which is not really what I wanted. I was missing dates for the posts (and calling them posts).</p> <p>I extended the layout for the regular page by just adding a date at the top, creating a new page type called post. Pretty straight forward.</p> <pre class="language-js"><code class="language-js"><span class="token operator">--</span><span class="token operator">-</span><br /><span class="token literal-property property">layout</span><span class="token operator">:</span> page<span class="token punctuation">.</span>njk<br /><span class="token operator">--</span><span class="token operator">-</span></code></pre> <p>Voíla! That is it. I might do some minor changes further down the line, but this is good for now.</p> How I was hired at Grafana 2020-08-20T00:00:00Z https://blog.skarhed.com/how-I-was-hired-at-grafana/ <p>For the past couple of years I have spent my summers working at Grafana as a Software Engineer. The people there are amazing, and I feel like it is pure luck that I ended up there. I thought I'd tell the story about how I ended up there.</p> <h2 id="my-situation">My situation<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#my-situation">#</a></h2> <p>Back in the spring of 2018 I was told how much I was going to pay in taxes. It was quite a high amount for someone in their early 20's. I needed to get a job for the summer so I wouldn't have to walk around the coming year worrying about the bottom line.</p> <p>There was a problem. I didn't think about this until May, when applications for summer jobs usually close around february (for the big industrial companies). It was going to be a bit of a challenge.</p> <p>I had about 14 months of prior experience with full time front end development. I had written some stuff with Ember and learned React/Redux entirely on the job. I thought &quot;Someone probably needs someone who can write React&quot;.</p> <h2 id="the-opportunity">The opportunity<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-opportunity">#</a></h2> <p>For a couple of weeks I scoured the web for jobs to apply to. I sent an application to someone I had met at a networking event in Luleå. My friend Emil Tullstedt (Currently at Grafana), who worked at Tink at the time, told me to send one application there as well.</p> <p>While browsing LinkedIn semi-casually, I saw that Emil had like a post by someone named Carl Berquist that said something along the lines of:</p> <blockquote> <p>We're looking for a front end web developer</p> </blockquote> <p>I messaged Carl and asked if they were looking for summer interns. He came back to me the next day and we scheduled the interview a couple of days later.</p> <h2 id="the-interview">The interview<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-interview">#</a></h2> <p>This was a time before Grafana had some kind of HR or people working specifically with hiring. I think I only had one interview for that reason. Or maybe it was because a summer intern wasn't that much of a risky investment.</p> <p>Three people interviewed me: Daniel Lee, Carl Bergquist and Leonard Gram. We talked a little bit about my previous experience and what I studied.</p> <p>They told me my initial work would be</p> <ol> <li>Converting Karma tests to Jest</li> <li>Converting Angular to React</li> </ol> <p>There was a problem though. I didn't know Karma, Jest or Angular (I had only fiddled with it a little bit). But it didn't seem to worry them.</p> <p>A couple of days later I got the contract, which pretty much only stated my start date and my salary. Let's just say that it isn't the case any more.</p> <p>I think the time from initial contact to signed contract was about a week. Pretty impressive.</p> <h2 id="after-the-first-summer">After the first summer<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#after-the-first-summer">#</a></h2> <p>After the first summer I had successfully converted tests and removed Karma from the code base. Overall the people at Grafana seemed pleasantly surprised, which was new to me.</p> <h3 id="the-thoughtful-people-at-grafana">The thoughtful people at Grafana<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-thoughtful-people-at-grafana">#</a></h3> <p>I have had a couple of conversations with Daniel, and he is always good at giving some input so it is possible to see the broader picture. He could probably one day end up being one of those managment people who post smart quotes on Twitter that makes everybody say &quot;Wow, so true&quot; or &quot;How insightful!&quot;.</p> <p>I asked Daniel at the end of the first summer, since taking me in was quite a bet: &quot;What did you think when you hired me?&quot;</p> <blockquote> <p>Worst case scenario: we would have had one more person to eat lunch with.</p> </blockquote> <p>I should probably print that on a T-shirt</p> <p>Finally, I would like to share some wisdom Daniel shared with me:</p> <blockquote> <p>In case you would happen to work somewhere else, remember that good people tend to stick together</p> </blockquote> <p>Find the good people and stick around!</p> Giving great compliments 2020-08-31T00:00:00Z https://blog.skarhed.com/giving-great-compliments/ <p>I remember a compliment I received a couple of years ago. A friend, who happened to be a perfectionist said:</p> <blockquote> <p>You're like a painting that hangs straight</p> </blockquote> <p>It is one of the best compliments I have ever received. I started thinking; &quot;How can I make other people feel the same way?&quot;. Here are some of the conclusions I've made during the last couple of years.</p> <h2 id="be-genuine">Be genuine<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#be-genuine">#</a></h2> <p>Giving compliments just for the sake of it works to some extent. Let's face it; not many people are going to have a heartfelt moment by them getting to know how good looking their jacket is, It is a bit more of a courtesy thing, which is not the thing you are going for. You want to play music on their heart.</p> <p>How do you get there, though? Think about the person and in what ways they have positively affected you. It is a little bit like a gratitude exercise. Then you notice that it is usually about something they do, or something related to their personality.</p> <h2 id="the-key-components">The key components<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#the-key-components">#</a></h2> <p>I have tried to break down a compliment into two components. It is inspired by the components in <a href="https://sv.wikipedia.org/wiki/Nonviolent_Communication">Nonviolent Communication</a>.</p> <h3 id="behaviour-trait">Behaviour/trait<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#behaviour-trait">#</a></h3> <p>Be specific with what is positive about them. Some time you need to zoom in a bit.</p> <h3 id="feeling">Feeling<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#feeling">#</a></h3> <p>What does it make you feel? Warm? Good? Thankful? It doesn't have to be very complicated - it just has to be true!</p> <h3 id="your-perspective">Your perspective<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#your-perspective">#</a></h3> <p>This part is about communicating the difference that the feeling made. It could be about how you had a really shitty morning and that it all went away just because they said &quot;Hi!&quot; and gave you a very friendly smile.</p> <p>This part isn't required, but rather a way to reinforce the compliment by underlining how they made your life less shitty.</p> <h2 id="example">Example<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#example">#</a></h2> <blockquote> <p>The way I see you <em>actively listen</em> to people makes me feel so <em>hopeful</em> in these <em>uncertain times</em></p> </blockquote> <ol> <li>Active listening</li> <li>Hopefullness</li> <li>Express some kind of general worry about the state of things</li> </ol> <h2 id="become-better-at-receiving-compliments">Become better at receiving compliments<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#become-better-at-receiving-compliments">#</a></h2> <p>I used to have a hard time receiving compliments. I just brushed them off as it was nothing. That behaviour doesn't really encourage people to give you compliments.</p> <p>At the very least; stand up straight, look them in the eyes and say &quot;Thank you, I appreciate it!&quot;.</p> <h2 id="in-the-future">In the future...<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#in-the-future">#</a></h2> <p>...make some paintings hang straight! Practice giving compliments to people as soon as you notice something positive they do.</p> <p>Have a good one! /Tobias</p> Change your coding font to this. You can't believe what happens next! 2021-02-16T00:00:00Z https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/ <p>The clickbait title of this post entirely reflects its content. Just sayin'.</p> <p>Perhaps you haven't spent much time on deciding a good coding font. Maybe you did a quick Google search and ended up with Fira Code. It has ligatures after all. But there is one question you need to ask yourself: Is this you?</p> <p>Maybe you're just like me in the sense that I am like nobody else. You're unique. Why would you want to use a font that everybody else uses? Be a wildcard, live on the edge!</p> <blockquote> <p>You're unique</p> </blockquote> <p>My initial approach was to use Comic Sans to code with, but as some of you may know, it isn't monospaced or open and free (Couldn't figure out a good way to get it on Ubuntu)<sup class="footnote-ref"><a href="https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/#fn1" id="fnref1">[1]</a></sup>. So I went with the open modern <a href="https://coding-fonts.css-tricks.com/fonts/comic-neue/">Comic Neue</a>.</p> <p>It isn't monospaced, but it gets the job done. It completely lacks ligatures, something that <a href="https://github.com/tskarhed/comiccode/tree/master/ComicCode">I tried to fix with horrendous results</a>. I would recommend using the bold version for code. <img src="https://res.cloudinary.com/css-tricks/image/fetch/w_1600,q_auto,f_auto/https://coding-fonts.css-tricks.com/screenshots/comic-neue/html-dark.png" alt="Comic Neue code sample" /></p> <p>I still wasn't fully satisfied. I couldn't use Comic Neue in my VSCode terminal since it wasn't monospace. It just didn't cut it. I needed something monospaced, so that next time someone looks at my insanely skilled commands they will say &quot;Wow&quot;.</p> <blockquote> <p>It just didn't cut it</p> </blockquote> <p>I went on a far journey throughout the internet. For many days and nights I searched, finding nothing. Until one day when it looked like the darkest, I saw a glimpse of light. Drawing closer I could sense the magnificance, subtleness and softness of it. I had found <a href="https://github.com/shannpersand/comic-shanns">Comic Shanns</a>. I had finally found what I was looking for. Even though it lacks ligatures, it makes up for it with how beautiful it looks in the terminal.</p> <p><img src="https://res.cloudinary.com/css-tricks/image/fetch/w_1600,q_auto,f_auto/https://coding-fonts.css-tricks.com/screenshots/comic-shanns/js-dark.png" alt="Comic Shanns code sample" /></p> <p><a href="https://coding-fonts.css-tricks.com/fonts/comic-shanns/">Have a quick look at it!</a>! Your life will change for the better! I promise!</p> <p>Yours truly, Tobias Skarhed</p> <hr class="footnotes-sep" /> <section class="footnotes"> <ol class="footnotes-list"> <li id="fn1" class="footnote-item"><p>After writing this, Emil Tullstedt informed me that I can use <code>apt install ttf-mscorefonts-installer</code> <a href="https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/#fnref1" class="footnote-backref">↩︎</a></p> </li> </ol> </section> How to create a basic Chrome extension 2021-03-07T00:00:00Z https://blog.skarhed.com/chrome-extension-that-just-adds-css-and-js/ <p>The Chrome extension documentation is pretty extensive; there is a lot you can do with extensions. It is possible to run background scripts via web workers, interact with the Chrome API directly and call your own API's if that's what you want.</p> <p>That's not what I wanted. I wanted:</p> <ul> <li>Update the styles of a specific website</li> <li>Read and modify the DOM</li> </ul> <p>In this article I will use <a href="https://github.com/tskarhed/playpilot-imdb-extension">an extension I wrote</a> that inserts a search link on a movie's IMDb page, so you can figure where it is possible to buy or stream it.</p> <h2 id="the-chrome-extension-manifest">The Chrome Extension manifest<a class="tdbc-anchor" href="https://blog.skarhed.com/chrome-extension-that-just-adds-css-and-js/#the-chrome-extension-manifest">#</a></h2> <p>The manifest describes what the extension is about and what permission are needed. It also includes metadata such as name, description, screenshots and icons. We won't be focusing on the metadata. To get the basics of the manifest, see <a href="https://developer.chrome.com/docs/extensions/mv3/getstarted/#manifest">this part of Chrome Extension documentation</a>.</p> <p>The goal here is to insert our own script and our own CSS file into a webpage - this case being a n IMDb movie page. For this we are going to use content scripts, that the Chrome Extension documentation names in a very jargonny way as &quot;<a href="https://developer.chrome.com/docs/extensions/mv3/content_scripts/#static-declarative">inject with static declarations</a>&quot;.</p> <p>We want to inject the files in the same directory as our manifest called <code>contentScript.js</code> and <code>style.css</code>.</p> <pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Where to watch - Playpilot/IMDb"</span><span class="token punctuation">,</span><br /> ... <br /> <span class="token property">"content_scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><br /> <span class="token property">"matches"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"https://www.imdb.com/title/*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"js"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"contentScript.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"css"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"styles.css"</span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><span class="token punctuation">,</span><br /> ...<br /><span class="token punctuation">}</span></code></pre> <p><em>This is an excerpt from <a href="https://github.com/tskarhed/playpilot-imdb-extension/blob/main/manifest.json">my extension manifest</a></em>.</p> <p>This just tells us what CSS and Javascript files we want to load into what sites, <code>matches</code>. Notice that all of these are arrays, which means you can load multiple scripts and stylesheets onto multiplite sites.</p> <p>The key here, which was my point of failure, is the <code>matches</code> URLs. If you files don't load it is most likely due to that. In my case I didn't add the <code>www</code> for the URL. The wildcard <code>*</code> just tells us to match all URLs that begins with everything to the left.</p> <p>1,2,3, we're done! Now you just need to write an awesome script and some beautiful styles!</p> <p>Have a good one! -Tobias</p> Grafana alerting notifications in Mattermost 2022-08-03T00:00:00Z https://blog.skarhed.com/grafana-alert-notification-in-mattermost/ <p>Grafana is a tool for monitoring whatever you want. Sometimes when the stuff you monitor behaves weirdly or goes all haywire, you want a notification. You have set up your Grafana alert and a notification policy that sends an email to your grandmother.</p> <p>That Ol' Gran gets her information is great, but you are looking for something more modern that fits the 2020's lifestyle. You want something that is more like a frappucino rather than a black coffee with milk.</p> <p>Your team uses <a href="https://mattermost.com/">Mattermost</a>, which is an open source alternative to Slack with the option to self-host. This is the modern way to communicate. Here you already have some bots informing you about your CI/CD pipelines, curing your loneliness and one that pings you when Wheatley logs in. So adding another shouldn't be that hard.</p> <p>You think to yourself:</p> <blockquote> <p>Mattermost and Slack looks the same and acts the same, so there must be a Grafana contact point option for Mattermost too</p> </blockquote> <p>In your quest to the solution you do a quick Google search. Nothing. You feel the awful dread of impending doom creeping up on you, just like someone from Gen Z. On the far horizon - the second page of Google - you find this blog post shining at you like a sunrise.</p> <p>Here is how you do it:</p> <h2 id="setting-up-mattermost-webhook">Setting up Mattermost webhook<a class="tdbc-anchor" href="https://blog.skarhed.com/grafana-alert-notification-in-mattermost/#setting-up-mattermost-webhook">#</a></h2> <p>In the top left corner of your Mattermost, you can find a menu button. Click it. In the menu you find an option called <strong>Integrations</strong>.</p> <p>Here you want to go to <strong>Create incoming webhook</strong>. This will create the endpoint that Grafana will use. Select which channel you want the bot to write its messages in.</p> <p>In the form, there are two very important options, which should be filled like this:</p> <table> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody> <tr> <td>Username</td> <td>Grot (grafanabot)</td> </tr> <tr> <td>Profile Picture</td> <td>https://avatars.githubusercontent.com/u/43478413?v=4</td> </tr> </tbody> </table> <p>This is brings the fierce dinosaur <a href="https://github.com/grafanabot">Grot the Grafanabot</a> to life!</p> <p><img src="https://avatars.githubusercontent.com/u/43478413?v=4" alt="Grot the Grafanabot" /></p> <p>When you are done with the settings, save it and copy the URL that has been generated for you.</p> <h2 id="setting-up-grafana-contact-point">Setting up Grafana contact point<a class="tdbc-anchor" href="https://blog.skarhed.com/grafana-alert-notification-in-mattermost/#setting-up-grafana-contact-point">#</a></h2> <p>In Grafana you want to configure a contact point. In the menu to the left hover the bell icon (Alerting) and select contact points. Here you want to click &quot;New contact point&quot;.</p> <blockquote> <p>Here comes the sneaky part</p> </blockquote> <p>Under &quot;Contact point type&quot; select &quot;Slack&quot;. 🙀 We fooled the system people!</p> <p>Give the contact point a mandatory name and paste the URL you copied from the Mattermost webhook into &quot;Webhook URL&quot;. You can configure the rest if you want, but it is not necessary and will override the settings you have made in Mattermost.</p> <hr /> <p>You can now freely use your contact point under &quot;Notification policies&quot; and Grot the Grafanabot will pop up in a channel near you with some news!</p> <p>And granny will still get her email, of course.</p> <p>/Tobias</p> The healing power of running 2022-10-23T00:00:00Z https://blog.skarhed.com/the-healing-power-of-running/ <p>My left hip was in pain. The constant upphill struggle had but a lot of tension on my thigh. I was glad that I had manage to reach the highest point of the race. Four days previously I had been in bed with a cold, too tired to get up to do the dishes. It had taken its toll during the race. My pulse was way higher higher than usually, and after 12km my body started stopped working properly if the pulse was higher than 170bpm. With the help of my friends, I prevailed. I finished my first trail run race, 24km with 900m altitude gain, with wet weather conditions in the Jura mountains.</p> <p>I hadn't been running actively for three years, since I had shin splints. That was at a time where I felt ambitious, so I decided to aim at running a 10k in 40 minutes or under. The training schedule was very intense. I went from running 3 times per week at a reasonably comfortable intensity, to running 5-6 times per week with some very intense sessions. I would almost always run with sore muscles from the weekly leg workout. It paid off though, as after two months I started beating my 10k PR every week. It wasn't even my intention of doing it during those runs, since they were always interval runs. I looked at the statistics from Garmin, and it said that during October 2018, I logged 120km. Apparently this was at the top 1% of Garmin users. I recorded my journey through a <a href="https://www.youtube.com/channel/UCccgVg1UYwSA0NRqFpdaEog/videos">set of video logs.</a> I felt like a machine.</p> <p>Then came the shin splints. I did not have the tools to deal with it. I took a month off from running, to see if it would improve. It did not. In fact, my mental health worsened. Since starting university I had consistently been running three times per week, something which worked as a great protection against stress and studying performance. Running had been a way for me to manage whatever life decided to throw at me.</p> <p>Then came 2019. Probably the worst year of my life. Some things happened which threw me into a deep depression. I basically wouldn't leave bed for 5 months.</p> <p>The job I had during that summer was very helpful to me. My main task wasn't very mentally straining, which meat I could show up to work wihtout being fully mentally present, and still deliver value. More than that, I managed to have an 8km commute, which took me a month to actually make use of. I bought an old road bike to use for commuting every day. 16km per weekday for a month really brought me out of the darkness.</p> <p>However, when I returned to university, I struggled to keep up with the frequency. And I didn't have my bike there either. Most of the studying I did there was very half-assed, and I did several smaller attempts at getting back into running. I went to a physiotherapist, who gave me exercises to do every day. I never managed to fully commit, because of the great catch-22 of bad mental health. I can't start doing the things that help me do the thing I want, because I can't do the thing I want. Supposedly, this is why cognitive behavioural therapy works, even though it is more focused on initially doing things that used to make you happy.</p> <p>University wass a horrible psychosocial environment. For probably 1,5 years I walked to the lectures every day and said to myself &quot;it will be over soon&quot;. The darkness of the arctic certainly did not help.</p> <p>I managed the finish the required courses, and moved to the Geneva area for a studendship at CERN. This was the change of environment I needed. Leaving my apartment, I would see the Jura mountains to the north every day. I committed to running again, slowly increasing intensity as the physiotherapist had recommended. For a couple of months I mostly ran 2km per week. I slightly increased that at some point.</p> <p>One of my colleagues found UTMJ - a mountain marathon with a set of distances, 24km the shortest and the longest an ultra distance of something like 170km. We decided to sign up for the shortest distance. I saw this as my opportunity get back to actively training. My goal was to finish it, even if I had to walk the entire way. I wanted to come out on the other side being able to exercise three times per week. There was only one issues: we had one month to prepare.</p> <p>My colleague set up an initial training schedule, and I thought it was way too intense. I did some of the activisties, and from what you can expect with a great increase in training, things started hurting. My right knee to be exact. So I stopped doing things for a couple of days. This time it was different though. I wouldn't let it beat me. I Googled all methods I could use to treat it; specific exercises, stretches, support taping and anti-inflammatory cream. To my surprise, it worked. During the race my knee was taped, and I felt nothing from it.</p> <p>Me being older and heavier, probably means that I will feel pain more times. I am currently feeling something in my hip, from a very intense leg workout a little while ago. I have a different mindset this time around. Reach out for professional help if you can't manage to Google the answers, and don't let the pain destroy your momentum. Many times it helps with just changing up the routine and exercises.</p> <p>Hopefully this has been helpful to someone! Now I am preparing the BAMM, arctic mountain marathon next year!</p> <p>/Tobias</p> SSG framework for displaying music scores 2023-04-10T00:00:00Z https://blog.skarhed.com/ <p>Table of contents: </p><div class="table-of-contents"><ul><li><a href="https://blog.skarhed.com/#background">Background</a></li><li><a href="https://blog.skarhed.com/#requirements">Requirements</a></li><li><a href="https://blog.skarhed.com/#alternatives">Alternatives</a><ul><li><a href="https://blog.skarhed.com/#defining-metadata">Defining metadata</a></li><li><a href="https://blog.skarhed.com/#scripting-with-templating-language">Scripting with templating language</a></li><li><a href="https://blog.skarhed.com/#eleventy-11ty">Eleventy (11ty)</a></li><li><a href="https://blog.skarhed.com/#astro">Astro</a></li></ul></li></ul></div><p></p> <h2 id="background">Background<a class="tdbc-anchor" href="https://blog.skarhed.com/#background">#</a></h2> <p>At university I used to be a part of a classical male choir, which is traditional for Swedish universities, dating back to the early 1800s. Our choir is anything but traditional, but that subject may be covered at a later date ;)</p> <p>A lot of the repertoire in this genre is rather old, which makes it a prt of the public domain. A lot of famous composers have songs that still to this day are common to sing during Swedish traditional holidays. Prince Gustaf, Otto Lindblad and Hugo Alfvén are some of the most famous of these composers.</p> <p>A big part of this genre, which is tightly connected to universities, is &quot;snapsvisor&quot;; drinking songs commonly sung before taking a schnapps.</p> <p>Joakim Sandström, a previous conductor of my choir Snapsakademien, started a project where he wrote a lot of the classical songs in <a href="http://lilypond.org/">Lilypond</a>. This is a programming language that enables easy generation of music scores, usually in the form of PDFs. The initial purpose for this was to generate PDFs to combine them into a song book that could be used during a semester.</p> <p>Lilypond provide possibilities for output aswell. MIDI-files, a music file format known for producing simple music, can be generated, so the melody can be listened to while practicing. This is perfect especially for people like me who have a hard time reading notes!</p> <p>The library has grown enough to be useful beyond a single choir, so these scores can really be useful to publish alognside the MIDI-files.</p> <h2 id="requirements">Requirements<a class="tdbc-anchor" href="https://blog.skarhed.com/#requirements">#</a></h2> <p>Joakim Sandström is a happy volunteer that write these scores in his spare time. He has good knowledge of Lilypond, and even though he may understand the technical implementations of publishing the scores to the web, he shouldn't need to worry about it. Volunteer efforts are super important, and we should do anything in our power to not make any of these tasks more difficult or complex.</p> <p>We can do this assumption that the knowledge should extend to the Lilypond output files. This means that we can assume the following:</p> <ul> <li>Song information is known, such as title, composer or artist.</li> <li>Lilypond output file name is known</li> <li>Output file location is known</li> </ul> <p>Furthermore, in order to make a clear connection to the structure of the website, it should preferably reflect the structure of the repository.</p> <p>These are some other features we might want to consider:</p> <ol> <li>Easy way to list all the available songs</li> <li>Simple way to implement a search feature</li> <li>Categories or tags to group songs</li> </ol> <h2 id="alternatives">Alternatives<a class="tdbc-anchor" href="https://blog.skarhed.com/#alternatives">#</a></h2> <ol> <li>Scripting with templating language</li> <li>eleventy (11ty)</li> <li>Astro</li> </ol> <h3 id="defining-metadata">Defining metadata<a class="tdbc-anchor" href="https://blog.skarhed.com/#defining-metadata">#</a></h3> <p>All of these need some kind of input data, as it is not trivial to extract data from Lilypond files. The choice of defining metadata highly depends on which SSG solution is chosen. Some alternatives for defining data could be:</p> <h4>JSON files</h4> <pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"composer"</span><span class="token operator">:</span> <span class="token string">"Otto Lindblad"</span><span class="token punctuation">,</span><br /> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Längtan till landet"</span><span class="token punctuation">,</span><br /> <span class="token property">"categories"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"spring"</span><span class="token punctuation">,</span> <span class="token string">"1800s"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"svgFiles"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"./page-1.svg"</span><span class="token punctuation">,</span> <span class="token string">"./page-2.svg"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"midiFiles"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"./all.midi"</span><span class="token punctuation">,</span> <span class="token string">"./t1.midi"</span><span class="token punctuation">,</span> <span class="token string">"./t2.midi"</span><span class="token punctuation">,</span> <span class="token string">"./b1.midi"</span><span class="token punctuation">,</span> <span class="token string">"./b2.midi"</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span></code></pre> <h4>Frontmatter YAML in Markdown files</h4> <pre class="language-yml"><code class="language-yml"><span class="token punctuation">---</span><br /><span class="token key atrule">composer</span><span class="token punctuation">:</span> <span class="token string">"Otto Lindblad"</span><br /><span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">"Längtan till landet"</span><br /><span class="token key atrule">categories</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"spring"</span><span class="token punctuation">,</span> <span class="token string">"1800s"</span><span class="token punctuation">]</span><br /><span class="token key atrule">svgFiles</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"./page-1.svg"</span><span class="token punctuation">,</span> <span class="token string">"./page-2.svg"</span><span class="token punctuation">]</span><br /><span class="token key atrule">midiFiles</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> <span class="token string">"./all.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./t1.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./t2.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./b1.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./b2.midi"</span><br /><span class="token punctuation">---</span></code></pre> <h3 id="scripting-with-templating-language">Scripting with templating language<a class="tdbc-anchor" href="https://blog.skarhed.com/#scripting-with-templating-language">#</a></h3> <p>The actual templating languiage does not matter much, as long a s it takes some kind of object and processes it. A personal preference would be Handlebars or Mustache.</p> <p>For this, a script has to be written to traverse the folder structure and render the HTML files. This could be done with something like a bash script or a Node.js script.</p> <p>The good thing with this approach is the flexibility. However, as soon as we look at thge requirements we listed previosuly, the complexity quickly increases. If we use this approach, then we basically need to write our own Static Site Generator.</p> <p>Withoout proper though into the initial arcfhitecture, handling collections of songs kmight be difficult. Furthermore, search provides more complexity.</p> <p>If we consider the fact that this project is on a volunteer basis, we want as little code as possible to maintain. With the features we require, the codebase may quickly increase uin size.</p> <h3 id="eleventy-11ty">Eleventy (11ty)<a class="tdbc-anchor" href="https://blog.skarhed.com/#eleventy-11ty">#</a></h3> <p>11ty offers a wide variety of templating languages. It also has something called a &quot;data cascade&quot; which defines the different levels from where it may get data.</p> <p>The data may be defined in a YAML frontmatter, a use case which fits really well for writing blog posts. In the frontmatter things like <code>title</code>, <code>date</code> and <code>description</code> may be added, whereas in the actual body of the document, you can write Markdown. Neat!</p> <p>In our case we do not have any need to write Markdown, so we can use JSON files instead, just containing the metadata. In a folder with songs in JSON format, an index template is applied to those and the JSONs in subfolders.</p> <p>All scripting and shortcodes need to be written in the 11ty config. It is possible to extend it quite a lot, but the bare bones work really well without any scripting. The only issue here is that there needs to be consistent folder structure and naming conventions.</p> <h3 id="astro">Astro<a class="tdbc-anchor" href="https://blog.skarhed.com/#astro">#</a></h3> <p>Astro is one among many SSGs with supercharged templating, in this case powered by Javascript. In this case, YAML frontmatter is the only way to go. A downside is also that the layout for a spoecific post needs to be defined in each file, which breaks the promise that the Liliypond writer does nto need to know anything about the implementation.</p>
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Tinkering Tobias</title>
<subtitle>I'm Tobias Skarhed. This is my blog. I do some software development and is generally interested in learning things.</subtitle>
<link href="https://blog.skarhed.com/feed/" rel="self"/>
<link href="https://blog.skarhed.com"/>
<updated>2023-04-10T00:00:00Z</updated>
<id>https://blog.skarhed.com</id>
<author>
<name>Tobias Skarhed</name>
</author>
<entry>
<title>Using an Eleventy starter</title>
<link href="https://blog.skarhed.com/using-an-eleventy-starter/"/>
<updated>2020-08-19T00:00:00Z</updated>
<id>https://blog.skarhed.com/using-an-eleventy-starter/</id>
<content type="html"><p>For a long time I've wanted a blog that doesn't require any form of maintenance hosting-wise. I hate hosting stuff. Spinning up a VPS or something similar just to get a blog started is just not worth it. And it isn't free. I scrolled through some options and found Eleventy (11ty) as an alternative.</p> <p>The concept is that it supports a ton of template languages etc. which means a couple of things:</p> <ul> <li>You are the direct owner of the content. (Hinting a bit at Medium here).</li> <li>It is easy to transition to if you used anything other previously.</li> <li>It is future proof.</li> </ul> <h2 id="using-a-starter">Using a starter<a class="tdbc-anchor" href="https://blog.skarhed.com/using-an-eleventy-starter/#using-a-starter">#</a></h2> <p>I need to be honest with you - the documentation is way too technical when trying to get started with Eleventy. That's why I used a <a href="https://www.11ty.dev/docs/starter/">starter</a>.</p> <p>I chose a beautiful starter made by Stephanie Eckles, called <a href="https://github.com/5t3ph/11ty-netlify-jumpstart">11ty-netlify-jumpstart</a>. It has a very good &quot;getting started&quot; section.</p> <h2 id="making-it-my-own">Making it my own<a class="tdbc-anchor" href="https://blog.skarhed.com/using-an-eleventy-starter/#making-it-my-own">#</a></h2> <p>This starter is more of a static website type of deal, which is not really what I wanted. I was missing dates for the posts (and calling them posts).</p> <p>I extended the layout for the regular page by just adding a date at the top, creating a new page type called post. Pretty straight forward.</p> <pre class="language-js"><code class="language-js"><span class="token operator">--</span><span class="token operator">-</span><br /><span class="token literal-property property">layout</span><span class="token operator">:</span> page<span class="token punctuation">.</span>njk<br /><span class="token operator">--</span><span class="token operator">-</span></code></pre> <p>Voíla! That is it. I might do some minor changes further down the line, but this is good for now.</p> </content>
</entry>
<entry>
<title>How I was hired at Grafana</title>
<link href="https://blog.skarhed.com/how-I-was-hired-at-grafana/"/>
<updated>2020-08-20T00:00:00Z</updated>
<id>https://blog.skarhed.com/how-I-was-hired-at-grafana/</id>
<content type="html"><p>For the past couple of years I have spent my summers working at Grafana as a Software Engineer. The people there are amazing, and I feel like it is pure luck that I ended up there. I thought I'd tell the story about how I ended up there.</p> <h2 id="my-situation">My situation<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#my-situation">#</a></h2> <p>Back in the spring of 2018 I was told how much I was going to pay in taxes. It was quite a high amount for someone in their early 20's. I needed to get a job for the summer so I wouldn't have to walk around the coming year worrying about the bottom line.</p> <p>There was a problem. I didn't think about this until May, when applications for summer jobs usually close around february (for the big industrial companies). It was going to be a bit of a challenge.</p> <p>I had about 14 months of prior experience with full time front end development. I had written some stuff with Ember and learned React/Redux entirely on the job. I thought &quot;Someone probably needs someone who can write React&quot;.</p> <h2 id="the-opportunity">The opportunity<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-opportunity">#</a></h2> <p>For a couple of weeks I scoured the web for jobs to apply to. I sent an application to someone I had met at a networking event in Luleå. My friend Emil Tullstedt (Currently at Grafana), who worked at Tink at the time, told me to send one application there as well.</p> <p>While browsing LinkedIn semi-casually, I saw that Emil had like a post by someone named Carl Berquist that said something along the lines of:</p> <blockquote> <p>We're looking for a front end web developer</p> </blockquote> <p>I messaged Carl and asked if they were looking for summer interns. He came back to me the next day and we scheduled the interview a couple of days later.</p> <h2 id="the-interview">The interview<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-interview">#</a></h2> <p>This was a time before Grafana had some kind of HR or people working specifically with hiring. I think I only had one interview for that reason. Or maybe it was because a summer intern wasn't that much of a risky investment.</p> <p>Three people interviewed me: Daniel Lee, Carl Bergquist and Leonard Gram. We talked a little bit about my previous experience and what I studied.</p> <p>They told me my initial work would be</p> <ol> <li>Converting Karma tests to Jest</li> <li>Converting Angular to React</li> </ol> <p>There was a problem though. I didn't know Karma, Jest or Angular (I had only fiddled with it a little bit). But it didn't seem to worry them.</p> <p>A couple of days later I got the contract, which pretty much only stated my start date and my salary. Let's just say that it isn't the case any more.</p> <p>I think the time from initial contact to signed contract was about a week. Pretty impressive.</p> <h2 id="after-the-first-summer">After the first summer<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#after-the-first-summer">#</a></h2> <p>After the first summer I had successfully converted tests and removed Karma from the code base. Overall the people at Grafana seemed pleasantly surprised, which was new to me.</p> <h3 id="the-thoughtful-people-at-grafana">The thoughtful people at Grafana<a class="tdbc-anchor" href="https://blog.skarhed.com/how-I-was-hired-at-grafana/#the-thoughtful-people-at-grafana">#</a></h3> <p>I have had a couple of conversations with Daniel, and he is always good at giving some input so it is possible to see the broader picture. He could probably one day end up being one of those managment people who post smart quotes on Twitter that makes everybody say &quot;Wow, so true&quot; or &quot;How insightful!&quot;.</p> <p>I asked Daniel at the end of the first summer, since taking me in was quite a bet: &quot;What did you think when you hired me?&quot;</p> <blockquote> <p>Worst case scenario: we would have had one more person to eat lunch with.</p> </blockquote> <p>I should probably print that on a T-shirt</p> <p>Finally, I would like to share some wisdom Daniel shared with me:</p> <blockquote> <p>In case you would happen to work somewhere else, remember that good people tend to stick together</p> </blockquote> <p>Find the good people and stick around!</p> </content>
</entry>
<entry>
<title>Giving great compliments</title>
<link href="https://blog.skarhed.com/giving-great-compliments/"/>
<updated>2020-08-31T00:00:00Z</updated>
<id>https://blog.skarhed.com/giving-great-compliments/</id>
<content type="html"><p>I remember a compliment I received a couple of years ago. A friend, who happened to be a perfectionist said:</p> <blockquote> <p>You're like a painting that hangs straight</p> </blockquote> <p>It is one of the best compliments I have ever received. I started thinking; &quot;How can I make other people feel the same way?&quot;. Here are some of the conclusions I've made during the last couple of years.</p> <h2 id="be-genuine">Be genuine<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#be-genuine">#</a></h2> <p>Giving compliments just for the sake of it works to some extent. Let's face it; not many people are going to have a heartfelt moment by them getting to know how good looking their jacket is, It is a bit more of a courtesy thing, which is not the thing you are going for. You want to play music on their heart.</p> <p>How do you get there, though? Think about the person and in what ways they have positively affected you. It is a little bit like a gratitude exercise. Then you notice that it is usually about something they do, or something related to their personality.</p> <h2 id="the-key-components">The key components<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#the-key-components">#</a></h2> <p>I have tried to break down a compliment into two components. It is inspired by the components in <a href="https://sv.wikipedia.org/wiki/Nonviolent_Communication">Nonviolent Communication</a>.</p> <h3 id="behaviour-trait">Behaviour/trait<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#behaviour-trait">#</a></h3> <p>Be specific with what is positive about them. Some time you need to zoom in a bit.</p> <h3 id="feeling">Feeling<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#feeling">#</a></h3> <p>What does it make you feel? Warm? Good? Thankful? It doesn't have to be very complicated - it just has to be true!</p> <h3 id="your-perspective">Your perspective<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#your-perspective">#</a></h3> <p>This part is about communicating the difference that the feeling made. It could be about how you had a really shitty morning and that it all went away just because they said &quot;Hi!&quot; and gave you a very friendly smile.</p> <p>This part isn't required, but rather a way to reinforce the compliment by underlining how they made your life less shitty.</p> <h2 id="example">Example<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#example">#</a></h2> <blockquote> <p>The way I see you <em>actively listen</em> to people makes me feel so <em>hopeful</em> in these <em>uncertain times</em></p> </blockquote> <ol> <li>Active listening</li> <li>Hopefullness</li> <li>Express some kind of general worry about the state of things</li> </ol> <h2 id="become-better-at-receiving-compliments">Become better at receiving compliments<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#become-better-at-receiving-compliments">#</a></h2> <p>I used to have a hard time receiving compliments. I just brushed them off as it was nothing. That behaviour doesn't really encourage people to give you compliments.</p> <p>At the very least; stand up straight, look them in the eyes and say &quot;Thank you, I appreciate it!&quot;.</p> <h2 id="in-the-future">In the future...<a class="tdbc-anchor" href="https://blog.skarhed.com/giving-great-compliments/#in-the-future">#</a></h2> <p>...make some paintings hang straight! Practice giving compliments to people as soon as you notice something positive they do.</p> <p>Have a good one! /Tobias</p> </content>
</entry>
<entry>
<title>Change your coding font to this. You can't believe what happens next!</title>
<link href="https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/"/>
<updated>2021-02-16T00:00:00Z</updated>
<id>https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/</id>
<content type="html"><p>The clickbait title of this post entirely reflects its content. Just sayin'.</p> <p>Perhaps you haven't spent much time on deciding a good coding font. Maybe you did a quick Google search and ended up with Fira Code. It has ligatures after all. But there is one question you need to ask yourself: Is this you?</p> <p>Maybe you're just like me in the sense that I am like nobody else. You're unique. Why would you want to use a font that everybody else uses? Be a wildcard, live on the edge!</p> <blockquote> <p>You're unique</p> </blockquote> <p>My initial approach was to use Comic Sans to code with, but as some of you may know, it isn't monospaced or open and free (Couldn't figure out a good way to get it on Ubuntu)<sup class="footnote-ref"><a href="https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/#fn1" id="fnref1">[1]</a></sup>. So I went with the open modern <a href="https://coding-fonts.css-tricks.com/fonts/comic-neue/">Comic Neue</a>.</p> <p>It isn't monospaced, but it gets the job done. It completely lacks ligatures, something that <a href="https://github.com/tskarhed/comiccode/tree/master/ComicCode">I tried to fix with horrendous results</a>. I would recommend using the bold version for code. <img src="https://res.cloudinary.com/css-tricks/image/fetch/w_1600,q_auto,f_auto/https://coding-fonts.css-tricks.com/screenshots/comic-neue/html-dark.png" alt="Comic Neue code sample" /></p> <p>I still wasn't fully satisfied. I couldn't use Comic Neue in my VSCode terminal since it wasn't monospace. It just didn't cut it. I needed something monospaced, so that next time someone looks at my insanely skilled commands they will say &quot;Wow&quot;.</p> <blockquote> <p>It just didn't cut it</p> </blockquote> <p>I went on a far journey throughout the internet. For many days and nights I searched, finding nothing. Until one day when it looked like the darkest, I saw a glimpse of light. Drawing closer I could sense the magnificance, subtleness and softness of it. I had found <a href="https://github.com/shannpersand/comic-shanns">Comic Shanns</a>. I had finally found what I was looking for. Even though it lacks ligatures, it makes up for it with how beautiful it looks in the terminal.</p> <p><img src="https://res.cloudinary.com/css-tricks/image/fetch/w_1600,q_auto,f_auto/https://coding-fonts.css-tricks.com/screenshots/comic-shanns/js-dark.png" alt="Comic Shanns code sample" /></p> <p><a href="https://coding-fonts.css-tricks.com/fonts/comic-shanns/">Have a quick look at it!</a>! Your life will change for the better! I promise!</p> <p>Yours truly, Tobias Skarhed</p> <hr class="footnotes-sep" /> <section class="footnotes"> <ol class="footnotes-list"> <li id="fn1" class="footnote-item"><p>After writing this, Emil Tullstedt informed me that I can use <code>apt install ttf-mscorefonts-installer</code> <a href="https://blog.skarhed.com/coding-font-you-didnt-know-you-needed/#fnref1" class="footnote-backref">↩︎</a></p> </li> </ol> </section> </content>
</entry>
<entry>
<title>How to create a basic Chrome extension</title>
<link href="https://blog.skarhed.com/chrome-extension-that-just-adds-css-and-js/"/>
<updated>2021-03-07T00:00:00Z</updated>
<id>https://blog.skarhed.com/chrome-extension-that-just-adds-css-and-js/</id>
<content type="html"><p>The Chrome extension documentation is pretty extensive; there is a lot you can do with extensions. It is possible to run background scripts via web workers, interact with the Chrome API directly and call your own API's if that's what you want.</p> <p>That's not what I wanted. I wanted:</p> <ul> <li>Update the styles of a specific website</li> <li>Read and modify the DOM</li> </ul> <p>In this article I will use <a href="https://github.com/tskarhed/playpilot-imdb-extension">an extension I wrote</a> that inserts a search link on a movie's IMDb page, so you can figure where it is possible to buy or stream it.</p> <h2 id="the-chrome-extension-manifest">The Chrome Extension manifest<a class="tdbc-anchor" href="https://blog.skarhed.com/chrome-extension-that-just-adds-css-and-js/#the-chrome-extension-manifest">#</a></h2> <p>The manifest describes what the extension is about and what permission are needed. It also includes metadata such as name, description, screenshots and icons. We won't be focusing on the metadata. To get the basics of the manifest, see <a href="https://developer.chrome.com/docs/extensions/mv3/getstarted/#manifest">this part of Chrome Extension documentation</a>.</p> <p>The goal here is to insert our own script and our own CSS file into a webpage - this case being a n IMDb movie page. For this we are going to use content scripts, that the Chrome Extension documentation names in a very jargonny way as &quot;<a href="https://developer.chrome.com/docs/extensions/mv3/content_scripts/#static-declarative">inject with static declarations</a>&quot;.</p> <p>We want to inject the files in the same directory as our manifest called <code>contentScript.js</code> and <code>style.css</code>.</p> <pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Where to watch - Playpilot/IMDb"</span><span class="token punctuation">,</span><br /> ... <br /> <span class="token property">"content_scripts"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><br /> <span class="token property">"matches"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"https://www.imdb.com/title/*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"js"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"contentScript.js"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"css"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"styles.css"</span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">]</span><span class="token punctuation">,</span><br /> ...<br /><span class="token punctuation">}</span></code></pre> <p><em>This is an excerpt from <a href="https://github.com/tskarhed/playpilot-imdb-extension/blob/main/manifest.json">my extension manifest</a></em>.</p> <p>This just tells us what CSS and Javascript files we want to load into what sites, <code>matches</code>. Notice that all of these are arrays, which means you can load multiple scripts and stylesheets onto multiplite sites.</p> <p>The key here, which was my point of failure, is the <code>matches</code> URLs. If you files don't load it is most likely due to that. In my case I didn't add the <code>www</code> for the URL. The wildcard <code>*</code> just tells us to match all URLs that begins with everything to the left.</p> <p>1,2,3, we're done! Now you just need to write an awesome script and some beautiful styles!</p> <p>Have a good one! -Tobias</p> </content>
</entry>
<entry>
<title>Grafana alerting notifications in Mattermost</title>
<link href="https://blog.skarhed.com/grafana-alert-notification-in-mattermost/"/>
<updated>2022-08-03T00:00:00Z</updated>
<id>https://blog.skarhed.com/grafana-alert-notification-in-mattermost/</id>
<content type="html"><p>Grafana is a tool for monitoring whatever you want. Sometimes when the stuff you monitor behaves weirdly or goes all haywire, you want a notification. You have set up your Grafana alert and a notification policy that sends an email to your grandmother.</p> <p>That Ol' Gran gets her information is great, but you are looking for something more modern that fits the 2020's lifestyle. You want something that is more like a frappucino rather than a black coffee with milk.</p> <p>Your team uses <a href="https://mattermost.com/">Mattermost</a>, which is an open source alternative to Slack with the option to self-host. This is the modern way to communicate. Here you already have some bots informing you about your CI/CD pipelines, curing your loneliness and one that pings you when Wheatley logs in. So adding another shouldn't be that hard.</p> <p>You think to yourself:</p> <blockquote> <p>Mattermost and Slack looks the same and acts the same, so there must be a Grafana contact point option for Mattermost too</p> </blockquote> <p>In your quest to the solution you do a quick Google search. Nothing. You feel the awful dread of impending doom creeping up on you, just like someone from Gen Z. On the far horizon - the second page of Google - you find this blog post shining at you like a sunrise.</p> <p>Here is how you do it:</p> <h2 id="setting-up-mattermost-webhook">Setting up Mattermost webhook<a class="tdbc-anchor" href="https://blog.skarhed.com/grafana-alert-notification-in-mattermost/#setting-up-mattermost-webhook">#</a></h2> <p>In the top left corner of your Mattermost, you can find a menu button. Click it. In the menu you find an option called <strong>Integrations</strong>.</p> <p>Here you want to go to <strong>Create incoming webhook</strong>. This will create the endpoint that Grafana will use. Select which channel you want the bot to write its messages in.</p> <p>In the form, there are two very important options, which should be filled like this:</p> <table> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody> <tr> <td>Username</td> <td>Grot (grafanabot)</td> </tr> <tr> <td>Profile Picture</td> <td>https://avatars.githubusercontent.com/u/43478413?v=4</td> </tr> </tbody> </table> <p>This is brings the fierce dinosaur <a href="https://github.com/grafanabot">Grot the Grafanabot</a> to life!</p> <p><img src="https://avatars.githubusercontent.com/u/43478413?v=4" alt="Grot the Grafanabot" /></p> <p>When you are done with the settings, save it and copy the URL that has been generated for you.</p> <h2 id="setting-up-grafana-contact-point">Setting up Grafana contact point<a class="tdbc-anchor" href="https://blog.skarhed.com/grafana-alert-notification-in-mattermost/#setting-up-grafana-contact-point">#</a></h2> <p>In Grafana you want to configure a contact point. In the menu to the left hover the bell icon (Alerting) and select contact points. Here you want to click &quot;New contact point&quot;.</p> <blockquote> <p>Here comes the sneaky part</p> </blockquote> <p>Under &quot;Contact point type&quot; select &quot;Slack&quot;. 🙀 We fooled the system people!</p> <p>Give the contact point a mandatory name and paste the URL you copied from the Mattermost webhook into &quot;Webhook URL&quot;. You can configure the rest if you want, but it is not necessary and will override the settings you have made in Mattermost.</p> <hr /> <p>You can now freely use your contact point under &quot;Notification policies&quot; and Grot the Grafanabot will pop up in a channel near you with some news!</p> <p>And granny will still get her email, of course.</p> <p>/Tobias</p> </content>
</entry>
<entry>
<title>The healing power of running</title>
<link href="https://blog.skarhed.com/the-healing-power-of-running/"/>
<updated>2022-10-23T00:00:00Z</updated>
<id>https://blog.skarhed.com/the-healing-power-of-running/</id>
<content type="html"><p>My left hip was in pain. The constant upphill struggle had but a lot of tension on my thigh. I was glad that I had manage to reach the highest point of the race. Four days previously I had been in bed with a cold, too tired to get up to do the dishes. It had taken its toll during the race. My pulse was way higher higher than usually, and after 12km my body started stopped working properly if the pulse was higher than 170bpm. With the help of my friends, I prevailed. I finished my first trail run race, 24km with 900m altitude gain, with wet weather conditions in the Jura mountains.</p> <p>I hadn't been running actively for three years, since I had shin splints. That was at a time where I felt ambitious, so I decided to aim at running a 10k in 40 minutes or under. The training schedule was very intense. I went from running 3 times per week at a reasonably comfortable intensity, to running 5-6 times per week with some very intense sessions. I would almost always run with sore muscles from the weekly leg workout. It paid off though, as after two months I started beating my 10k PR every week. It wasn't even my intention of doing it during those runs, since they were always interval runs. I looked at the statistics from Garmin, and it said that during October 2018, I logged 120km. Apparently this was at the top 1% of Garmin users. I recorded my journey through a <a href="https://www.youtube.com/channel/UCccgVg1UYwSA0NRqFpdaEog/videos">set of video logs.</a> I felt like a machine.</p> <p>Then came the shin splints. I did not have the tools to deal with it. I took a month off from running, to see if it would improve. It did not. In fact, my mental health worsened. Since starting university I had consistently been running three times per week, something which worked as a great protection against stress and studying performance. Running had been a way for me to manage whatever life decided to throw at me.</p> <p>Then came 2019. Probably the worst year of my life. Some things happened which threw me into a deep depression. I basically wouldn't leave bed for 5 months.</p> <p>The job I had during that summer was very helpful to me. My main task wasn't very mentally straining, which meat I could show up to work wihtout being fully mentally present, and still deliver value. More than that, I managed to have an 8km commute, which took me a month to actually make use of. I bought an old road bike to use for commuting every day. 16km per weekday for a month really brought me out of the darkness.</p> <p>However, when I returned to university, I struggled to keep up with the frequency. And I didn't have my bike there either. Most of the studying I did there was very half-assed, and I did several smaller attempts at getting back into running. I went to a physiotherapist, who gave me exercises to do every day. I never managed to fully commit, because of the great catch-22 of bad mental health. I can't start doing the things that help me do the thing I want, because I can't do the thing I want. Supposedly, this is why cognitive behavioural therapy works, even though it is more focused on initially doing things that used to make you happy.</p> <p>University wass a horrible psychosocial environment. For probably 1,5 years I walked to the lectures every day and said to myself &quot;it will be over soon&quot;. The darkness of the arctic certainly did not help.</p> <p>I managed the finish the required courses, and moved to the Geneva area for a studendship at CERN. This was the change of environment I needed. Leaving my apartment, I would see the Jura mountains to the north every day. I committed to running again, slowly increasing intensity as the physiotherapist had recommended. For a couple of months I mostly ran 2km per week. I slightly increased that at some point.</p> <p>One of my colleagues found UTMJ - a mountain marathon with a set of distances, 24km the shortest and the longest an ultra distance of something like 170km. We decided to sign up for the shortest distance. I saw this as my opportunity get back to actively training. My goal was to finish it, even if I had to walk the entire way. I wanted to come out on the other side being able to exercise three times per week. There was only one issues: we had one month to prepare.</p> <p>My colleague set up an initial training schedule, and I thought it was way too intense. I did some of the activisties, and from what you can expect with a great increase in training, things started hurting. My right knee to be exact. So I stopped doing things for a couple of days. This time it was different though. I wouldn't let it beat me. I Googled all methods I could use to treat it; specific exercises, stretches, support taping and anti-inflammatory cream. To my surprise, it worked. During the race my knee was taped, and I felt nothing from it.</p> <p>Me being older and heavier, probably means that I will feel pain more times. I am currently feeling something in my hip, from a very intense leg workout a little while ago. I have a different mindset this time around. Reach out for professional help if you can't manage to Google the answers, and don't let the pain destroy your momentum. Many times it helps with just changing up the routine and exercises.</p> <p>Hopefully this has been helpful to someone! Now I am preparing the BAMM, arctic mountain marathon next year!</p> <p>/Tobias</p> </content>
</entry>
<entry>
<title>SSG framework for displaying music scores</title>
<link href="https://blog.skarhed.com/"/>
<updated>2023-04-10T00:00:00Z</updated>
<id>https://blog.skarhed.com/</id>
<content type="html"><p>Table of contents: </p><div class="table-of-contents"><ul><li><a href="https://blog.skarhed.com/#background">Background</a></li><li><a href="https://blog.skarhed.com/#requirements">Requirements</a></li><li><a href="https://blog.skarhed.com/#alternatives">Alternatives</a><ul><li><a href="https://blog.skarhed.com/#defining-metadata">Defining metadata</a></li><li><a href="https://blog.skarhed.com/#scripting-with-templating-language">Scripting with templating language</a></li><li><a href="https://blog.skarhed.com/#eleventy-11ty">Eleventy (11ty)</a></li><li><a href="https://blog.skarhed.com/#astro">Astro</a></li></ul></li></ul></div><p></p> <h2 id="background">Background<a class="tdbc-anchor" href="https://blog.skarhed.com/#background">#</a></h2> <p>At university I used to be a part of a classical male choir, which is traditional for Swedish universities, dating back to the early 1800s. Our choir is anything but traditional, but that subject may be covered at a later date ;)</p> <p>A lot of the repertoire in this genre is rather old, which makes it a prt of the public domain. A lot of famous composers have songs that still to this day are common to sing during Swedish traditional holidays. Prince Gustaf, Otto Lindblad and Hugo Alfvén are some of the most famous of these composers.</p> <p>A big part of this genre, which is tightly connected to universities, is &quot;snapsvisor&quot;; drinking songs commonly sung before taking a schnapps.</p> <p>Joakim Sandström, a previous conductor of my choir Snapsakademien, started a project where he wrote a lot of the classical songs in <a href="http://lilypond.org/">Lilypond</a>. This is a programming language that enables easy generation of music scores, usually in the form of PDFs. The initial purpose for this was to generate PDFs to combine them into a song book that could be used during a semester.</p> <p>Lilypond provide possibilities for output aswell. MIDI-files, a music file format known for producing simple music, can be generated, so the melody can be listened to while practicing. This is perfect especially for people like me who have a hard time reading notes!</p> <p>The library has grown enough to be useful beyond a single choir, so these scores can really be useful to publish alognside the MIDI-files.</p> <h2 id="requirements">Requirements<a class="tdbc-anchor" href="https://blog.skarhed.com/#requirements">#</a></h2> <p>Joakim Sandström is a happy volunteer that write these scores in his spare time. He has good knowledge of Lilypond, and even though he may understand the technical implementations of publishing the scores to the web, he shouldn't need to worry about it. Volunteer efforts are super important, and we should do anything in our power to not make any of these tasks more difficult or complex.</p> <p>We can do this assumption that the knowledge should extend to the Lilypond output files. This means that we can assume the following:</p> <ul> <li>Song information is known, such as title, composer or artist.</li> <li>Lilypond output file name is known</li> <li>Output file location is known</li> </ul> <p>Furthermore, in order to make a clear connection to the structure of the website, it should preferably reflect the structure of the repository.</p> <p>These are some other features we might want to consider:</p> <ol> <li>Easy way to list all the available songs</li> <li>Simple way to implement a search feature</li> <li>Categories or tags to group songs</li> </ol> <h2 id="alternatives">Alternatives<a class="tdbc-anchor" href="https://blog.skarhed.com/#alternatives">#</a></h2> <ol> <li>Scripting with templating language</li> <li>eleventy (11ty)</li> <li>Astro</li> </ol> <h3 id="defining-metadata">Defining metadata<a class="tdbc-anchor" href="https://blog.skarhed.com/#defining-metadata">#</a></h3> <p>All of these need some kind of input data, as it is not trivial to extract data from Lilypond files. The choice of defining metadata highly depends on which SSG solution is chosen. Some alternatives for defining data could be:</p> <h4>JSON files</h4> <pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br /> <span class="token property">"composer"</span><span class="token operator">:</span> <span class="token string">"Otto Lindblad"</span><span class="token punctuation">,</span><br /> <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Längtan till landet"</span><span class="token punctuation">,</span><br /> <span class="token property">"categories"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"spring"</span><span class="token punctuation">,</span> <span class="token string">"1800s"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"svgFiles"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"./page-1.svg"</span><span class="token punctuation">,</span> <span class="token string">"./page-2.svg"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br /> <span class="token property">"midiFiles"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"./all.midi"</span><span class="token punctuation">,</span> <span class="token string">"./t1.midi"</span><span class="token punctuation">,</span> <span class="token string">"./t2.midi"</span><span class="token punctuation">,</span> <span class="token string">"./b1.midi"</span><span class="token punctuation">,</span> <span class="token string">"./b2.midi"</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span></code></pre> <h4>Frontmatter YAML in Markdown files</h4> <pre class="language-yml"><code class="language-yml"><span class="token punctuation">---</span><br /><span class="token key atrule">composer</span><span class="token punctuation">:</span> <span class="token string">"Otto Lindblad"</span><br /><span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">"Längtan till landet"</span><br /><span class="token key atrule">categories</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"spring"</span><span class="token punctuation">,</span> <span class="token string">"1800s"</span><span class="token punctuation">]</span><br /><span class="token key atrule">svgFiles</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"./page-1.svg"</span><span class="token punctuation">,</span> <span class="token string">"./page-2.svg"</span><span class="token punctuation">]</span><br /><span class="token key atrule">midiFiles</span><span class="token punctuation">:</span><br /> <span class="token punctuation">-</span> <span class="token string">"./all.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./t1.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./t2.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./b1.midi"</span><br /> <span class="token punctuation">-</span> <span class="token string">"./b2.midi"</span><br /><span class="token punctuation">---</span></code></pre> <h3 id="scripting-with-templating-language">Scripting with templating language<a class="tdbc-anchor" href="https://blog.skarhed.com/#scripting-with-templating-language">#</a></h3> <p>The actual templating languiage does not matter much, as long a s it takes some kind of object and processes it. A personal preference would be Handlebars or Mustache.</p> <p>For this, a script has to be written to traverse the folder structure and render the HTML files. This could be done with something like a bash script or a Node.js script.</p> <p>The good thing with this approach is the flexibility. However, as soon as we look at thge requirements we listed previosuly, the complexity quickly increases. If we use this approach, then we basically need to write our own Static Site Generator.</p> <p>Withoout proper though into the initial arcfhitecture, handling collections of songs kmight be difficult. Furthermore, search provides more complexity.</p> <p>If we consider the fact that this project is on a volunteer basis, we want as little code as possible to maintain. With the features we require, the codebase may quickly increase uin size.</p> <h3 id="eleventy-11ty">Eleventy (11ty)<a class="tdbc-anchor" href="https://blog.skarhed.com/#eleventy-11ty">#</a></h3> <p>11ty offers a wide variety of templating languages. It also has something called a &quot;data cascade&quot; which defines the different levels from where it may get data.</p> <p>The data may be defined in a YAML frontmatter, a use case which fits really well for writing blog posts. In the frontmatter things like <code>title</code>, <code>date</code> and <code>description</code> may be added, whereas in the actual body of the document, you can write Markdown. Neat!</p> <p>In our case we do not have any need to write Markdown, so we can use JSON files instead, just containing the metadata. In a folder with songs in JSON format, an index template is applied to those and the JSONs in subfolders.</p> <p>All scripting and shortcodes need to be written in the 11ty config. It is possible to extend it quite a lot, but the bare bones work really well without any scripting. The only issue here is that there needs to be consistent folder structure and naming conventions.</p> <h3 id="astro">Astro<a class="tdbc-anchor" href="https://blog.skarhed.com/#astro">#</a></h3> <p>Astro is one among many SSGs with supercharged templating, in this case powered by Javascript. In this case, YAML frontmatter is the only way to go. A downside is also that the layout for a spoecific post needs to be defined in each file, which breaks the promise that the Liliypond writer does nto need to know anything about the implementation.</p> </content>
</entry>
</feed>