<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[drumm.sh: Recent Blogs RSS Feed]]></title><description><![CDATA[Blog, lectures and projects by Prof. Dr. Christian Drumm.]]></description><link>https://drumm.sh</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 11 May 2026 16:17:48 GMT</lastBuildDate><item><title><![CDATA[Grievt – Continued Collaboration]]></title><description><![CDATA[A short backstory Grievy is an app that serves as a digital companion after the loss of a loved one.
It was developed through a…]]></description><link>https://drumm.sh/student-blog/2024/04/ip-wise23-philipps/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2024/04/ip-wise23-philipps/</guid><pubDate>Wed, 13 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;a-short-backstory&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-short-backstory&quot; aria-label=&quot;a short backstory permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A short backstory&lt;/h2&gt;
&lt;p&gt;Grievy is an app that serves as a digital companion after the loss of a loved one.
It was developed through a collaboration between Nele Stadtbäumer, who came up with
the idea, Professor Drumm, who facilitated the project, and a team of six students
from Fachhochschule Aachen, who turned Nele’s ideas into a software product.
The idea had such momentum, that Nele and two of the students founded a startup
and refined their idea and product. Some features, including support with
bureaucratic tasks, had to be dropped in this refinement process.
Now, two years after the launch of
grievy, the startup has decided to work together with FH Aachen again, to
realize these organizational features in a sister app for grievy. Grievt
gives users handy advice surrounding funerals
and other topics, an editable checklist of things that need to be done after
the death of a loved one, and a feature for automatically generating letters of
termination for different contracts.&lt;/p&gt;
&lt;h2 id=&quot;forming--storming--norming&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#forming--storming--norming&quot; aria-label=&quot;forming  storming  norming permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Forming – Storming – Norming…&lt;/h2&gt;
&lt;p&gt;Within Scrum, you need a product owner, a scrum master and a development team. Daniel
Bachmann, one of the students who worked on grievy and went on as cofounder of the
startup, now took the role of product owner, and Professor Drumm took the role of Scrum
Master. For the development team, six students from FH Aachen were chosen, but after
the first two weeks of the semester, only four of us remained. This worried us in the
beginning, but with time we came to appreciate working in a small team. While many
things were new for us, we benefitted from the fact that Daniel and Professor Drumm
had not only worked on this kind of project before but also worked together before.&lt;/p&gt;
&lt;p&gt;In any kind of group work, there needs to be time spent storming and norming between
group members, before the stage of performing is entered. In the end, the size of our
team and the previous experience of Daniel and Professor Drumm helped us become productive
quite fast.&lt;/p&gt;
&lt;h2 id=&quot;what-we-learned&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-we-learned&quot; aria-label=&quot;what we learned permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we learned&lt;/h2&gt;
&lt;p&gt;Working on grievt provided invaluable learning opportunities. We gained experience
using Typescript and the Ionic framework, Github, SAST tools and developing and testing
for the Apple appstore and Google playstore, and most importantly working with Scrum.&lt;/p&gt;
&lt;p&gt;In the second half
of the semester, Herr Drumm started tracking our accuracy and velocity, teaching us
about the usual trajectory of these measures and emphasizing the importance of correct
evaluation and the advantage of well-written user stories. There were times when we
believed we would finish a particular user story within a sprint, but some details
kept us pulling our hair. Within the last two weeks of the project, a lot of bug fixing
occurred and last-minute amendments were made. Suddenly, issues that took us hours
only a month ago were solved in a fraction of that time. We had gotten to know the
technology and our app so much better that we could come up with solutions quicker
and more creatively.&lt;/p&gt;
&lt;h2 id=&quot;the-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-app&quot; aria-label=&quot;the app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The App&lt;/h2&gt;
&lt;p&gt;At the end of January, we showed the final result of our app to our peers in a live
presentation. It was exciting to take a step back and see the full picture of what
we worked on closely all semester. While app store deployment still awaited review
at this time, grievt became available to the general public two weeks later. This
marked the success and endpoint of our project. Today, when I navigate to
grievt in the app store, it notifies me of the fact that I am an internal tester,
a sweet reminder of the work I put into the app.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Using SAP AI Services in Python 🐍]]></title><description><![CDATA[Between April and June 2022 my colleague Stephan and I taught a Python MOOC
on the openSAP platform. The course was named Python for…]]></description><link>https://drumm.sh/blog/2022/10/16/python-sap-ai-service/</link><guid isPermaLink="true">https://drumm.sh/blog/2022/10/16/python-sap-ai-service/</guid><pubDate>Sun, 16 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Between April and June 2022 my colleague Stephan and I taught a &lt;a href=&quot;https://www.python.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Python&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Massive_open_online_course&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MOOC&lt;/a&gt;
on the &lt;a href=&quot;https://open.sap.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;openSAP&lt;/a&gt; platform. The course was named &lt;a href=&quot;https://open.sap.com/courses/python1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Python for Beginners&lt;/a&gt;.
It was very popular with over 40.000 participants and very well received. Many participants asked the following questions in the forum:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why is &lt;a href=&quot;https://www.sap.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP&lt;/a&gt; teaching &lt;a href=&quot;https://www.python.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How can &lt;a href=&quot;https://www.python.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Python&lt;/a&gt; be used in the SAP ecosystem&lt;/li&gt;
&lt;li&gt;What is a possible next step for course participants&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post I try to answer the second and third question in the list.
I will show one possibility of using Python in the SAP ecosystems. In particular, I choose a topic which does not require any
prior expertise in the SAP ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;sap-and-python&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sap-and-python&quot; aria-label=&quot;sap and python permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SAP and Python&lt;/h2&gt;
&lt;p&gt;Today, a search for &lt;a href=&quot;https://developers.sap.com/tutorial-navigator.html?search=Python&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Tutorial related to Python&lt;/a&gt; in the tutorial section of the
&lt;a href=&quot;https://developers.sap.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP Developer Center&lt;/a&gt; returns 18 tutorials from a variety of areas. There
is even a &lt;a href=&quot;https://developers.sap.com/tutorials/hana-cloud-python-analysis-multimodel-1.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tutorial&lt;/a&gt;
showing how to set up a connection between SAP &lt;a href=&quot;https://www.sap.com/products/technology-platform/hana/what-is-sap-hana.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;HANA&lt;/a&gt;
and a &lt;a href=&quot;http://jupyter.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Juypter Notebook&lt;/a&gt;. From the different available option I choose the
&lt;a href=&quot;https://help.sap.com/docs/SAP_AI_BUS&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP AI Business Services&lt;/a&gt; as the basis for this blog post. The reason being the these services
are easy to consume and do not require any expertise with other SAP products like SAP ERP or &lt;a href=&quot;https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP S/4HANA&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;sap-ai-business-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sap-ai-business-service&quot; aria-label=&quot;sap ai business service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SAP AI Business Service&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://help.sap.com/docs/SAP_AI_BUS&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP AI Business Services&lt;/a&gt; are a collection of six services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Business Entity Recognition&lt;/li&gt;
&lt;li&gt;Data Attribute Recommendation&lt;/li&gt;
&lt;li&gt;Document Classification&lt;/li&gt;
&lt;li&gt;Document Information Extraction&lt;/li&gt;
&lt;li&gt;Personalized Recommendations&lt;/li&gt;
&lt;li&gt;Service Ticket Intelligence.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The remainder of this blog post will use the &lt;a href=&quot;https://help.sap.com/docs/Business_Entity_Recognition&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Business Entity Recognition&lt;/a&gt; service as an example.
Using the content form this blog post it should easily be possible to use the other services as well.&lt;/p&gt;
&lt;p&gt;So what exactly is Business Entity Recognition?
The &lt;a href=&quot;https://help.sap.com/docs/Business_Entity_Recognition/b43f8f61368d455793a241d2b10baeb2/894afc838ee54c0f8c7f7381a9dae27a.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt;
states that Business Entity Recognition is used to:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Detect and highlight entities in unstructured text using machine learning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given the following plain text as input:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Christian Drumm works at the FH Aachen.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;The FH Aachen is located at the Eupener Str. 70 in Aachen, Germany&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Business Entity Recognition service could, for example, identify the following concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Address&lt;/strong&gt;: Eupener Str. 70, Aachen, Germany&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Person&lt;/strong&gt;: Christian Drumm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organization&lt;/strong&gt;: FH Aachen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Exactly which concepts can be identified depend on the variant of the Business Entity Recognition service used. A discussion of the differences
and possibilities is beyond the scope of this post and can be found in the documentation.&lt;/p&gt;
&lt;p&gt;For testing the Business Entity Recognition service two possibilities exist. Either a public sandbox can be used or a free trail of the service.
I would recommend using the free trial. While it requires some initial set up (which is nicely described in this
&lt;a href=&quot;https://developers.sap.com/tutorials/cp-aibus-ber-service-instance.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tutorial&lt;/a&gt;) it has a much better performance then the sandbox system.
Depending on when you try to use the service the sandbox sometimes requires waiting several minutes for results.&lt;/p&gt;
&lt;h2 id=&quot;sap-api-business-hub&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sap-api-business-hub&quot; aria-label=&quot;sap api business hub permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SAP API Business Hub&lt;/h2&gt;
&lt;p&gt;The first step to testing the Business Entity Recognition service is to understand the &lt;a href=&quot;https://en.wikipedia.org/wiki/API&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;API&lt;/a&gt; of
the service. All APIs offered by different SAP products are listed on the &lt;a href=&quot;https://api.sap.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP API Business Hub&lt;/a&gt;.
The SAP API Business Hub provides two main features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;discovering available APIs&lt;/li&gt;
&lt;li&gt;documentation and test functionality for the APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Important notice: In order to follow use the test functionality it is necessary to register and login to the SAP API Business
Hub. Otherwise some of the functionality is not available.&lt;/p&gt;
&lt;h3 id=&quot;api-of-business-entity-recognition-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#api-of-business-entity-recognition-service&quot; aria-label=&quot;api of business entity recognition service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;API of Business Entity Recognition Service&lt;/h3&gt;
&lt;p&gt;The image below shows the overview page of the &lt;a href=&quot;https://api.sap.com/api/business_entity_recognition_api/overview&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;API of the Business Entity Recognition Service&lt;/a&gt;
on the API Business Hub.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a5cc8a65e2eed68232ac54437212cf3b/c27e7/ber_api_business_hub.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACC0lEQVR42p2Ra3PSQBSG0+Eb5V5JCCRlcGpVHGwLhEq9i07rT++PsNOpJRAQgSbknrye3Uh0Oh0/uDPvnLO35z1nV5Cen0CS65DFKgr5HHaEHRSLRezuZlEul5HNZlGpVCBJIs9LpRLfz2QyfL9QKCCXy/G1fD4PodF6gr3mAcTWIWoHbTyqK6hWq6jX6wTao4N0qVSGVJMhk6qiCJn2JEniZ0RRQqOhoNl6jP1mC4Kqqjh8+gy9wStop0P0tAF6fQ1nwzN+sUiwbJ65F9FQFIhSjQNUdR8KzWtk0lBUUhMySXj95i0uvnzG+fkFRqMR3r3/iA+faH7xFcPhEMcnXbRfdNAk95dHx+j2+uhrp1zaIIn9/gDtzhE6XQ1CHMcIw5CLUlh3C8z0b3BsE8vlCq7nYbOxYZkWPMrX6zUcx+Fi8/tD2CYMGAQBRZ9mMf53pMDlconxeMxjFMWkiCsIwr86SIxM00wLcF03hbHtFLii9qZTA1NjBl2fYDKdkowkn0xxS2a2bafmvu9zmGVZD1eoG3Nc33zHzDAIMElAus5zBpzP5hzCKjPoDAPdr3DjR3+Ad26Ahe3TIrVCLTOZXohNECGk3AvpGXjLyXOw9lP9ZlxezxMgO8h0u3Zw9dOGSxCmm5WDHxsPDuUssrWHxhZ4tbASIHNxqZ2AnH32CVGcmmzF1raf8q9f/gX2/d+chfH5xAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Overview of the Business Entity Recognition Service&quot;
        title=&quot;&quot;
        src=&quot;/static/a5cc8a65e2eed68232ac54437212cf3b/5a190/ber_api_business_hub.png&quot;
        srcset=&quot;/static/a5cc8a65e2eed68232ac54437212cf3b/772e8/ber_api_business_hub.png 200w,
/static/a5cc8a65e2eed68232ac54437212cf3b/e17e5/ber_api_business_hub.png 400w,
/static/a5cc8a65e2eed68232ac54437212cf3b/5a190/ber_api_business_hub.png 800w,
/static/a5cc8a65e2eed68232ac54437212cf3b/c1b63/ber_api_business_hub.png 1200w,
/static/a5cc8a65e2eed68232ac54437212cf3b/29007/ber_api_business_hub.png 1600w,
/static/a5cc8a65e2eed68232ac54437212cf3b/c27e7/ber_api_business_hub.png 2144w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A detailed specification of the API is available on the API Reference page. The Try Out page enables
the testing of the service directly in the SAP API Business Hub.&lt;/p&gt;
&lt;p&gt;The API Reference page show which operations are offered by the Business Entity Recognition service. The service
offers operations related to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Datasets&lt;/li&gt;
&lt;li&gt;Training&lt;/li&gt;
&lt;li&gt;Models&lt;/li&gt;
&lt;li&gt;Deployments&lt;/li&gt;
&lt;li&gt;Inference.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The operations related to datasets, training, models and deployments are relevant when training own models. For
testing the service these operations are not necessary. Only the operation related to inference are used in the following.&lt;/p&gt;
&lt;h3 id=&quot;testing-the-api&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#testing-the-api&quot; aria-label=&quot;testing the api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Testing the API&lt;/h3&gt;
&lt;p&gt;In order to understand the Business Entity Recognition
service I will not describe how to test the service in the SAP API Business Hub. Instead I will explain how
to test the API using &lt;a href=&quot;https://httpie.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;HTTPie&lt;/a&gt; (other options to test the API are tools like &lt;a href=&quot;https://www.postman.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Postman&lt;/a&gt;
or the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=humao.rest-client&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rest Client&lt;/a&gt; for Visual Studio Code).&lt;/p&gt;
&lt;p&gt;Although HTTPie provides a Web-based tool and a native app I will be using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Command-line_interface&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CLI&lt;/a&gt;
client in the following. The reason for this is that &lt;a href=&quot;https://blogs.sap.com/tag/thefutureisterminal/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;#TheFutureIsTerminal&lt;/a&gt; 😉.&lt;/p&gt;
&lt;h2 id=&quot;testing-the-inference-of-the-business-entity-recognition-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#testing-the-inference-of-the-business-entity-recognition-service&quot; aria-label=&quot;testing the inference of the business entity recognition service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Testing the Inference of the Business Entity Recognition Service&lt;/h2&gt;
&lt;p&gt;In order to test the inference of the Business Entity Recognition service the following steps are necessary:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Getting an OAuth access token for the service&lt;/li&gt;
&lt;li&gt;Posting the inference data&lt;/li&gt;
&lt;li&gt;Getting the result of the inference.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of this steps is described in detail in the following sections.&lt;/p&gt;
&lt;h3 id=&quot;get-an-oauth-access-token&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#get-an-oauth-access-token&quot; aria-label=&quot;get an oauth access token permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get an OAuth Access Token&lt;/h3&gt;
&lt;p&gt;Describing the details of OAuth is beyond the scope of this blog post. This &lt;a href=&quot;https://community.sap.com/media/devtoberfest/cloud-apis-ex-2-oauth-2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;video&lt;/a&gt;
provides a nice introduction to the topic.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://help.sap.com/docs/Business_Entity_Recognition/b43f8f61368d455793a241d2b10baeb2/c4517867c219438ab35d8d3daa93edd9.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt;
describes the steps necessary to get an OAuth bearer token. In order to get a token an HTTP GET request needs to be send
to the path &lt;code&gt;/outh/token&lt;/code&gt;. In order to get the bearer token the parameter &lt;code&gt;grant_type&lt;/code&gt; needs to be set to &lt;code&gt;client_credentials&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The important question is now where to send the GET request. In the SAP BTP this information is contained in the
service key of the respective service. To find the service key navigate to &lt;em&gt;Instances and Subscriptions&lt;/em&gt;. Select your instance there
and open the details of the service key.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6ffb0ce93bc01ea2310e412f664efe70/0e288/ber-service-key.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 43.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABxklEQVR42lVSS4/TMBjMv+aABIfd5SUeWxAHaJeekODvII7QipK2eTSx4/gRx0mHsasesDSKnPk8mhk7e7n8jo/rb7hZrPHoxWc8fbvC41dLPHmzxM39KuFu8QV3769Y4/b+4cK9W+F28YDXn77i+Yc1npHLwugRl3MOUkgIwjmLMAM/i4B5nhHGESFEeIycP5/x3xo4bMcZE4lsk1fIK4GmM4TG4D2macJM0nHIWov9scTuUGPL2U1eotMW83TmOf4/HSFkD9nbZCYrqwrWDRBdj7+HkqRE27YkBaQUcINH1TkoO8GPIcENAwUnCNOj1iK5jK5jmkwplTaOoqe6TmJ1XaFpGvR9T4cOXa9hjIWn+4FiXddBEiGElCamGllL5LMocKZibwwORcVBBWUcNPfxsNYabXOiuOLeJXgeHvwAYy8znui1gSKyaDMuKTpsdgX2ZYvfx5admNSf5pBUmi4vX8GvalpYJvN+xK7coxI1Z4fEZ9crM4cC202OvBb48ecXSqFx6iw61WO7r1BLk1BKln88wVMwMG7eFOy4wcT48aVk16s3dFOWVeomlh67u8DCMZqPUa/g07E8bFjLyEuLUCmJwT9vp56Wrb2jEAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Service Key&quot;
        title=&quot;&quot;
        src=&quot;/static/6ffb0ce93bc01ea2310e412f664efe70/5a190/ber-service-key.png&quot;
        srcset=&quot;/static/6ffb0ce93bc01ea2310e412f664efe70/772e8/ber-service-key.png 200w,
/static/6ffb0ce93bc01ea2310e412f664efe70/e17e5/ber-service-key.png 400w,
/static/6ffb0ce93bc01ea2310e412f664efe70/5a190/ber-service-key.png 800w,
/static/6ffb0ce93bc01ea2310e412f664efe70/c1b63/ber-service-key.png 1200w,
/static/6ffb0ce93bc01ea2310e412f664efe70/29007/ber-service-key.png 1600w,
/static/6ffb0ce93bc01ea2310e412f664efe70/0e288/ber-service-key.png 3018w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The service key is in JSON format ans should look similar to this&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://business-entity-recognition.cfapps.eu10.hana.ondemand.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;swagger&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/api/v1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;uaa&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;clientid&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;lt;your-client-id&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;clientsecret&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;lt;your-client-secret&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;url&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://&amp;lt;your-instance-id&amp;gt;.authentication.eu10.hana.ondemand.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the URL given in the &lt;code&gt;uaa&lt;/code&gt; part of the service key a bearer token can be requested. Using HTTPie the GET request
looks like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;http -a &amp;lt;your-client-id&amp;gt;:&amp;lt;your-client-secret&amp;gt; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://&amp;lt;your-instance-id&amp;gt;.authentication.eu10.hana.ondemand.com/oauth/token?grant_type=client_credentials&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to save some typing I usually store the client id and client secret in en environment variable. But this is not required.
Furthermore, it might be necessary to surround the values with single quotes &lt;code&gt;&apos;&lt;/code&gt;. If everything works the response should look something
like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;....&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;access_token&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eyJhbGciOiJS...&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;expires_in&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: 43199,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;jti&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;27294b49bf47456380850bcf68ccaa04&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;uaa.resource ner-production!b30772.default&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;token_type&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;bearer&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important part of the response is the access token. This very long token is used to invoke the different operations
of the Entity Recognition service.&lt;/p&gt;
&lt;h1 id=&quot;posting-the-inference-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#posting-the-inference-data&quot; aria-label=&quot;posting the inference data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Posting the Inference Data&lt;/h1&gt;
&lt;p&gt;Recognising entities using the Business Entity Recognition service is a two step process. First the
data is uploaded to the service. The service performs the recognition of the entities asynchronously.
After the recognition is complete, the result can be retrieved. Therefore, the next step is now
to upload the inference data. For this blog post I will use the following text as inference data:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Christian Drumm works at Eupener Str. 70 in 52072 Aachen, Germany.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To upload this data to the Business Entity Recognition service a &lt;code&gt;POST&lt;/code&gt; request to the path
&lt;code&gt;/inference/jobs&lt;/code&gt; needs to be executed. The URL for the service can again be found in the service key.
The URL consists of the two parts &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;swagger&lt;/code&gt;. Authentication for the service is performed using
the access token retrieved in the previous step.&lt;/p&gt;
&lt;p&gt;The actual data is uploaded as an JSON object. HTTPie
automatically build a JSON object form the provided parameters.&lt;/p&gt;
&lt;p&gt;In addition it is required to define which inference model should be used.
In this example the &lt;a href=&quot;https://help.sap.com/docs/Business_Entity_Recognition/b43f8f61368d455793a241d2b10baeb2/55ab2ca0f9064aefbc1425246a1b3d1f.html?locale=en-US&amp;#x26;q=sap_address_entity&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;sap_address_entity&lt;/a&gt;
is used.&lt;/p&gt;
&lt;p&gt;So in summary the data can be uploaded using the following
command.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;http -A bearer -a &amp;lt;your-bearer-token&amp;gt; POST \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;https://business-entity-recognition.cfapps.eu10.hana.ondemand.com/api/v1/inference/jobs \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;text=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Christian Drumm works at Eupener Str. 70 in 52072 Aachen, Germany.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;modelName=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sap_address_entity&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything works the service returns a response like the one below:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;freePlanUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;inferenceCharactersUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Maximum limit of 120000 , utilized 471 Inference characters and remaining 119529&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;inferenceRequestsUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Maximum limit of 30 , utilized 3 Inference count and remaining 27&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;e74fbde9-11e7-4e04-94db-dbf56768ec4e&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Inference job has been submitted&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sap_address_entity&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;modelVersion&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;PENDING&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response show that the inference job has been submitted. The ID of the job is returned in the &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-results&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#getting-the-results&quot; aria-label=&quot;getting the results permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting the results&lt;/h2&gt;
&lt;p&gt;In order to get the result of the inference service a GET request is executed to the path &lt;code&gt;/inference/jobs/&amp;#x3C;job-id&gt;&lt;/code&gt;.
The job id in this path is the job id from the previous service. So in order to get the result the following
HTTPie command can be used.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;http -A bearer -a &amp;lt;your-bearer-token&amp;gt; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;https://business-entity-recognition.cfapps.eu10.hana.ondemand.com/api/v1/inference/jobs/&amp;lt;job-id&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Below is the result of this request.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;createdAt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2022-10-14T10:26:45Z&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;freePlanUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;inferenceCharactersUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Maximum limit of 120000 , utilized 603 Inference characters and remaining 119397&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;inferenceRequestsUsage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Maximum limit of 30 , utilized 5 Inference count and remaining 25&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;684ad559-b42f-462a-b865-65958e1c2865&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;modifiedAt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2022-10-14T10:26:58Z&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;cityTownVillage&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Aachen&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;country&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.9&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Germany&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;customerName&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.92&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Christian Drumm works&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;district&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;houseNumber&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.99&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;70&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;35&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;36&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;37&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;stateProvince&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;38&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;street&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;39&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;40&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;41&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;at Eupener Str&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;42&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;43&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;44&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;zip&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;45&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;46&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;confidence&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;47&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;52072&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;48&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;49&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;50&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;51&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;52&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;SUCCESS&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;53&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;54&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;status&lt;/code&gt; in line 52 show that the inference job completed successfully. In addition each identified entity is
returned together with confidence value. For example, line 31 ff shows that the concept
house number has been identified with a confidence of 0.99 and the value of the house number is 70.
Line 44ff shows that the concept zip has been identified with a confidence of 1.0 and the
value is 52072.&lt;/p&gt;
&lt;h2 id=&quot;using-the-service-in-python&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-the-service-in-python&quot; aria-label=&quot;using the service in python permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using the Service in Python&lt;/h2&gt;
&lt;p&gt;After using HTTPie to invoke the service the next step is to build a simple Python program to do the same.
The following listing contains a simple Python program executing the previous steps.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; time&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Constants&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;CLIENTID = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;lt;your-client-id&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;CLIENTSECRET = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;lt;your-client-secret&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;AUTH_SERVICE = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://&amp;lt;your-instance&amp;gt;.authentication.eu10.hana.ondemand.com/oauth/token?grant_type=client_credentials&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;BER_SERVICE = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://business-entity-recognition.cfapps.eu10.hana.ondemand.com/api/v1/inference/jobs&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#Get input from the use&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;user_input = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Please enter a text: &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Step 1: get the bearer token&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;authentication = requests.get(AUTH_SERVICE, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (CLIENTID, CLIENTSECRET))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Check if we got an authentication token&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; authentication.status_code == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#Step 2: Submit the inference job&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    payload = {&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: user_input, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;modelName&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sap_address_entity&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    headers = {&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Bearer &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + authentication.json()[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;access_token&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    submitted_job = requests.post(BER_SERVICE, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=payload, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=headers)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#Step 3: Wait until the job is finished&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    job_finished = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; job_finished:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        job_result = requests.get(BER_SERVICE + &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + submitted_job.json()[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=headers)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; job_result.json()[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;SUCCESS&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            job_finished = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;True&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Job finished&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;35&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;36&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            time.sleep(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;37&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;38&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Print the job results&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;39&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    format_jason = json.dumps(job_result.json(), &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;40&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(format_jason)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To call the service in Python the &lt;a href=&quot;https://pypi.org/project/requests/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;requests&lt;/a&gt; library is used. This library
is imported in line 1. Lines 6 - 10 defines a few constants. The values &lt;code&gt;&amp;#x3C;your-client-id&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;your-client-secret&gt;&lt;/code&gt; and
&lt;code&gt;&amp;#x3C;your-instance&gt;&lt;/code&gt; need to be replaced with the values for your service. Line 13 get the text from the user
to be analysed.&lt;/p&gt;
&lt;p&gt;The first step (line 16) is to get the bearer token using the service URL. The
authentication for this service is performed using the client id and client secret.
If the request was successful (line 19) the POST request is created in lines 22 - 25.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;while&lt;/code&gt; loop in lines 28 - 36 checks the job result (line 30) until the status is &lt;code&gt;&quot;SUCCESS&quot;&lt;/code&gt;.
If the job ended successfully the result is formatted using the &lt;code&gt;json&lt;/code&gt; library (line 39) and printed.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;I hope this blog post showed how easy it is to consume SAP service in Python. While I used the Business Entity Recognition service,
using other services works using the same approach. So now you are able to apply the Python knowledge from
the &lt;a href=&quot;https://open.sap.com/courses/python1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Python for Beginners&lt;/a&gt; course in the SAP ecosystem.&lt;/p&gt;
&lt;p&gt;If you have any question please feel free to ask them in the comments.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk14 { color: #F44747; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Blog Posts from the CBIS Lecture]]></title><description><![CDATA[This post contains pointers to the different blog posts
written by students during the lecture Cloud-based Information Systems in the winter…]]></description><link>https://drumm.sh/student-blog/2023/03/cbis-ws22/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2023/03/cbis-ws22/</guid><pubDate>Mon, 07 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This post contains pointers to the different blog posts
written by students during the lecture Cloud-based Information Systems in the winter term 2022.
Some of the blog posts are hosted on this Web site, some on external sites.&lt;/p&gt;
&lt;p&gt;The table below contains the links to the blog posts as well as the names of the authors.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Students&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://powerusers.microsoft.com/t5/Power-Platform-Integrations/Tutorial-How-to-use-a-REST-API-in-Power-Apps/m-p/2003174&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;How to use REST-APIs in PowerApps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ben Pauly, Fabian Lösch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/power_fx&quot;&gt;Power FX Tutorial&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Marvin Lützeler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/sharepoint_online&quot;&gt;Share-Point Online&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Vijitha Susilakumar, Artur Sichwardt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/oeeai_powerapps&quot;&gt;oee.ai and PowerApps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Anas Kudaish, Heram Kritharan, Wesam Habib&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/pdf_creator&quot;&gt;PDF Creator in Power Apps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Anton Zajcev, Fabian Kirchhoff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/compare_excel&quot;&gt;How to compare two Excel files using Power automate Desktop&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Ali Ayadi, Hassen Trabelsi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/office_script&quot;&gt;Power Automate und Office-Skripte&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Muteba Kayembe, Ahmed Wafi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://techcommunity.microsoft.com/t5/excel/cloudbasierte-informationssysteme-dkv-mobility/m-p/3754017&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Cloudbasierte Informationssysteme – DKV Mobility&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Evangelos Sarantis, Martin Nolte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/teaching/lectures/2022/winter_term/cbis/webhooks&quot;&gt;Webhooks&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dorian Loeben&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Production order and confirmation integration – a university project]]></title><description><![CDATA[Production order and confirmation integration – a university project This blog post is part of a series of posts, describing an integration…]]></description><link>https://drumm.sh/student-blog/2022/03/cbis-ws21/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2022/03/cbis-ws21/</guid><pubDate>Tue, 01 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;production-order-and-confirmation-integration--a-university-project&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#production-order-and-confirmation-integration--a-university-project&quot; aria-label=&quot;production order and confirmation integration  a university project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Production order and confirmation integration – a university project&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This blog post is part of a series of posts, describing an integration project that
connects the oee.ai Manufacturing Intelligence Platform with the production planning
capabilities of an on-premise S/4HANA System. The project was realized by students from
the FH Aachen University of applied Sciences, with great support from project partners at oee.ai and SAP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The blog post is available on the &lt;a href=&quot;https://blogs.sap.com/2022/03/03/production-order-and-confirmation-integration-a-university-project/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP Community&lt;/a&gt;.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[From semester project to start-up]]></title><description><![CDATA[The beginning of the project As part of the interdisciplinary project, I had the opportunity to get to know
many different interesting…]]></description><link>https://drumm.sh/student-blog/2021/11/13/IP-ws20-student-bachmann-experience/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2021/11/13/IP-ws20-student-bachmann-experience/</guid><pubDate>Sat, 13 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-beginning-of-the-project&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-beginning-of-the-project&quot; aria-label=&quot;the beginning of the project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The beginning of the project&lt;/h2&gt;
&lt;p&gt;As part of the interdisciplinary project, I had the opportunity to get to know
many different interesting projects. From the beginning, grievy particularly
caught my eye. On the one hand, I had a direct connection
to the idea of grievy, as a digital accompaniment after a death, since I had to
mourn a death in my family a few years ago. On the other hand, grievy was a
start-up with an innovative idea and a young, interesting team.
With a little luck of the draw (I was not the only one who found grievy very
interesting) I made it into the team of my wishes.&lt;/p&gt;
&lt;h2 id=&quot;the-realization-of-the-project&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-realization-of-the-project&quot; aria-label=&quot;the realization of the project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The realization of the project&lt;/h2&gt;
&lt;p&gt;Together with 5 fellow students I was part of the developer team, while Nele
acted as product owner and Christian Drumm was the scrum master.
Since none of us knew anything about programming an app, it took a while until
we found our way into the project.
But with each sprint we became more productive, organized and efficient.
We also got to know each other better and improved our collaboration more and more.
At the end of the project, we had a very good product, which we were able to
present to the other teams in a final presentation.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-i-learned&quot; aria-label=&quot;what i learned permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What I learned&lt;/h2&gt;
&lt;p&gt;In addition to my programming skills, I was also able to improve collaboration
with other project participants. Furthermore, I was able to enhance my
self-organization and time management. Last but not least, the project taught us
the agile Scrum method, as we used it every week. For the changing requirements
within the project, this method was optimal.&lt;/p&gt;
&lt;h2 id=&quot;what-happened-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-happened-next&quot; aria-label=&quot;what happened next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What happened next&lt;/h2&gt;
&lt;p&gt;I was very pleased with the way the project went. The result was excellent and I
also had a lot of fun during it.
A face-to-face final event, which unfortunately couldn&apos;t take place due to the
pandemic, would have been the cherry on the cake.&lt;/p&gt;
&lt;p&gt;But the project should not be over for me yet. Nele, the product owner in the
project and founder of grievy, was so happy with the result of our
collaboration that she asked me and a colleague if we would like to continue
working on grievy in the long term.
I didn&apos;t have to think long, for me grievy is a great opportunity and I have
fun working on it. So our partnership continues.&lt;/p&gt;
&lt;h2 id=&quot;where-we-stand-today&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#where-we-stand-today&quot; aria-label=&quot;where we stand today permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where we stand today&lt;/h2&gt;
&lt;p&gt;Since the end of the interdisciplinary project, we have continued to work on
grievy. Aenis, my colleague and friend, and I are responsible for the
development of the app and all the technical aspects around it. Together with
Nele we have further developed the app itself and grievy in general.&lt;/p&gt;
&lt;p&gt;In October we finished the first test version of our app. A closed group of
testers was able to put the app under the microscope.
Among the testers were funeral directors, grief counselors, software
developers and of course the original team from the interdisciplinary project.
The response was very positive and we received a lot of praise. But of course
there are still things we need to correct and optimize. We are very grateful
for the positive feedback and constructive criticism. At the moment we are
working on implementing the feedback and completing the app. We are very
excited to finally release the app next year.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 780px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/770baab2d2ac89a587c06a28eeb4cff2/a1792/grievy_vergleich.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 102%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAFH0lEQVR42pWUfWwTZRzHC4wERMIC2f6AITqLKL4tQBHUMEJ0hICQEIhsDCZOjRjZAFEggpMYwQhT2BAsI7zM8KYwRxmdUFibvTFGu04Ga7e2t75fe+1197Le9e569/NpN+AP/zA+yfee3/2e3Cff3++551Gp/t8Y9R9ro1Q2m20ix3GFLMsWI62nKCqtVDyiVL6wtdU2Uacte8Z8dffm1vMfbTGeXrOlSbu0zHBsUdmt6rmf7i/NUSPgaFU4HFbLsizC8FDQgEQiASiXfk89UJw4d/mvF+82n7oM8TaI9x1N0vd2QKT5Q+BbVif9xiLYV7nldwScoEJu1IIgcIODgzJN0yKSlBLDMCmJJEnKaJ2pv359Xun+b61Oz0OgvAaB/fuAJHXvlh42bBSK934MK3Z83jV1nGq6iud5dQrkcDjA6XQqGIaBz+cDl8uVmhWUAwTmdDqdJhTFu1KOE6xfNrf8AoeqSmF20Up5+dc7YcPeLyzI4Yw0kGFo0eMZAL/Po/j9XvCi2OPGwO3GlAHMCTRNcXoEJKmINcbTIIgJ2RXwwo+XLoC+oz3dGxfW1zUCpNQMy4luXwwCYUYJhllIxyEaaCahDNIicJyQBuK41+oPemFgoE8OB93AxsIQwb0IKEEI9w07pChQCxwhsn4d6k29QvuuwlBAB2FXPfj7rylSRA8ST3BXdCYNEfJaB8kwct8vY1gfOBw26Ot/KAuJIQj43MMOKQA1F70jBkz54G1arHhuL4Zo+xJorl0Iuze9oJDtbwEbbub0Jq8mFPJYYzECMMwp+30YAjvA0d8ri0IKiI2UjIAs0SHeb3gXLFcLFMufBWC/uQwuVS6E1aveVC6eXQMK1cz9pnNpGCpoxR7oAHd3yARJot7GQBCG0j3EHvUwzINaHOwWBWshcJYiJW4pAnhQBNdPrwPNe8XKph0lQAS7OYPJriEIj7Xz9kUI2m7LPhwHDG0cQYTk1O/qdNqGgQiu9scCYm17DZxp1Spn205AbYsWztw7BU2Om0qv2wI+MsQZdHpNnI1agbUDFfXLLEtBgmdA4JkRh44nwA6vTSyo2QkFJ75SltbsghXnKuDVXRtge+1hpQW3Qw/u5Ez6Lg1P2q1V2nKwdDfJ/iAOEbRBDDP4b4edHpu4rHorLPu5TFl1cics2VMKnyzXQPH7+crKo9vgrucB12No0zBMzGrzuYGIBmXkDLg4BfGhFDD5pIcpYG94QNzWWAXb9UeUrTerYeNnH4C37jhEdFrFWH8Uegkn16bv0cRjtq5+42Hw2MwyThBAUSQqm320KZbHwPtuH7/u0HGlsPJXaf1P2uTa744k1/5Qk/zmwPfS5n17lE7My/a0dWqiEZdFcDVCHMfEUCSURL9QkqZJUZI4VLLd/BjoChJiVYMJqhtMSmWdAY41NkPlNSNc+eOkYtCfB1swyrffapyDzrQ55Yblh2QpKaUvo2RSSjtE574TAaepBnD8WT4+ZEd9wFC+P8HSDjQ7QJac6RlVIwm87UJd3fNd5jtlNIkHMD/mwImAi6UjDjKKuyLhgLe+/vKX6euroqJitM5sfqq8vDzztXnzXnlj0TsvvZyX9/r8+W/Pzl+wQF178OCEGzduTMjPz89AH4xByhmfkTF/rEo1B8ULkOYiTUd6GikjfXfn5OSMz8rKUk+aNOk5pNzMzMwZU6ZMmZqdnZ07efLknBFQqj1jSkpKxk2fNWuqOi8va+bMmdNyc3OztVrtWKPRmIb9A3B1PEi/+WMxAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;grievy nach dem IP&quot;
        title=&quot;&quot;
        src=&quot;/static/770baab2d2ac89a587c06a28eeb4cff2/a1792/grievy_vergleich.png&quot;
        srcset=&quot;/static/770baab2d2ac89a587c06a28eeb4cff2/772e8/grievy_vergleich.png 200w,
/static/770baab2d2ac89a587c06a28eeb4cff2/e17e5/grievy_vergleich.png 400w,
/static/770baab2d2ac89a587c06a28eeb4cff2/a1792/grievy_vergleich.png 780w&quot;
        sizes=&quot;(max-width: 780px) 100vw, 780px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As you can see, a lot has changed at grievy since the prototype from the
interdisciplinary project. The most work for me was programming and
continuously improving the app. But there was also a lot to do organizationally.
We applied for scholarships, successfully participated in competitions for
founders, planned the long-term development of grievy, and much more.&lt;/p&gt;
&lt;p&gt;In addition to our work as software developers for grievy, Aenis and I,
together with Nele, will also be involved in the start-up as co-founders. To
put it in a nutshell, grievy and the interdisciplinary project are a great
opportunity for me and I look forward to the journey ahead.&lt;/p&gt;
&lt;h2 id=&quot;contact-us&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#contact-us&quot; aria-label=&quot;contact us permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Contact us&lt;/h2&gt;
&lt;h3 id=&quot;grievy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#grievy&quot; aria-label=&quot;grievy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;grievy&lt;/h3&gt;
&lt;p&gt;E-Mail: &lt;a href=&quot;mailto:hallo@grievy.de&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;hallo@grievy.de&lt;/a&gt;&lt;br&gt;
Website: &lt;a href=&quot;https://grievy.de/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://grievy.de/&lt;/a&gt;&lt;br&gt;
Instagram: &lt;a href=&quot;https://www.instagram.com/grievy.app/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://www.instagram.com/grievy.app/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;me&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#me&quot; aria-label=&quot;me permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Me&lt;/h3&gt;
&lt;p&gt;E-Mail: &lt;a href=&quot;mailto:daniel.bachmann@grievy.de&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;daniel.bachmann@grievy.de&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href=&quot;https://www.linkedin.com/in/daniel-bachmann-2b7160211/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://www.linkedin.com/in/daniel-bachmann-2b7160211/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;nele-stadtbäumer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nele-stadtb%C3%A4umer&quot; aria-label=&quot;nele stadtbäumer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Nele Stadtbäumer&lt;/h3&gt;
&lt;p&gt;E-Mail: &lt;a href=&quot;mailto:nele.stadtbaeumer@grievy.de&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nele.stadtbaeumer@grievy.de&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href=&quot;https://www.linkedin.com/in/nelestadtbaeumer/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://www.linkedin.com/in/nelestadtbaeumer/&lt;/a&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[More Bitwarden CLI Shell Scripting]]></title><description><![CDATA[In my previous blog post I started to explore shell scripting
by adapting the Bitwarden CLI
to my needs. Luckily, DJ and markhepburn
also…]]></description><link>https://drumm.sh/blog/2021/09/17/more-bw-cli/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/09/17/more-bw-cli/</guid><pubDate>Tue, 31 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my previous &lt;a href=&quot;/blog/2021/08/25/bw-cli&quot;&gt;blog post&lt;/a&gt; I started to explore shell scripting
by adapting the &lt;a href=&quot;https://bitwarden.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bitwarden&lt;/a&gt; &lt;a href=&quot;https://bitwarden.com/help/article/cli/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CLI&lt;/a&gt;
to my needs. Luckily, &lt;a href=&quot;https://twitter.com/qmacro&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DJ&lt;/a&gt; and &lt;a href=&quot;https://github.com/markhepburn&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;markhepburn&lt;/a&gt;
also wrote blog posts on the topic (cf. &lt;a href=&quot;https://qmacro.org/2021/08/26/learning-by-rewriting/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;
and &lt;a href=&quot;https://blog.markhepburn.com/posts/automating-ssh-login-involving-totp-codes/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;).
Based on their blog posts I tried a few more ideas. Finally, I was able to improve
my initial shell script a bit (at least in my opinion 😉).&lt;/p&gt;
&lt;h2 id=&quot;additional-requirements&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#additional-requirements&quot; aria-label=&quot;additional requirements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Additional Requirements&lt;/h2&gt;
&lt;p&gt;After reading DJ&apos;s and Mark&apos;s blog post I added the following requirements to
my &lt;a href=&quot;http://localhost:8000/blog/bw-cli#my-requirements&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;initial list&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If a &lt;a href=&quot;https://en.wikipedia.org/wiki/Time-based_One-Time_Password&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;TOTP&lt;/a&gt; token&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;is available for an entry, my custom CLI should also copy this token.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Simply my shell script by using some to the features DJ used in his script.&lt;/li&gt;
&lt;li&gt;Distinguish between different username / passwords for the same Web site.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These requirements didn&apos;t look like much work. However, especially the first
one required me to change the approach I took in the shell script.&lt;/p&gt;
&lt;h2 id=&quot;my-new-solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-new-solution&quot; aria-label=&quot;my new solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My New Solution&lt;/h2&gt;
&lt;p&gt;Before going into more details here is the resulting script.
The complete script is also
available on &lt;a href=&quot;https://github.com/ceedee666/devenv-dotfiles/blob/master/.scripts/bwc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#!/bin/zsh&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;copy_data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; id=&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; login=&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sessionkey=&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; totp&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Name: $(jq -r &amp;quot;.name&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the username to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Copying Username&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.username&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;lt;&amp;lt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Wait for user input before coping the password&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Press any key to copy password...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the password to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Copying Password&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.password&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;lt;&amp;lt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy a TOTP Token if available&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  totp=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(jq -r &amp;quot;.login.totp&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [[ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$totp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; != &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ]]; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Wait for user input before coping the totp token&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Press any key to copy TOTP Token...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Copying TOTP Token&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    bw get totp &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --session &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$sessionkey&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;35&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;36&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;37&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;38&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; searchterm=&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;39&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sessionkey logins login id&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;40&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;41&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#Unlock the vault an store the session key&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;42&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  sessionkey=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(bw unlock --raw)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;43&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;44&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Search for passwords using the search term&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;45&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  logins=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(bw list items --search &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$searchterm&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; --session &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$sessionkey&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;46&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;47&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  id=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(jq -r &amp;#39;.[] | &amp;quot;\(.name)\t\(.login.username)\t\(.id)&amp;quot;&amp;#39; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;48&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; fzf --reverse --with-nth=1,2 --delimiter=&amp;quot;\t&amp;quot; --select-1 --exit-0 \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;49&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; awk -F&amp;quot;\t&amp;quot; &amp;#39;{print $3}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;50&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;51&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;52&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [[ -n &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ]]; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;53&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    login=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(jq &amp;quot;.[] | select(.id == &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;54&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    copy_data &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$sessionkey&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;55&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;56&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;57&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;58&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;main &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;main-function&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#main-function&quot; aria-label=&quot;main function permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Main Function&lt;/h2&gt;
&lt;p&gt;The first change I implemented is to introduce a &lt;code&gt;main&lt;/code&gt; function
(cf. lines 37 – 56).
This idea I copied directly from DJs &lt;a href=&quot;https://qmacro.org/2021/08/26/learning-by-rewriting/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog post&lt;/a&gt;.
The execution of the script starts in line 58 by invoking this &lt;code&gt;main&lt;/code&gt; function.
The special parameter &lt;code&gt;$@&lt;/code&gt; is used to pass all parameters of the script to the
main function.&lt;/p&gt;
&lt;p&gt;Besides that, I also qualified all the variables with &lt;code&gt;local&lt;/code&gt;
(cf. lines 6 – 9 and 38 – 39). Also coping the positional
parameters (e.g. &lt;code&gt;$1&lt;/code&gt; or &lt;code&gt;$2&lt;/code&gt;) to a local variable at the beginning of the
function seems to be a good idea (cf. lines 6 – 8).&lt;/p&gt;
&lt;h2 id=&quot;here-string-&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#here-string-&quot; aria-label=&quot;here string  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here String &amp;#x3C;&amp;#x3C;&amp;#x3C;&lt;/h2&gt;
&lt;p&gt;In the previous blog post I described how I ran into some
problems due to the handling of special characters like &lt;code&gt;\n&lt;/code&gt; by
&lt;a href=&quot;http://localhost:8000/blog/2021/08/25/bw-cli/#be-careful-with-echo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;echo&lt;/a&gt;.
My first solution was to use &lt;code&gt;printf&lt;/code&gt; instead. In DJ&apos;s &lt;a href=&quot;https://qmacro.org/2021/08/26/learning-by-rewriting/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog post&lt;/a&gt;
I learned about &lt;a href=&quot;https://tldp.org/LDP/abs/html/x17837.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here strings&lt;/a&gt;. I used
these in the new version of the script as well (e.g. lines 15, 23, 26 or 47).&lt;/p&gt;
&lt;p&gt;However, currently I&apos;m unsure if I like the syntax of here strings or of &lt;code&gt;printf&lt;/code&gt;
better. The advantage of here strings is conciseness. The disadvantage in my
point of view is, that suddenly line can&apos;t be read from left to right anymore.
For example, line 15 could be nicely read from left to right using &lt;code&gt;printf&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the username to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.username&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the here string I need to read until the &lt;code&gt;&amp;#x3C;&amp;#x3C;&amp;#x3C;&lt;/code&gt; in order to
understand where the input of &lt;code&gt;jq&lt;/code&gt;is coming from. Nevertheless,
I stuck with the here strings for the new version of the script
just to get used to them.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the username to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.username&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;lt;&amp;lt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fzf-features&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fzf-features&quot; aria-label=&quot;fzf features permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;fzf-Features&lt;/h2&gt;
&lt;p&gt;In the initial script I used a conditional to distinguish between the
situations that one or many results are returned by the
search. This complexity is unnecessary and was removed in the current version
of the script. Instead, the parameter &lt;code&gt;--select-1&lt;/code&gt; is used to tell
fzf to immediately return when only one element was passed.&lt;/p&gt;
&lt;p&gt;In order to distinguish between logins with the same name and different
passwords, used the &lt;code&gt;--delimiter&lt;/code&gt; parameter
DJ used in his &lt;a href=&quot;https://qmacro.org/2021/08/26/learning-by-rewriting/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the script the name, the login name and the id of the entries are passed to fzf
separated by a tab.
This input is generated using &lt;code&gt;jq&lt;/code&gt; &lt;a href=&quot;https://stedolan.github.io/jq/manual/#Stringinterpolation-(foo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;string interpolation&lt;/a&gt;).
For each entry returned by &lt;code&gt;bw list items&lt;/code&gt; in line 45 a string consisting
of the name, a tab, the username, a tab and the id is generated.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.[] | &amp;quot;\(.name)\t\(.login.username)\t\(.id)&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;lt;&amp;lt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;--with-nth=1,2&lt;/code&gt; parameter tells fzf to only display the first two elements of the input.
The resulting invocation of fzf is shown in line 48. The following screenshot shows the
resulting user interface when the search returns multiple entries for the
same system with different user names.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 337px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5c03e2d7deab4baf092b58ed26781b0b/f6b51/fzf_selection.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 29.000000000000004%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABIklEQVR42l2PSXOCQBCF+SmpEmFYVMwAbhAkYskiGtSkknDQ5JB4iJf8e04vM6NjWTl808t709Wt/Jx+m9m8bO5anYbYXqNbbqMb9BwZ5FJr/yBSk/4LSlm9Ik5SqPo92sSFxmgbLlrauVYJhWZ4INbgCq+5rupUeAx7KOCaEoxD7A97JPMU0TQRhGGMp+oZ0zhBlpeYBBHsjoOeQ0UcjgKs1hsUyzX7l7GhVAwnlg9l+rjA9/GEotxikZaMFTMtcfj8QlZU2OzeEEZzELMPu+vBtCmoN8F7/YHdS4282KDa1UjzLdvchWL3xqB+jB4N0e0HV3jPoQ+ib3VH0EwPOttA0ncjoXPNH83gDmLozKPwh0/m8Fwie7LPz7nlVpM5P/kPG93DhyuufIwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;fzf user interface&quot;
        title=&quot;&quot;
        src=&quot;/static/5c03e2d7deab4baf092b58ed26781b0b/f6b51/fzf_selection.png&quot;
        srcset=&quot;/static/5c03e2d7deab4baf092b58ed26781b0b/772e8/fzf_selection.png 200w,
/static/5c03e2d7deab4baf092b58ed26781b0b/f6b51/fzf_selection.png 337w&quot;
        sizes=&quot;(max-width: 337px) 100vw, 337px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;more-bitwarden-cli&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-bitwarden-cli&quot; aria-label=&quot;more bitwarden cli permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More Bitwarden CLI&lt;/h2&gt;
&lt;p&gt;The major changes of the new version of my script are related to the
&lt;a href=&quot;https://bitwarden.com/help/article/cli/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bitwarden CLI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Whenever the
password vault is locked and a command like &lt;a href=&quot;https://bitwarden.com/help/article/cli/#get&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;get&lt;/a&gt;
or &lt;a href=&quot;https://bitwarden.com/help/article/cli/#list&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;list&lt;/a&gt; is executed,
the &lt;a href=&quot;https://bitwarden.com/help/article/cli/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bitwarden CLI&lt;/a&gt; asks for the
password to unlock the vault. In my initial script
this was not a problem. It only accessed the fault once using &lt;code&gt;bw list &amp;#x3C;searchterm&gt;&lt;/code&gt;.
However, the JSON data returned by this command doesn&apos;t contain the current TOTP
token for an entry. To get a TOTP token &lt;code&gt;bw get totop &amp;#x3C;ID&gt;&lt;/code&gt; needs to be
executed with the ID of a vault entry. As I don&apos;t want to enter my password
multiple times for one entry in the password vault the script needs to use
the &lt;a href=&quot;https://bitwarden.com/help/article/cli/#session-management&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;log in&lt;/a&gt; functionality
of the Bitwarden CLI.&lt;/p&gt;
&lt;p&gt;This log in functionality consists of two steps. First, the password vault is unlocked
in line 42 using &lt;code&gt;bw unlock&lt;/code&gt;. This command requires entering the password to unlock
the vault. If the correct password is entered, a session key is returned. In my script
this session key is then stored in the local variable &lt;code&gt;sessionkey&lt;/code&gt;. For all subsequent
invocations of the Bitwarden CLI (cf. line 45 and 33), the session key is passed
to the command using the
&lt;code&gt;--session&lt;/code&gt; parameter.&lt;/p&gt;
&lt;h2 id=&quot;final-result&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-result&quot; aria-label=&quot;final result permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Result&lt;/h2&gt;
&lt;p&gt;The following GIF shows the new script in action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6ef8764f18b3113a3056b3511b23acd3/result.gif&quot; alt=&quot;Resulting Script&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;Using what I learned from DJ I was able to improve my initial script quite
a bit. Right now I&apos;m pretty happy with the result. Let&apos;s see if I&apos;ll continue
with more shell scripting in the future.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Adapting the Bitwarden CLI with Shell Scripting]]></title><description><![CDATA[Bitwarden has been my password manager of
choice since it was recommended to me by
Frank about two years ago. I
like most of its…]]></description><link>https://drumm.sh/blog/2021/08/25/bw-cli/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/08/25/bw-cli/</guid><pubDate>Wed, 25 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://bitwarden.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bitwarden&lt;/a&gt; has been my password manager of
choice since it was recommended to me by
&lt;a href=&quot;https://twitter.com/koehntopp&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Frank&lt;/a&gt; about two years ago. I
like most of its functionality. However, one thing kept annoying
me. To be honest this was already the case with my previous
password manager.&lt;/p&gt;
&lt;p&gt;The integration of Bitwarden into the browser is great. When I&apos;m
not in the browser the interaction with Bitwarden often felt
cumbersome. For example, I quite often work or in a
virtual machine running Windows&lt;sup id=&quot;a1&quot;&gt;&lt;a href=&quot;#f1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; or in
the terminal in full screen mode. In order to get a password
from Bitwarden when I&apos;m not in the browser I need to do the
following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Switch to the browser&lt;/li&gt;
&lt;li&gt;Click on the Bitwarden icon&lt;/li&gt;
&lt;li&gt;Enter the master password (in most of the cases)&lt;/li&gt;
&lt;li&gt;Enter a search string&lt;/li&gt;
&lt;li&gt;Click on the icon to copy the password&lt;/li&gt;
&lt;li&gt;Switch back to my work environment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Especially, when working in the terminal, the need to suddenly
switch to using the mouse annoyed me.&lt;/p&gt;
&lt;h2 id=&quot;bitwarden-cli&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bitwarden-cli&quot; aria-label=&quot;bitwarden cli permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bitwarden CLI&lt;/h2&gt;
&lt;p&gt;One of the nice features of Bitwarden is, that there is also
a &lt;a href=&quot;https://bitwarden.com/help/article/cli/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;command-line interface&lt;/a&gt; available.
I had a look at this CLI a few weeks back, but I
did not find it useful. With the ID of an entry in my
vault the Bitwarden CLI would allow me to look up the password
using&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;bw get password &amp;lt;ID&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to get the necessary ID I could use&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;bw list items &amp;lt;search-string&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, the &lt;code&gt;bw list items&lt;/code&gt; command returns a JSON string
containing all the information of the entries matching the
&lt;code&gt;&amp;#x3C;search-string&gt;&lt;/code&gt;. In particular, I didn&apos;t see an easy way to
get the ID from the results and use it to get the password. So
after playing with the CLI for about half an hour, I gave up.&lt;/p&gt;
&lt;h2 id=&quot;shell-scripting-to-the-rescue&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#shell-scripting-to-the-rescue&quot; aria-label=&quot;shell scripting to the rescue permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shell Scripting to the Rescue&lt;/h2&gt;
&lt;p&gt;A few days ago I read the blog post &lt;a href=&quot;https://blog.kellybrazil.com/2019/11/26/bringing-the-unix-philosophy-to-the-21st-century/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bringing the Unix Philosophy to the 21st Century&lt;/a&gt;
by &lt;a href=&quot;https://github.com/kellyjonbrazil&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kelly Brazil&lt;/a&gt; (found via
&lt;a href=&quot;https://twitter.com/qmacro/status/1429463349239197701&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@qmacro&lt;/a&gt; of cause).
After reading this post i thought: &lt;a href=&quot;https://youtu.be/XFoXmnBuLw0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&quot;hold up, wait a minute&quot;&lt;/a&gt;. The Bitwarden
CLI returns JSON. I have already used command-line tools &lt;a href=&quot;https://stedolan.github.io/jq/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;jq&lt;/a&gt; and
&lt;a href=&quot;https://github.com/junegunn/fzf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fzf&lt;/a&gt; a bit. It should be possible
to adapt the Bitwarden CLI to my needs with those tools.&lt;/p&gt;
&lt;p&gt;Of course, being a good software developer, I started with a Web search first. And, surprise,
I found a &lt;a href=&quot;https://benaaron.dev/blog/bitwarden-cli/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog post&lt;/a&gt; by Ben Aaron Goldberg that
describes almost exactly what I wanted to have. Using this blog post as a basis I was sure I
could create the CLI for Bitwarden that I needed.&lt;/p&gt;
&lt;h3 id=&quot;my-requirements&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-requirements&quot; aria-label=&quot;my requirements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Requirements&lt;/h3&gt;
&lt;p&gt;What features did I want to have in my bespoke Bitwarden CLI?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I want to be able to search for usernames and passwords using a search string&lt;/li&gt;
&lt;li&gt;If only one entry is found, first the username and after that the password&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;for the entry should be copied to the clip board.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If more than one entry is found I want to be able to search through the&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;results and select the entry I was looking for. After that the username and
password should again be copied to the clip board.&lt;/p&gt;
&lt;p&gt;The following screenshot shows what I had in mind for the CLI.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7a9c1d9d28b613f94976c8de43ebf6d0/d9199/bwc-idea.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 59.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACH0lEQVR42p2S2U7bUBCG/QhElWhVdSNREjt2cOx4d5w4OGkIJCxhKRXQJVCiLhJQtSBuuiBVfYFe9WW/HodEggsqtRef/nOkmdHMPyMd//jNwdlPRh+/sT8652B0wtn5F7Y+fCXePaG98ZLV7V1am0Pc1SF6dx9jaZdoZY/tvUO89UOePn9L/Owd3uYIyTRcvCDA8QIqhoVpWlRNm3KlimY4NOImzWaCX0+oBk2qjo85oWr7WG5I1Y3QnQg57iHFyQJxp0t7eUC7s0az1SesL1ITlMoehZJFsWQjp6gTFRQnTP9K2cHsLiIlPR8/XBCdLNNMeoI+XtgmiDo4fjIuKqvOrRQUm7xsUdId1HYD6Z78BMOpEza6WE6MaTdQNHdMWizVafL0PdVS2aVSrQki1Hkbp2Ugzekq3d4KtbiLNu/fKDBNVlK9/p7ElHVfWCOmqbVxgwZbL5aQgqPPyGL+gmi7+JfRbqMoPM4WTIIw4fvlKVJ08QvFiCam/3tBRbvqXtYsPl28R9IPLpH18L8LXuGKazCRAw0pPzilWBbepatPjZ74VbqBPWbsXxp3/VzGy/EFNpafR3rQGjKnBWQV4YU4gTEicO46mjcmJ5aRE4vLVwKKpphKaE54+Dir8SirijwZaba+xx1vQMbuk3H6zLgrZPxVZoI1ZsKBYJ1MvMNs5xX3l4bkNt4w//oETywzGB5TPzpF3TnkrhXxUCnzB4mai0ExkEwWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;My Bitwarden CLI&quot;
        title=&quot;&quot;
        src=&quot;/static/7a9c1d9d28b613f94976c8de43ebf6d0/5a190/bwc-idea.png&quot;
        srcset=&quot;/static/7a9c1d9d28b613f94976c8de43ebf6d0/772e8/bwc-idea.png 200w,
/static/7a9c1d9d28b613f94976c8de43ebf6d0/e17e5/bwc-idea.png 400w,
/static/7a9c1d9d28b613f94976c8de43ebf6d0/5a190/bwc-idea.png 800w,
/static/7a9c1d9d28b613f94976c8de43ebf6d0/d9199/bwc-idea.png 960w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;my-solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-solution&quot; aria-label=&quot;my solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Solution&lt;/h3&gt;
&lt;p&gt;My requirements didn&apos;t sound overly complicated. So I stared building a shell script
implementing them. This is what I came up with after quite some trial and error.
I created a shell script called &lt;a href=&quot;https://github.com/ceedee666/devenv-dotfiles/blob/master/.scripts/bwc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;bwc&lt;/a&gt; -
a mnemonic for Bitwaren Copy.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;copy_uname_and_passwd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Print the name of the selected login&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Name: $(printf &amp;quot;%s&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq -r &amp;quot;.name&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Copying Username&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the username to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.username&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Press any key to copy password...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Wait for user input before coping the password&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt; Copying Password&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy the password to the clipboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;%s&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | jq -r &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.login.password&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Search for passwords using the search term&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;logins=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(bw list items --search &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(printf &amp;quot;%s&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq &amp;quot;. | length&amp;quot;)&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -eq 1  ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  login=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(printf &amp;quot;%s&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq &amp;quot;.[0]&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  name=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(printf &amp;quot;%s&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq -r &amp;quot;.[].name&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; fzf --reverse)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  login=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(printf &amp;quot;%s&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq &amp;quot;.[] | select(.name == &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;copy_uname_and_passwd &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$login&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lines 3 - 15 are mostly copied from the blog post mentioned above. The only thing
I did was wrapping it in a function that I could reuse.&lt;/p&gt;
&lt;p&gt;The execution of the script starts in line 19. The Bitwarden CLI
is used to search for items using the search term passed to the
script as a parameter. The result is stored in the variable &lt;code&gt;logins&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, the length of the resulting JSON array is calculated using
&lt;code&gt;jq &quot;. | length&quot;&lt;/code&gt;. If only one entry is found, this entry is stored
in the variable &lt;code&gt;login&lt;/code&gt; (line 23). If more than one entry is found
the names of these entries are passed to fzf. The name of the
selected entry is stored in the variable &lt;code&gt;name&lt;/code&gt;. This variable is used
line 26 to get the selected login from the result array &lt;code&gt;logins&lt;/code&gt; and
store it in the variable &lt;code&gt;login&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the function &lt;code&gt;copy_uname_and_passws&lt;/code&gt; is called with the
&lt;code&gt;login&lt;/code&gt; as a parameter.&lt;/p&gt;
&lt;p&gt;The following two GIFs show the script in action. First, with only
one result returned from the search:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/9bb922250bfc3fe5ba71a9c35c6ac48f/bwc-one-result.gif&quot; alt=&quot;bwc with one result&quot;&gt;&lt;/p&gt;
&lt;p&gt;Second, with multiple results returned by the search:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/c5382235c08a8a8f1ccb84422dcbfe69/bwc-multiple-results.gif&quot; alt=&quot;bwc with multiple result&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;be-careful-with-echo&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#be-careful-with-echo&quot; aria-label=&quot;be careful with echo permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be careful with echo&lt;/h3&gt;
&lt;p&gt;One of the problems I was facing during development of the script was this
error message from jq:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 6, column 13&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After lots of trial and error I noticed the problem was the &lt;code&gt;echo&lt;/code&gt; I was
using in the script. &lt;code&gt;echo&lt;/code&gt; does some special handling of
characters like &lt;code&gt;\n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, initial line 21 contained the following code:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;$(echo &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$logins&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; jq &amp;quot;. | length&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Due to the special handling of &lt;code&gt;\n&lt;/code&gt; the JSON piped from &lt;code&gt;echo&lt;/code&gt; to &lt;code&gt;jq&lt;/code&gt; was not valid. Once
I changed &lt;code&gt;echo&lt;/code&gt; to &lt;code&gt;printf&lt;/code&gt; everything worked as expected.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;I now have exactly the Bitwarden CLI I was looking for. Furthermore, creating the shell script
showed me, again, the power of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Unix philosophy&lt;/a&gt;
of having a program do exactly one thing and do this well.&lt;/p&gt;
&lt;p&gt;As this is my first shell script I&apos;m sure there my things to improve. I would be happy
to hear any suggestions by some of the command-line and shell
scripting magicians 🧙‍♀️ out there.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;b id=&quot;f1&quot;&gt;1&lt;/b&gt; This is due to the fact that VMware doesn&apos;t have
a working version of its proprietary VPN solution for any recent
MacOS.&lt;a href=&quot;#a1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Microcontrollers at 3°C]]></title><description><![CDATA[Networking on multiple levels Ever spent a week at 3°C with microcontrollers and sensors? We have. We are
Corinna Aufderheide
and Anne Mayer…]]></description><link>https://drumm.sh/student-blog/2021/08/23/ipss21-auderheide/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2021/08/23/ipss21-auderheide/</guid><pubDate>Mon, 23 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;networking-on-multiple-levels&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#networking-on-multiple-levels&quot; aria-label=&quot;networking on multiple levels permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Networking on multiple levels&lt;/h2&gt;
&lt;p&gt;Ever spent a week at 3°C with microcontrollers and sensors? We have. We are
&lt;a href=&quot;https://www.linkedin.com/in/corinna-aufderheide-085613209/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Corinna Aufderheide&lt;/a&gt;
and Anne Mayer and in this blog post we would like to tell
you about our experiences in the lecture &quot;Industrial Production and Industry 4.0&quot;
and give you some insights into our last semester.&lt;/p&gt;
&lt;p&gt;&quot;Industrial Production and Industry 4.0&quot; is a lecture in the second semester of
the 4-semester master&apos;s program &lt;a href=&quot;https://www.fh-aachen.de/en/course-of-study/industrial-engineering/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Industrial Engineering&lt;/a&gt;.
Beforehand, we were given the task to order some hardware components like a
&lt;a href=&quot;https://www.amazon.de/dp/B06Y1LZLLY&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ESP8266 Microcontroller&lt;/a&gt;,
breadboards and a &lt;a href=&quot;https://www.amazon.de/dp/B01M30ZWQR/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;sensorkit&lt;/a&gt;
with seemingly endless possibilities. Due to the lack of prior experience with
microcontroller and sensor, we were
overwhelmed by the variety of the sensors to choose from. During an
introductory session &lt;a href=&quot;https://drumm.sh&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Prof. Drumm&lt;/a&gt; and
&lt;a href=&quot;https://www.fh-aachen.de/menschen/meinecke/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Prof. Meinecke&lt;/a&gt; gave us various examples of what
can be done with the sensors. For example, we learned how to trigger an LED when
pressing a button or how to measure temperature and humidity in a room.&lt;/p&gt;
&lt;p&gt;The following image shows a few of the components we used in our project.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 605px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/188878f06979ce2fbaa349251dc2785e/90cbd/Hardware.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAACN0lEQVR42lVSS2sTURjND3Gn7uqiutCNuHTXtZtCiSC6K7RC60IXIqjFR1tLFaToqkEpCobiTpDupEkgVSevTpOZTB7zSCaTSWYmmRy/78ZJyIU79zLn3vOdc74bAw21WoUk/UY2m0GzUedfsG1brDnpD46OfqLf7yMajIVhKPajcITRaDTBYvy5c+8u5q9cwo3r83i0vjq+1G6Lg5VKGXt7b7Gz+wbHqdQMYadlQj75hYb8F+FwOCU8lU+xvLKMq9cuY2HhJja3XsNxHAyHIZGGOPx+gFfbz7G6toLE/j5834cfeDC0M7iODauhwnedMWEkN3uSxcbLF1hcvIX1tfvCYkh2XNfGt+RnvP+wi8dPHiKdOhaEg8EAdAADz0fge2x+qrDT6aDX6wmLum7AMEwi6pLCsQ3XdXEml1AuyzOWKT10yEkQBJMcYwzW63XKqgKtqqFWqxGhAVVV0Wq1xGX+12w2YVNhLs6YZVlCBK9ckFW3KfdY1C2n14WslieVmEjYouENAuimQR0dn23/b5hltUhMDYpSIUHKbIa6qWP73Y6oFMXAmOd5+JHJ4MGzp0il0wJjBzw2Nrdw7sJFnJ+bw1I8PkvI9pbityfvjwk5Q8ZrTR0HySSqmjY5K96oLONjIoFPX79AyuenhJwFd5UbwXlwyBEh731SyXtWyw74SfGdIPBFDMwhnhJNQagoCgqFgpjFYlFY4kuM8V7K5VAslZCjtdsdF9VIbZ5U5fMFsTJmmib+AfrjIOdlkWd7AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;microcontroller, breadboard and sensors&quot;
        title=&quot;&quot;
        src=&quot;/static/188878f06979ce2fbaa349251dc2785e/90cbd/Hardware.png&quot;
        srcset=&quot;/static/188878f06979ce2fbaa349251dc2785e/772e8/Hardware.png 200w,
/static/188878f06979ce2fbaa349251dc2785e/e17e5/Hardware.png 400w,
/static/188878f06979ce2fbaa349251dc2785e/90cbd/Hardware.png 605w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;At this point We were very glad that we took the Python introductory lecture
in the previous semester. This enabled us to quickly program the microcontroller
using PyCharm and to analyse data using Jupyter Notebooks. In addition, we were
also introduced to the &lt;a href=&quot;https://aws.amazon.com/iot/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AWS IoT Services&lt;/a&gt;. These are
cloud services
provided by Amazon to collect and process large amounts of data.&lt;/p&gt;
&lt;h2 id=&quot;industry-40&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#industry-40&quot; aria-label=&quot;industry 40 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Industry 4.0&lt;/h2&gt;
&lt;p&gt;But the question that interested everyone in the course: What do I do with
all this in real life?&lt;/p&gt;
&lt;p&gt;Industry 4.0 - as the fourth industrial revolution is known - has become an
integral part of the industrial context. It is about digitalization and the
intelligent networking of machines and processes using internet technologies.
The possibilities and potentials that Industry 4.0 holds for
industrial production were the central topic of the lecture taught by
Prof. Drumm, Prof. Meinecke and Prof. Luft. In addition to the introductory session,
we were provided with 12 learning videos on different topics in the context
of Industry 4.0. The topics included cyber-physical systems, cloud computing,
Big Data, business analytics and the autonomization of production. The
underlying question always was: How can industrial production
be supported and improved using those technologies?&lt;/p&gt;
&lt;h2 id=&quot;a-real-world-use-case&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-real-world-use-case&quot; aria-label=&quot;a real world use case permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A real-world use case&lt;/h2&gt;
&lt;p&gt;Building on this question, we were asked to find a use case for
an IoT project. The goal was to investigate a real-world problem by recording
data using sensors and microcontrollers, storing the data using AWS IoT service,
and then analyzing the data to generate some insights. If possible, the use case should
be in an industrial context. This was a big challenge for most of the students due to the
pandemic situation. We were lucky and were able to conduct our project together
with a company. Through research and several discussions, we came into contact
with a logistics service provider that specializes in the storage and
transport of frozen goods. For this company we implemented a project in which we examined
temperature changes in a cold storage hall for fresh products. For the project
microcontrollers were attached to all doors of the cold storage hall as well as to the ceiling.
The microcontrollers were connected to 5 motion sensors at the gates and 9 temperature sensors
distributed throughout the storage hall at heights of 2 and 8 meters.
The images below show the prototypical setup with a temperature sensor and a motion
sensor respectively.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 294px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1fbda18f76f05d79c4d3d47b0ac7539f/04a86/Tempsensor.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 64.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADfklEQVR42iWT60+bVRzH+z+YmPiGbYyIyZZsyeYtxBhNNMyBIkvAeCFBTSBGdIAhG4uJBnSjXMa6rR2FAqOAdKVcCi1QytM+fZ620NLSGy33lctQl/jC7A/4eKgvPjm/8+L3Od9fzjmaja1jEutZ4jn2SWYOc0STe/jDGXyBBG7vKpIcQVZjeJUYS6JelMKCVVxSSLDCnMvP1LQbTTyZZU00x1JZook9UT/NyU/WwGoGj7KWa3J7Q7naqyTEPoLkixFPRPD73TjnHdidKtN2CU0ktpMTReO7rEQ2WY5sEU0dEMscEVzbQVLjOFxBZpeiSMEE/tCKSCgLsZdYzIfTYWZq0oxlfIFxmwuNf3mdYHiDcGxXjJklvXXISjiEpARwe3xMOl0syAGiipO4sxPXQDNjD5pQpH7cswZMvZ30mx7xeHgG88gMmsByQpwWQgmKBHKYltbfqKqqoOmHr2isq8L4QItT34iuoZjO5u8Y0bcz0PYz7lE9Dksr+u5btHfoMfaNC+k0mp3NNJtJH/KilcbrNeQXFPBK3hnOnX+VzytL0X5/jZqKC+TlvUTRO0UYejrR9d6n7osyDL98w42GL6mtradbZ2JgcAJNMvWUne0sx8+eo9W2k3fqFGeE9Gzha3x65T1KL+fzwbtnKcx/mdcvFnKntRHzqIHyj96nqbqImq+vUnKlhNYWLUbjH2jS6X0yG0ccPnuB6g9SXV1JWVkx5eVXeePNSxQUnObypXO8/dZFvq2+xsP7rUxNmWlorOPC+dN8VlFKSfGH/FhXj667F00qtcfGxoEQ/sv+QZYxSx8mcw9DYyb0fffo0N2m497vtHX9ysOeDoyDevqHjXQb7vLTrSY6ulqoKC8V4kra2u6KkZM7IuEBR3++YG8zhscxguQYRV54IrCium1458aYsZpYsA8zaxvEbh1gxvaYmfEh5iaGuFlfS/knH9N2ux1NIr6dS5g9+Ie/n//F4W6SZEQmHvKQjqokwjKJ1f9ZDUiE1UUCkhPP3CQu+xPm7Va6tHdovnGT7rs6MfJJwsw+m9vHbO0ek0pvEwpFUcQ7lH0qihrM4VMD+JQgkkdlfmFJ/Aontgk7FouNoaFRjD39PDL0iUtZ3yWdFg9a/N91kTQa3yIQiOARjSf4fMtCHMTr8SPLQdxuhdnZRaxWO6MjVoaHLTn6B0bo7R3kP/5dABIWW8boAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Microcontroller and temperature sensor&quot;
        title=&quot;&quot;
        src=&quot;/static/1fbda18f76f05d79c4d3d47b0ac7539f/04a86/Tempsensor.png&quot;
        srcset=&quot;/static/1fbda18f76f05d79c4d3d47b0ac7539f/772e8/Tempsensor.png 200w,
/static/1fbda18f76f05d79c4d3d47b0ac7539f/04a86/Tempsensor.png 294w&quot;
        sizes=&quot;(max-width: 294px) 100vw, 294px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 298px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d717ef946c644db83c2e25f3998e75b1/ca501/Bewegsensor.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAADqUlEQVR42h2S6U/TBxyHf/+CZoMdDiQwpsCkcgQoR0RGhAlsohxyZAoCrYJBtgiLDrMYlxg5nCJnwVLGNaBAC21pB4WBchY67mOkjNGhwUjw1ZItefZzL57km0/yeV588hWWdvb4880/TK9toVA1kZ6awJkIqUgwoSGB+Pme4FOv43h4HMPd3Q0Xl6M4OztxVMTV1YXjx9zw8nQnOewkpUkRCFW11YzNrzM4u8rjmnoSEs4R4O+Fv48HPhIPvE94iCV3nJ3ex/mj93A64sAHjodxdDjMu+8c4siHjnh+7ExKmIRbMVKEEKk/imY1w5ZV6praKfr2NjkyOfJr10hJS+NytpwM2VUyxexCShrnEtPJyr6KXJ5HfkEhlzNlJMTFECdxQ3baH6GkvJIN2ysWV3dYeMuaneXNl1iX/qCjfxjr3AbW5/PoOg10dxlRtP9CZdMAo5NrzC5so2rRYhqcIjclmXifTxC27Acsrf0lyuzMr9iZXdpmXrx7B0Yxd/SzpDfT+EiJpkXDcGc/Y916fhLFtS0menS/irurGRPlBtMU1y9dQngr+21lR8TOwvoLln7fY3H7gO7WXuaNzxixbtKkn2ZqdZfx1ReYe4cY7DFS0WSkrlGNThQNjS5gMs+h1Y0hWJd3Wdh4JYpeY1m0MTw+jtqgp+HeD/QbDNS2dlFS9ZROrZb61nZUbW00lJZSUFxG2ZNmWrrMNLUb6egdRqN7hrC9bWNy8jkNjc3i4Ml8FhXJ2c9DkUUGcz0znsT09P/f5qI8l4z8rzkV8yXxiUlcyUglNUfOxQwZwRFnkRV8T7dmFMG+Y2NleYGcnGy8vL0JDQ/HXxqIj5sbp4J9kQSG4ODoQGFZJcq2n0lLSsY75AySsGhu37vLjw9LuRAbTf7Nu9Q/7UVY39pne+9fjGYj2bJUklPPk5hyHkmAL0FhQUj8TvJFQgx5N4vw8w8g/HQ4vsGRHHKVcD49i9jYODy8PEn7Kovyh0oE284+u6//xrY1h0pVTrWinCqRR1UPqKh+wJOaEpSt1WJWQZA0lKjoKPLyZOTmXaH4zi18fQOQBku5UVDE/fuVCGube+ztv2F3ZwbLhIaJMTWz0zosk31MT2mYmdYyM6XFOqtnZERNf58KjboWQ58SraaBwm9uUPzdHcrKHlNeXoWwur6L/eUBmzYrE+N9DJvVjI8bmJo0MjE5wLRlCItlRMxMjI7qMZv7MJk0GAw9dHW1UFenQKFQUlunpKZWyX+BnK44mb7ioAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Microcontroller and motion sensor&quot;
        title=&quot;&quot;
        src=&quot;/static/d717ef946c644db83c2e25f3998e75b1/ca501/Bewegsensor.png&quot;
        srcset=&quot;/static/d717ef946c644db83c2e25f3998e75b1/772e8/Bewegsensor.png 200w,
/static/d717ef946c644db83c2e25f3998e75b1/ca501/Bewegsensor.png 298w&quot;
        sizes=&quot;(max-width: 298px) 100vw, 298px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Within a week, 2.5 million data points were collected using those 14
microcontrollers and sensors. All this data had to be analysed afterwards.&lt;/p&gt;
&lt;h2 id=&quot;some-difficult-problems&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#some-difficult-problems&quot; aria-label=&quot;some difficult problems permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Some difficult problems&lt;/h2&gt;
&lt;p&gt;We worked several hours per week on the project, and it was a strain on our nerves.
In contrast to the &quot;laboratory conditions&quot; at home, WLAN interruptions, daily
resets and inexplicable phenomena in the industrial context were more
difficult to analyse and solve on site. But we also learned first-hand what to
look out for when carrying out a project in an industrial setting. For example, we learned a
lot about data protection, the right choice of sensors and that working in a
cold storage hall at 3 °C can be really tough.&lt;/p&gt;
&lt;p&gt;We also had to deal with the
problems that arose from the people working in the storage hall.
For example, we discovered that an
infrared sensor also reacted to the body temperatures of the employees behind
the gates and provided unusable data for the project. We therefore decided to use ultrasonic
sensors instead.&lt;/p&gt;
&lt;p&gt;We also had to deal with WLAN dropouts at night. These can be seen in
the image below. For some unexplained reason WLAN connection of the microcontroller
stopped every night. A software solution was not successful here and the
application of a hardware reset was not feasible in the short project phase.
Therefore, the only option for us was a manual reset every microcontroller every morning
with the help of an employee of the logistics company in order to record suitable data.&lt;/p&gt;
&lt;p&gt;During programming and analysis, further problems arose due to the high number
of data. All the data stored in AWS had to be cleaned and changed to the
same format. This resulted in high run times for the data analysis program. As
a result we had to learn about parallel processing in Python on our own
to be able to present a descriptive and fast solution.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 605px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a0e2cf49658162edfcb494c07313ded8/90cbd/Auswertung.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 29.000000000000004%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABaklEQVR42j2Ru08bQRCH/ScmtFGkdPwFUFCQhiIVHekjGijSBiQSHpaIIwHmIcd5ycSGgAQ6zmff7u37vowPxK5GO7P7zW9nZ1sxRrwPOOfxM/Oe8BRPJ1OKomBSTBjn48Z3zj3zIYSGd9ZhjaWua1ozIIkodZKN2EApSUwSX0BribLG6ETEymVe0CgWHn2ZzipGV0PJS7SMKCuV+HVecPlzKlCknEZ+fy/JHzyzcXdr+ftHS6WP8c2o4upSE2JNngX6Jzm3w1ykRbAaXzPY/Mj23BIHb5bJj/forX3g84tFzpZXUdddvq2858vLBQbrG2Tdffbm39F+vUR2ut+wW6/ecrzTIc4qtN5gb4aYow7uxwWhUujeBXpnC9PvEWxFedim3P6E+TfCZvfoziGqvYvP7vCjAfroK1ryYhRBpRRenCRPMdLLsqpIdd3EWhpvpOG+hiAPKo3Bh9icWalGSbuCsFGsqnTzQf8BXzW9y/ZE0BUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Excerpt of the collected data&quot;
        title=&quot;&quot;
        src=&quot;/static/a0e2cf49658162edfcb494c07313ded8/90cbd/Auswertung.png&quot;
        srcset=&quot;/static/a0e2cf49658162edfcb494c07313ded8/772e8/Auswertung.png 200w,
/static/a0e2cf49658162edfcb494c07313ded8/e17e5/Auswertung.png 400w,
/static/a0e2cf49658162edfcb494c07313ded8/90cbd/Auswertung.png 605w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;our-results&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#our-results&quot; aria-label=&quot;our results permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Our results&lt;/h2&gt;
&lt;p&gt;After the analysis, we presented our results to the logistics company and made
the analysis tool available to them. Based on our analysis the logistics company
will start to work on the detected problems and thereby improve the cold chain
for fresh products.&lt;/p&gt;
&lt;h2 id=&quot;some-thoughts-on-the-lecture&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#some-thoughts-on-the-lecture&quot; aria-label=&quot;some thoughts on the lecture permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Some thoughts on the lecture&lt;/h2&gt;
&lt;p&gt;The project was a real challenge through which we were able to learn what it means
to carry out a project in practice. Through our
perseverance, we were ultimately able to create value for our project partner.
In summary the lecture gave us the opportunity to gain valuable experience in
practice and to experience for ourselves how Industry 4.0 technologies can be
used and what their potential is. With the expansion of our network,
knowledge and experience, the high effort of the module was definitely worth it.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Building my Python Dev Environment with VIM]]></title><description><![CDATA[A few months ago I finally took the time to learn VIM.
This whole endeavour was inspired by DJ Adams through
his Hands-on SAP Dev
videos…]]></description><link>https://drumm.sh/blog/2021/05/29/vim-python-dev-environment/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/05/29/vim-python-dev-environment/</guid><pubDate>Sat, 29 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few months ago I finally took the time to learn &lt;a href=&quot;https://www.vim.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;VIM&lt;/a&gt;.
This whole endeavour was inspired by &lt;a href=&quot;https://twitter.com/qmacro&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DJ Adams&lt;/a&gt; through
his &lt;a href=&quot;https://youtube.com/playlist?list=PL6RpkC85SLQABOpzhd7WI-hMpy99PxUo0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Hands-on SAP Dev&lt;/a&gt;
videos. After seeing all the incredible things DJ did in the terminal using VIM,
I wanted to be able to do this as well.&lt;/p&gt;
&lt;p&gt;In summary, learning some of the command line tools I saw in DJs videos really changed
the way I&apos;m working. Today, I spend a lot more in the terminal time using
&lt;a href=&quot;https://github.com/ranger/ranger&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ranger&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Tmux&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tmux&lt;/a&gt; and VIM.&lt;/p&gt;
&lt;p&gt;However, one thing I did not do so far was customizing VIM to my requirements.
While I installed quite a few plugins, I never took the time to really
adjust VIM and the plugins to my needs. Last week I decided to create
a default project setup for my Python 🐍 projects. As a result, I also
tried various VIM plugins. Here is what my current development environment
in VIM looks like and the settings I decided to use.
The whole configuration is available on
&lt;a href=&quot;https://github.com/ceedee666/devenv-dotfiles/blob/master/.vimrc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;basic-os-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#basic-os-settings&quot; aria-label=&quot;basic os settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Basic OS Settings&lt;/h2&gt;
&lt;p&gt;One of the first things I did when learning VIM was to remap the &lt;code&gt;&amp;#x3C;caps lock&gt;&lt;/code&gt;
key. I highly recommend doing this as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;#x3C;caps lock&gt;&lt;/code&gt; is really not useful unless you are developing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ABAP&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ABAP&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you will need to use the &lt;code&gt;&amp;#x3C;esc&gt;&lt;/code&gt; key a lot in VIM&lt;/li&gt;
&lt;li&gt;VIM offers out of the box functionality for&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://vim.fandom.com/wiki/Switching_case_of_characters&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;switching cases of characters&lt;/a&gt;
using &lt;code&gt;&amp;#x3C;g&gt;&amp;#x3C;U&gt;&lt;/code&gt; and &lt;code&gt;&amp;#x3C;g&gt;&amp;#x3C;u&gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;basic-vim-settings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#basic-vim-settings&quot; aria-label=&quot;basic vim settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Basic VIM Settings&lt;/h2&gt;
&lt;p&gt;The most important setting for me is to activate the syntax highlighting and
automatic indentation. This
is done by adding this code to the &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;syntax on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;set autoindent&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The simplest approach to editing the &lt;code&gt;.vimrc&lt;/code&gt; file is by executing
&lt;code&gt;:e $MYVIMRC&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, of course, is a proper color there. After trying different ones, I finally
settled for the &lt;a href=&quot;https://draculatheme.com/vim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Dracular Theme&lt;/a&gt;. As I&apos;m using the
&lt;a href=&quot;https://github.com/junegunn/vim-plug&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vim-plug&lt;/a&gt; as the plugin manager, I installed
the theme using:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Plug &amp;#39;dracula/vim&amp;#39;, { &amp;#39;as&amp;#39;: &amp;#39;dracula&amp;#39; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The color scheme is activated by adding &lt;code&gt;colorscheme dracula&lt;/code&gt; to the &lt;code&gt;.vimrc&lt;/code&gt;.
The following screenshot shows the dracula theme in action while editing
this blog post.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/52ff8b3bcf15b6e175a9e94437971e27/6b26f/dracular-theme.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB4klEQVR42n1TWZKdQAx7B8rAY2l632l4k0pV7n8aRTRJJqnU5ENldxuEZJuHUg5GazjnoBk3KbFtG5TSkJuE5Pn5fP4H0+98GAY86r7jfDXknPjyhmWZiBnzPGGa+CAxjsON5/gzHz/ufp1Ze3v7gkd0B2p8wSoLbzOcTh1iMVBbgBYB28r8iteduJxsvSaZG5l7fROG72g8pPAsaqpaqGrBMq/EgnVhXO5cXPfrxvp1JzDz2ed4252nhU7oiBiHJx7WOpSUO3JMSLkgEqlUlECUA6GcCK9vsO0r/Pt3uHrA+oCFPZ7mmcRjJx+GNzy8TzjyjuQiWqqIJAp1R24nbKD9VCD5URMybCywPLtcoUgotKNyQbUknKZ7KFqzd8HDWgPvHbxe4dWK4G2fvtEKWilYY3p01nL67CGnv9L6SJK/ppyMx0Fbrr0QjneCttp7txhqI5GFIMG1SkIIRtl7PU1Tx58r1Am9vdRZ2otw7GGPl1Va1IaK/V2XSnI3FQyVfrabt0L2ba8VtRS01lBrQckZ+85YIuPOWHAcR48xxk+XvBMGqjnPs5Od54sErZO0g7Fx2indDrrKW+HcJ/sJoRUSkc1XnLamTekCDKdpqFywvysXfqX11d75wl/yY1X+JfwBsreNS6eDAIUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;VIM with Dracula Theme&quot;
        title=&quot;&quot;
        src=&quot;/static/52ff8b3bcf15b6e175a9e94437971e27/5a190/dracular-theme.png&quot;
        srcset=&quot;/static/52ff8b3bcf15b6e175a9e94437971e27/772e8/dracular-theme.png 200w,
/static/52ff8b3bcf15b6e175a9e94437971e27/e17e5/dracular-theme.png 400w,
/static/52ff8b3bcf15b6e175a9e94437971e27/5a190/dracular-theme.png 800w,
/static/52ff8b3bcf15b6e175a9e94437971e27/c1b63/dracular-theme.png 1200w,
/static/52ff8b3bcf15b6e175a9e94437971e27/29007/dracular-theme.png 1600w,
/static/52ff8b3bcf15b6e175a9e94437971e27/6b26f/dracular-theme.png 1658w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Next, I enabled relative line numbers by adding
&lt;code&gt;set number relativenumber&lt;/code&gt; to the &lt;code&gt;.vimrc&lt;/code&gt;. This way it is easy to see how many
lines I need to move up or down to put the cursor on a certain line.
Additionally, highlighting the current line with &lt;code&gt;set cursorline&lt;/code&gt; helps me to
quickly spot the current line.&lt;/p&gt;
&lt;p&gt;Finally, I added keyboard shortcuts to simplify moving between panes by
pressing &lt;code&gt;&amp;#x3C;ctrl&gt;&lt;/code&gt; and &lt;code&gt;&amp;#x3C;h&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;j&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;k&gt;&lt;/code&gt; and &lt;code&gt;&amp;#x3C;l&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;map &amp;lt;C-j&amp;gt; &amp;lt;C-W&amp;gt;j&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;map &amp;lt;C-k&amp;gt; &amp;lt;C-W&amp;gt;k&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;map &amp;lt;C-h&amp;gt; &amp;lt;C-W&amp;gt;h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;map &amp;lt;C-l&amp;gt; &amp;lt;C-W&amp;gt;l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;vim-plug-ins&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vim-plug-ins&quot; aria-label=&quot;vim plug ins permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;VIM Plug Ins&lt;/h2&gt;
&lt;p&gt;With the basic configuration in place, the next step is adding plugins to
extend the functionality of VIM. As mentioned above, I use
&lt;a href=&quot;https://github.com/junegunn/vim-plug&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vim-plug&lt;/a&gt; as my plugin manager.
In my current configuration I use the following plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/vim-airline-superman&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vim-airline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/nerdtree-red&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NERDTree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/fzf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fzf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/coc-nvim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Conquer of Completion (CoC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/ale&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Asynchronous Linting Engine (ALE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/neoterm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Neoterm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/plugin/vim-test-all-too-well&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;test.vim&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;improved-status-bar&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#improved-status-bar&quot; aria-label=&quot;improved status bar permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Improved Status Bar&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://vimawesome.com/plugin/vim-airline-superman&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vim-airline&lt;/a&gt; offers
a highly customizable status bar. I simply installed this plugin with its
default configuration. The following screenshot shows my status bar while
writing this blog post.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/152f343ff28704fb30ae764e1b727635/2dc7d/status-bar.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 16%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAt0lEQVR42lXOwUrDQBSF4byPTXOnNHYykyZzZ8YQkFSwVbqsUFeiggvBp/9N1Y2LDw4HDpxCzJptowSXadtM45Vr17K2DXXjqa37NefNpatrRAQx/5kLMRSmXJE6nQVuhgFNiV6VLgSCRkKMaMz0Qen7Duc2SLlEripkUWH+lGXFYrmiCE8j09eR8fNAvB/o3HYeObz3tDNr7c8r7x0575lunxlOD+SPHfntjvQyEV93nM8j74+Jb2jYZ3QAoM4qAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Status bar after installing vim-airline&quot;
        title=&quot;&quot;
        src=&quot;/static/152f343ff28704fb30ae764e1b727635/5a190/status-bar.png&quot;
        srcset=&quot;/static/152f343ff28704fb30ae764e1b727635/772e8/status-bar.png 200w,
/static/152f343ff28704fb30ae764e1b727635/e17e5/status-bar.png 400w,
/static/152f343ff28704fb30ae764e1b727635/5a190/status-bar.png 800w,
/static/152f343ff28704fb30ae764e1b727635/c1b63/status-bar.png 1200w,
/static/152f343ff28704fb30ae764e1b727635/29007/status-bar.png 1600w,
/static/152f343ff28704fb30ae764e1b727635/2dc7d/status-bar.png 1760w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;project--file-system-explorer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#project--file-system-explorer&quot; aria-label=&quot;project  file system explorer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Project / File System Explorer&lt;/h3&gt;
&lt;p&gt;A useful feature all IDEs offer is a file system explorer for projects or
directories. &lt;a href=&quot;https://vimawesome.com/plugin/nerdtree-red&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NERDTree&lt;/a&gt; provides
exactly this feature for VIM. Again, I simply installed the plugin in its
default configuration. In contrast to IDEs there is no concept of a project
in NERDTree. Instead NERDTree simply show the directory from which VIM was
launched. As all of my projects are organized in different directories anyway,
this is all I need.&lt;/p&gt;
&lt;p&gt;One of the nice feature of NERDTree is the action menu, which can be accessed
by hitting &lt;code&gt;&amp;#x3C;m&gt;&lt;/code&gt; inside the NERDTree window. This action menu provides
quick access to functions like creating, renaming, moving and deleting
files. The following screenshot shows the NERDTree and the actions menu
in the directory for this blog.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ab9002ec52739224f2782be0745e68c1/5b6ee/nerd-tree.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAACgklEQVR42o2T3W7UMBSE8ygggUTb3c3m33YSO3F+d1eCLltKKS19BiohuEDlAgTiqYdxtu1FEaIXn459oox9ZhIvES3C2GAZahzMMhzOJQ5nDoEZ90cLrsnRQv3F4VE24d4LY41UNPDSuMBYvUWvT9CUx2j1DnGkkCYKndAwVQ9ZD8ibFaTl2g77WjWIhSI5wiiB7y+xXAbwpDDYNO+xsmdY1WcY61OK5UhiBZUayKSEyAyiRHCKCEEU39aIQjGCOEEQhggCJ7iEp6TBqt1h1W/R2TVaO1JMoMhLDLZF3/Www4Cq7VF1IzR7NavtB5imZX9A03XQWu8FZVqhr05QSMuGf0sIKXPosoQpNXRRIEsSHhRNVaQZ0kwQ1jRlP0ZEJkHnW1/t2JTwnditFzItodMakn66sXVmUfJwEWb0OEaYMIhMThbM53MsFou9oMlX9EjRg2BqOHw/4MkSRVFCKYVSSJJD0YZUCAhJf/MCUuX3a8G+0/CapsFqPaKqzGTsYjHDgresqgrDOGLoewZmYUwFXTcoiWn6yTvnq6aPxjaTh258r2s2WA+vkAuOw9GymNAj513Nk2v6lxMpJaS7HX17iHLPSMa1d7G9xofdZ5y/vMbl9hOudl94wBab9QavyfFqjY4pFneiD3CjGmOm59PIhqPapoK1NUqdMzkmFoWIXXJMNOYYEb853/f/iQvkPhRNb5yPdW0nynJ/k4Ri+4D2L90F9j88Q8P7cYBtG7R9h5o3VbmCUJI35J8QBhPLR+IV/M7qVKNktazpYYjZ0wMEz+dYPpth9uQF5tw/Fs983KL9eoruhv/xr0t0P84x/LzA5vcVuu/vUN2coP725tH8AXyv+5etvrchAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;NERDTree and the actions menu&quot;
        title=&quot;&quot;
        src=&quot;/static/ab9002ec52739224f2782be0745e68c1/5a190/nerd-tree.png&quot;
        srcset=&quot;/static/ab9002ec52739224f2782be0745e68c1/772e8/nerd-tree.png 200w,
/static/ab9002ec52739224f2782be0745e68c1/e17e5/nerd-tree.png 400w,
/static/ab9002ec52739224f2782be0745e68c1/5a190/nerd-tree.png 800w,
/static/ab9002ec52739224f2782be0745e68c1/c1b63/nerd-tree.png 1200w,
/static/ab9002ec52739224f2782be0745e68c1/29007/nerd-tree.png 1600w,
/static/ab9002ec52739224f2782be0745e68c1/5b6ee/nerd-tree.png 1672w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To enable me to quickly access NERDTree inside VIM I added the following
mapping to my &lt;code&gt;.vimrc&lt;/code&gt;. This mapping allows me to toggle the NERDTree by
hitting &lt;code&gt;&amp;#x3C;ctrl&gt;-&amp;#x3C;n&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;map &amp;lt;C-n&amp;gt; :NERDTreeToggle&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;fzf---the-command-line-fuzzy-finder&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fzf---the-command-line-fuzzy-finder&quot; aria-label=&quot;fzf   the command line fuzzy finder permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;FZF - the Command-line Fuzzy Finder&lt;/h3&gt;
&lt;p&gt;Having a project tree is nice. However, searching files in large project
or somewhere on the file system is quiet tedious this way. This is when
&lt;a href=&quot;https://github.com/junegunn/fzf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fzf&lt;/a&gt; becomes very useful. Using fzf inside
VIM requires the installation of &lt;a href=&quot;https://vimawesome.com/plugin/fzf-vim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;two plugins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Again, I simply used the default configuration for this plugin. With
the plugins installed there are a few new commands available in VIM.
&lt;code&gt;:FZF&lt;/code&gt; starts fzf in the directory of the current file. &lt;code&gt;:Files&lt;/code&gt;
in contrast allows to specify a directory from
which fzf starts to search. The following screenshot shows the fzf pop up window
after executing &lt;code&gt;:Files&lt;/code&gt; in the root directory of my website project and
entering a few search characters.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c77dc2885267a4fc4c24a5dc55a3ca36/5ab15/fzf.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 45.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8klEQVR42p2Ry3KDMAxF+SLCO4DpxG/Z8P/fc2M5NYu2KZ0uzlhe6MyVVK3rCmsttNYwxkAqCfl4QGqJzXykWqLrOtR1jdvtlutxHDPDMJzwv+97VJvYEPcIFzwoBnhPCQ8fCIYsvPMQQqBpmhOWMm3bnpR/tSxLavaQUeeknNI6+6q1gVIK0zTldCwr7zs+hQQVXiIWeu+ykOFxeNzScCnkHYYjQu0GlMZjKRFlON3XhkuhWEUW6sMhUsj7K8J5nr8J/pSQ9gB1WIR0EOdchsflRf8vYRLqaPJFS0K+7E/Nl8L7fU6JCOs65xEL7xpY+BtPu88oiUbq88YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;fzf running inside VIM&quot;
        title=&quot;&quot;
        src=&quot;/static/c77dc2885267a4fc4c24a5dc55a3ca36/5a190/fzf.png&quot;
        srcset=&quot;/static/c77dc2885267a4fc4c24a5dc55a3ca36/772e8/fzf.png 200w,
/static/c77dc2885267a4fc4c24a5dc55a3ca36/e17e5/fzf.png 400w,
/static/c77dc2885267a4fc4c24a5dc55a3ca36/5a190/fzf.png 800w,
/static/c77dc2885267a4fc4c24a5dc55a3ca36/c1b63/fzf.png 1200w,
/static/c77dc2885267a4fc4c24a5dc55a3ca36/29007/fzf.png 1600w,
/static/c77dc2885267a4fc4c24a5dc55a3ca36/5ab15/fzf.png 2446w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;autocompletion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#autocompletion&quot; aria-label=&quot;autocompletion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Autocompletion&lt;/h3&gt;
&lt;p&gt;Of course, every development environment needs proper auto-completion.
For VIM, there a lots of different plugins offering this kind of functionality.
I decided to use &lt;a href=&quot;https://vimawesome.com/plugin/coc-nvim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Conquer of Completion (CoC)&lt;/a&gt;.
CoC support the &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Language Server Protocol&lt;/a&gt;
which is the protocol &lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;VS Code&lt;/a&gt; uses as well. Because of this,
CoC offers a similar feature set to the auto-completion in VS Code.&lt;/p&gt;
&lt;p&gt;I added the following configuration to my &lt;code&gt;.vimrc&lt;/code&gt;. I copied this configuration from
the CoC documentation. Lines 2 - 12 enable &lt;code&gt;&amp;#x3C;tab&gt;&lt;/code&gt; to complete suggestions.  Line 15
allows to trigger the suggestion popup using &lt;code&gt;&amp;#x3C;ctrl&gt;-&amp;#x3C;space&gt;&lt;/code&gt;.
Lines 23 - 31 allow displaying documentation for the word under the cursor using
&lt;code&gt;&amp;#x3C;K&gt;&lt;/code&gt;. Finally, lines 35 - 42 add keyboard shortcuts to enable the navigation to
definitions, implementations and references.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Use tab for trigger completion with characters ahead and navigate. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;inoremap &amp;lt;silent&amp;gt;&amp;lt;expr&amp;gt; &amp;lt;TAB&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \ pumvisible() ? &amp;quot;\&amp;lt;C-n&amp;gt;&amp;quot; :&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \ &amp;lt;SID&amp;gt;check_back_space() ? &amp;quot;\&amp;lt;TAB&amp;gt;&amp;quot; :&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \ coc#refresh()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;inoremap &amp;lt;expr&amp;gt;&amp;lt;S-TAB&amp;gt; pumvisible() ? &amp;quot;\&amp;lt;C-p&amp;gt;&amp;quot; : &amp;quot;\&amp;lt;C-h&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;function! s:check_back_space() abort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  let col = col(&amp;#39;.&amp;#39;) - 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  return !col || getline(&amp;#39;.&amp;#39;)[col - 1]  =~# &amp;#39;\s&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;endfunction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Use &amp;lt;c-space&amp;gt; to trigger completion.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;inoremap &amp;lt;silent&amp;gt;&amp;lt;expr&amp;gt; &amp;lt;c-space&amp;gt; coc#refresh()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Use &amp;lt;cr&amp;gt; to confirm completion, `&amp;lt;C-g&amp;gt;u` means break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; undo chain at current position.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Coc only does snippet and additional edit on confirm.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;inoremap &amp;lt;expr&amp;gt; &amp;lt;cr&amp;gt; pumvisible() ? &amp;quot;\&amp;lt;C-y&amp;gt;&amp;quot; : &amp;quot;\&amp;lt;C-g&amp;gt;u\&amp;lt;CR&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Use K to show documentation in preview window&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nnoremap &amp;lt;silent&amp;gt; K :call &amp;lt;SID&amp;gt;show_documentation()&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;function! s:show_documentation()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  if (index([&amp;#39;vim&amp;#39;,&amp;#39;help&amp;#39;], &amp;amp;filetype) &amp;gt;= 0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    execute &amp;#39;h &amp;#39;.expand(&amp;#39;&amp;lt;cword&amp;gt;&amp;#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    call CocAction(&amp;#39;doHover&amp;#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;endfunction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; GoTo code navigation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; gd &amp;lt;Plug&amp;gt;(coc-definition)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; gy &amp;lt;Plug&amp;gt;(coc-type-definition)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;35&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; gi &amp;lt;Plug&amp;gt;(coc-implementation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;36&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; gr &amp;lt;Plug&amp;gt;(coc-references)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;37&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;38&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Remap keys for applying codeAction to the current buffer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;39&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;leader&amp;gt;ac  &amp;lt;Plug&amp;gt;(coc-codeaction)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;40&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Apply AutoFix to problem on the current line.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;41&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;leader&amp;gt;qf  &amp;lt;Plug&amp;gt;(coc-fix-current)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following GIF shows the plugin in action in a small python project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3b608e63b4406d78aeec2c39b429483b/coc.gif&quot; alt=&quot;The CoC Plugin&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; CoC uses its own plugin manager. This means that CoC plugins
are not installed using the VIM plugin manager. Instead the command
:CocInstall is used to install the plugins. In my environment I
currently have the following CoC plugins installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;coc-markdownlint&lt;/li&gt;
&lt;li&gt;coc-json&lt;/li&gt;
&lt;li&gt;coc-html&lt;/li&gt;
&lt;li&gt;coc-tsserver&lt;/li&gt;
&lt;li&gt;coc-pyright&lt;/li&gt;
&lt;li&gt;coc-css&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;linting-and-fixing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#linting-and-fixing&quot; aria-label=&quot;linting and fixing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Linting and Fixing&lt;/h3&gt;
&lt;p&gt;With code completion in place I wanted to integrate linting and automatic
fixing of linting errors as well. For this purpose I installed the
&lt;a href=&quot;https://vimawesome.com/plugin/ale&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Asynchronous Linting Engine (ALE)&lt;/a&gt;.
ALE basically works out of the box. However, ALE also supports the Language
Server Protocol a providing code completion. In my setup I wanted to use CoC
for code completion and ALE for linting. Therefor, I followed the suggestion
from the &lt;a href=&quot;https://github.com/dense-analysis/ale#faq-coc-nvim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ALE FAQs&lt;/a&gt; and
added the following line to the CoCConfig:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;js&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;diagnostic.displayByAle&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition, I disabled the usage of the Language Server Protocol for ALE by
putting the following line at the very beginning of my &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let g:ale_disable_lsp = 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I configured which fixers ALE should use based on different file types.
For all files I want to remove trailing lines and trailing white space. Javascript
should be fixed using &lt;a href=&quot;https://eslint.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;eslint&lt;/a&gt;. Python 🐍 files are fixed using
&lt;a href=&quot;https://pypi.org/project/isort/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;isort&lt;/a&gt; and &lt;a href=&quot;https://pypi.org/project/black/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;black&lt;/a&gt;.
Maybe I should also add &lt;a href=&quot;https://pypi.org/project/flake8/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;flake8&lt;/a&gt; to this list 🤔.&lt;/p&gt;
&lt;p&gt;Setting &lt;code&gt;g:ale_fix_on_save&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; enables the automatic execution of the fixers
when a file is saved.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let g:ale_fixers = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \   &amp;#39;*&amp;#39;: [&amp;#39;remove_trailing_lines&amp;#39;, &amp;#39;trim_whitespace&amp;#39;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \   &amp;#39;javascript&amp;#39;: [&amp;#39;eslint&amp;#39;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \   &amp;#39;python&amp;#39;: [&amp;#39;isort&amp;#39;, &amp;#39;black&amp;#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      \}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; Set this variable to 1 to fix files when you save them.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let g:ale_fix_on_save = 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;terminal&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#terminal&quot; aria-label=&quot;terminal permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Terminal&lt;/h3&gt;
&lt;p&gt;Although I mostly run VIM inside tmux I also installed
&lt;a href=&quot;https://vimawesome.com/plugin/neoterm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Neoterm&lt;/a&gt;. Neoterm
provides a nice integration of a terminal as well as the
REPLs of different programming languages.&lt;/p&gt;
&lt;p&gt;I added the following
configuration to my &lt;code&gt;.vimrc&lt;/code&gt;. The first line specifies
that the terminal should be opened in a new window below
the current one (cf. &lt;a href=&quot;https://github.com/kassio/neoterm/blob/cae4f19aeac40037039e914932da850443b7729f/doc/neoterm.txt#L245&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt;).
The key mappings allow to toggle the terminal in all
modes using &lt;code&gt;&amp;#x3C;ctrl&gt;-&amp;#x3C;y&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let g:neoterm_default_mod = &amp;#39;botright&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nnoremap &amp;lt;c-y&amp;gt; :Ttoggle&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;inoremap &amp;lt;c-y&amp;gt; &amp;lt;Esc&amp;gt;:Ttoggle&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;tnoremap &amp;lt;c-y&amp;gt; &amp;lt;c-\&amp;gt;&amp;lt;c-n&amp;gt;:Ttoggle&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;unit-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unit-testing&quot; aria-label=&quot;unit testing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unit Testing&lt;/h3&gt;
&lt;p&gt;The plugin that completes my VIM setup is
&lt;a href=&quot;https://vimawesome.com/plugin/vim-test-all-too-well&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Test.VIM&lt;/a&gt;. This
plugin allows to run unit test in different languages and using
different unit test frameworks. For Test.VIM I added the following
configuration to my &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first line specifies that I want to use pytest as the
test runner for python projects. Line 4 configures
Test.VIM to run all commands using Neoterm. Lines 7 - 11
define keyboard shortcuts to execute different
commands like running a test file (&lt;code&gt;&amp;#x3C;t&gt;, &amp;#x3C;ctrl&gt;-&amp;#x3C;n&gt;&lt;/code&gt;) or
running a whole test suite (&lt;code&gt;&amp;#x3C;t&gt;, &amp;#x3C;ctrl&gt;-&amp;#x3C;s&gt;&lt;/code&gt;).
Finally, lines 13 - 19 defines an auto-command to execute
all unit tests in a file whenever the buffer is saved.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let test#python#runner = &amp;#39;pytest&amp;#39; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; make test commands execute using neoterm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;let test#strategy = &amp;quot;neoterm&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot;keyboard short cuts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; t&amp;lt;C-n&amp;gt; :TestNearest&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; t&amp;lt;C-f&amp;gt; :TestFile&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; t&amp;lt;C-s&amp;gt; :TestSuite&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; t&amp;lt;C-l&amp;gt; :TestLast&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;nmap &amp;lt;silent&amp;gt; t&amp;lt;C-g&amp;gt; :TestVisit&amp;lt;CR&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;quot; auto commoand to run tests automatically&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;augroup test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  autocmd!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  autocmd BufWrite * if test#exists() |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        \   TestFile |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        \ endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;augroup END&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;With the configuration and plugins describes in this
post I have now a really nice development environment
based on VIM. I hope this post helps others to configure
VIM to their needs without the need for all the trial and
error I went through.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#useful-resources&quot; aria-label=&quot;useful resources permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vimawesome.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vimawesome&lt;/a&gt;: collection of awesome VIM plugins.&lt;/li&gt;
&lt;li&gt;YT &lt;a href=&quot;https://youtube.com/playlist?list=PLu-ydI-PCl0OEG0ZEqLRRuCrMJGAAI0tW&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Playlist&lt;/a&gt; on using VIM as an IDE&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vimfromscratch.com/articles/vim-for-python/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;VIM for Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;My &lt;a href=&quot;https://github.com/ceedee666/devenv-dotfiles/blob/master/.vimrc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;.vimrc&lt;/a&gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[grievy - My Experiences as a Product Owner in the Digital Lab]]></title><description><![CDATA[The project Through a death in my family, I have experienced what it means to lose a loved one.
Many relatives feel overwhelmed with…]]></description><link>https://drumm.sh/student-blog/2021/05/25/dl-ws20-product-owner-experience/</link><guid isPermaLink="true">https://drumm.sh/student-blog/2021/05/25/dl-ws20-product-owner-experience/</guid><pubDate>Tue, 25 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-project&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-project&quot; aria-label=&quot;the project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The project&lt;/h2&gt;
&lt;p&gt;Through a death in my family, I have experienced what it means to lose a loved one.
Many relatives feel overwhelmed with organizational matters and left alone with their
grief. The scientific situation shows: the risk of mental illness is demonstrably
increased after an experienced bereavement. The handling of the many organizational
tasks, as well as the accompaniment through the grief have hardly arrived in the
digital space.&lt;/p&gt;
&lt;p&gt;My idea is to develop an app that accompanies, supports and demonstrably relieves
people at exactly these points after the death of a loved one. My name
is &lt;a href=&quot;http://www.linkedin.com/in/nelestadtbaeumer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Nele Stadtbäumer&lt;/a&gt;, I am a psychologist and
founder of &lt;a href=&quot;http://www.grievy.de&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;grievy&lt;/a&gt; - the first digital companion after a death.&lt;/p&gt;
&lt;h2 id=&quot;the-beginning-of-the-collaboration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-beginning-of-the-collaboration&quot; aria-label=&quot;the beginning of the collaboration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The beginning of the collaboration&lt;/h2&gt;
&lt;p&gt;For the implementation of the grievy app, I needed technically-savvy people who could bring the
content created by our psychotherapists and designers into the format of an app. My goal was to
give young people the chance to actively shape and collaborate on a practical project.
Through the recommendation of a friend, I turned to Prof. Christian Drumm. Fortunately, it
was just before the winter semester and the start of the project seminar. Luckily, I had
the chance to become a project partner with grievy.&lt;/p&gt;
&lt;h2 id=&quot;the-collaboration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-collaboration&quot; aria-label=&quot;the collaboration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The collaboration&lt;/h2&gt;
&lt;p&gt;The collaboration started with a presentation of all projects and project partners for the students in
seminar. All projects were very interesting and in total very diverse, so that there should have been
something for every area of interest. My concern was that grievy is only an idea and a start-up in its
infancy, and therefore not very interesting for students. Especially in contrast to the big companies
involved. However, my concerns were completely unfounded. The project was very popular with the
students and the participants had to be chosen through a lottery. Finally, a great team of 6 students as
developers, Christian Drumm as Scrum Master and myself as Product Owner was founded.&lt;/p&gt;
&lt;p&gt;We worked remote throughout the entire project (due to the pandemic). We organized all user stories
via a common Trello board and communicated via mail and Zoom. As the collaboration progressed, we
could see the students growing in their tasks and becoming more independent and organized. They really
outgrew themselves over the course of the project seminar and, with no prior knowledge of app
programming, created a first product version that was something to behold!&lt;/p&gt;
&lt;p&gt;I enjoyed the collaboration very much and learned a lot myself. I felt informed at all times and was
surprised every week how much the students achieved within a week. They brought in their own ideas
and showed me different ways to implement each idea of mine. Our Scrum Master, Christian Drumm,
steered us safely through the project and kept an eye on the time frame and the tasks.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;The final presentation in the plenum rounded off the project seminar. During the seminar we
focused on the organizational part of the grievy app. The final state after the project seminar
was an app with all organizational information and services, as well as placeholders for what is
still planned in the future. We would not have expected this great result in such a short time!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fe02cff7c3ea450d0bf2833b763321d2/66caf/grievy-overview.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAER0lEQVR42m2UC0xTVxiA77YqbNNNKS29fdOWcimFQm/fUi6lSFBYG1pfy7JNIhDmXJggw8zgjEFlCiplE8NLMgFBQFmAiZsMirBGR0bc2BzbeEmc2UoBjSMyevvvlrFlJjvJl3NyTs6X/zz+H0EQ5BkKmkQiCZDJtq+VSFIC/PjHCKysPdUIgqDpdLrn/QgERODfeyQBfseqC6HR6Yb1fD6OonxcyUAVm5jsWD2Xq1KzWcqSEKaiLYShaGLRFZdYwTFXeGw8T8RTq3io0shnqwxivhbncnUciUTzEoLgaxAUxV8IDdWGiIWGnRFhpt8iw81zcmnirFgY5zFssnnTrFmQasmErdZsSE1/C2KUqU94QsOsSGryCMMS3YIw00NBaNxeKloWnR6+HqEGG1A6jmHRm4uyykogr74S8ms+gn3Hi8By4Bi5+1yz901HozfzhMO7+8gpb0ZOga+p6BD0lJfBcH0l6TxfAclG69k1L2JyDDPTETampvNRLY4pzKesNcWwpfm472hPo6+ts9UXlZEHyv0nQZlHYXkNPqxthJy978Hg8YO+8QulviedVd7Hn1bDtiRbLRIo18vl2hBEIoljcJhKXWTMZkdVbxeUDXT4eu58DTe+HARrQTHkVrdBhqMR9LuyIL/0Y3i/8Ag0FLwDfeXFMFpXSk5edIDNbLtIWxcVr5YRrBXhxo1yvVptqZiZ+RWWl/70PXz0CJxOFzj7XQDeJfB45uCX8QlYJkloq6qD7kP74ae6MpjqvkTeb68Fm8naQNsgJ3DMiP4r1GotFZNTU+Cedfvm5+bBNTQM9S2d4PzmO/jcNQx9t0fA9eMEnDtZDtcP58N0QwXc7uslv7/aBDsSLI3/K5yYvAdut9vnoYQ/3LkLOwpKoKSpA2qvOaGO4nTXALyx513oKz4I4/Vn4e7NXnKyqxnsxCtPC4OConSU0OEXzi8sUBEugPOmC+wFJ6D++gAMfTsGIz9PQ/utUcjYkwuu4kKYqi6Bqc9ayJnLVWAj0qgjx8avCKVSIjgoSKZRay1nJqdnfEtLS97Fx4vkFwOD3sxiB3lrbJyc+X2WXPhjkRx94CH3HThKflVTSY51tpKeYeeyx3UDbFteracFyuJWHoX65UEcjkaBYcSxNOoD2+w5YKdIMu2Cwx+cga6efmi+3A0tV3qg81o/ZGYXgpHYBpb0bEjf/jZp35kL0dEp51msWJVIpGciMhmxTizWSfh8g53JjL3AZMa0BwcrWik+4XJUIxxUdZ/LVk1zUPwel40/4HLwIQZd3hTCkHcwgqOv0unRTXy+5nWBQI+JRPjLlBBZi6JEsFBoCJfLk1QUhB+FIlEjDjcZpFJjIoYZk6mrSQkLi98qksaZIyPNCRERCVSfaFIokjVhgvgIf/quFgnkWQSRBPiT2z/J4xnY/8DnG9FwqheLjTyhUC/4L2KxiucvCv49/shWZc/9BXQw/ibJRpNmAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The grievy app&quot;
        title=&quot;&quot;
        src=&quot;/static/fe02cff7c3ea450d0bf2833b763321d2/5a190/grievy-overview.png&quot;
        srcset=&quot;/static/fe02cff7c3ea450d0bf2833b763321d2/772e8/grievy-overview.png 200w,
/static/fe02cff7c3ea450d0bf2833b763321d2/e17e5/grievy-overview.png 400w,
/static/fe02cff7c3ea450d0bf2833b763321d2/5a190/grievy-overview.png 800w,
/static/fe02cff7c3ea450d0bf2833b763321d2/66caf/grievy-overview.png 853w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Even today, two of the students are still working on grievy. I always look back on that time with
pleasure and I am very happy that this collaboration came about. I am already thinking about how
we can be involved again in the next project seminar. I am already looking forward to the next
collaboration!&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Docker Hates Me]]></title><description><![CDATA[In this blog I described what I learned when trying to replicate the examples from the third
chapter of the Kubernetes in Action by
Marko…]]></description><link>https://drumm.sh/blog/2021/03/23/docker-hates-me/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/03/23/docker-hates-me/</guid><pubDate>Tue, 23 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this blog I described what I learned when trying to replicate the examples from the third
chapter of the &lt;a href=&quot;https://www.manning.com/books/kubernetes-in-action&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes in Action&lt;/a&gt; by
&lt;a href=&quot;https://twitter.com/markoluksa&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Marko Luksa&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 360px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/839a405a4e95ad2e4a2842c13c944cdf/158ba/book.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 125.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAZABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAYE/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHHTzNDl0DRMUstWEDf/8QAHRAAAQQDAQEAAAAAAAAAAAAAAAECAyEEETQQEv/aAAgBAQABBQLE6Ptoi7I6jiTcaUQWNppidPn/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwEhP//EABwQAAICAgMAAAAAAAAAAAAAAAABAhARITEyQf/aAAgBAQAGPwJN+bOUaFgTeajBdmKoX//EAB4QAQACAgEFAAAAAAAAAAAAAAEAERBBITFxgaGx/9oACAEBAAE/Ia21BUwrkAtWTvB5ioUsAKIw9QJXiGs6Me+/JrH/2gAMAwEAAgADAAAAEDcFfP/EABcRAQEBAQAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8Q0exMn//EABcRAQEBAQAAAAAAAAAAAAAAAAEQESH/2gAIAQIBAT8QSsGdn//EACEQAQACAQQBBQAAAAAAAAAAAAEAESExQVFhEIGRocHw/9oACAEBAAE/ECENcHVfcULu3zKPOQhVLN9Nzh9oYMnK1jQ+JeRS94uBQPUy9RXYIDnx+9yjBpP/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Kubernetes in Action Cover&quot;
        title=&quot;&quot;
        src=&quot;/static/839a405a4e95ad2e4a2842c13c944cdf/158ba/book.jpg&quot;
        srcset=&quot;/static/839a405a4e95ad2e4a2842c13c944cdf/e07e9/book.jpg 200w,
/static/839a405a4e95ad2e4a2842c13c944cdf/158ba/book.jpg 360w&quot;
        sizes=&quot;(max-width: 360px) 100vw, 360px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, I rarely stick to tutorials or descriptions in books. Most of the time I try to
extend the examples just a little. This usually leads me down the next rabbit hole. And after
lengthy debugging session and lots of searching on the internet is usually haven&apos;t exactly achieved
what I wanted but also learned lots of stuff along the way. This is exactly what happen in this case 😉!&lt;/p&gt;
&lt;h2 id=&quot;python-echo-server&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#python-echo-server&quot; aria-label=&quot;python echo server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Python Echo Server&lt;/h2&gt;
&lt;p&gt;In order to have a little application to deploy to my Kubernetes cluster I decided to implement an echo server.
But in contrast to the echo server described in the Kubernetes in Action book I wanted to use Python 🐍 and
&lt;a href=&quot;https://fastapi.tiangolo.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FastAPI&lt;/a&gt; to implement the echo server.&lt;/p&gt;
&lt;p&gt;Implementing an echo server is straight forward with FastAPI. The following snippet shows my implementation.
The code is also available on &lt;a href=&quot;https://github.com/ceedee666/py-echo-server/blob/main/main.py&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; uvicorn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; socket&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; fastapi &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; FastAPI, Request&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app = FastAPI()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@app.get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: Request):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;client&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: request.client.host,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: socket.gethostname(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Hello World from Python!&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  uvicorn.run(app, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The echo server can be run locally by executing &lt;code&gt;python main.py&lt;/code&gt;. Once the server is running
sending an HTTP Get request to it will return a simple JSON object containing client IP,
the host name and a message (cf. lines 11 - 13 in the code snippet).
Below is the output of running &lt;code&gt;curl -s localhost:8000 | jq&lt;/code&gt; on my laptop.
Note that I use the &lt;code&gt;-s&lt;/code&gt; option to suppress progress output. Furthermore, the result is formatted
for better readability using &lt;a href=&quot;https://stedolan.github.io/jq/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;jq&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;client&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Christians-MBP-2.local&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;comparison-between-virtual-machines-and-containers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#comparison-between-virtual-machines-and-containers&quot; aria-label=&quot;comparison between virtual machines and containers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Comparison between Virtual Machines and Containers&lt;/h2&gt;
&lt;p&gt;Before I continue with the explanation of how to deploy the echo server to Kubernetes it is important
to understand what containers are and how they differ from virtual machines. The following figure &lt;sup id=&quot;a1&quot;&gt;&lt;a href=&quot;#f1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
shows a comparison of running applications in virtual machines and containers.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 691px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d8cd5baacb6f5de40bbc6dee533da087/e185b/containers.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 44.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB8klEQVR42mWSfW+bMBDGkbqPPKn7AltXpZ+k32GK1qlTOjVNuiSEQICADbYx5sXQt0DyzEjrP6mlkx9bd7/znc8iNCkXSxtBGB2rqoTIJGaPiy6TCkqpc8ssAGeDDToi5AuhKez1pk/SdPDBcrU+BrsYK3vNLUYCOPNbiNiB1hq5oHBmt12bEzRN+fUUWGT8Er1GK4O+raTx0dByh66mSCIPVpk6R+2P0Ua/UZYVnosIlfejg3agBP0PvD4bj8efBp1zenkoPGSbX72WMRpdQ4X3KP0Jds70aJXMgw4naMgDyqrCkyKo/EmHJoTK6LdToCl5JPICrh/2KROoqhobz0dMGf4uVrDckOHOFphuhHlhgZgVw7nz2DNoyi8GyLUp9x3IkugKewWdrvum5KZNNRruYV+EIIENaxsx3DscC1+iNsCEF5g6vIvlm8mafj8F5oxc9cUWqX3TN6bPbVOj2D2gCO4QuzNYlKtDIhvQrAbLzS5qo3XXvAGU5xfvn/IO5FkxajuAqeeeqScT0yI1JvUejhcdLF+8wpPAOt3j55ziz0Zhm6ETBhjnLx9KJtnLiL0AXoZ+YkvcmBg72cNXwNxcWm6QSifgWHn0uNjEWLpk0D0RGjsqPn+Yw0ScR6yGvU36hfFdumb+XHL0IonHlZ/8A6RiOKqaPqv+AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;VMs vs. Containers&quot;
        title=&quot;&quot;
        src=&quot;/static/d8cd5baacb6f5de40bbc6dee533da087/e185b/containers.png&quot;
        srcset=&quot;/static/d8cd5baacb6f5de40bbc6dee533da087/772e8/containers.png 200w,
/static/d8cd5baacb6f5de40bbc6dee533da087/e17e5/containers.png 400w,
/static/d8cd5baacb6f5de40bbc6dee533da087/e185b/containers.png 691w&quot;
        sizes=&quot;(max-width: 691px) 100vw, 691px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Virtual machines as well as containers
are technologies for &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtualization&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;virtualisation&lt;/a&gt;. The goal of both technologies is to provide
an isolated environment to run applications. In the case of virtual machines hardware virtualisation is used to achieve this. The host
machine executes multiple virtual machines. Each virtual machine contains its own operating system. Furthermore, each
virtual machine contains the necessary libraries as well as the applications. This is shown on the left side of the figure.&lt;/p&gt;
&lt;p&gt;In contrast to that, containers rely on special features of the host operating system for the creation of isolates environments
(e.g. &lt;a href=&quot;https://en.wikipedia.org/wiki/Cgroups&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;cgroups&lt;/a&gt; in Linux). As shown on the right side of the figure,
containers do not contain a guest operating system.
Containers only contain the necessary libraries and the application. As a result containers have a smaller
runtime overhead and are much smaller than comparable virtual machines.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker&lt;/a&gt; is a well known software for the creation of containers. Kubernetes was especially develop as a system&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;for automating deployment, scaling, and management of containerized applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;creating-a-docker-image&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-a-docker-image&quot; aria-label=&quot;creating a docker image permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating a Docker Image&lt;/h2&gt;
&lt;p&gt;The next step in order to deploy the echo server to my cluster is to create a &lt;a href=&quot;https://www.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker&lt;/a&gt; image.
Docker images are created using a &lt;code&gt;Dockerfile&lt;/code&gt;. This file specifies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The base image on which the new image will be based&lt;/li&gt;
&lt;li&gt;What libraries need to be installed&lt;/li&gt;
&lt;li&gt;Which command is executed in order to run the application inside the container.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following listing shows the contents of the &lt;code&gt;Dockerfile&lt;/code&gt; I created for the Python echo server.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;dockerfile&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Pull base image&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; python:3.8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Copy files&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; *.py Pipfile* /&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Install dependencies&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pip install pipenv&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pipenv install --system --dev&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Run server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;EXPOSE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; 8000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;python&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;main.py&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Line 2 specifies the &lt;a href=&quot;https://hub.docker.com/_/python&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;python&lt;/a&gt; as the base image. Furthermore, the tag &lt;code&gt;3.8&lt;/code&gt; details the version of the python image to use.
Next, line 5 specifies that all &lt;code&gt;*.py&lt;/code&gt; files and all files starting with &lt;code&gt;Pipfile*&lt;/code&gt; should be copied to the root directory of the container.
Lines 8 and 9 are responsible foe installing the necessary Python libraries using the &lt;code&gt;pipenv&lt;/code&gt; tool. Finally, line 12 exposes port 8000 of the container and
line 13 starts the echo server by executing &lt;code&gt;python main.py&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;building-the-docker-container&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#building-the-docker-container&quot; aria-label=&quot;building the docker container permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building the Docker Container&lt;/h3&gt;
&lt;p&gt;Based on the &lt;code&gt;Dockerfile&lt;/code&gt; the container is created using the docker CLI.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;docker build -t ceedee666/py-echo-server &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Builds a docker image using the &lt;code&gt;Dockerfile&lt;/code&gt; in the current directory&lt;/li&gt;
&lt;li&gt;Names the image with &lt;code&gt;ceedee666/py-echo-server&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the image name &lt;code&gt;ceedee666&lt;/code&gt; is my &lt;a href=&quot;https://hub.docker.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker Hub&lt;/a&gt; username. Adding the username to the name of the image is required in order to be
able to push the image to Docker Hub. Once the image is build, it can be used to crate a container and run it.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;docker run --name py-echo-container -p 1234:8000 -d ceedee666/py-echo-server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command above consist of three main parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It creates and runs a  container named &lt;code&gt;py-echo-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The container is based on the image &lt;code&gt;ceedee666/py-echo-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Maps the port &lt;code&gt;1234&lt;/code&gt; of the host to the port &lt;code&gt;8000&lt;/code&gt; of the container.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After the container is running it is now possible to test the echo server running inside the container using e.g.
&lt;code&gt;curl -s localhost:1234 | jq&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;pushing-the-image-to-docker-hub&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pushing-the-image-to-docker-hub&quot; aria-label=&quot;pushing the image to docker hub permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pushing the Image to Docker Hub&lt;/h3&gt;
&lt;p&gt;The final step is to push the Docker image to the Docker Hub. This enables Kubernetes in the next step to use this
image and deploy it to the Raspberry Pi cluster. Pushing an image can be done using the following command:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;docker push ceedee666/py-echo-server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;first-rabbit-hole---exec-format-error&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#first-rabbit-hole---exec-format-error&quot; aria-label=&quot;first rabbit hole   exec format error permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First Rabbit Hole - exec format error&lt;/h2&gt;
&lt;p&gt;After the Docker image is pushed to the Docker Hub the next step is to deploy it to the Raspberry Pi cluster.
The easiest way to do this is using a &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/controllers/deployment/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deployment&lt;/a&gt;.
Deplyoments can be created using the Kubernetes CLI. To following command creates a deployment named &lt;code&gt;py-echo-server&lt;/code&gt;
based on the Docker image &lt;code&gt;ceedee666/py-echo-server&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k create deployment py-echo-server --image=ceedee666/py-echo-server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once I executed this command I could see in the Kubernetes dashboard that a deployment, a &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;replica set&lt;/a&gt;
and a &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pod&lt;/a&gt; were created. However, the pod kept restarting and never got to the status
&lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;running&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the pod logs I found the following error message:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;standard_init_linux.go:219: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; user process caused: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; format error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After I bit of searching it became clear that the Docker image was build for the
wrong system architecture. I create the image on my Intel-base MacBook Pro and
tried to run it on the ARM-based Raspberry Pi cluster.&lt;/p&gt;
&lt;p&gt;Fortunately, Docker supports cross platform build using
&lt;a href=&quot;https://docs.docker.com/buildx/working-with-buildx/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Buildx&lt;/a&gt;. For example,
the following command can be used to build a Docker image for the ARM-based
system.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;docker buildx build --platform linux/arm/v7 -t ceedee666/py-echo-server &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;second-rabbit-hole---github-actions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#second-rabbit-hole---github-actions&quot; aria-label=&quot;second rabbit hole   github actions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Second Rabbit Hole - Github Actions&lt;/h2&gt;
&lt;p&gt;After build the image for the correct platform using Buildx I tried to push
the image to Docker Hub again. For whatever reason, the push was suddenly
extremely slow. It took more then 6 hour to push the small image. And I never
found out why. While waiting for the push to complete I started reading about
Github Actions for building Docker images.&lt;/p&gt;
&lt;p&gt;Based on this &lt;a href=&quot;https://www.henry.wang/2019/12/05/arm-dockerhub.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog&lt;/a&gt;
and lots of experimenting I was able to create a Github Action in my
&lt;a href=&quot;https://github.com/ceedee666/py-echo-server/blob/main/.github/workflows/docker-image-builder.yml&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;repository&lt;/a&gt;
that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the Docker image for different platforms&lt;/li&gt;
&lt;li&gt;Pushes the resulting images to Docker Hub.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following listing show the YAML file for the action.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;[builder] CI for releases&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Checkout&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Dockerhub login&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;DOCKER_PASSWORD&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ secrets.DOCKER_PASSWORD }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;DOCKER_USERNAME&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ secrets.DOCKER_USERNAME }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;          echo &amp;quot;${DOCKER_PASSWORD}&amp;quot; | docker login --username ${DOCKER_USERNAME} --password-stdin&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Set up Docker Buildx&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;buildx&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;crazy-max/ghaction-docker-buildx@v1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Build dockerfile (with push)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;          docker buildx build \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;          --platform linux/amd64,linux/arm/v7,linux/arm64 \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;          --push --tag ceedee666/py-echo-server:latest .&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Line 1 sets the name of the action. Line 3 - 6 define that the action should be
run on every push to the main branch. Line 8 enables the manual triggering of
the action. Starting with line 10 the build process for the image is defined.&lt;/p&gt;
&lt;p&gt;Line 18 - 23 read the Docker Hub password and username from &lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github secrets&lt;/a&gt;
and use these to log on to Docker Hub. After setting up Docker Buildx, lines
30 - 34 perform the actual build of the images and push them to Docker Hub.&lt;/p&gt;
&lt;p&gt;The following screenshot show the running action after it has been manually
triggered. Using this action the image can now be build for multiple platforms
and pushed to Docker Hub in about 5 minutes.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2dfe2262edccb05b99baca005fca6122/5b2ff/build_action_run.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 53.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAACI0lEQVR42n1SWW8SURidP2E0MVplK1BmA4ZFFgVN++KLLz6qqRo0+seavvhEo2lLW8si9dm00BqtyJKmEKAwO8dvBmligr3Jyfnm3u+enDnfZdLZZbCiBD4cg48V4fHzcPsF8NI9CAQuFIMYSdjgw3G4lwQ4fRwcXhZOL2fDzUpgQ3H4xBiY/HYFaxslfPhUwvpGEWv5Igqfy6hUD1D+coBSpYpy9atdW9jZ20f+4yZxEVuFXWzt7KFA9eb2LvZLZTCqbkLRDVzIGlTDRH+kQNF0yLICeSxD03UoqkpsQDcMyIpi76kq9Vt99pmO2WLk8RCDwRDD4RAXQ4sH0KjRoIu6BRIxTdNunkwm/7Bd05lJ/ZhM95neeRu/m210ez20Ox2cd7uon3xH7fgEh/VjHNXq+NVooNVuo9lqXXKz2bK58fMUp9+O8OOwhs7ZGTmUVRjkYrYUcvX4yVOEYml4uTA8gSANQoSLBjWD9c1HUuCjafhpGIFoCguLHF7m3oHpD/qUkTbNiPIcU3aJzDLcJLTIhnDHw86Fw8fTtAXcpSm7iK/ddOLZag7MaDSyBQ0aiGlOyKGKZGYFQjSJcDxNl/i5cHg5G1btIcfXb7nw/NUbMJfh/g1a0zQksyvgpCQiiYz9vmYX/4eZ4IvXb+cLpuixC2EJ0dRDRJJZLInRKwWtTG8suLGaez9PUEfiwSP4uCAkchiK30cwlrraYYAc3p7+8h94Xkq1Pmna/AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Running Github Action&quot;
        title=&quot;&quot;
        src=&quot;/static/2dfe2262edccb05b99baca005fca6122/5a190/build_action_run.png&quot;
        srcset=&quot;/static/2dfe2262edccb05b99baca005fca6122/772e8/build_action_run.png 200w,
/static/2dfe2262edccb05b99baca005fca6122/e17e5/build_action_run.png 400w,
/static/2dfe2262edccb05b99baca005fca6122/5a190/build_action_run.png 800w,
/static/2dfe2262edccb05b99baca005fca6122/c1b63/build_action_run.png 1200w,
/static/2dfe2262edccb05b99baca005fca6122/29007/build_action_run.png 1600w,
/static/2dfe2262edccb05b99baca005fca6122/5b2ff/build_action_run.png 2190w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-echo-server&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#deploying-the-echo-server&quot; aria-label=&quot;deploying the echo server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploying the Echo Server&lt;/h2&gt;
&lt;p&gt;With the Docker image for the processor architecture on Docker Hub I could finally
create the deployment again:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k create deployment py-echo-server --image=ceedee666/py-echo-server&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time the pod started successfully as shown in the following screenshot.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c83169bff784367b782cd4823de57b21/ddc6c/kubernetes_dashboard.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 83.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAADMklEQVR42nVUz48URRTuG+Fk+DdISEj8F+Ri/BtMNHjwygE84cmLB47GBORASIxnFKMH+RXQZXDDsMkuw+7M7vROzyw9013V1d31q6v781V1tglRZ/Klqt68+vK+976a6MFY48mOwt/7Bi8mFR5up3j0coMnr/IBj8cZ/toTGM/Mf2OqMXrT4ME2Q/T1nRzf/Mhx9Ycc125luHpzQ2v+v/jqNgt4L34zoxjHle8SRHEc4+06RVWX4JxhdbJEIRhqWVJMDCg9KgFeMDCeU05B5zJAlILya6Rpimh/OsPhPAYr/IUKpSjhGod/fTpAKgXGOASRta7pg4Sua0OKvxstkiWO4mPkvEBV1ah0jdiuMTdrxIRjs8FUr+icQmkDSZVOE4N7Wwb3n+sBvzxvsDvjiI6TE2SMYUOQUqEyEpMixh6fY8LjgD02x1QkECRLa4U0rzGZlzhYSLyeC+wdFbRXWKxyRLN4RX17G/QzqjIn4rqoAQNYZQOasBo45aCUhtQS1koYW6NtGrTWwjmFTZ4hmh4eIVmdgJN+QT2sygqcmr8guQ6t79DwXZJ82erQr7brwrq2HGvDw17Q3cj3L1muwlAqJcMP1xe3cXbrEn7a/DHM5Dc+wrnRJ/hydmOIpZbhwvgzfDj+AryroCvVE6abrB+K7Amvzb/Hma2PcHf9+3D5Z/YnPhh9jMvTb4fYymY4//JTXBx/jqwTRKgRHcwO4a2zznKyRS+H6xIv0l1YZ4Mzuq6XvMMPwGzZS257q0zYEfZZ/M42vkKPY7KPKMncRRH8hqaDaWgY1HBLjTe0dhRrrN+bIdY2LcUcGvIly1k/FE/WD6UMxtXGhoo8mTEmrM45uM6Fva/OxxsiVUb1SuhTUDFB8mT/IEgW9Nyk8Um9+08vSeot53wg9oQ+VpErfJyR1XzFBc0hWtCEl96HNJiCqpRkXnsqleAJG+eGc6jaE9Pz9PKbkGtCTp6TsT1ZvEjgicu6Dv3zHvOV+CoUnU9le/LTNkh6MWVdkUxfhA75hRD9ULxlGKc/BymwEQaZ6EKTLV1MkgTL5ZKenB6I/dQfp9u4Fz/Dr6MKT3fK8CR9D/8BuSrwX/WzMQoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Kubernetes Dashboard&quot;
        title=&quot;&quot;
        src=&quot;/static/c83169bff784367b782cd4823de57b21/5a190/kubernetes_dashboard.png&quot;
        srcset=&quot;/static/c83169bff784367b782cd4823de57b21/772e8/kubernetes_dashboard.png 200w,
/static/c83169bff784367b782cd4823de57b21/e17e5/kubernetes_dashboard.png 400w,
/static/c83169bff784367b782cd4823de57b21/5a190/kubernetes_dashboard.png 800w,
/static/c83169bff784367b782cd4823de57b21/c1b63/kubernetes_dashboard.png 1200w,
/static/c83169bff784367b782cd4823de57b21/ddc6c/kubernetes_dashboard.png 1534w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In order to access the echo server outside
the cluster it is necessary to expose the echo server as a service. There a different
types of &lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;service&lt;/a&gt;
available in Kubernetes. As on my local cluster no external load balancer is available
the type &lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#nodeport&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NodePort&lt;/a&gt;
can be used. The following command exposes the echo server on port 8000.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; k expose deployment/py-echo-server --type=NodePort --port 8000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this command &lt;code&gt;k get services&lt;/code&gt; returns the following list of services.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kubernetes       ClusterIP   10.152.183.1     &amp;lt;none&amp;gt;        443/TCP          53d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;py-echo-server   NodePort    10.152.183.126   &amp;lt;none&amp;gt;        8000:31862/TCP   15d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using port forwarding it is now possible to access the echo server. The following
command forwards port 9090 to the py-echo-server.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k port-forward service/py-echo-server 9090:8000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it is possible to access the echo server running in the Kubernetes cluster. For example, executing
&lt;code&gt;curl -s http://localhost:9090 | jq&lt;/code&gt; returns:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;client&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;py-echo-server-5465f599f5-plvrd&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Hello World from Python!&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;scaling-the-echo-server&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#scaling-the-echo-server&quot; aria-label=&quot;scaling the echo server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Scaling the Echo Server&lt;/h2&gt;
&lt;p&gt;Now I&apos;m able to scale the
deployment up and down by specifying the desired replica count. The following command, for example, scales the
replica set to 5. Consequently, 5 pods running the echo server will be started.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k scale deployment/py-echo-server --replicas=5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following GIF shows the process of scaling the deployment. First, only one pod is running. Curl always hits the same
pod. Next the deployment is scaled up to 5 pods. Curl starts hitting all of them. Finally, the deployment is scaled down to 2 pods.
Consequently, curl only hits the two remaining pods.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/2e7b19fa7e3277b62baaf34df7cd71bd/scaling.gif&quot; alt=&quot;Scaling the Deployment&quot;&gt;&lt;/p&gt;
&lt;p&gt;Note, that I use &lt;code&gt;curl -s http://pi-picard:31580&lt;/code&gt; to access the echo server. The reason is, that performing a port forwarding of the
NodePort service selects a target pod. Therefore, no load balancing is preformed. To see the load balancing, the service must be invoked
via the control pane, which is running on &lt;code&gt;pi-picard&lt;/code&gt; in my cluster.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#next-steps&quot; aria-label=&quot;next steps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Basically, my Raspberry Pi cluster is now up and running, and the first application has been deployed. Now I need to thinking about
what to try out next. Currently, my list of ideas contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploying an &lt;a href=&quot;https://cap.cloud.sap/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP CAP&lt;/a&gt; application to the cluster&lt;/li&gt;
&lt;li&gt;Try out &lt;a href=&quot;https://www.openfaas.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;OpenFAAS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s see what the next blog will bring... 😉.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;h2 id=&quot;references&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#references&quot; aria-label=&quot;references permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;b id=&quot;f1&quot;&gt;[1]&lt;/b&gt; The figure is based on M. Lukša, Kubernetes in action. Shelter Island, NY: Manning Publications Co, 2018. &lt;a href=&quot;#a1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Exploring the Raspberry Pi Cluster]]></title><description><![CDATA[In the previous blog I described the initial steps to build and set up
a Raspberry Pi cluster. With this initial setup in place, the next…]]></description><link>https://drumm.sh/blog/2021/03/08/first-steps-rpi-cluster/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/03/08/first-steps-rpi-cluster/</guid><pubDate>Mon, 08 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the &lt;a href=&quot;/blog/building-rpi-cluster&quot;&gt;previous blog&lt;/a&gt; I described the initial steps to build and set up
a Raspberry Pi cluster. With this initial setup in place, the next step is to connect the four Raspberry
Pis together to form a Kubernetes cluster.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-kubernetes-cluster&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-a-kubernetes-cluster&quot; aria-label=&quot;creating a kubernetes cluster permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating a Kubernetes Cluster&lt;/h2&gt;
&lt;p&gt;As described in the &lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/components/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes documentation&lt;/a&gt;
a Kubernetes cluster consists of the
&lt;a href=&quot;https://kubernetes.io/docs/reference/glossary/?all=true#term-control-plane&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;control plane&lt;/a&gt; and
several workers &lt;a href=&quot;https://kubernetes.io/docs/concepts/architecture/nodes/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nodes&lt;/a&gt;. The worker nodes
execute the containerizes applications while the control plane is responsible for managing
the worker nodes. The final configuration step in my Raspberry Pi cluster is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Define which node acts as the control plane (Note: in a productive environment the control plane would
also be running on several computers)&lt;/li&gt;
&lt;li&gt;Add the worker nodes to the control plane.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note, that the following description is specific for &lt;a href=&quot;https://microk8s.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MikroK8s&lt;/a&gt;. However, it should be
easily adoptable to different Kubernetes variants.&lt;/p&gt;
&lt;p&gt;Defining the control plane and adding worker nodes to the cluster is that last time requiring to log
into the individual Raspberry Pis directly. Once the cluster is set up all interactions with the
cluster are performed using the &lt;a href=&quot;https://kubernetes.io/docs/tasks/tools/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;kubectl&lt;/a&gt;, the Kubernetes CLI.&lt;/p&gt;
&lt;h3 id=&quot;adding-worker-node&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adding-worker-node&quot; aria-label=&quot;adding worker node permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding Worker Node&lt;/h3&gt;
&lt;p&gt;In my cluster the Raspberry Pi with the host name &lt;code&gt;pi-picard&lt;/code&gt; is obviously going to run the
control plane 🖖. To add worker nodes to a node it is necessary to log in using SSH
(e.g. &lt;code&gt;ssh ubuntu@pi-picard&lt;/code&gt;). Once you are logged into the Raspberry Pi that is going to
be the control plane execute the following command (caveat: this is specific for MikroK8s):&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;microk8s add-node&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result of this command should be some joining instructions similar to the ones below:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  From the node you wish to join to this cluster, run the following:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    microk8s join 192.168.178.251:25000/b5379006e31afba0056940b2ceea37f3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  If the node you are adding is not reachable through the default interface you can use one of the following:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    microk8s join 192.168.178.251:25000/b5379006e31afba0056940b2ceea37f3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    microk8s join 10.1.2.64:25000/b5379006e31afba0056940b2ceea37f3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Therefore, the next step is to log into the worker nodes (&lt;code&gt;pi-ricard&lt;/code&gt;, &lt;code&gt;pi-data&lt;/code&gt; and &lt;code&gt;pi-worf&lt;/code&gt;)
in my case and the and execute the join command. Once the worker nodes are joined to the cluster, &lt;code&gt;kubnectl&lt;/code&gt; can
be used to show the nodes in the cluster.&lt;/p&gt;
&lt;p&gt;In my cluster executing&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;microk8s kubectl get no&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;results in the following output:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME        STATUS   ROLES    AGE   VERSION&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;pi-data     Ready    &amp;lt;none&amp;gt;   30d   v1.20.2-34+c6851e88267786&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;pi-riker    Ready    &amp;lt;none&amp;gt;   30d   v1.20.1-34+97978f80232b01&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;pi-picard   Ready    &amp;lt;none&amp;gt;   30d   v1.20.2-34+c6851e88267786&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;pi-worf     Ready    &amp;lt;none&amp;gt;   30d   v1.20.2-34+c6851e88267786&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Furthermore, using &lt;code&gt;microk8s status&lt;/code&gt; shows some additional information regarding the cluster:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;microk8s is running&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;high-availability: yes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  datastore master nodes: 192.168.178.251:19001 192.168.178.252:19001 192.168.178.253:19001&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  datastore standby nodes: 192.168.178.254:19001&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;addons:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  enabled:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    dashboard            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# The Kubernetes dashboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    dns                  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# CoreDNS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ha-cluster           &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Configure high availability on the current node&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    metrics-server       &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# K8s Metrics Server for API access to service metrics&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  disabled:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This output shows that in my cluster the high availability is configured and the services &lt;code&gt;dns&lt;/code&gt;,
&lt;code&gt;dashboard&lt;/code&gt; and &lt;code&gt;metrics-server&lt;/code&gt; are running. Disabling and enabling service can also be
performed using the &lt;code&gt;microk8s&lt;/code&gt; CLI. See the MicroK8s &lt;a href=&quot;https://microk8s.io/docs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentation&lt;/a&gt;
for further details.&lt;/p&gt;
&lt;h2 id=&quot;configuring-kubectl&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuring-kubectl&quot; aria-label=&quot;configuring kubectl permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuring kubectl&lt;/h2&gt;
&lt;p&gt;From this point on it is possible to interact with the Raspberry Pi cluster using the Kubernetes
CLI &lt;code&gt;kubectl&lt;/code&gt;. In order to do so, &lt;code&gt;kubectl&lt;/code&gt; needs to know on which server the control plane is
running and what user credential to use to access the cluster. This information is stored in the
&lt;code&gt;kubeconfig&lt;/code&gt; file. According to the
&lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes documentation&lt;/a&gt;
the following process is used by &lt;code&gt;kubectl&lt;/code&gt; to find the &lt;code&gt;kubeconfig&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, kubectl looks for a file named config in the $HOME/.kube directory.
You can specify other kubeconfig files by setting the KUBECONFIG environment variable
or by setting the --kubeconfig flag.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I chose to store the &lt;code&gt;kubeconfig&lt;/code&gt; file for my cluster in a different location and set the
&lt;code&gt;KUBECONFIG&lt;/code&gt; environment variable whenever I want to interact with the cluster.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; KUBECONFIG=~/Documents/development/rpi-cluster/kubeconfig&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;creating-the-kubeconfig-file&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-the-kubeconfig-file&quot; aria-label=&quot;creating the kubeconfig file permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating the kubeconfig File&lt;/h3&gt;
&lt;p&gt;The interesting question is which information &lt;code&gt;kubeconfig&lt;/code&gt; file needs to contain. Again, there
are different approaches how to create a &lt;code&gt;kubeconfig&lt;/code&gt; file. Especially, in more advanced scenarios
than the one I described here, there are lots of different
&lt;a href=&quot;https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;features available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For my cluster I simply executed:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;microk8s config&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the control plane node. The output of this command should look something like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;v1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;clusters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;cluster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;certificate-authority-data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;LS0tLS1CRUdJT...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;https://192.168.178.251:16443&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;microk8s-cluster&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;contexts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;cluster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;microk8s-cluster&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;admin&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;microk8s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;current-context&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;microk8s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Config&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;preferences&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;admin&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;THNNNU...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply store the output of the command on the computer that is used to access the cluster and configure
&lt;code&gt;kubectl&lt;/code&gt; to use it.&lt;/p&gt;
&lt;h2 id=&quot;using-kubectl&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-kubectl&quot; aria-label=&quot;using kubectl permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using kubectl&lt;/h2&gt;
&lt;p&gt;With the &lt;code&gt;kubeconfig&lt;/code&gt; in place it is now possible to interact with the cluster using the
&lt;code&gt;kubectl&lt;/code&gt; command.&lt;/p&gt;
&lt;h3 id=&quot;adding-a-kubectl-shortcut&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adding-a-kubectl-shortcut&quot; aria-label=&quot;adding a kubectl shortcut permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding a kubectl Shortcut&lt;/h3&gt;
&lt;p&gt;To interact with the cluster the &lt;code&gt;kubectl&lt;/code&gt; command will be used a lot! As it in
not exactly the shortest command to type it is useful to configure a shortcut for it. I simply added
the following alias to my (&lt;a href=&quot;https://ohmyz.sh/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ohmyz.sh&lt;/a&gt;) shell config:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; k=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;kubectl&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this alias in place I can now use &lt;code&gt;k&lt;/code&gt; to invoke the &lt;code&gt;kubectl&lt;/code&gt; command. For example executing
&lt;code&gt;k -h&lt;/code&gt; results in the following output:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kubectl controls the Kubernetes cluster manager.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; Find more information at: https://kubernetes.io/docs/reference/kubectl/overview/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Basic Commands (Beginner):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  create        Create a resource from a file or from stdin.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  expose        Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  run           Run a particular image on the cluster&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;           Set specific features on objects&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;accessing-the-kubernetes-dashboard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#accessing-the-kubernetes-dashboard&quot; aria-label=&quot;accessing the kubernetes dashboard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Accessing the Kubernetes Dashboard&lt;/h3&gt;
&lt;p&gt;In order to explore the Kubernetes cluster a little and get familiar with &lt;code&gt;kubectl&lt;/code&gt;, the next
step is to access the Kubernetes Dashboard. The &lt;a href=&quot;https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes Dashboard&lt;/a&gt;
is a web application that can be used to manage the cluster. Accessing the Kubernetes Dashboard requires
a few steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identifying the service name of the dashboard&lt;/li&gt;
&lt;li&gt;Configuring port forwarding from the client to the cluster&lt;/li&gt;
&lt;li&gt;Retrieving client secrets to access the dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;identifying-the-service-name&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#identifying-the-service-name&quot; aria-label=&quot;identifying the service name permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Identifying the Service Name&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Kubectl&lt;/code&gt; can be used to get the services running in the Kubernetes cluster. Executing&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k get services&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;result in the following output in my cluster:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kubernetes    ClusterIP      10.152.183.1    &amp;lt;none&amp;gt;        443/TCP          30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously, the output does not contain the dashboard service. The reason is, that the dashboard service is deployed in a
different namespace. Using &lt;code&gt;k get namespace&lt;/code&gt; a list of all the namespaces in the cluster can be retrieved. In my cluster the
following namespaces are available:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME              STATUS   AGE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kube-system       Active   30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kube-public       Active   30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kube-node-lease   Active   30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;default           Active   30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In MikroK8s the dashboard is deployed in the &lt;code&gt;kube-system&lt;/code&gt; namespace. Executing&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k get services -n kube-system &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;returns the services running in this namespace. In my cluster the command returns the following list of services.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;metrics-server              ClusterIP   10.152.183.97    &amp;lt;none&amp;gt;        443/TCP                  30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kubernetes-dashboard        ClusterIP   10.152.183.88    &amp;lt;none&amp;gt;        443/TCP                  30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dashboard-metrics-scraper   ClusterIP   10.152.183.143   &amp;lt;none&amp;gt;        8000/TCP                 30d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kube-dns                    ClusterIP   10.152.183.10    &amp;lt;none&amp;gt;        53/UDP,53/TCP,9153/TCP   29d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;configuring-port-forwarding&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuring-port-forwarding&quot; aria-label=&quot;configuring port forwarding permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuring Port Forwarding&lt;/h4&gt;
&lt;p&gt;Once the exact name and namespace of a service is know it is possible to configure port forwarding to this
service. The &lt;code&gt;kubnectl&lt;/code&gt; [documentation]/(&lt;a href=&quot;https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/&lt;/a&gt;) contains
a detailed example how to use port forwarding to access applications running in the cluster. To access the Kubernetes Dashboard a port of the local machine
needs to be forwarded to the appropriate service.&lt;/p&gt;
&lt;p&gt;The following command forwards the local port &lt;code&gt;8080&lt;/code&gt; to the port &lt;code&gt;443&lt;/code&gt; of the service &lt;code&gt;kubernetes-dashboard&lt;/code&gt; in the namespace &lt;code&gt;kube-system&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k port-forward -n kube-system service/kubernetes-dashboard 8080:443&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the port forwarding is running it is possible to access the Kubernetes Dashboard at the URL &lt;a href=&quot;https://localhost:8080&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://localhost:8080&lt;/a&gt;. Accessing this URL in a
browser results in the login window shown below.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cf8541ac2d8e4bc1c2d4a951b8692691/afa26/dashboard-login.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACvElEQVR42oWRS0hUYRTH7zJIIx9gpmEkWUJuXCQUQTOjo+OkRGYURRG0qpX2cmaaEfORjhY+EiUIWgSRtAlqExS1aR2jM86DKV9oOo879zmPe2f+nXudFNr0wY/zfd895//9z7nMCfNNHDtpRr35Gk5Zr6Oh5SrqTZ2orjei4ngDSqvqsP9gDfYfqEZR+VEUVdRiX1k1CsuOoLD0EApKKlFQXIm9xeXYU1IFppYKm86egdloxPm2c7jceQGXOi6i3doKq6UFluZmWFstaLVY0Ga1op1yGhsbYTQYYDA1UZ2BMMFE9Ydr6sDc6RnCysoqPJ55eOa9xAJ8Pi/8fh/8gUUEg4sIhfwIBf36PhDQzgH9Lkh3odAi5XoR/rWMW7e7wNgGJqCthCBBSiYhyCksbSYR3pDxkwiuyfAuS/Atyzt4lyS6294vLFHOqqBr3LX3gnkwNI1sLoutWBwsx2EzyuHNFwGvP0t4+03Gq08SZj6IOrMfpTxiHgFT70XMfU0gl1PR9dABpmd4hg5ZROMs4gkOnCAiwfHY/L0GgWchcHGIfAwiF4UsUBTiEEQZksAikxKRyypIpdNQ1Oy2oPPFO2TVDAkm8oICeF7A6to6YuQ6EokiGo0TMUQoRmI85YqIxAXEWA6iKCGZIsFsXtA2Pae/EiFBlpwlSExR0pAlHpIkQ5ZptpJEkfbJFM05u4uchqqquw5tLjD33S9BiiSotcxTOwJ+hNMIr6v6oHM5/Hf9Fex29IHp7p9ERlWwQa1txTRRFt/nWXjCPNIpmVqSdaf/IuaRyLk282Q6g3t2cmh/MpV/JQOV5qCRI1van1eonR0UhVCR0WOe/DetVlu23gEwp61X8Ng9iZ6+Edj7R3Vs/WM6jsFncAyN49HwJFzu53C6p+AanYZrbEaPTqpzjkzAPvgUA+OzMHXcwB+gvAPMH+Oa8wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Kubernetes Dashboard Login&quot;
        title=&quot;&quot;
        src=&quot;/static/cf8541ac2d8e4bc1c2d4a951b8692691/5a190/dashboard-login.png&quot;
        srcset=&quot;/static/cf8541ac2d8e4bc1c2d4a951b8692691/772e8/dashboard-login.png 200w,
/static/cf8541ac2d8e4bc1c2d4a951b8692691/e17e5/dashboard-login.png 400w,
/static/cf8541ac2d8e4bc1c2d4a951b8692691/5a190/dashboard-login.png 800w,
/static/cf8541ac2d8e4bc1c2d4a951b8692691/c1b63/dashboard-login.png 1200w,
/static/cf8541ac2d8e4bc1c2d4a951b8692691/afa26/dashboard-login.png 1258w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Login is possible by either selecting the &lt;code&gt;kubeconfig&lt;/code&gt; file or providing a authentication token.&lt;/p&gt;
&lt;h4 id=&quot;retrieving-secrets-to-access-the-dashboard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#retrieving-secrets-to-access-the-dashboard&quot; aria-label=&quot;retrieving secrets to access the dashboard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Retrieving Secrets to Access the Dashboard&lt;/h4&gt;
&lt;p&gt;In order to further explore the possibilities of &lt;code&gt;kubectl&lt;/code&gt; I will use the authentication token to access the dashboard. In order to read the correct
authentication token it is first necessary to find out which tokens exist. The following command returns a list of all secrets in the namespace
&lt;code&gt;kube-system&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;kubectl -n kube-system get secret&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this command returns a long list of available secrets. In my cluster the this is the first part of the returned list:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME                                             TYPE                                  DATA   AGE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;calico-node-token-spnt5                          kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;resourcequota-controller-token-6tc67             kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;calico-kube-controllers-token-p8dlv              kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;job-controller-token-lhkst                       kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;ttl-controller-token-m96b7                       kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;attachdetach-controller-token-kw5fg              kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;pod-garbage-collector-token-xrjns                kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;disruption-controller-token-bv46c                kubernetes.io/service-account-token   3      31d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to access the Kubernetes Dashboard a secret of type &lt;code&gt;service-account-token&lt;/code&gt; is required. In my cluster the respective secret is called
&lt;code&gt;kubernetes-dashboard-token-ccpfl&lt;/code&gt;. Using the following command this secret can be read:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;k -n kube-system describe secret kubernetes-dashboard-token-ccpfl&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Executing the above command returns the following information:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;zsh&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Name:         kubernetes-dashboard-token-ccpfl&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Namespace:    kube-system&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Labels:       &amp;lt;none&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Annotations:  kubernetes.io/service-account.name: kubernetes-dashboard&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              kubernetes.io/service-account.uid: 11cca18d-288b-4166-b0fb-feb1d3e49053&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              Type:  kubernetes.io/service-account-token&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              Data&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              ====&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              ca.crt:     1103 bytes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              namespace:  11 bytes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InBsUVlzU...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pasting the returned token into the login screen should provide access to the dashboard. The following screenshot shows the node overview of my cluster.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/92f250f647b092652db06b56ac794482/5f652/dashboard.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 101.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAETUlEQVR42l1T2U9UVxi/j02kNu2DxeWhq2WzcMEpswGiqKTEAoKBFLGbqG1qbUy6QJs0TZ/6J/jQuvXFhz70UWsJUEVEFikxtMgsd/aNYZmZe+/MvTO/ft8Zxpre5JfvnPOd+/t+33KklxzvYk9tGypa+tDY9TFqj7yHiuYTeLGyCc+/3IDn9uzD9l1V2L6zklBRtLv3oWx3Dcp2VWMb7cvIv23Ha3hmxxuQdla2wPrWfjRZrWhrbUVnRzuOdXTgQHMznHY7mp1ONDkcsDY2wm6zweGwQ5brUC/LkBsssNbLsMgNqKt9E8+Wvw5JPtiP327N4PboDP4Yn8bUvSncGp3AzdtjGJ2YxOj4JJ1PYuLOfTyYeYj7M/N4MLeAabJTMwuYn53FxN1Z/D42jb11TZBesQ1i5KqK72+Y+PFXA99cz+GrKxq+vKzii5/V/+wVFSPXssLPGGFc0/E1nQ2LcwPlVYch1bWdxN15BQ+XE5j7O4o7c7xexZJrEy5Fx4pXJWhw+7NY8qaFb3YpTjaJRbqz6NoQ9pF7A3v3t0Fydg/B43EjGPAhkYgiFPRDVVNwpRV4zSAi+TgiZgyPksuIxINYTyaQy6aRN7MQX6GwZQqosR+FZH+7H8srXoIbvkAQXsWHjKbhUuQmhj1X8YP/Br51XceZX77Dpcs/wad4sa4CYwsa/lzUMUEY/0tHNJlD7cFOSPXOw/D5A4jESEksAX8wCNM0kdxYw+oWEhtJrKU3kVFVZLM61tZT8ATW4AtvQAkVsZnWUdfeSzV0HBHKNlJpROMJKD4fNlMZaBkdmlqEmtGga1moGq11OiMYBiGniwDZrAaNfNUWB6SGA8fwz+MVxBKriCeSQm0qlRIq+cvn809sLpeDrjNBFul0GplMRqxzOQMm+asbbFTD9h6suNxQiChGhP5AQDhNMy8KHY1EEA6HxY9MxsFUSp0tk2pUb9MwRMCq+kZItr4LcHsVSjcuFCp+BRlKZUsgwpEYIkTK6hglQibiALzOkmXCmsZmIhwYhps6y/VjcFMKW2PAXzBEConQNIsqWCmXoxSA93wuFFqckBx9F2lkXKKOnPb/FQaCMYTCka1a5USarIrBNWTFfC4U2kihtfOsIGQyt8cLj6LALFDEokBEeZxIoUF1YmWcaknd00qZsL6Fnp6l4xRW3B5qRhCJVZqtgB+6wReKhP5gFJFoTBAyWBnXjsHkoilEzISWNhpsS3s/Ebrx2F18KYrfB40IaRKKhPx6vF4xb/xjibBUgpJln71rgF7KoR5K04dQJEqEIUGYy5t0oSAak0hu0qCnYdAPrDCTYULtSZeLJTDEmMmHSKHc+o6oU4y7HIvRa9AEUalzBhHnn9qzj5GjLERdOTiBA8pHT0B64VUZnQNDOD54Bt0CZ9FF+66T59A1eA7dpz7B8fc/Rc8H59H74Xn0EHo/+gy9pz9H79DFIk5fEGfltS34F1h8F6Jixs9JAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Kubernetes Dashboard&quot;
        title=&quot;&quot;
        src=&quot;/static/92f250f647b092652db06b56ac794482/5a190/dashboard.png&quot;
        srcset=&quot;/static/92f250f647b092652db06b56ac794482/772e8/dashboard.png 200w,
/static/92f250f647b092652db06b56ac794482/e17e5/dashboard.png 400w,
/static/92f250f647b092652db06b56ac794482/5a190/dashboard.png 800w,
/static/92f250f647b092652db06b56ac794482/c1b63/dashboard.png 1200w,
/static/92f250f647b092652db06b56ac794482/5f652/dashboard.png 1302w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;Accessing the Kubernetes Dashboard concludes this blog. In the next blog I&apos;ll describe how to build a small Node.js application and deploy it into
the cluster.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Building a Raspberry Pi Cluster]]></title><description><![CDATA[About a year ago I decided to build a Raspberry PI. I can't remember
anymore how I got the initial idea. Basically, I though it is a quite…]]></description><link>https://drumm.sh/blog/2021/03/05/building-rpi-cluster/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/03/05/building-rpi-cluster/</guid><pubDate>Fri, 05 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;About a year ago I decided to build a &lt;a href=&quot;https://www.raspberrypi.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Raspberry PI&lt;/a&gt;. I can&apos;t remember
anymore how I got the initial idea. Basically, I though it is a quite nice project. Furthermore,
I wanted to learn about technologies like &lt;a href=&quot;https://kubernetes.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes&lt;/a&gt; and
&lt;a href=&quot;https://www.openfaas.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;OpenFaas&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of cause there are lots of different options to learn Kubernetes besides building a physical
cluster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/products/kubernetes&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker Desktop&lt;/a&gt; offers functionality to setup a local Kubernetes cluster&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://minikube.sigs.k8s.io/docs/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;minikube&lt;/a&gt; is a tools to &quot;helping application developers and new Kubernetes users&quot; in setting up a local cluster&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AWS&lt;/a&gt;,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/kubernetes-engine/docs/quickstart&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GCP&lt;/a&gt; and &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/aks/intro-kubernetes&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Azure&lt;/a&gt; also provide the possibility to deploy Kubernetes clusters.&lt;/p&gt;
&lt;p&gt;Nevertheless, I decided to get my hands dirty 👷  and went ahead to build a Raspberry Pi cluster. In
this blog, which is hopefully the first in a series of blogs on the topic, I describe the necessary
steps to build the cluster and install the required software.&lt;/p&gt;
&lt;h2 id=&quot;bill-of-materials&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bill-of-materials&quot; aria-label=&quot;bill of materials permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bill of Materials&lt;/h2&gt;
&lt;p&gt;There are a large number of blogs on building Raspberry Pi based clusters (e.g.
&lt;a href=&quot;https://magpi.raspberrypi.org/articles/build-a-raspberry-pi-cluster-computer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://magpi.raspberrypi.org/articles/clusterhat-review-cluster-hat-kit&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;https://www.raspberrypi.org/blog/five-years-of-raspberry-pi-clusters/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;).
I didn&apos;t do much research when building my cluster and just went for
a straight forward setup with four Raspberry PIs. My cluster consist of the following components:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi 4 Model B, 4GB&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.raspberrypi.org/products/raspberry-pi-4-model-b/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;List of Resellers&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SanDisk Ultra 16GB microSD&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anker PowerPort 6 (6-Port USB charger)&lt;/td&gt;
&lt;td&gt;1 &lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.anker.com/products/variant/powerport-6/A2123123&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Anker Website&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ICY BOX 4 Way Raspberry Pi 4 Case with Fan&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D-Link DGS-108 8-Port Switch&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://us.dlink.com/en/products/dgs-108-8-port-unmanaged-gigabit-metal-desktop-switch&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;D-Link Website&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Of cause, I also bought a set of network and USB cables. Furthermore, a SD card reader is required in
order to install the operation system on the SD cards.&lt;/p&gt;
&lt;p&gt;Building the cluster was very simple. The most complex part was assembling the ICY BOX case. However, after about 30 minutes this was finished as well and the cluster was nearly ready.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHMklEQVR42iWVa1CU5x3F95OdzCTTOFFQEVFQQBaQXVjkust1LywsuwsLu8tlZS/sLtcsLMilICAgghI1mgAOeIVIraFQW1IvidZLM2nVtLEdNZle0hqdZqYfMv3Y6a+P+OGZ98P7vuc5zznnfx7J98+f8vKfT3j+t8d8/fg+D+9d5c4n86xe/oArc+NcODnA3Ik+ZsY6ODvWxer8KZYvnqS33U9vwEN2yk662twkyxNQKGRIXgG9EICv1rM/fcHD+6vcu36J1Z9Nc3lugvnpES5O9jI/HOT8eD9T3S0s9LUyc6iTpcVp3A4LJfoC1r3xBnv3yl8D/vXrRzz5411efPOAp1/+hvuffsyt1Xkun32PsYEAk++6ODHcSX9fOynyPWRJoznX4uDMaB9jowcY7O/Abi0jNTUZyXff/pmXz59wa2WOJw9u8NmvFri6+OEaw/nThzlysJPw0BB+tG4db771Jhs2biAqMpzufWX0GYuZGTmIy1XFzKlJUlJTkbz8x1MuLczywfh+psfaGQ46aHBVcHy0jV/MDXNuMkh7vYne5kq6fGbkchmNdRamD3fTGmiltspKk7eanq4ONFo1kl+vXEIuS6DJaWSi20FjtZr+jn10tdoJ+ky4bfk0u0oJeM14HXpSFAn8JOhiYWqMO3dvcPvWDYb6gszOvI+33onk6uWzfPXwPuenDtPT7mSgP0Bzg42Bbq/QpZjC/DRycxSUGQvExrvJypRh1mfx2co5xscHWV5e5PLCFMtLlwgGA0iuLc/z7bMHXP/5LJ/fXBIu3+DCmVM8uv9LFs7NMH5okEOjQ0yMj9HZGeTAwABtTU7uXlvizu2bXFtdEYCzLFw8T0dnO5IHt1eEszf5ZPEkNz+eEaZ8xE8X5vjmD7dZvDBFd0cTObnZxCcmkJaeSqJsD6o0OTdWFhge7KGiSInDZmDk0CgefwOSv3y+yuNri9xbmuV3N6/w20+XWLx4mo/mjtPd7sXrtgvRazl4IMjowV7aAo14RPam3htkeKiXwd42sfEM5+cvYjCXIbl+ZIhpYwmTpmIWZyc4IPIV8FdjKVVj0GZToFIgT4hDERdDujwJjULOQb+DcycnOH5skuGxEY70tzNxaIgCjXD5Py++4oe//54vr14QkXFjyEokM0VKYlwk6bJY1LkKVBlJKLPT1oK7eetW9MKYoL2cjjIzDdUWgo11grUdo8il5H//fQ78ix/+/YwrZ8Y5MzOK312OIjlGTEUsClk0e+UxlKjTyc2UszN6F55KLQZ1FsdGOjja30Rvax3BJj81FWYkj764xfffPeDRrQtcOnWA28uzzJ4YoMVXha++EmuFBktFESXGQrKy5CQJ9l5LAYF3q6nxWnDVWRkS810u9LNZq5GcHu2htthAc1kJfQ12Wj1VIoPNjA2207O/gf0dPjr3tzAw0EVHuw+H00qzTUtrfRWtzW6RzyJcNWbi46WCfbQwZXkak1ZDfFQK7T4Hp4/3c/rEoGBoJ0eVhtGkW3O6rcWF319HS6uXbp+VFjFur9jV2EppcFaSo0xHlhSPJCBAGp3lwlUNxXlp6JR70KiSCdsaypbwzURERRAfE0WaLB51TgbZmam0ucw0uyspKzdQX1dFoN6Kp7acfFU6kv62fbSIGFRZjaSI0ZIJM+ITIwXgBiJ3bCZq5xZ2hYcSvX0rkVs2kxERhq9Yhc9uwGLSCo3FrLst5Inw11TokRwN5DLWKgqhQY/LpkGvUVGsV1KqzxSFKSUyaguRkZuJj9tORIRgHLaJfcLhoEnDiN9Kfb2ZMn0uoZtC1kpG0uoR+ji1TDVGc6Qpk+HeBo6J6moTBplNhaLjpCTs2UlM7Dbx03refufHZCikmGsKqLBrqTRr0auziY2JRBq3C0mzENTjsOIUznkqlfQEnLwverHRU4G6UEmZRY9WpyIpaTdpGTKylHKsRhX6sjwK8zIoEmxt5kJMRTnUWHRI/GIuPTUmau2lay9TU6IxFGUSsT2M9e+8zS5pFIUaJXpdLrbKEgxiJO2luejUSgoLsrAYVNhM+dSKrHqqTEjc1UbqbCVru2jzRJskRBIdv41tUaFsi9hEiDBn08b1SEXt56QmUZqfTlejkMNQiE6XgdGQTmVpPs4qA35H+SvAUursJVRbtKI4laQlxxIXs10EdQcROzYRHhH6eoVvJHT9WyQIl+srdOJUJdTs04pZT8FpLcIrTtnktCDxOcp4zdJAVbmGUm2WmFkZ6UJ4qSiIqJ1hAjCEMAEaErKeFCH+fm8FTX4TmSKz1eYC3Ha9ADTSIvK8BuipNQmWBsFSh7k4hxJNJgU5KeQI4My9CeyO3U6kyGOoOL4saiteW5HQUIG+IJ3a8kKx1DgrdTQ7RR821pWLy8e8pkGNOEqlqWAN1KDJokjcJ8WF6ejEc2+ylJiYCBITo/AWZ1OtzhTf5lFlzufoYBvnT44QbLDxf+iHlR/YUz3SAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;My Raspberry Pi Cluster&quot;
        title=&quot;&quot;
        src=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png&quot;
        srcset=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/772e8/pi_cluster.png 200w,
/static/db33fc8c8ef8ef4b5b3f20c41ab70918/e17e5/pi_cluster.png 400w,
/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;installing-the-os&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installing-the-os&quot; aria-label=&quot;installing the os permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installing the OS&lt;/h2&gt;
&lt;p&gt;Basically, it is possible to install every OS on a Raspberry Pi that supports the ARM architecture. For
novices the official Linux distribution Raspberry Pi OS (previously called Raspbian, available
&lt;a href=&quot;https://www.raspberrypi.org/software/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; is the best choice. However, no novice ever tried to build
a cluster. So there are lots of different options to choose from.&lt;/p&gt;
&lt;p&gt;For my cluster I chose to install the latest development release of
&lt;a href=&quot;https://ubuntu.com/download/raspberry-pi&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ubuntu&lt;/a&gt;. At the time of writing this blog this was
Ubuntu Server 20.10. Of cause, it would also be possible to use the desktop version of Ubuntu.
However, the cluster will mainly be accessed using different command line tools.
Therefore, all the UI components of the desktop version would therefore never be used.&lt;/p&gt;
&lt;p&gt;Installing the OS is straight forward. There is also a large number of tutorial available on
this topic. I simply followed the nice step by step
&lt;a href=&quot;https://ubuntu.com/tutorials/how-to-install-ubuntu-on-your-raspberry-pi&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tutorial&lt;/a&gt; on the Ubuntu
website. The only challenge when installing the OS was to execute the same steps four times. It would
also have been possible to clone the SD cards. However, I was lazy and just installed the OS four times.&lt;/p&gt;
&lt;p&gt;Kubernetes requires &lt;a href=&quot;https://en.wikipedia.org/wiki/Cgroups&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;cgroups&lt;/a&gt; being enabled. To enable
cgroups add the following line to the &lt;code&gt;boot/firmware/cmdline.txt&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;cgroup_enable=memory swapaccount=1 cgroup_memory=1 cgroup_enable=cpuset&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the SD cards are prepared with the OS it is time to insert them into the Raspberry Pis and power
up the cluster for the first time!&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-os&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuring-the-os&quot; aria-label=&quot;configuring the os permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuring the OS&lt;/h3&gt;
&lt;p&gt;Once all Raspberry Pis are up and running there are a few configuration steps necessary. These steps are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Change the default password of the &lt;code&gt;ubuntu&lt;/code&gt; user&lt;/li&gt;
&lt;li&gt;Set a hostname for each Raspberry Pi&lt;/li&gt;
&lt;li&gt;(Optional) Copy SSH key to each Raspberry Pi&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first step ist to change the default password of the &lt;code&gt;ubuntu&lt;/code&gt; user. In order to change the password
it is necessary to log on to each Raspberry Pi using SSH. To log on to the Raspberry Pis their IP addresses
are required. The installation &lt;a href=&quot;https://ubuntu.com/tutorials/how-to-install-ubuntu-on-your-raspberry-pi&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tutorial&lt;/a&gt;
describes one possibility how to identify the IP addresses of the Raspberry Pis. The default password
for the user &lt;code&gt;ubuntu&lt;/code&gt; is &lt;code&gt;ubuntu&lt;/code&gt;. On the first login Ubuntu asks to change this password. In my
cluster I used the same password for all four Raspberry Pis.&lt;/p&gt;
&lt;p&gt;The next step is to set the hostnames of the Raspberry Pis. I used the following hostnames for my cluster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pi-picard&lt;/li&gt;
&lt;li&gt;pi-ricard&lt;/li&gt;
&lt;li&gt;pi-worf&lt;/li&gt;
&lt;li&gt;pi-data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As &lt;a href=&quot;https://twitter.com/rotnroll666/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Michael&lt;/a&gt; pointed out on
&lt;a href=&quot;https://twitter.com/rotnroll666/status/1358767107517906946?s=20&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt; I missed the obvious
pi-card 🤦.&lt;/p&gt;
&lt;p&gt;Setting the hostname in Ubuntu is done using the following command. After setting the hostname I rebooted
the Raspberry Pis. However, this is not necessary.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sudo hostnamectl set-hostname &amp;lt;new-computer-name-here&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sudo reboot&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I copied my public SSH key to the Raspberry Pis to enable login without a password. I
simply used my existing SSH key. Generation of an SSH key can be performed using the
&lt;code&gt;ssh-keygen&lt;/code&gt; command on the local machine (not on the Raspberry Pis). Copying the public SSH
key to the Raspberry Pis is done using the following command:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sh-copy-id -i ~/.ssh/id_rsa ubuntu@&amp;lt;raspberry-pi-IP&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this step the configuration of the OS is finished. Next I configured my local DNS to simplify
connecting to the RaspberryPis.&lt;/p&gt;
&lt;h3 id=&quot;configuring-local-dns&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configuring-local-dns&quot; aria-label=&quot;configuring local dns permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configuring local DNS&lt;/h3&gt;
&lt;p&gt;Accessing the Raspberry Pis using their IPs is quite cumbersome. This is especially true if due to the
DHCP configuration the Raspberry Pis get different IP addresses on the local network all the time.
Therefor I performed two configuration steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configure a fixed IP address for each Raspberry Pi.&lt;/li&gt;
&lt;li&gt;Added the hostnames to the local DNS server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the DHCP config of my local network I set gave each Raspberry Pi a fixed IP in the range
192.168.178.251 - 192.168.178.254.&lt;/p&gt;
&lt;p&gt;In my local network I already have a &lt;a href=&quot;https://pi-hole.net/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Pi-hole&lt;/a&gt; instance running. Therefore, I could
simply add the hostnames of the Raspberry Pis to the local DNS configuration of the Pi-hole. After that,
the Raspberry Pis were accessible using their individual hostnames.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/dbf79122987d89f3dccde87f52eb4e90/c4451/dns-setup.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 59.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABmklEQVR42n2T204jMRBE55P5rH3kKxArgRDwxAvSssAkmfvV92mqOmGIQqCllq223T5V48l2ZS3v+Qa5lde3d2QuBWrWBU3n42EM4kNc6z9l5pyXELx478U5h9FJjEEYy7JonSPXrDE6/y2ymNL5FRyc51m2ZSUGdHU36HxG4/hLTyUk1WkkXNR1vfSTkcGADl08GpmQxB86kjYEWhG+GjZtK5vNBjKjNjlOhseFLfY4v7clnOxrdjupi2KFyPphkKZpVg9Pk/VpHKXAwQIHOWeNflKXubkW9+9ZHP3G/mwYRqnrWtEp4TQZ9LKqKt3HS5QGpFx197cS3v7vLSBhC5/KstRbj/OYsO97yfNcrRkPhM5a8SR8uBP3+qL+sg7Jo7SQnNKy+vKNEPK2xZ7w8wOSkC7bv1cSIDkdapnHk+AHOQ7Kp0wLClIazIOdlI71eTbqlzauK1mmaX1qZ98hG3Vdp1L7ppKnl1wu/tzoRxlQ45oB9dl3aPFrxZjwHL4yUj5u40iSop/l8nEL6Xa1hGu6H7/j5zkfknwA1tWoMl/2O3UAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Pi-hole DNS Configuration&quot;
        title=&quot;&quot;
        src=&quot;/static/dbf79122987d89f3dccde87f52eb4e90/5a190/dns-setup.png&quot;
        srcset=&quot;/static/dbf79122987d89f3dccde87f52eb4e90/772e8/dns-setup.png 200w,
/static/dbf79122987d89f3dccde87f52eb4e90/e17e5/dns-setup.png 400w,
/static/dbf79122987d89f3dccde87f52eb4e90/5a190/dns-setup.png 800w,
/static/dbf79122987d89f3dccde87f52eb4e90/c1b63/dns-setup.png 1200w,
/static/dbf79122987d89f3dccde87f52eb4e90/c4451/dns-setup.png 1450w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Note, that the last configuration step is very important. If the cluster nodes in an Kubernetes cluster
are not addressable using their hostnames, certain commands in the Kubernetes CLI don&apos;t work. It took
me quite a while to find out that the underlying reason for some of these error messages where due to
the missing DNS configuration.&lt;/p&gt;
&lt;h2 id=&quot;installing-kubernetes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installing-kubernetes&quot; aria-label=&quot;installing kubernetes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installing Kubernetes&lt;/h2&gt;
&lt;p&gt;The final installation step is the installation of Kubernetes on the Raspberry Pis. Again, there are
different options available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://k3s.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;K3S&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://microk8s.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MicroK8s&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For no particular reason I chose MicroK8s for my cluster. MicroK8s can be installed in Ubuntu using
the following command:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sudo snap install microk8s --classic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note, this command needs to be executed on all Raspberry Pis in the cluster. After this, the software
installation on the cluster is finished. To complete the setup, it is necessary to install the
Kubernetes tools (i.e. kubectl) on the computer that will be used to control the cluster. Installation
instructions for different operating systems are available &lt;a href=&quot;https://kubernetes.io/docs/tasks/tools/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;After build the Raspberry Pi cluster and installing the necessary software the cluster is ready for usage.
The next step is to try out the different features of Kubernetes on the cluster. This will be described
in the next blog of this series.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Adding comments to my blog]]></title><description><![CDATA[Allowing visitors to add comments to my blogs is a functionality, that was quite high on my product backlog from the start. Today I finally…]]></description><link>https://drumm.sh/blog/2021/03/03/adding-comment-to-my-blog/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/03/03/adding-comment-to-my-blog/</guid><pubDate>Wed, 03 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Allowing visitors to add comments to my blogs is a functionality, that was quite high on my product backlog from the start. Today I finally managed to add it. In this blog I describe
the problem I had implementing the feature using &lt;a href=&quot;http://utteranc.es&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Utterances&lt;/a&gt;. My problem where mainly due to me being a Gatsby / React / JavaScript novice. Maybe this
blog will help novices in the future.&lt;/p&gt;
&lt;h2 id=&quot;comments-functionality&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#comments-functionality&quot; aria-label=&quot;comments functionality permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Comments Functionality&lt;/h2&gt;
&lt;p&gt;Allowing reads to comment is a quite common feature for blogging sites. In fact, it is so common, that the &lt;a href=&quot;https://www.gatsbyjs.com/docs/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Gatsby documentation&lt;/a&gt; has an own
&lt;a href=&quot;https://www.gatsbyjs.com/docs/how-to/adding-common-features/adding-comments/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;section&lt;/a&gt; on adding comment. As described on that side there are many options
for adding comments to a Gatsby site. I didn&apos;t spent much time comparing the different options, but after briefly reviewing different options, &lt;a href=&quot;https://utteranc.es/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Utterances&lt;/a&gt; look
like a very promising option.&lt;/p&gt;
&lt;p&gt;The nice feature of Utterances is, that &lt;a href=&quot;https://github.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github&lt;/a&gt; issues are used to store comments. Therefore, adding a comment requires a Github user. While this might discourage
some people from commenting, this is a very nice prerequisite in my case. As mention in a &lt;a href=&quot;/blog/why-i-created-my-own-webpage&quot;&gt;previous blog&lt;/a&gt; I want to use my web site and blog also
for teaching. Therefore, I can use the comment functionality in the future to introduce some Github features to students.&lt;/p&gt;
&lt;h2 id=&quot;adding-utterances&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adding-utterances&quot; aria-label=&quot;adding utterances permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding Utterances&lt;/h2&gt;
&lt;p&gt;The Utterances &lt;a href=&quot;https://utteranc.es/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;website&lt;/a&gt; contains actually a code generator to help adding the Utterances to a website. After the initial configuration steps and providing some
information an HTML fragment is generated. In my case the following fragment was generated:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;html&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://utteranc.es/client.js&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;ceedeee666/drumm.sh-comments&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;issue-term&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;pathname&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;github-light&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;crossorigin&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;anonymous&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing I tried was adding this fragment to my Layout component. However, nothing happened. After some searching (not Googling as I use &lt;a href=&quot;https://duckduckgo.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DuckDuckGo&lt;/a&gt; as
my main search engine) I found out that one can&apos;t simply &lt;a href=&quot;https://stackoverflow.com/questions/34424845/adding-script-tag-to-react-jsx/64815699&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;add script tags to JSX&lt;/a&gt;. Further searching
revealed a list of blogs that describe how to add Utterances to a Gatsby / React site in detail. Here are just a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://divyanshu013.dev/blog/gatsby-comments-utterances/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://divyanshu013.dev/blog/gatsby-comments-utterances/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/creativcoder/how-to-add-comment-support-on-your-gatsby-blog-using-github-utterances-423n&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://dev.to/creativcoder/how-to-add-comment-support-on-your-gatsby-blog-using-github-utterances-423n&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tiagofsanchez.com/blog/2020-12-01-comments-made-easy-with-utterances/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://www.tiagofsanchez.com/blog/2020-12-01-comments-made-easy-with-utterances/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/vincentntang/installing-gatsbyjs-blog-comments-using-utterances-1h8j&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://dev.to/vincentntang/installing-gatsbyjs-blog-comments-using-utterances-1h8j&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;function-components-cannot-have-string-refs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#function-components-cannot-have-string-refs&quot; aria-label=&quot;function components cannot have string refs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Function components cannot have string refs&lt;/h2&gt;
&lt;p&gt;I basically followed the first &lt;a href=&quot;https://divyanshu013.dev/blog/gatsby-comments-utterances/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog&lt;/a&gt;. The reasons are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I only used functional components so far in my site&lt;/li&gt;
&lt;li&gt;it contained all the functionality in one component.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After implementing my Comments component I got the following error message:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error: Function components cannot have string refs. We recommend using useRef() instead.
Learn more about using refs safely here: &lt;a href=&quot;https://fb.me/react-strict-mode-string-ref&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://fb.me/react-strict-mode-string-ref&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/36d59a60720c36b7cc5f59222593be92/cc7de/error.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 46.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABvklEQVR42pWRSU9TYRSG7z9w48aY2tAyFClNNAY3sDL+EqOJISQOe+NW0NIGjDuJO9Pa6VJSKNzQCyFxY9ihK3daqbftbUtoe6fH0wl3Did5cqb3O/lyjuIPLzA9e5PIrXluL9xlbv4O4RtzhKQWCM0SnAoTmJwhMDVDMBRh4nqEyekwV3xBfGMT+MdD+K4F8Y+Nc+nyVZTHT55xvLuNlnhPKZUUUujZLKV0Gj2TGZJFV9WBl/xIzbKfynGQy0k9hybaT4eHPFh8hBJff0vP7GoN6nWoiTdNaDYHvtX6nY9qZkMe2IzMHsYrq2soL19v4LoupxVD9GectztYtis42I4jPQ9H+o549wIX1/Mu6FpWf+CLaBxlLZmX0KTRLMvA75y1yliWIdSwBc9r/JWetmfLq1GUWCKD1/lC5fSY+s8TjOpnKsYJ3fZXPPfHP2F1v8m4c1bir1Ci7xLgGLKqcv9H3W6NTqcqe6njOmYfR+I/0WkbMtBlORaTo2x8GC7WGWzY479tdJTY+huU+0+fU9w/IJnbIqUWSG8OyOR3UAt7qNsa+WKJrb0e+gBN7+f5HY3NQlF0u+hHH7n3cIlf7Xhe1PHJsrgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Error&quot;
        title=&quot;&quot;
        src=&quot;/static/36d59a60720c36b7cc5f59222593be92/5a190/error.png&quot;
        srcset=&quot;/static/36d59a60720c36b7cc5f59222593be92/772e8/error.png 200w,
/static/36d59a60720c36b7cc5f59222593be92/e17e5/error.png 400w,
/static/36d59a60720c36b7cc5f59222593be92/5a190/error.png 800w,
/static/36d59a60720c36b7cc5f59222593be92/c1b63/error.png 1200w,
/static/36d59a60720c36b7cc5f59222593be92/29007/error.png 1600w,
/static/36d59a60720c36b7cc5f59222593be92/cc7de/error.png 1605w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;my-solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-solution&quot; aria-label=&quot;my solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Solution&lt;/h2&gt;
&lt;p&gt;Reading the React documentation on &lt;a href=&quot;https://reactjs.org/docs/refs-and-the-dom.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Refs and the DOM&lt;/a&gt; it was obvious I needed to use the &lt;code&gt;useRef()&lt;/code&gt; function.
After some experiments this is the solution I came up with (the complete source code of my site is available &lt;a href=&quot;https://github.com/ceedee666/drumm.sh&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;1&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;react&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;2&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useStaticQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;graphql&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;gatsby&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;3&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;4&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Comments&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;5&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useStaticQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;graphql&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    query RepoQuery {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;7&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      site {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;8&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        siteMetadata {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;9&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;          commentsRepo&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;10&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;11&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;12&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;13&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;  `&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;14&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;15&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;commentsRef&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;16&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;17&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;18&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;19&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://utteranc.es/client.js&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;20&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;21&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;repo&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;siteMetadata&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;commentsRepo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;22&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;issue-term&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;pathname&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;23&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;label&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;comment :speech_balloon:&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;24&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;25&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;theme&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;26&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;github-light&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;27&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;28&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;crossorigin&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;anonymous&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;29&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;30&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;commentsRef&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;31&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;32&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }, [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;33&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;34&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;35&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;commentsRef&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;36&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;37&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;38&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-gutter-pad&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-gutter grvsc-line-number&quot; aria-hidden=&quot;true&quot; data-content=&quot;39&quot;&gt;&lt;/span&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Comments&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code cosists of the following parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Line 5: Here I create a query to read the Github repository from the &lt;code&gt;gatsby-config.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Line 15: Creates a Ref using the &lt;code&gt;useRef()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Line 17: The &lt;code&gt;useEffect()&lt;/code&gt; functions builds the script element and adds it to the element identified by the &lt;code&gt;commentsRef&lt;/code&gt;. It is important to note&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;that the DOM element in the Ref is available using the &lt;code&gt;.current&lt;/code&gt; attribute.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Line 34: Finally, the &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; for the comments script is create and returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whit this Comments component in place I can now add comment functionality to the pages of my website by just adding a &lt;code&gt;&amp;#x3C;Comments /&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;result&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#result&quot; aria-label=&quot;result permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Result&lt;/h2&gt;
&lt;p&gt;The following screenshot shows the final result. Already including some comment by &lt;a href=&quot;https://twitter.com/tobiashofmann/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Tobias&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/deb7b8a0ec385f05ed935878c35800f4/7b1dc/result.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABbElEQVR42q1SW26DMBDk/n9Vf3ueqFdoFQgkacLDGGyDwTEwXZsSpSVSo6qWRrZ3Vzszawe661AUDKwsUZYcVVVd75xzH2OMgVO8qmqfdznGStRC+HhRFCipdhxHBK4g2sVIkj222xBxnGAXx7TvaU8QJwn2+wPCaOdrwjDy+Yjuh8MRx48TzmmKNMugtUbgWLIs90x5TkxOmVNT1/OdmGs6O0VObUFqZ9WlVzsMA6ZpuiJI0wyn0xn/tQLX1Xl3y+3WDsQ6emaHJfdww+WglELbajBeQciGBi49pGo8wThOK7i4E2CJ+JtCt97f3uhV6QW58HMSUkIoTWjRGwtzGVbQnYFsNFTbYekT3Mq11kKQqq6tgcn8bYbLoZE1lBTo6ekHsuOtEMEy03uWZ8zznn5afnl+wutmA6UNspyhEgq8lh7OkqHm/eU+ZNOuLXe9gel7+luczr2P3f6v34H1DAerqanwydtiPIIvy5/7rKTdyTQ2MwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Comment Functionality&quot;
        title=&quot;&quot;
        src=&quot;/static/deb7b8a0ec385f05ed935878c35800f4/5a190/result.png&quot;
        srcset=&quot;/static/deb7b8a0ec385f05ed935878c35800f4/772e8/result.png 200w,
/static/deb7b8a0ec385f05ed935878c35800f4/e17e5/result.png 400w,
/static/deb7b8a0ec385f05ed935878c35800f4/5a190/result.png 800w,
/static/deb7b8a0ec385f05ed935878c35800f4/7b1dc/result.png 956w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I hope this blog will help other when trying to add Utterances to their Gatsby website.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Why I Created My Own Website]]></title><description><![CDATA[This is the first (of hopefully a lot more to come) post on my brand new Website. In this post I describe the journey that brought this…]]></description><link>https://drumm.sh/blog/2021/02/26/why-i-created-my-own-webpage/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/02/26/why-i-created-my-own-webpage/</guid><pubDate>Thu, 25 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is the first (of hopefully a lot more to come) post on my brand new &lt;a href=&quot;https://drumm.sh&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Website&lt;/a&gt;. In this post I describe the journey that brought this
website into existence. Along the way I hope to clarify why building my first personal website was an inevitable choice.&lt;/p&gt;
&lt;h2 id=&quot;how-it-all-started&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-it-all-started&quot; aria-label=&quot;how it all started permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How it all started&lt;/h2&gt;
&lt;p&gt;Every journey starts with the first step. So what was this first step in my case? About a year ago after reading some of &lt;a href=&quot;https://twitter.com/alexellisuk&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Alex Ellis&lt;/a&gt; tweets
and blogs I decided to build a four node &lt;a href=&quot;https://www.raspberrypi.org/products/raspberry-pi-4-model-b/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Raspberry Pi&lt;/a&gt; cluster. Here is a photo of the result:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHMklEQVR42iWVa1CU5x3F95OdzCTTOFFQEVFQQBaQXVjkust1LywsuwsLu8tlZS/sLtcsLMilICAgghI1mgAOeIVIraFQW1IvidZLM2nVtLEdNZle0hqdZqYfMv3Y6a+P+OGZ98P7vuc5zznnfx7J98+f8vKfT3j+t8d8/fg+D+9d5c4n86xe/oArc+NcODnA3Ik+ZsY6ODvWxer8KZYvnqS33U9vwEN2yk662twkyxNQKGRIXgG9EICv1rM/fcHD+6vcu36J1Z9Nc3lugvnpES5O9jI/HOT8eD9T3S0s9LUyc6iTpcVp3A4LJfoC1r3xBnv3yl8D/vXrRzz5411efPOAp1/+hvuffsyt1Xkun32PsYEAk++6ODHcSX9fOynyPWRJoznX4uDMaB9jowcY7O/Abi0jNTUZyXff/pmXz59wa2WOJw9u8NmvFri6+OEaw/nThzlysJPw0BB+tG4db771Jhs2biAqMpzufWX0GYuZGTmIy1XFzKlJUlJTkbz8x1MuLczywfh+psfaGQ46aHBVcHy0jV/MDXNuMkh7vYne5kq6fGbkchmNdRamD3fTGmiltspKk7eanq4ONFo1kl+vXEIuS6DJaWSi20FjtZr+jn10tdoJ+ky4bfk0u0oJeM14HXpSFAn8JOhiYWqMO3dvcPvWDYb6gszOvI+33onk6uWzfPXwPuenDtPT7mSgP0Bzg42Bbq/QpZjC/DRycxSUGQvExrvJypRh1mfx2co5xscHWV5e5PLCFMtLlwgGA0iuLc/z7bMHXP/5LJ/fXBIu3+DCmVM8uv9LFs7NMH5okEOjQ0yMj9HZGeTAwABtTU7uXlvizu2bXFtdEYCzLFw8T0dnO5IHt1eEszf5ZPEkNz+eEaZ8xE8X5vjmD7dZvDBFd0cTObnZxCcmkJaeSqJsD6o0OTdWFhge7KGiSInDZmDk0CgefwOSv3y+yuNri9xbmuV3N6/w20+XWLx4mo/mjtPd7sXrtgvRazl4IMjowV7aAo14RPam3htkeKiXwd42sfEM5+cvYjCXIbl+ZIhpYwmTpmIWZyc4IPIV8FdjKVVj0GZToFIgT4hDERdDujwJjULOQb+DcycnOH5skuGxEY70tzNxaIgCjXD5Py++4oe//54vr14QkXFjyEokM0VKYlwk6bJY1LkKVBlJKLPT1oK7eetW9MKYoL2cjjIzDdUWgo11grUdo8il5H//fQ78ix/+/YwrZ8Y5MzOK312OIjlGTEUsClk0e+UxlKjTyc2UszN6F55KLQZ1FsdGOjja30Rvax3BJj81FWYkj764xfffPeDRrQtcOnWA28uzzJ4YoMVXha++EmuFBktFESXGQrKy5CQJ9l5LAYF3q6nxWnDVWRkS810u9LNZq5GcHu2htthAc1kJfQ12Wj1VIoPNjA2207O/gf0dPjr3tzAw0EVHuw+H00qzTUtrfRWtzW6RzyJcNWbi46WCfbQwZXkak1ZDfFQK7T4Hp4/3c/rEoGBoJ0eVhtGkW3O6rcWF319HS6uXbp+VFjFur9jV2EppcFaSo0xHlhSPJCBAGp3lwlUNxXlp6JR70KiSCdsaypbwzURERRAfE0WaLB51TgbZmam0ucw0uyspKzdQX1dFoN6Kp7acfFU6kv62fbSIGFRZjaSI0ZIJM+ITIwXgBiJ3bCZq5xZ2hYcSvX0rkVs2kxERhq9Yhc9uwGLSCo3FrLst5Inw11TokRwN5DLWKgqhQY/LpkGvUVGsV1KqzxSFKSUyaguRkZuJj9tORIRgHLaJfcLhoEnDiN9Kfb2ZMn0uoZtC1kpG0uoR+ji1TDVGc6Qpk+HeBo6J6moTBplNhaLjpCTs2UlM7Dbx03refufHZCikmGsKqLBrqTRr0auziY2JRBq3C0mzENTjsOIUznkqlfQEnLwverHRU4G6UEmZRY9WpyIpaTdpGTKylHKsRhX6sjwK8zIoEmxt5kJMRTnUWHRI/GIuPTUmau2lay9TU6IxFGUSsT2M9e+8zS5pFIUaJXpdLrbKEgxiJO2luejUSgoLsrAYVNhM+dSKrHqqTEjc1UbqbCVru2jzRJskRBIdv41tUaFsi9hEiDBn08b1SEXt56QmUZqfTlejkMNQiE6XgdGQTmVpPs4qA35H+SvAUursJVRbtKI4laQlxxIXs10EdQcROzYRHhH6eoVvJHT9WyQIl+srdOJUJdTs04pZT8FpLcIrTtnktCDxOcp4zdJAVbmGUm2WmFkZ6UJ4qSiIqJ1hAjCEMAEaErKeFCH+fm8FTX4TmSKz1eYC3Ha9ADTSIvK8BuipNQmWBsFSh7k4hxJNJgU5KeQI4My9CeyO3U6kyGOoOL4saiteW5HQUIG+IJ3a8kKx1DgrdTQ7RR821pWLy8e8pkGNOEqlqWAN1KDJokjcJ8WF6ejEc2+ylJiYCBITo/AWZ1OtzhTf5lFlzufoYBvnT44QbLDxf+iHlR/YUz3SAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;My Raspberry Pi Cluster&quot;
        title=&quot;&quot;
        src=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png&quot;
        srcset=&quot;/static/db33fc8c8ef8ef4b5b3f20c41ab70918/772e8/pi_cluster.png 200w,
/static/db33fc8c8ef8ef4b5b3f20c41ab70918/e17e5/pi_cluster.png 400w,
/static/db33fc8c8ef8ef4b5b3f20c41ab70918/0a47e/pi_cluster.png 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, this project went down the road of many personal projects. It ended up sitting half finished on my desk. After the winter term of 2020/2021 was finished a few weeks
ago I decided to reactive the cluster. After a few days I had it running on &lt;a href=&quot;https://microk8s.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MicroK8s&lt;/a&gt; and was ready to start learning more about &lt;a href=&quot;https://kubernetes.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes&lt;/a&gt;
and &lt;a href=&quot;https://12factor.net/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;cloud native development&lt;/a&gt;. This was about the time I published the following &lt;a href=&quot;https://twitter.com/ceedee666/status/1358758331544928256&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tweet&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 557px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d36a3d32892f15350ca3573297672ba4/30d00/initial_tweet.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 146.00000000000003%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAYAAACqhkzFAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF5ElEQVR42o1WW2xUVRSdGIMfVkApQhQRWqYFlEBpO9BC3y19QFtIixIwqIn6Z8KHXxj99YHRELAqjxDCp4QAyjM+PnxQsKWdttDpY6ad5525M3fmzuPeec9y7zNtmn4YOcnOPj33zDr77L3WPjXouo7+e/0IhkJwulyQvF7IsgyXx4uhcT+0mIZYLIZIJIpEIgFN0xCN6UgkU+CRywmH8WAWPi0LQzAYwsWLFzAxMY6xR48xNGzGsPkRRkdG8bvZg/4ZFWZnCBZJhcUbw5gUhdXth8PhhNfnowB8cDsdmPRriNAZhmw2h3Q6DUVRIEleuN0uuO1mBINBhMIq5JAKRQ1DpoMVmssKeZr7/bLYE6DfBQIBxKIRZLPZPCAPPu3+g0H09z/AwN83MDVtw/T0DGy2WVitbDOYmrIJb5mYxjiZZdKKCVpjm6Z9yVQahnQ6IwB/vHwNxSWVWG+sxJZtjSgyVmDz69UwbtwB46adKC41oay8Dq+s34bnXijGshUbsJSs4PkiYUueXYM//3rAgGkBeObcJbxaVIaX120jwBqsLdoO4+YqbCAgNgbasrUGJXTAzuo92F3bIfyK1RuxbGUJnilYi19/+2MB8PszF/Hi6lIULF8ngAtXGrHmpRIsL9wg5gVL19L3jShcVULRb0fJJhOKjeV4eskqGJ4qhMGwNA+YyWSIAkmMWyZx8tQP+LbvPE6ePoNvvu7DqS9P4rMTp/HFiVOL7avTC0Z/fz635vXJTJsgvuvrg4s46JP98BANFMUPu0fFpDu+iGv/N3K00RAj4o6MDOdJ7QvA7vJADihIU8WYBnyDJzVmjEENh4l7Hrg9HgHqdLowa7cLXs6f+qRDRJiiSDRNF7KKx+PCYiQv9gtrOlJJ8jrJLhJBYm5fnL7znkWAYYrw4dAwRsfGMD5uwWOye/33SX4jtPaIJDkB88Qs/rE4MDTlxMBjK0atToxZpuh3Q7A7HIsB+QSWjo+UEiJpsSksO2oWnI6wGoIUicOhATNqBq5oBrKeg48k6Ha7oetxAcT5Fjnk7uHzeYUuWcesUa9Xgodyymv8TQnI0FTlyXKo6UnYnH5Icgg2uwczDkmYddYNu5s6iRSA0yPj8pWfceXqTVy9fnvBrt3C9Z/u4BrZTzfuihZnsHkSOHtTwYW7EfJBnLsVwvnbKs7fIaP5pV/iOHvdhZb2QzDtbEG5qRkVO1pIenuFb2jaj9a2g+KbmdqeIRLVqVMQqQNR+JUIYvE09GSW1JNDkCrp0SLUcVw40HMU9Y3dqK3vRG1DF1rbDwrftf8IenrfRk3dPgw+NMPASXU63QiHI4IKyWSeCimSY1BT4Y0rkCUf2va+ifLKfHSVZNU1HWJe39SNPW29qKDIBwaHSSnEQbfEzTIkmqVKzTQeT4jq6XoC2XQWnnlAvq6phYCaUbWrjdpZo4isZU+PWB8YNOcB7Q4XUSQi3pUkvRVcrVQqJSLmESAp8tX4utW727GL8tfS2ovauk5x9b37DtEB7XTlkTygk/QbjsQQIyVww2X1JOnKHCnzy+8PiDxxAeoob/WNXWhrf0PMO7sPo/fgO2igNX6LiDZxWKl9++QA+AVkkXN0PGdAYpcA7Nr/FnZR3qooQs5fY/MB8XcHpaKr+4hIgSgKRzhrdyJEuYtQhGo0SRVOU04VoQQ+wOfzo30f57AJpqoWYdU17ZTLJioKRdvRS7RpzgNyY7DN2BGgokQp2pieEq8gS4/lKAC9MpoaerD5tUZs2lxP1oCtW1tRWlqPsrJ2mEydMBprqAc8ZC0n6W2VqcJBRKJRAcYgXBwuSiaTRcDvxYfHW3H4WBmOflSBI8cq8N7HJnzwqQnvf5K3d4+XwWIj2vB/AIFgmN5crnKY5iqCav6NnR8811I+6GkP4hmJvIRETkIKEigc4bW0C8lMIg8Y07i3JcEF0qkQUUoDRyiqTQXi9zabmWu08/02t9iy9BqnibMG3sygTBeuKnsGVSha/1y0fAOm1XxH+S/j9vUvh3lVhT97+4IAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Tweet about my @RaspberryPi cluster&quot;
        title=&quot;&quot;
        src=&quot;/static/d36a3d32892f15350ca3573297672ba4/30d00/initial_tweet.png&quot;
        srcset=&quot;/static/d36a3d32892f15350ca3573297672ba4/772e8/initial_tweet.png 200w,
/static/d36a3d32892f15350ca3573297672ba4/e17e5/initial_tweet.png 400w,
/static/d36a3d32892f15350ca3573297672ba4/30d00/initial_tweet.png 557w&quot;
        sizes=&quot;(max-width: 557px) 100vw, 557px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the thread of this tweet &lt;a href=&quot;https://twitter.com/koehntopp&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Frank&lt;/a&gt; requested a blog on the topic. Furthermore, &lt;a href=&quot;https://twitter.com/qmacro&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DJ Adams&lt;/a&gt; encouraged me to blog even
if I don&apos;t understand everything i write about in full detail. So this was decided. I was going to write a blog about Kubernetes on my Raspberry Pi cluster.
At least such a blog would help me to remember what I did, which problems I encountered and how I was able to solve them.&lt;/p&gt;
&lt;h2 id=&quot;why-no-sap-community-blog&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-no-sap-community-blog&quot; aria-label=&quot;why no sap community blog permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why no SAP Community Blog?&lt;/h2&gt;
&lt;p&gt;In the past I would have simply written this blog in the &lt;a href=&quot;http://community.sap.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SAP Community&lt;/a&gt;. However, now I started thinking. There were several reasons for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The SAP Community is focused on SAP related topics. A blog on installing Kubernetes on a Raspberry Pi cluster doesn&apos;t really fit there.&lt;/li&gt;
&lt;li&gt;I have several other topics in mind on which i want to write a blog. Most of them are related to my lectures at the &lt;a href=&quot;http://ww.fh-aachen.de&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FH Aachen&lt;/a&gt; and&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;would also not fit on the SAP Community.
3. In the last semester I asked two of my students to write a blog instead of taking an exam. They published these blogs on the SAP Community as well
(&lt;a href=&quot;https://blogs.sap.com/2021/01/26/building-a-sap-cap-application-in-the-sap-business-application-studio-using-the-example-of-the-bundesliga-table/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; and
&lt;a href=&quot;https://blogs.sap.com/2021/01/25/building-a-sap-cap-application-in-the-sap-business-application-studio-using-the-example-of-a-students-exam-registration/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;). I&apos;m really happy
with the result of this experiment and want to further expand it in the future. Again, the SAP Community doesn&apos;t seem to be the right place to post those blogs.&lt;/p&gt;
&lt;p&gt;After one or two days I decided I needed a solution to write blogs. In my head I had collected the following requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I want to be able to write blogs myself.&lt;/li&gt;
&lt;li&gt;I want to easily allow my students to write blogs as well.&lt;/li&gt;
&lt;li&gt;If possible I want to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Markdown&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Markdown&lt;/a&gt; to write the blogs.&lt;/li&gt;
&lt;li&gt;Ideally the new solution would offer some kind of integration with &lt;a href=&quot;https://github.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github&lt;/a&gt; for version control.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The last two requirements originated form some past experience. Firstly, I started writing my lecture materials using Markdown
and publishing them on Github (cf &lt;a href=&quot;https://github.com/ceedee666/erp_scp_end_2_end&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;End to End SAP ERP Process&lt;/a&gt;). I really like using
Markdown and Github as it allows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;me to quickly correct errors in the lecture material and publish the updated material&lt;/li&gt;
&lt;li&gt;enables students to submit improvements using pull requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, I loath the Typo 3 installation we have a the FH Aachen. Creating and updating a personal website using it is just 🤬. Therefore, I
was sure i needed something different.&lt;/p&gt;
&lt;h2 id=&quot;learning-about-the-jamstack-again&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#learning-about-the-jamstack-again&quot; aria-label=&quot;learning about the jamstack again permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learning about the JAMStack (again)&lt;/h2&gt;
&lt;p&gt;At this point I sent a massage to &lt;a href=&quot;https://twitter.com/oliver&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Oliver&lt;/a&gt;. He is basically the only &lt;em&gt;Web Dev person&lt;/em&gt; I know. Although he has done
some real stuff, i.e. &lt;a href=&quot;https://en.wikipedia.org/wiki/ABAP&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ABAP&lt;/a&gt;, in the past 😎. A few evening later we talk over Zoom and he recommended
&lt;a href=&quot;gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; and &lt;a href=&quot;https://www.netlify.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Netlify&lt;/a&gt;. After all, those are the tools he used to build &lt;a href=&quot;https://opensit.net/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;openSIT&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After this chat I was sold on the idea of developing my own personal website using the &lt;a href=&quot;https://jamstack.wtf/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;JAMStack&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;gettings-started-with-gatsby&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#gettings-started-with-gatsby&quot; aria-label=&quot;gettings started with gatsby permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gettings started with Gatsby&lt;/h3&gt;
&lt;p&gt;Getting started with Gatsby is quite easy. There are several good tutorials available. I worked trough the &lt;a href=&quot;https://www.youtube.com/watch?v=8t0vNu2fCCM&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Great Gatsby Bootcamp&lt;/a&gt;.
After that I felt ready to go. And then I went through the usual loop many times:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I have an idea&lt;/li&gt;
&lt;li&gt;It&apos;s more complex then I thought 🤔&lt;/li&gt;
&lt;li&gt;I hate programming ☹️&lt;/li&gt;
&lt;li&gt;&lt;em&gt;I hate programming&lt;/em&gt; 😖&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I hate programming&lt;/strong&gt; 🤬&lt;/li&gt;
&lt;li&gt;It works!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I love programming&lt;/strong&gt; 😍&lt;/li&gt;
&lt;li&gt;Goto 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-i-learned&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-i-learned&quot; aria-label=&quot;what i learned permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What I learned&lt;/h3&gt;
&lt;p&gt;First and foremost, developing using Gatsby is really fun. From creating the frist hello world app until the final style adjustments I liked the whole experience.
The main problems I ran into were due to me trying to learn 3 things in parallel. This site is built using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gatsby and JavaScript&lt;/li&gt;
&lt;li&gt;Gatsby plugins&lt;/li&gt;
&lt;li&gt;Gatsby uses &lt;a href=&quot;https://graphql.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Graphql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://getbootstrap.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sass-lang.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SCSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides JavaScript, I didn&apos;t know any of these technologies before. And my JavaScript skills are very bad as well. For everything I was able to
find solutions online. Once I read the solution to a problem it most of the time seemed obvious. So in the end I was able to build this website.
The source code is available &lt;a href=&quot;https://github.com/ceedee666/drumm.sh&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;. If you notice any bad mistakes I&apos;m looking forward to a pull request.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-next&quot; aria-label=&quot;whats next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s Next?&lt;/h2&gt;
&lt;p&gt;There is still a lot of work to do. The sections for teaching and projects are still empty. However, the next term starts in about four weeks.
So at least the lecture section will need to contain some content soon. Furthermore, I hope to get back to regularly write blogs. I will start
with a blog series about my Raspberry Pi cluster soon. And then there are lots of functions missing which I want to add. For example there should be
the possibility to comment on blogs. I&apos;m most likely going to implement it using &lt;a href=&quot;https://utteranc.es/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;utterances&lt;/a&gt;. Let&apos;s see where this journey will lead.&lt;/p&gt;
&lt;p&gt;Christian&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Hello World]]></title><description><![CDATA[Lorem Ipsum Lorem ipsum dolor sit amet. Nam tempora officia sit ullam officia ut quia asperiores et aliquid
consectetur est consequatur…]]></description><link>https://drumm.sh/blog/2021/02/23/hello-world/</link><guid isPermaLink="true">https://drumm.sh/blog/2021/02/23/hello-world/</guid><pubDate>Tue, 23 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d96d918aeb93fab5e940dbd54f5045a/c58a3/ettringen.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUCAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAAB0SSWwtBMD//EABoQAAMAAwEAAAAAAAAAAAAAAAABAgQSExT/2gAIAQEAAQUCWQ2d6R6LJpmzQz//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPwGH/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/Aa1//8QAFxAAAwEAAAAAAAAAAAAAAAAAARAhIP/aAAgBAQAGPwKFTH//xAAbEAADAAMBAQAAAAAAAAAAAAAAAREhMYFhkf/aAAgBAQABPyFjGdKN3wdtPhiZGw4+jVn/2gAMAwEAAgADAAAAEI8v/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhUf/aAAgBAwEBPxCmTD//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFx/9oACAECAQE/EFCNH//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQWGB/9oACAEBAAE/EHpib6iwmrq6msI9zlTo4vsOch9RiVzXJ//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Ettringen&quot;
        title=&quot;&quot;
        src=&quot;/static/3d96d918aeb93fab5e940dbd54f5045a/4b190/ettringen.jpg&quot;
        srcset=&quot;/static/3d96d918aeb93fab5e940dbd54f5045a/e07e9/ettringen.jpg 200w,
/static/3d96d918aeb93fab5e940dbd54f5045a/066f9/ettringen.jpg 400w,
/static/3d96d918aeb93fab5e940dbd54f5045a/4b190/ettringen.jpg 800w,
/static/3d96d918aeb93fab5e940dbd54f5045a/e5166/ettringen.jpg 1200w,
/static/3d96d918aeb93fab5e940dbd54f5045a/c58a3/ettringen.jpg 1500w&quot;
        sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;lorem-ipsum&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lorem-ipsum&quot; aria-label=&quot;lorem ipsum permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lorem Ipsum&lt;/h3&gt;
&lt;p&gt;Lorem ipsum dolor sit amet. Nam tempora officia sit ullam officia ut quia asperiores et aliquid
consectetur est consequatur eligendi et quis amet. Amet mollitia ut quam
eveniet qui fugiat dolorem ut unde rerum rem deleniti velit est minima galisum.
Non consequatur omnis et animi eveniet est quia nemo eos quae molestiae. Ut
esse beatae sit officiis doloribus et blanditiis natus et laudantium autem.&lt;/p&gt;
&lt;p&gt;Ab dolorum nihil et animi ullam ad nemo dolores est iure internos At maxime
voluptatem. Sed quae porro quo velit eligendi et praesentium rerum eum
doloremque magnam vel impedit culpa. Non vero culpa ex corrupti asperiores rem
velit porro.&lt;/p&gt;
&lt;p&gt;Ut molestiae omnis et molestiae ratione aut officiis soluta. Qui omnis
consectetur quo error provident et quae quis vel repellendus magnam At quam
nihil. Qui quasi necessitatibus tempora consequuntur et nullpa rerum est
molestiae dolorem non cupiditate officiis ut libero doloremque est eaque sint.&lt;/p&gt;
&lt;h3 id=&quot;bye&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bye&quot; aria-label=&quot;bye permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bye!&lt;/h3&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item></channel></rss>