<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Harald Sitter&#39;s KDE Blog</title>
    <link>https://kde.haraldsitter.eu/</link>
    
    
    <description>Harald Sitter&#39;s KDE Blog Posts</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>2025-09-19T17:20:03+00:00</lastBuildDate>
    <atom:link href="https://kde.haraldsitter.eu/index.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Åkademy, Okademy, in Berlinemy!</title>
        <link>https://kde.haraldsitter.eu/posts/akademy-2025/</link>
        <pubDate>Fri, 19 Sep 2025 17:29:19 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/akademy-2025/</guid>
        <description>
          
          &lt;p&gt;Akademy 2025 is history. What an Akademy it was - and it was grand!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://akademy.kde.org/&#34;&gt;Akademy&lt;/a&gt; is &lt;a href=&#34;https://kde.org&#34;&gt;KDE&lt;/a&gt;&amp;rsquo;s annual conference.
This year it happend to be in Berlin, so I hopped on a short 🤥 10 hour train to the north
to meet friends - old and new - and discuss the latest ventures of KDE.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_104931_hu_72d4dfca8db172c4.webp 320w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_104931_hu_1905026de407a433.webp 579w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_104931.jpg&#34;
        width=&#34;579&#34;
        height=&#34;404&#34;
        alt=&#34;Some statue in Berlin&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;The biggest topic of them all was, of course, &lt;a href=&#34;https://kdelinux.org&#34;&gt;KDE Linux&lt;/a&gt;.
Once again we sent the conference buzzing.
This year with the news of it entering alpha status. There were bananas a plenty,
inspired by the original codename of the distribution: project banana.
We even had a self defense course against fruit: How to defend yourself against someone
armed with a banana.&lt;/p&gt;
&lt;p&gt;Talks were great all around. Well done everyone!&lt;/p&gt;
&lt;p&gt;As is tradition the ad-hoc hallway track was well attended and yielded many useful
results.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_dabe94514e5e94ad.webp 320w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_711801c3dd271f63.webp 640w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_f6653b984b0ff298.webp 960w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_f4676732251f329c.webp 1280w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_f44d9823936e508d.webp 1296w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_c265eb0720f454cc.webp 1920w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847_hu_a18528f22a08b821.webp 2016w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_4847.jpeg&#34;
        width=&#34;2016&#34;
        height=&#34;1134&#34;
        alt=&#34;Me dressed as a banana and Nico not paying attention to my talk&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;The weekend closed out with a great social bash on Sunday at &lt;a href=&#34;https://c-base.org/&#34;&gt;c-base&lt;/a&gt;, a crashed
space station in the middle of Berlin! We had fun, pizza, and discussed input
methods as well as the ultimate question of life, the universe, and everything, before
ending the night at a Späti, Berlin&amp;rsquo;s characteristic late night one-stop shops
for everything from cheap beer to expensive beer.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_319f0284c3ef7fd8.webp 320w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_5850aad9029e7ec2.webp 640w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_d1519a6885baafff.webp 960w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_f3fd91adb8a7277a.webp 1280w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_3645ea8f1dd8097.webp 1296w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_cb2db7a65c19834.webp 1920w,https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141_hu_75bac712550c9773.webp 2000w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/akademy-2025/IMG_20250910_163141.jpg&#34;
        width=&#34;2000&#34;
        height=&#34;1500&#34;
        alt=&#34;Some statue in Berlin&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;During the week we had &lt;a href=&#34;https://community.kde.org/Akademy/2025#Birds_of_a_Feather_%28BoF%29_sessions,_workshops,_and_meetings&#34;&gt;Birds of a Feather sessions&lt;/a&gt;, our informal discussion format.
Every day we had naturally something KDE Linux related to keep our fresh fruit intake
up.&lt;/p&gt;
&lt;p&gt;On Monday we mused on shared immutable distro topics and resolved to lean more
onto &lt;a href=&#34;https://kde-builder.kde.org/&#34;&gt;kde-builder&lt;/a&gt; respectively our repo-metadata
as original source of truth for packaging information.
We discussed automatic data migration onto a different machine,
considered the various types of data a user might want to migrate,
and how to even implement this.
Plasma&amp;rsquo;s solution for backups is a bit wanting. We think it&amp;rsquo;d be a good
idea to double down on &lt;a href=&#34;https://apps.kde.org/kup/&#34;&gt;Kup&lt;/a&gt;, an existing backup solution,
to produce a tidier, more integrated backup experience.&lt;/p&gt;
&lt;p&gt;Volunteers welcome!&lt;/p&gt;
&lt;p&gt;On Tuesday and Thursday we rendered a whole bunch of decisions on KDE Linux issues
that were in need of decision making. No large changes from the status quo though.
Well, the biggest change is that we now have manpages. For now 🥸&lt;/p&gt;
&lt;p&gt;Wednesday was the traditional day trip. It took us on a scavenger hunt through Berlin in
an attempt to secure as many scavenged points as possible. I regretfully don&amp;rsquo;t know
which team won as I got distracted by lunch, but it was great fun all the same.
In the afternoon Aleix and I took to a tea house for some &lt;em&gt;Ostfriesentee&lt;/em&gt; and
light afternoon hacking.&lt;/p&gt;
&lt;p&gt;To close the event on Thursday, Eike, Aleix and I headed to a pub for tomfoolery and baby guinesses.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/akademy-2025/1000054136_hu_b482103ca55aaaa0.webp 320w,https://kde.haraldsitter.eu/posts/akademy-2025/1000054136_hu_ada7b53bcaaef1f6.webp 500w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/akademy-2025/1000054136.jpg&#34;
        width=&#34;500&#34;
        height=&#34;664&#34;
        alt=&#34;Banana!&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Thanks so much to everyone who attended, the Akademy team for organizing, the &lt;a href=&#34;https://akademy.kde.org/2025/sponsors/&#34;&gt;sponsors&lt;/a&gt; and the &lt;a href=&#34;https://ev.kde.org/&#34;&gt;KDE e.V.&lt;/a&gt; for financing, and &lt;a href=&#34;https://techpaladinsoftware.com/&#34;&gt;Techpaladin LLC&lt;/a&gt; for sponsoring my attendance.&lt;/p&gt;
&lt;p&gt;Maybe next year we will learn how to defend yourself against a pointed stick.&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Filelight Speed on Windows</title>
        <link>https://kde.haraldsitter.eu/posts/filelight-speed-windows/</link>
        <pubDate>Fri, 08 Aug 2025 19:25:17 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/filelight-speed-windows/</guid>
        <description>
          
          &lt;p&gt;As of a couple days ago Filelight on Windows is performing its search many times faster than before. Go check it out!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apps.kde.org/filelight/&#34;&gt;https://apps.kde.org/filelight/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s shocking that it was slow to begin with… A few years ago I rewrote the Filelight file walking logic to use native API for Linux and Windows. I thought I did a pretty good job of it and speed wasn&amp;rsquo;t too shabby.
You can imagine my surprise when a friend recently pointed out that a similar piece of software performed maybe even better. Obviously this couldn&amp;rsquo;t stand. I immediately went to profile the situation and indeed Filelight wasn&amp;rsquo;t as fast as expected.&lt;/p&gt;
&lt;p&gt;It turns out there are multiple competing APIs for querying file information on Windows and depending on which gets used performance may not be what you would expect.
There&amp;rsquo;s a good write-up at &lt;a href=&#34;https://www.cppstories.com/2024/cpp-query-file-attribs-faster/&#34;&gt;https://www.cppstories.com/2024/cpp-query-file-attribs-faster/&lt;/a&gt; in case you care to read more.&lt;/p&gt;
&lt;p&gt;Long story short: by not calling slow API, Filelight is now heaps faster than before. Scans that took multiple seconds before now finish in the blink of an eye.&lt;/p&gt;
&lt;p&gt;In case you are wondering just how much faster it is:&lt;/p&gt;
&lt;h2 id=&#34;new&#34;&gt;New&lt;/h2&gt;
&lt;div&gt;
  &lt;video
    controls
    width=&#34;640&#34;
    preload=&#34;auto&#34;
    muted
  &gt;
    &lt;source src=&#34;https://kde.haraldsitter.eu/posts/filelight-speed-windows/new.webm&#34; type=&#34;video/webm&#34;&gt;
  &lt;/video&gt;
&lt;/div&gt;

&lt;h2 id=&#34;old&#34;&gt;Old&lt;/h2&gt;
&lt;div&gt;
  &lt;video
    controls
    width=&#34;640&#34;
    preload=&#34;auto&#34;
    muted
  &gt;
    &lt;source src=&#34;https://kde.haraldsitter.eu/posts/filelight-speed-windows/old.webm&#34; type=&#34;video/webm&#34;&gt;
  &lt;/video&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Plasma in Graz</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-in-graz/</link>
        <pubDate>Mon, 21 Apr 2025 18:37:37 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-in-graz/</guid>
        <description>
          
          &lt;p&gt;This week Plasma developers have descended on the lovely Austrian city of Graz! 🍦&lt;/p&gt;
&lt;p&gt;During the 2025 Plasma Sprint in Graz we&amp;rsquo;ll be discussing a range of topic both for desktop and mobile. Of course there&amp;rsquo;ll also be a fair amount of hacking. If you are in the area, feel free to stop by at &lt;a href=&#34;https://www.linuxtage.at/de/&#34;&gt;Grazer Linuxtage&lt;/a&gt; on Saturday April 26th where we will have a booth!&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_5dc026693815ef89.webp 320w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_f250005aa473d0f9.webp 640w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_d47a50b842159701.webp 960w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_ffd0e41840de5b55.webp 1280w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_c8e10003dac75d18.webp 1296w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_ae4b90a0beae1f41.webp 1920w,https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps_hu_2342d67686a6ab28.webp 4000w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-in-graz/thepeeps.jpg&#34;
        width=&#34;4000&#34;
        height=&#34;3000&#34;
        alt=&#34;Hacking aggressively&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Plasma Crash Course - Sentry</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/</link>
        <pubDate>Fri, 10 Jan 2025 14:11:31 +0100</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/</guid>
        <description>
          
          &lt;p&gt;A while ago a colleague of mine asked about our crash infrastructure in Plasma
and whether I could give some overview on it. This seems very useful to
others as well, I thought. Here I am, telling you all about it!&lt;/p&gt;
&lt;p&gt;Our crash infrastructure is comprised of a number of different components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://api.kde.org/frameworks/kcrash/html/index.html&#34;&gt;KCrash&lt;/a&gt;: a KDE Framework performing crash interception and prepartion for handover to&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html&#34;&gt;coredumpd&lt;/a&gt;: a systemd component performing process core collection and handover to&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://invent.kde.org/plasma/drkonqi&#34;&gt;DrKonqi&lt;/a&gt;: a GUI for crashes sending data to&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sentry.io/welcome/&#34;&gt;Sentry&lt;/a&gt;: a web service and UI for tracing and presenting crashes for developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We already looked at &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/&#34;&gt;KCrash&lt;/a&gt;, &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/&#34;&gt;coredumpd&lt;/a&gt;, and &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/&#34;&gt;DrKonqi&lt;/a&gt;. This week it&amp;rsquo;s time to look at the final piece of the puzzle — Sentry.&lt;/p&gt;
&lt;h2 id=&#34;sentry&#34;&gt;Sentry&lt;/h2&gt;
&lt;p&gt;Sentry is the service we have on the developer side of a crash to manage incoming reports.&lt;/p&gt;
&lt;p&gt;As we&amp;rsquo;ve learned in the DrKonqi post, a Sentry-specific trace created by the &lt;code&gt;preamble&lt;/code&gt; is eventually sent off to our Sentry server. In Sentry, yet more processing happens!&lt;/p&gt;
&lt;h3 id=&#34;symbolication&#34;&gt;Symbolication&lt;/h3&gt;
&lt;p&gt;If the user hasn&amp;rsquo;t explicitly opted into it, there usually aren&amp;rsquo;t debug symbols available on the user system. This would ordinarily render backtraces useless since they are just a bunch of memory addresses without names or references to our source code.
One of the reasons we adopted Sentry is because it can
fill in the gaps through a process called symbolication. For symbolication it essentially needs to know all the loaded libraries and can then fetch the relevant debug symbols via the various &lt;a href=&#34;https://sourceware.org/elfutils/Debuginfod.html&#34;&gt;debuginfod&lt;/a&gt; instances out there. Once it has the debug symbols it can resolve that the address &lt;code&gt;0x2343244&lt;/code&gt; is really the function &lt;code&gt;int main(int argc, char **argv)&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;fingerprinting&#34;&gt;Fingerprinting&lt;/h3&gt;
&lt;p&gt;When a trace has been symbolicated it&amp;rsquo;s ready for fingerprinting. This tries to merge together the same
crash appearing in different submission into one single sentry event. Generally speaking if two submissions have the same trace frames, they are considered the same crash and merged into one event (in practice the &lt;a href=&#34;https://docs.sentry.io/concepts/data-management/event-grouping/fingerprint-rules/&#34;&gt;rules&lt;/a&gt; are a bit more complicated).&lt;/p&gt;
&lt;h3 id=&#34;result&#34;&gt;Result&lt;/h3&gt;
&lt;p&gt;Eventually the crash event appears for us to fix.&lt;/p&gt;
&lt;p&gt;In a future blog post, I&amp;rsquo;ll also give a more detailed guide on how to use Sentry to its full potential.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_ae388d47abcabfd9.webp 320w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_10a5161c18a8c42e.webp 640w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_32065592268bcfa6.webp 960w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_eb4a585600b21694.webp 1280w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_515abe2512538544.webp 1296w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_9a6e1d63d0eca9c2.webp 1920w,https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry_hu_59ab55e6b8a089c6.webp 3092w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-sentry/sentry.png&#34;
        width=&#34;3092&#34;
        height=&#34;4184&#34;
        alt=&#34;Sentry&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Plasma Crash Course - DrKonqi</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/</link>
        <pubDate>Wed, 04 Sep 2024 22:18:38 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/</guid>
        <description>
          
          &lt;p&gt;A while ago a colleague of mine asked about our crash infrastructure in Plasma
and whether I could give some overview on it. This seems very useful to
others as well, I thought. Here I am, telling you all about it!&lt;/p&gt;
&lt;p&gt;Our crash infrastructure is comprised of a number of different components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://api.kde.org/frameworks/kcrash/html/index.html&#34;&gt;KCrash&lt;/a&gt;: a KDE Framework performing crash interception and prepartion for handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html&#34;&gt;coredumpd&lt;/a&gt;: a systemd component performing process core collection and handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://invent.kde.org/plasma/drkonqi&#34;&gt;DrKonqi&lt;/a&gt;: a GUI for crashes sending data to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sentry.io/welcome/&#34;&gt;Sentry&lt;/a&gt;: a web service and UI for tracing and presenting crashes for developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ve already looked at &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/&#34;&gt;KCrash&lt;/a&gt; and &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/&#34;&gt;coredumpd&lt;/a&gt;. Now it is time to look at DrKonqi.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/notification_hu_3893010800b41bfb.webp 320w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/notification_hu_ed95e80e574d08b.webp 640w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/notification_hu_4ac77b77a481e469.webp 960w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/notification_hu_94605c1db3104a.webp 1013w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/notification.png&#34;
        width=&#34;1013&#34;
        height=&#34;494&#34;
        alt=&#34;DrKonqi notification&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;h2 id=&#34;drkonqi&#34;&gt;DrKonqi&lt;/h2&gt;
&lt;p&gt;DrKonqi is the UI that comes up when a crash happens. We&amp;rsquo;ll explore how it integrates with coredumpd and Sentry.&lt;/p&gt;
&lt;h3 id=&#34;crash-pickup&#34;&gt;Crash Pickup&lt;/h3&gt;
&lt;p&gt;When I outlined the functionality of &lt;code&gt;coredumpd&lt;/code&gt;, I mentioned that it starts an instance of &lt;code&gt;systemd-coredump@.service&lt;/code&gt;. This not only allows the core dumping itself to be controlled by systemd&amp;rsquo;s
resource control and configuration systems, but it also means other systemd units can tie into the crash handling as well.&lt;/p&gt;
&lt;p&gt;That is precisely what we do in DrKonqi. It installs &lt;code&gt;drkonqi-coredump-processor@.service&lt;/code&gt; which, among other things, contains the rule:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WantedBy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;systemd-coredump@.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;…meaning systemd will not only start &lt;code&gt;systemd-coredump@unique_identifier&lt;/code&gt; but also a corresponding &lt;code&gt;drkonqi-coredump-processor@unique_identifier&lt;/code&gt;. This is similar to how services start as part of the system boot sequence: they all are &amp;ldquo;wanted by&amp;rdquo; or &amp;ldquo;want&amp;rdquo; some other service, and that is how systemd knows what to start and when (I am simplifying here 😉). Note that &lt;code&gt;unique_identifier&lt;/code&gt; is actually a systemd feature called &amp;ldquo;instances&amp;rdquo; — one systemd unit can be instantiated multiple times this way.&lt;/p&gt;
&lt;h4 id=&#34;drkonqi-coredump-processor&#34;&gt;drkonqi-coredump-processor&lt;/h4&gt;
&lt;p&gt;When &lt;code&gt;drkonqi-coredump-processor@unique_identifier&lt;/code&gt; runs, it first has some synchronization to do.&lt;/p&gt;
&lt;p&gt;As a brief recap from the &lt;code&gt;coredumpd&lt;/code&gt; post: coredumpd&amp;rsquo;s crash collection ends with writing a &lt;code&gt;journald&lt;/code&gt; entry that contains all collected data. DrKonqi needs this data, so we wait for it to appear in the journal.&lt;/p&gt;
&lt;p&gt;Once the journal entry has arrived, we are good to go and will &lt;a href=&#34;http://0pointer.de/blog/projects/socket-activation.html&#34;&gt;systemd-socket-activate&lt;/a&gt; a helper in the relevant user.&lt;/p&gt;
&lt;p&gt;The way this works is a bit tricky: &lt;code&gt;drkonqi-coredump-processor&lt;/code&gt; runs as root, but DrKonqi needs to be started as the user the crash happened to. To bridge this gap a new service &lt;code&gt;drkonqi-coredump-launcher&lt;/code&gt; comes into play.&lt;/p&gt;
&lt;h4 id=&#34;drkonqi-coredump-launcher&#34;&gt;drkonqi-coredump-launcher&lt;/h4&gt;
&lt;p&gt;Every user session has a &lt;code&gt;drkonqi-coredump-launcher.socket&lt;/code&gt; systemd unit running that provides a socket. This socket gets connected to by the &lt;code&gt;processor&lt;/code&gt; (remember: it is root so it can talk to the user socket). When that happens, an instance of &lt;code&gt;drkonqi-coredump-launcher@.service&lt;/code&gt; is started (as the user) and the &lt;code&gt;processor&lt;/code&gt; starts streaming the data from journald to the &lt;code&gt;launcher&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The crash has now traveled from the user, through the kernel, to system-level systemd services, and has finally arrived back in the actual user session.&lt;/p&gt;
&lt;p&gt;Having been started by systemd and initially received the crash data from the &lt;code&gt;processor&lt;/code&gt;, &lt;code&gt;drkonqi-coredump-launcher&lt;/code&gt;
will now augment that data with the KCrash metadata originally &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/&#34;&gt;saved to disk by KCrash&lt;/a&gt;.
Once the crash data is complete, the launcher only needs to find a way to &amp;ldquo;pick up&amp;rdquo; the crash. This will usually be DrKonqi, but technically other types of crash pickup are also supported. Most notably, developers can set the environment variable &lt;code&gt;KDE_COREDUMP_NOTIFY=1&lt;/code&gt; to receive system notifications about crashes with an easy way to open &lt;code&gt;gdb&lt;/code&gt; for debugging. I&amp;rsquo;ve already &lt;a href=&#34;https://kde.haraldsitter.eu/posts/drkonqi-dev-notifications/&#34;&gt;written about this&lt;/a&gt; a while ago.&lt;/p&gt;
&lt;p&gt;When ready, the &lt;code&gt;launcher&lt;/code&gt; will start DrKonqi itself and pass over the complete metadata.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;the crashed application
└── kernel
    └── systemd-coredumpd
        ├── systemd-coredumpd@unique_identifier.service
        └── drkonqi-coredump-processor@unique_identifier.service
            ├── drkonqi-coredump-launcher.socket
            └── drkonqi-coredump-launcher@unique_identifier.service
                └── drkonqi
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What a journey!&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_9c277d8ff4957533.webp 320w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_b8d95ff40779d277.webp 640w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_39137ac2da9123ce.webp 960w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_9a008ae7d511f9c3.webp 1280w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_901fb355d7f4e8.webp 1296w,https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi_hu_e076e1f8c82d90ba.webp 1731w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-drkonqi/drkonqi.png&#34;
        width=&#34;1731&#34;
        height=&#34;947&#34;
        alt=&#34;DrKonqi&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;h3 id=&#34;crash-processing&#34;&gt;Crash Processing&lt;/h3&gt;
&lt;p&gt;DrKonqi kicks off crash processing. This is hugely complicated and probably worth its own post. But let&amp;rsquo;s at least
superficially explore what is going on.&lt;/p&gt;
&lt;p&gt;The launcher has provided DrKonqi with a mountain of information so it can now utilize the CLI for systemd-coredump, called
&lt;code&gt;coredumpctl&lt;/code&gt;, to access the core dump and attach an instance of the debugger &lt;a href=&#34;https://sourceware.org/gdb/&#34;&gt;GDB&lt;/a&gt; to it.&lt;/p&gt;
&lt;p&gt;GDB runs as a two step automated process:&lt;/p&gt;
&lt;h3 id=&#34;preamble-step&#34;&gt;Preamble Step&lt;/h3&gt;
&lt;p&gt;As part of this automation, we run a service called the &lt;code&gt;preamble&lt;/code&gt;: a Python program that interfaces with
the &lt;a href=&#34;https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html#Python-API&#34;&gt;Python API&lt;/a&gt; of GDB.
Its most important functionality is to create a well-structured backtrace that can be converted to a
&lt;a href=&#34;https://develop.sentry.dev/sdk/event-payloads/exception/&#34;&gt;Sentry payload&lt;/a&gt;.
Sentry, for the most part, doesn&amp;rsquo;t ingest platform specific core dumps or crash reports, but instead relies on an abstract
payload format that is generated by so called Sentry SDKs. DrKonqi essentially acts as such an SDK for us.
Once the preamble is done, the payload is transferred into DrKonqi and the next step can continue.&lt;/p&gt;
&lt;h3 id=&#34;trace-step&#34;&gt;Trace Step&lt;/h3&gt;
&lt;p&gt;After the &lt;code&gt;preamble&lt;/code&gt;, DrKonqi executes an actual GDB trace (i.e. the literal &lt;code&gt;backtrace&lt;/code&gt; command in &lt;code&gt;gdb&lt;/code&gt;) to generate the developer output. This is also the trace that gets sent to KDE&amp;rsquo;s Bugzilla instance at bugs.kde.org if the user chooses to file a bug report. The reason this is separate from the already
created backtrace is mostly for historic reasons. The trace is then routed through a text parser to figure out if it is of sufficient
quality; only when that is the case will DrKonqi allow filing a report in Bugzilla.&lt;/p&gt;
&lt;h3 id=&#34;transmission&#34;&gt;Transmission&lt;/h3&gt;
&lt;p&gt;With all the trace data assembled, we just need to send them off to Bugzilla or Sentry, depending on what the user chose to do.&lt;/p&gt;
&lt;h4 id=&#34;bugzilla&#34;&gt;Bugzilla&lt;/h4&gt;
&lt;p&gt;The Bugzilla case is simply sending a very long string of the backtrace to the &lt;a href=&#34;https://bugzilla.readthedocs.io/en/latest/api/&#34;&gt;Bugzilla API&lt;/a&gt; (albeit surrounded by some JSON).&lt;/p&gt;
&lt;h4 id=&#34;sentry&#34;&gt;Sentry&lt;/h4&gt;
&lt;p&gt;The Sentry case on the other hand requires more finesse. For starters, the Sentry code also works when offline. The trace and optional user message get converted into a &lt;a href=&#34;https://develop.sentry.dev/sdk/envelopes/&#34;&gt;Sentry envelope&lt;/a&gt; tagged with a receiver address — a Sentry-specific URL for ingestion so it knows under which project to file the crash. The envelope is then written to &lt;code&gt;~/.cache/drkonqi/sentry-envelopes/&lt;/code&gt;. At this point, DrKonqi&amp;rsquo;s job is done; The actual transmission happens in an auxiliary service.&lt;/p&gt;
&lt;p&gt;Writing an envelope to disk triggers &lt;code&gt;drkonqi-sentry-postman.service&lt;/code&gt; which will attempt to send all pending envelopes to Sentry using the URL inside the payload. It will try to do so every once in a while in case there are pending envelopes as well, thereby making sure crashes that were collected while offline still make it to Sentry eventually. Once sent successfully, the envelopes are archived in &lt;code&gt;~/.cache/drkonqi/sentry-sent-envelopes/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This concludes DrKonqi&amp;rsquo;s activity. There&amp;rsquo;s much more detail going on behind the scenes but it&amp;rsquo;s largely inconsequential to the overall flow. Next time we will look at the final piece in the puzzle — Sentry itself.&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Plasma Crash Course - coredumpd</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/</link>
        <pubDate>Wed, 28 Aug 2024 00:08:38 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/</guid>
        <description>
          
          &lt;p&gt;A while ago a colleague of mine asked about our crash infrastructure in Plasma
and whether I could give some overview on it. This seems very useful to
others as well, I thought. Here I am, telling you all about it!&lt;/p&gt;
&lt;p&gt;Our crash infrastructure is comprised of a number of different components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://api.kde.org/frameworks/kcrash/html/index.html&#34;&gt;KCrash&lt;/a&gt;: a KDE Framework performing crash interception and prepartion for handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html&#34;&gt;coredumpd&lt;/a&gt;: a systemd component performing process core collection and handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://invent.kde.org/plasma/drkonqi&#34;&gt;DrKonqi&lt;/a&gt;: a GUI for crashes sending data to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sentry.io/welcome/&#34;&gt;Sentry&lt;/a&gt;: a web service and UI for tracing and presenting crashes for developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ve looked at &lt;a href=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/&#34;&gt;KCrash&lt;/a&gt; previously. This time we look at &lt;code&gt;coredumpd&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;coredumpd&#34;&gt;Coredumpd&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;coredumpd&lt;/code&gt; collects all crashes happening on the system, through the &lt;a href=&#34;https://man.archlinux.org/man/core.5#Core_dumps_and_systemd&#34;&gt;core_pattern&lt;/a&gt; system. It is shipped as part of &lt;code&gt;systemd&lt;/code&gt; and as such mostly available out of the box.&lt;/p&gt;
&lt;p&gt;It is fairly sophisticated and can manage the backlog of crashes, so old crashes get cleaned out from time
to time. It also tightly integrates with &lt;code&gt;journald&lt;/code&gt; giving us a well-defined interface to access crash
metadata.&lt;/p&gt;
&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/coredumpctl_hu_935891b79ab711f4.webp 320w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/coredumpctl_hu_1dcf57f16a35b10.webp 640w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/coredumpctl_hu_6d1ec0e45e5056db.webp 960w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/coredumpctl_hu_7628dd19c12066bb.webp 1195w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/coredumpctl.png&#34;
        width=&#34;1195&#34;
        height=&#34;743&#34;
        alt=&#34;coredumpctl screenshot&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;But before we dive into the inner workings of &lt;code&gt;coredumpd&lt;/code&gt;, let&amp;rsquo;s talk about cores.&lt;/p&gt;
&lt;h3 id=&#34;what-are-cores&#34;&gt;What are cores?&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&#34;https://man.archlinux.org/man/core.5&#34;&gt;core&lt;/a&gt;, or more precisely: a core dump file, is a copy of the memory image of a process and its process status (registers, mappings, etc.) in a file. Simply put, it&amp;rsquo;s like we took a copy of the running
process from RAM and stored it in a file. The purpose of such a core is that it allows us to look at
a snapshot of the process at that point in time without having the process still running. Using this data, we can perform analysis of the process to figure out what exactly went wrong and how we ended up
in that situation.&lt;/p&gt;
&lt;p&gt;The advantage is that since the process doesn&amp;rsquo;t need to be running anymore, we can investigate crashes even hours or days after they happened. That is of particular use when things crash while we are not
able to deal with them immediately. For example if Plasma were to crash on logout there&amp;rsquo;d be no way
to deal with it besides stopping the logout, which may not even be possible anymore. Instead we
let the crash drop into coredumpd, let it collect a core file, and on next login we can tell the user
about the crash.&lt;/p&gt;
&lt;p&gt;With that out of the way, it&amp;rsquo;s time to dump a core!&lt;/p&gt;
&lt;h3 id=&#34;core-dumps&#34;&gt;Core Dumps&lt;/h3&gt;
&lt;p&gt;We already talked about KCrash and how it intercepts crashes to write some metadata to disk. Once
it is done it calls &lt;code&gt;raise()&lt;/code&gt; to generate one of those core dumps we just discussed. This
actually very briefly turns over control to &lt;a href=&#34;https://github.com/torvalds/linux/blob/c0ecd6388360d930440cc5554026818895199923/fs/coredump.c#L642&#34;&gt;the kernel&lt;/a&gt; which will more or less simply invoke the defined &lt;code&gt;core_pattern&lt;/code&gt; process. In our case, &lt;code&gt;coredumpd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;coredumpd&lt;/code&gt; will immediately &lt;a href=&#34;http://0pointer.de/blog/projects/socket-activation.html&#34;&gt;systemd-socket-activate&lt;/a&gt; itself and forward the data received from the kernel. In other words: it will start an instance of &lt;code&gt;systemd-coredump@.service&lt;/code&gt; and the actual processing will happen in there. The advantage of this is
that regular systemd security configuration can be applied as well as cgroup resource control and all that jazz — the core dumping happens in a regular systemd service.&lt;/p&gt;
&lt;p&gt;The primary task here is to actually write the dump to a file. In addition, &lt;code&gt;coredumpd&lt;/code&gt; will also
collect lots of additional metadata besides what is in the core already. Most notably various bits
and pieces of &lt;code&gt;/proc&lt;/code&gt; information such as cgroup information, mount information, the auxillary vector (auxv), etc.&lt;/p&gt;
&lt;p&gt;Once all the data is collected a &lt;code&gt;journald&lt;/code&gt; entry is written and the &lt;code&gt;systemd-coredump@.service&lt;/code&gt; instance quits again.&lt;/p&gt;
&lt;p&gt;The journal entry will contain the metadata as entry fields as well as the path of the core dump on disk, so we can later access it.
It essentially serves as a key-value store for the crash data. A severely shortened version looks like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Tue 2024-08-27 17:52:27.593233 CEST […]
    COREDUMP_UID=60106
    COREDUMP_GID=60106
    COREDUMP_SIGNAL_NAME=SIGSYS
    COREDUMP_SIGNAL=31
    COREDUMP_TIMESTAMP=1724773947000000
    COREDUMP_COMM=wine64
    COREDUMP_FILENAME=/var/lib/systemd/coredump/core.wine64.….zst
    …
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;Since this is all rather abstract, we can look at a trivial example to illustrate things a bit better.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s open two terminals. In the first we can watch the journal for the crash to appear.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;journalctl -xef SYSLOG_IDENTIFIER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;systemd-coredump
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the second terminal we run an instance of &lt;code&gt;sleep&lt;/code&gt; in the background, and then trigger a &lt;a href=&#34;https://en.cppreference.com/w/c/program/SIG_types&#34;&gt;segmentation fault&lt;/a&gt; crash.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep 99999999999&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kill -SEGV $!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the first terminal you&amp;rsquo;ll see the crash happening:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Aug 27 15:01:49 ajax systemd-coredump[35535]: Process 35533 (sleep) of user 60106 terminated abnormally with signal 11/SEGV, processing...
Aug 27 15:01:49 ajax systemd-coredump[35549]: [🡕] Process 35533 (sleep) of user 60106 dumped core.

                                              Stack trace of thread 35533:
                                              #0  0x0000729f1b961dc0 n/a (/lib/ld-linux-x86-64.so.2 + 0x1cdc0)
                                              ELF object binary architecture: AMD x86-64
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So far so interesting. &amp;ldquo;But where is the additional data from &lt;code&gt;/proc&lt;/code&gt; hiding?&amp;rdquo; you might wonder. We need to look at the verbose entry to see all data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;journalctl -o verbose SYSLOG_IDENTIFIER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;systemd-coredump
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
  &lt;div&gt;
    &lt;picture&gt;
      &lt;source
        type=&#34;image/webp&#34;
        srcset=&#39;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/journal_hu_9b7c156c59722260.webp 320w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/journal_hu_d66aa795256a0040.webp 640w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/journal_hu_953c3f7dd3aa7d80.webp 960w,https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/journal_hu_9cc2b5a024210180.webp 1195w&#39;
        
      /&gt;

      
      &lt;img class=&#34;img-fluid img-thumbnail rounded mw-100 h-100&#34;
        src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-coredumpd/journal.png&#34;
        width=&#34;1195&#34;
        height=&#34;743&#34;
        alt=&#34;journalctl -o verbose of a crash&#34;
        loading=&#34;lazy&#34;
      /&gt;
    &lt;/picture&gt;
  &lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;This actually already concludes coredumpd&amp;rsquo;s work. In the next post DrKonqi will step onto the stage.&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>Plasma Crash Course - KCrash</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/</link>
        <pubDate>Tue, 20 Aug 2024 18:42:58 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/</guid>
        <description>
          
          &lt;p&gt;A while ago a colleague of mine asked about our crash infrastructure in Plasma
and whether I could give some overview on it. This seems very useful to
others as well, I thought. Here I am, telling you all about it!&lt;/p&gt;
&lt;p&gt;Our crash infrastructure is comprised of a number of different components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://api.kde.org/frameworks/kcrash/html/index.html&#34;&gt;KCrash&lt;/a&gt;: a KDE Framework performing crash interception and prepartion for handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html&#34;&gt;coredumpd&lt;/a&gt;: a systemd component performing process core collection and handover to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://invent.kde.org/plasma/drkonqi&#34;&gt;DrKonqi&lt;/a&gt;: a GUI for crashes sending data to…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sentry.io/welcome/&#34;&gt;Sentry&lt;/a&gt;: a web service and UI for tracing and presenting crashes for developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will look at them in turn. This post introduces KCrash.&lt;/p&gt;
&lt;h2 id=&#34;kcrash&#34;&gt;KCrash&lt;/h2&gt;
&lt;p&gt;KCrash, as the name suggests, is our KDE framework for crash handling. While it is a mid-tier framework and could be used by outside projects, it mostly doesn&amp;rsquo;t make sense to, because some behavior is very KDE-specific.&lt;/p&gt;
&lt;p&gt;It installs POSIX &lt;a href=&#34;https://man.archlinux.org/man/signal.7.en&#34;&gt;signal&lt;/a&gt; handlers to intercept crash signals and then prepares the crashed process for handover to coredumpd and DrKonqi. More on these two in another post. Once prepared it sends the crash signal into
the next higher level crash handler until the signal eventually reaches the &lt;a href=&#34;https://en.cppreference.com/w/c/program/SIG_strategies&#34;&gt;default handler&lt;/a&gt; and cause the kernel to invoke the &lt;a href=&#34;https://man.archlinux.org/man/core.5#Core_dumps_and_systemd&#34;&gt;core pattern&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before that can happen, a bunch of work needs doing inside KCrash. Most of it quite boring, but also somewhat challenging.&lt;/p&gt;
&lt;p&gt;You see, when handling a signal you need to
only use &lt;a href=&#34;https://man.archlinux.org/man/signal-safety.7&#34;&gt;signal-safe functions&lt;/a&gt;. The manpage explains very well why. This proves quite challenging at the level we usually are at (i.e. Qt) because it is entirely unclear what is and isn&amp;rsquo;t ultimately signal-safe under the hood. Additionally, since we are dealing with crash scenarios, we must not trigger new memory allocation, because the heap management may have had an accident.&lt;/p&gt;
&lt;p&gt;To that end, KCrash has to use fairy low-level API. To make that easier to work with, there are actually two parts to KCrash:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Initialization Stage&lt;/li&gt;
&lt;li&gt;The Crash Stage&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-initialization-stage&#34;&gt;The Initialization Stage&lt;/h3&gt;
&lt;p&gt;Initialization is generally triggered by calling &lt;code&gt;KCrash::initialize&lt;/code&gt;. You may already wonder what kind of initialization KCrash could possibly need. Well, the obvious one is setting up the signal handling. But beyond that the init stage is also used to prepare us for the crash stage. I&amp;rsquo;ve already mentioned the serious constraints we will encounter once the signal hits, so we had best be prepared for that. In particular we&amp;rsquo;ll do as much of the work as possible during initialization. This most important includes copying &lt;code&gt;QString&lt;/code&gt; content into pre-allocated &lt;code&gt;char *&lt;/code&gt; instances such that we later only need to read existing memory. The second most important aspect is the metadata file preparation for use in…&lt;/p&gt;
&lt;h3 id=&#34;the-crash-stage&#34;&gt;The Crash Stage&lt;/h3&gt;
&lt;p&gt;Once initialization has happened, we are ready for crashes. Ideally the application doesn&amp;rsquo;t crash, of course. 😉&lt;/p&gt;
&lt;p&gt;But if it does the biggest task is rescuing our data!&lt;/p&gt;
&lt;h4 id=&#34;metadata&#34;&gt;Metadata&lt;/h4&gt;
&lt;p&gt;Inside KCrash we have the concept of Metadata: everything we know about the crashed application: the signal, process ID, executable, used graphics device… and so on and so forth. All this data is collected into a metadata file on-disk in &lt;code&gt;~/.cache/kcrash-metadata&lt;/code&gt; at the time of crash.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[KCrash]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exe&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/bin/kwin_wayland&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;glrenderer&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;platform&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;wayland&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;appname&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kwin_wayland&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;apppath&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/usr/bin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;signal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pid&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;1353&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;appversion&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;6.1.80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;programname&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;KWin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bugaddress&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;submit@bugs.kde.org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual fields vary depending on what is available for any given application, but it&amp;rsquo;s generally more or less what is shown in the example.&lt;/p&gt;
&lt;p&gt;This metadata file will later be consumed by DrKonqi in an effort to obtain information that only existed at runtime inside the application - such as the version that was running, or whether it was running in legacy X11 mode.&lt;/p&gt;
&lt;h4 id=&#34;handoff&#34;&gt;Handoff&lt;/h4&gt;
&lt;p&gt;Once the metadata is safely saved to disk, KCrash simply calls &lt;code&gt;raise()&lt;/code&gt;. This re-raises the signal into the default handler, and through that causes a &lt;a href=&#34;https://man.archlinux.org/man/core.5&#34;&gt;core dump&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What happens next is up to the system configuration as per the &lt;code&gt;core&lt;/code&gt; manpage.&lt;/p&gt;
&lt;p&gt;The recommended setup for distributions is that a crash handler be configured as &lt;code&gt;core_pattern&lt;/code&gt; and that this handler consumes the crash. We recommend an implementation of the &lt;code&gt;coredumpd&lt;/code&gt; and &lt;code&gt;journald&lt;/code&gt; interfaces as that will then allow our crash handler to come in and log the crash with KDE.&lt;/p&gt;
&lt;p&gt;So that was KCrash, the first in our four-step crash-handling pipeline. In the next blog post I&amp;rsquo;ll tell you all about the next one: &lt;code&gt;coredumpd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; alt=&#34;Konqi chasing after bugs&#34; src=&#34;https://kde.haraldsitter.eu/posts/plasma-crash-course-kcrash/konqi.png&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/p&gt;
        </description>
      </item>
    
      <item>
        <title>LLVM and dot graphs</title>
        <link>https://kde.haraldsitter.eu/posts/llvm-dot/</link>
        <pubDate>Wed, 01 Nov 2023 15:14:10 +0100</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/llvm-dot/</guid>
        <description>
          
          &lt;p&gt;The other day I had to dive into the ksmserver code, the core of session management
in &lt;a href=&#34;https://kde.org/plasma-desktop/&#34;&gt;KDE Plasma&lt;/a&gt;, but found it all a bit difficult to read.
If only I could get a callgraph I thought&amp;hellip;&lt;/p&gt;
&lt;p&gt;Turns out it actually is possible!&lt;/p&gt;
&lt;p&gt;In fact it is almost too easy with clang/llvm. There are already
solutions that attach LLVM bitcode to existing binaries. e.g. &lt;a href=&#34;https://github.com/SRI-CSL/gllvm&#34;&gt;gllvm&lt;/a&gt;. gllvm basically is a shim sitting between &lt;a href=&#34;https://ninja-build.org/&#34;&gt;ninja&lt;/a&gt;
and the actual compiler and injects some behavior for us.
This enables the use without having to refit anything in our existing code.
You might note that &lt;a href=&#34;https://invent.kde.org/sdk/clazy&#34;&gt;clazy&lt;/a&gt;, our most excellent code analyzer, works in a similar fashion.&lt;/p&gt;
&lt;p&gt;Here is how to use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# install gllvm (NOTE: as a pre-requisite you should have Go properly set up)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go install -v github.com/SRI-CSL/gllvm/cmd/...@latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# clone plasma-workspace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://invent.kde.org/plasma/plasma-workspace
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# change directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd plasma-workspace
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# export environment variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CXX&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gclang++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export CC&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gclang
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You may need to set some additional vars so gllvm can find your compilers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## export LLVM_CC_NAME=clang-16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## export LLVM_CXX_NAME=clazy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Configure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmake -S . -B build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmake --build build/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# extract the bitcode (into build/bin/ksmserver.bc by default)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get-bc -m -v build/bin/ksmserver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Run through llvm&amp;#39;s opt program to generate a callgraph&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opt --disable-output --passes&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dot-callgraph build/bin/ksmserver.bc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# copy into working directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp build/bin/ksmserver.bc.callgraph.dot callgraph.dot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# prettify the c++ names (this may produce invalid labels, so I&amp;#39;m skipping it here)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## cat build/bin/ksmserver.bc.callgraph.dot | llvm-cxxfilt &amp;gt; callgraph.dot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# generate an SVG of the graph&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dot -x -Tsvg -ocallgraph.svg callgraph.dot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# we now have a callgraph.svg \o/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Depending on the complexity of the software and how many libraries it uses this
graph may be incredibly large and verbose though. We&amp;rsquo;ll need to apply some filtering
to make it useful. Or at least I thought so when working with ksmserver.&lt;/p&gt;
&lt;p&gt;To further filter the graph you can use the &lt;code&gt;gvpr&lt;/code&gt; helper. It is a bit &lt;a href=&#34;https://linux.die.net/man/1/gvpr&#34;&gt;clunky&lt;/a&gt;
but gets the job done. You can build a filter expression to only include interesting
functions like so&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;N&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;$.label!&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@(*_ZN9KSMServer*)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; $.label&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@(*metacall*)&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        delete&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;$G, $&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and then filter the dot graph with&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Filter out uninteresting functions (filter.prog is the filter expression from above)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gvpr -c -f filter.prog build/bin/ksmserver.bc.callgraph.dot &amp;gt; intermediate.gv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Filter out all empty nodes (they call nothing and are of no interest)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gvpr -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;N[&lt;/span&gt;$&lt;span style=&#34;color:#e6db74&#34;&gt;.degree==0]{delete(root, &lt;/span&gt;$&lt;span style=&#34;color:#e6db74&#34;&gt;)}&amp;#34;&lt;/span&gt; intermediate.gv &amp;gt; final.gv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# generate an SVG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat final.gv | dot -x -Tsvg -ocallgraph.svg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Final result&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; alt=&#34;Screenshot&#34; src=&#34;https://kde.haraldsitter.eu/posts/llvm-dot/callgraph.svg&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>DrKonqi Developer Notifications</title>
        <link>https://kde.haraldsitter.eu/posts/drkonqi-dev-notifications/</link>
        <pubDate>Thu, 07 Sep 2023 07:00:00 +0200</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/drkonqi-dev-notifications/</guid>
        <description>
          
          &lt;p&gt;For a while now DrKonqi has a special developer notification system when used in
combination with coredumpd. I just realized I never told anyone about it 😅
though.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s terribly simple: When used with coredumpd, parts of DrKonqi implicitly
look at all crashes that pertain to your current user. Because of that it can
also notify on all crashes, not just the KDE-related ones. Obviously it can&amp;rsquo;t
report bugs or anything but sometimes, as a developer, it&amp;rsquo;s nice to know when
things explode.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; alt=&#34;Screenshot&#34; src=&#34;https://kde.haraldsitter.eu/posts/drkonqi-dev-notifications/notification.png&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;This is a purely opt-in feature and shouldn&amp;rsquo;t be enabled unless you know
your way around the debugger GDB or really want to know about all the crashes.&lt;/p&gt;
&lt;p&gt;To enable the feature simply add &lt;code&gt;KDE_COREDUMP_NOTIFY=1&lt;/code&gt; to your environment.
For example using an environment.d file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.config/environment.d/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;KDE_COREDUMP_NOTIFY=1&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.config/environment.d/50-$USER.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
        </description>
      </item>
    
      <item>
        <title>Debugging App Crashes on Windows</title>
        <link>https://kde.haraldsitter.eu/posts/debugging-app-crashes-on-windows/</link>
        <pubDate>Mon, 04 Sep 2023 08:19:58 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/debugging-app-crashes-on-windows/</guid>
        <description>
          
          &lt;p&gt;The other week the question came up how one can debug an application crash when the Windows Store crash tracking system is unable to produce a usable stack trace. Seemed a good enough opportunity to share some wisdom :)&lt;/p&gt;
&lt;p&gt;Generally speaking in order to get a stack trace you first need a &lt;a href=&#34;https://learn.microsoft.com/en-us/windows/win32/debug/minidump-files&#34;&gt;minidump&lt;/a&gt;. minidumps are kind of like &lt;a href=&#34;https://man7.org/linux/man-pages/man5/core.5.html&#34;&gt;core&lt;/a&gt; dumps on POSIX systems, well, except, mini. Acquiring that is should be your first goal.&lt;/p&gt;
&lt;p&gt;There are a million ways to get a dump, I&amp;rsquo;ll highlight two of the easiest that I know of.&lt;/p&gt;
&lt;h1 id=&#34;partner-center-dumps&#34;&gt;Partner Center Dumps&lt;/h1&gt;
&lt;p&gt;Ideally the &lt;a href=&#34;https://partner.microsoft.com/en-us/dashboard&#34;&gt;Microsoft Partner Center&lt;/a&gt; will have a dump for you. You can find it usually where the stack trace is as well. To get access to KDE&amp;rsquo;s applications you need to be a KDE developer and file a sysadmin request. Once you have access you have to head from the &lt;code&gt;Dashboard&lt;/code&gt; to &lt;code&gt;Insights&lt;/code&gt; then navigate in the left hand pane to &lt;code&gt;Health&lt;/code&gt; there use the drop-down to select the application you want to look at. This should give you every bit of information about the application health your heart could desire. You&amp;rsquo;ll probably also want to switch from viewing the last 72 hours to the last month, unless the application is particularly faulty of course.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-at-07-53-38-health-apps-and-games-insights-partner-center.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-at-07-53-38-health-apps-and-games-insights-partner-center.png?w=801&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now all you need to do is click on the crash you want to look at, and not get too annoyed over the unknown crashes you can&amp;rsquo;t do anything about 😡.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-at-07-55-26-health-details-apps-and-games-insights-partner-center.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-at-07-55-26-health-details-apps-and-games-insights-partner-center.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At this point you should be able to find a stack trace link and an additional download link. Sometimes the download link is not there, I have no idea why but I&amp;rsquo;m sure it&amp;rsquo;s documented somewhere. The download link is what we are after, it contains the minidump along with some other metadata.&lt;/p&gt;
&lt;h1 id=&#34;user-mode-dumps&#34;&gt;User-Mode Dumps&lt;/h1&gt;
&lt;p&gt;Now, sometimes the partner center is not able to help us for whatever reason. Maybe the download link is missing, maybe it just doesn&amp;rsquo;t show the crash we are after, maybe the dump on the partner center is useless. Who knows. In that case we need some help from the user. Thankfully it&amp;rsquo;s not too painful. They need to enable collection of &lt;a href=&#34;https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps&#34;&gt;user-mode dumps&lt;/a&gt; by creating the registry key &lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps&lt;/code&gt;, which then causes the Windows Error Reporting to throw a minidump into &lt;code&gt;%LOCALAPPDATA%\CrashDumps&lt;/code&gt;. The user then needs to reproduce the crash and obtain the dmp file from the aforementioned location.&lt;/p&gt;
&lt;h1 id=&#34;debug-symbols&#34;&gt;Debug Symbols&lt;/h1&gt;
&lt;p&gt;Once you have obtained a minidump it&amp;rsquo;s time to find us some debug symbols. The sad truth here is that I can&amp;rsquo;t really help with that. Depending on how your application was built you&amp;rsquo;ll be able to get &lt;a href=&#34;https://devblogs.microsoft.com/cppblog/whats-inside-a-pdb-file/&#34;&gt;PDBs&lt;/a&gt; &lt;strong&gt;somehow&lt;/strong&gt; &lt;em&gt;hopefully&lt;/em&gt;. They will either float around as PDBs somewhere or at the very least will be available inside the .appxupload or .appxsym zip files. As a general best practice for KDE software I would advise that when you do a binary release to the Windows Store you also release the &lt;code&gt;x86_64-dbg.7z&lt;/code&gt; file to download.kde.org so we can get the relevant PDBs when needed.&lt;/p&gt;
&lt;h1 id=&#34;tracing&#34;&gt;Tracing&lt;/h1&gt;
&lt;p&gt;Alright, I hope you had luck with finding your debug symbols, because now it&amp;rsquo;s time to do some tracing! Whee. You&amp;rsquo;ll need &lt;a href=&#34;https://visualstudio.microsoft.com/&#34;&gt;Microsoft Visual Studio&lt;/a&gt;. Any edition will do. &lt;code&gt;File-&amp;gt;Open-&amp;gt;File...&lt;/code&gt; the minidump and you should be greeted by a nice overview of metadata about the crash.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-004227.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-004227.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First we&amp;rsquo;ll want to setup our debug symbols. For that you first want to place your PDBs somewhere in convenient in your file system. I&amp;rsquo;m lazy and usually just slap them on the Desktop. In Visual Studio you should find the option &lt;code&gt;Set symbol paths&lt;/code&gt; in the right hand list of actions. The option opens the settings window on the correct page. Simply hit the ➕ and type out the path where you extracted the PDBs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-004309.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-004309.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the symbol paths are set up you can hit &lt;code&gt;Debug with Mixed&lt;/code&gt; and off the tracer goes. Slowly, because it needs to download a million symbols. But eventually you&amp;rsquo;ll arrive at your stack trace.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-005323.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/09/screenshot-2023-09-04-005323.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(nevermind my crazy setup, I was doing some wonky multi threaded debugging earlier and don&amp;rsquo;t know how to restore the UI 😅)&lt;/p&gt;
&lt;p&gt;Hope this helps some!&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Hugging Websites</title>
        <link>https://kde.haraldsitter.eu/posts/hugging-websites/</link>
        <pubDate>Fri, 18 Aug 2023 16:33:36 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/hugging-websites/</guid>
        <description>
          
          &lt;p&gt;&amp;hellip;very hard.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://kde.org&#34;&gt;KDE&lt;/a&gt; relies heavily on web services, and many of them need to be kept responsive even under strenuous load. I&amp;rsquo;ve recently had the opportunity to spend some time on load testing one of our websites and would like to share how that worked out.&lt;/p&gt;
&lt;p&gt;To properly test things I wanted to have multiple computers make concurrent requests to the service and ensure that the service still performs within acceptable limits. To that end I needed a bunch of servers, software that can pressure the web service, and software that can make sure the service works.&lt;/p&gt;
&lt;p&gt;The server bit is the easiest task there&amp;hellip; any cloud provider will do.&lt;/p&gt;
&lt;p&gt;The software also seemed easy. After very quick research &lt;a href=&#34;https://locust.io/&#34;&gt;Locust&lt;/a&gt; seemed as good a choice as any to poke at the service and make sure it responds. Except, after some pondering I came to realize that this is actually not so. You see, Locust does HTTP performance testing. That is: it makes HTTP requests and tracks their response time / error rate. That is amazing for testing an API service, but when dealing with a website we also care about the javascripty bits on top being responsive. Clearly a two-prong approach was necessary here. On the one hand Locust can put pressure on the backend and then something else can poke the frontend with a stick to see if it is dead. Enter our old friend: &lt;a href=&#34;https://www.selenium.dev/&#34;&gt;Selenium&lt;/a&gt;. An obvious choice given my recent work on a &lt;a href=&#34;https://apachelog.wordpress.com/2022/12/14/selenium-at-spi-gui-testing/&#34;&gt;Selenium-based application testing framework&lt;/a&gt;. The advantage here is that Selenium can more or less accurately simulate a user using the website giving us a fairly good idea about perceived performance being up to spec. Better yet, both Locust and Selenium have master/client architectures whereby we can utilize the cloud to do the work while a master machine just sits there orchestrating the show.&lt;/p&gt;
&lt;p&gt;The three building blocks I&amp;rsquo;ve arrived at are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A cloud to scale in&lt;/li&gt;
&lt;li&gt;Locust for performance testing (that the thing stays responsive)&lt;/li&gt;
&lt;li&gt;Selenium for interaction testing (that the thing actually &amp;ldquo;works&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I actually thought about showing you some code here, but it&amp;rsquo;s exceptionally boring. You can go look at it at &lt;a href=&#34;https://invent.kde.org/sitter/load&#34;&gt;https://invent.kde.org/sitter/load&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At first I needed to write some simple tests for Locust and Selenium. They were fairly straight forward, a bit of login, a bit of logout. Just to start putting pressure on the server-under-test.&lt;/p&gt;
&lt;p&gt;With simple tests out of the way it was time to glue everything together. For this I needed a couple more puzzle pieces. I&amp;rsquo;ve mentioned that both Locust and Selenium have &amp;ldquo;server&amp;rdquo; components that can manage a number of clients. For Locust that is &lt;a href=&#34;https://docs.locust.io/en/stable/running-distributed.html&#34;&gt;distributed load generation&lt;/a&gt;, and for Selenium it&amp;rsquo;s called a &lt;a href=&#34;https://www.selenium.dev/documentation/grid/&#34;&gt;Grid&lt;/a&gt;. For convenience I&amp;rsquo;ve opted to manage them using docker-compose.&lt;/p&gt;
&lt;p&gt;The last piece of the puzzle was some provisioning logic for the cloud server to install and start Selenium as well as Locust Workers.&lt;/p&gt;
&lt;p&gt;When all the pieces were in place amazing things started happening!&lt;/p&gt;
&lt;p&gt;On my local machine I had a Selenium Grid and a Locust master running. Magically, cloud servers started connecting to them as workers and after a while I didn&amp;rsquo;t have the Selenium and Locust power of one machine, no, UNLIMITED POWER! (cheeky Star Wars reference).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-03-28-21-selenium-grid.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-03-28-21-selenium-grid.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;By starting a load test in Locust it was distributed across all available nodes, simulating more concurrent access than one machine would or could ordinarily do.&lt;/p&gt;
&lt;p&gt;A simple loop also starts a number of concurrent Selenium tests that get distributed across the available grid nodes.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;for i in {1..5}; python3 test.py&amp;amp; done
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The end result is a Locust making hundreds of requests per second while Selenium is trying to use the UI. Well, for a while anyway&amp;hellip; I naturally wanted to know the limits so I kept bumping the request numbers. At first all was cool.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-02-18-17-locust-for-locustfile.py_.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-02-18-17-locust-for-locustfile.py_.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Response times in the sub 100ms at 300 users is pretty good I think. CPU usage was also at a comfortable level.&lt;/p&gt;
&lt;p&gt;So I increased it to 600 users, which was still OKish. But when I started going towards 1200 users the problems started to appear.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-02-27-09-locust-for-locustfile.py_.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-02-27-09-locust-for-locustfile.py_.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the bottom graph you can see the two bumps from 300 to 600 and then to 1200. What you can see super clearly is how the response time keeps getting poorer and poorer the difference is so enormous that you almost can&amp;rsquo;t make out the response time changes from 300 to 600 anymore. Eventually the service started having intermittent interruptions when the Selenium tests were also trying to get their work done. Yet CPU and memory were not fully at capacity - In particular the intermittent failure hike is very suspicious. A look at the failures gave the hint: it was running into software limits. I bumped up the limits because the hardware still had leeway, and presto: no more failure spikes even when at 2048 users. Hooray! Response time does suffer though, so in the end there would need to be more reshuffling if that was an expected user count.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-19-59-43-locust-for-locustfile.py_.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot-2023-08-13-at-19-59-43-locust-for-locustfile.py_.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Knowing the limits of our services is very useful for a number of reasons, ranging from knowing how many users we can support, to how oversized our servers are for the task they are performing, to whether our service is susceptible to malicious use. Knowing the capabilities and weaknesses of our systems helps us ensure high availability.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;To discuss this blog post check out &lt;a href=&#34;https://discuss.kde.org/t/hugging-websites&#34;&gt;KDE Discuss&lt;/a&gt;.&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>resvg for SVGs in Qt</title>
        <link>https://kde.haraldsitter.eu/posts/resvg-for-svgs-in-qt/</link>
        <pubDate>Sat, 12 Aug 2023 17:18:34 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/resvg-for-svgs-in-qt/</guid>
        <description>
          
          &lt;p&gt;People keep lamenting how lackluster &lt;a href=&#34;https://doc.qt.io/qt-6/qsvgrenderer.html&#34;&gt;Qt&amp;rsquo;s SVG renderer&lt;/a&gt; is. It leads to &lt;a href=&#34;https://bugs.kde.org/show_bug.cgi?id=448234&#34;&gt;poorly rendered icons&lt;/a&gt; and wallpapers and it mostly only implements the &lt;a href=&#34;https://www.w3.org/TR/SVGTiny12/&#34;&gt;SVG Tiny&lt;/a&gt; specification. As a weekend project I put together a &lt;a href=&#34;https://github.com/RazrFalcon/resvg&#34;&gt;resvg&lt;/a&gt; based image handler replacement. It was super easy because resvg is amazing!&lt;/p&gt;
&lt;h1 id=&#34;the-plugins&#34;&gt;The Plugins&lt;/h1&gt;
&lt;p&gt;An application that uses QSvgRenderer actually can, for the most part, just use &lt;a href=&#34;https://github.com/RazrFalcon/resvg/blob/e1424f9a436d06b25986e9a129df7ed0eabad238/crates/c-api/ResvgQt.h&#34;&gt;resvg&amp;rsquo;s Qt header&lt;/a&gt; and call it a day. It has a very convenient interface that lets you replace most uses of QSvgRenderer with resvg&amp;rsquo;s. That&amp;rsquo;s all lovely, except who wants to port every application to a new library.&lt;/p&gt;
&lt;p&gt;Luckily, most applications don&amp;rsquo;t actually use QSvgRenderer directly, they use it through 2 plugins. The &lt;a href=&#34;https://doc.qt.io/qt-6/qiconengineplugin.html&#34;&gt;iconengine&lt;/a&gt; plugin, providing a &lt;a href=&#34;https://doc.qt.io/qt-6/qiconengine.html&#34;&gt;QIconEngine&lt;/a&gt;. And the &lt;a href=&#34;https://doc.qt.io/qt-6/qimageioplugin.html&#34;&gt;imageformats&lt;/a&gt; plugin, providing a &lt;a href=&#34;https://doc.qt.io/qt-6/qimageiohandler.html&#34;&gt;QImageIOHandler&lt;/a&gt;. Understanding when which is used is the first step.&lt;/p&gt;
&lt;p&gt;Duh! The icon engine is used for icons! - Well, yes, usually&amp;hellip;&lt;/p&gt;
&lt;p&gt;The SVG &lt;a href=&#34;https://doc.qt.io/qt-6/qiconengine.html&#34;&gt;QIconEngine&lt;/a&gt; confusingly isn&amp;rsquo;t actually used on KDE Plasma, instead we &lt;a href=&#34;https://invent.kde.org/plasma/plasma-integration/-/blob/ae17d6caf5d8a1c1e953807417c13763ba99a7ac/qt6/src/platformtheme/kdeplatformtheme.cpp#L371&#34;&gt;route all icon lookups&lt;/a&gt; through KIconEngine which does some magic. Ah! But where does it then get the icon from? If we follow the code paths a bit we end up &lt;a href=&#34;https://invent.kde.org/frameworks/kiconthemes/-/blob/3b55e72106242f6010b05bc3ddadf6683103445b/src/kiconloader.cpp#L687&#34;&gt;here&lt;/a&gt; and after some reading on &lt;a href=&#34;https://doc.qt.io/qt-6/qimagereader.html&#34;&gt;QImageReader&lt;/a&gt; we learn that on KDE Plasma icon lookup is actually not running through the SVG iconengine plugin but the imageformats plugin. Slightly confusing but actually beneficial because it means that icon rendering is ultimately running through the same code paths as regular SVG image reading when e.g. loading an &lt;code&gt;Image&lt;/code&gt; in QML.&lt;/p&gt;
&lt;p&gt;By creating an imageformats plugin we can replace most uses of QSvgRenderer with resvg without having to touch every application. Hooray!&lt;/p&gt;
&lt;h1 id=&#34;qimageiohandler&#34;&gt;QImageIOHandler&lt;/h1&gt;
&lt;p&gt;And the good news keeps on coming. A basic &lt;a href=&#34;https://doc.qt.io/qt-6/qimageiohandler.html&#34;&gt;QImageIOHandler&lt;/a&gt; is super easy to implement.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    bool canRead() const override;
    bool read(QImage \*image) override;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All we need to do is implement reading&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    \*image = ResvgRenderer(device()-&amp;gt;readAll(), ResvgOptions()).renderToImage();
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That gets us a working plugin. There are some extra features one can and should implement but for the most part that is all that&amp;rsquo;s needed. You can check out the &lt;a href=&#34;https://invent.kde.org/sitter/qresvgimageiohandler&#34;&gt;complete source&lt;/a&gt; to see where things are at.&lt;/p&gt;
&lt;h1 id=&#34;duel-of-plugins&#34;&gt;Duel of Plugins&lt;/h1&gt;
&lt;p&gt;Now that we have a plugin we just need to make Qt actually use ours instead of its own. Unfortunately this is where our luck runs out. Qt appears to have no facilities for manipulating which imageformats plugin is used when there are multiple candidates for the same format. In our case we have qsvg and qresvg both supporting SVG and it appears undefined behavior which of the two gets used. So, for the time being we&amp;rsquo;ll have to overwrite qsvg to get our plugin to reign supreme. Somewhat unfortunate.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Plugins are cool. Resvg is also cool. Making a resvg plugin is double cool.&lt;/p&gt;
&lt;p&gt;You can give it a try at &lt;a href=&#34;https://invent.kde.org/sitter/qresvgimageiohandler&#34;&gt;https://invent.kde.org/sitter/qresvgimageiohandler&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it looks like. On the left hand side you can see the image from a bug report where the image viewer icon is misrendered, on the right you can see the same icon rendered correctly using resvg.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot_20230812_160935.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/08/screenshot_20230812_160935.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To discuss this blog post head on over to &lt;a href=&#34;https://discuss.kde.org/t/resvg-for-svgs-in-qt&#34;&gt;KDE Discuss&lt;/a&gt;.&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Windows Store Crashes in Sentry</title>
        <link>https://kde.haraldsitter.eu/posts/windows-store-crashes-in-sentry/</link>
        <pubDate>Sat, 05 Aug 2023 08:18:56 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/windows-store-crashes-in-sentry/</guid>
        <description>
          
          &lt;p&gt;At KDE we make software for many different platforms. One of them is Microsoft Windows. But what if an application crashes on Windows? New tech enables us to track crashes right in Sentry! Time to learn about it.&lt;/p&gt;
&lt;p&gt;When an application crashes on Windows the user can submit crash data to Microsoft. Later KDE, as publisher of the app, can retrieve the crashes from there. This is the standard crash handling for the platform and it works incredibly well. What&amp;rsquo;s more, it means we don&amp;rsquo;t need to engineer our own custom solution for the entire process. So, that is all lovely.&lt;/p&gt;
&lt;p&gt;Alas, since we are rolling out a KDE-wide crash tracking system called &lt;a href=&#34;https://sentry.io/welcome/&#34;&gt;Sentry&lt;/a&gt; it would be even nicer if we had Windows crashes in there rather than third party service. That is just what I&amp;rsquo;ve built recently.&lt;/p&gt;
&lt;p&gt;Crashes for our Windows applications now get imported into Sentry!&lt;/p&gt;
&lt;p&gt;There are two pieces to this puzzle. One is a &lt;a href=&#34;https://invent.kde.org/sitter/sentry-symstore/&#34;&gt;symstore&lt;/a&gt; and one is the actual &lt;a href=&#34;https://invent.kde.org/sitter/sentry-windows-import&#34;&gt;importer&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;symbol-storage&#34;&gt;Symbol Storage&lt;/h1&gt;
&lt;p&gt;In the Linux world we not so long ago grew debuginfod, it&amp;rsquo;s basically a tiny service that lays out debug symbols in a standardized file path so it may be consumed by any number of tools by making HTTP GET requests to well-known URIs.&lt;/p&gt;
&lt;p&gt;Windows has something like this called &lt;a href=&#34;https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-storage-format&#34;&gt;symbol storage&lt;/a&gt;. It&amp;rsquo;s incredibly simple and merely lays out Windows debug information in a well defined path setup for consumption in tools.&lt;/p&gt;
&lt;p&gt;To maintain a symstore of our own we use the excellent python module &lt;a href=&#34;https://pypi.org/project/symstore/&#34;&gt;symstore&lt;/a&gt; along with some custom rigging to actually retrieve our debug information files.&lt;/p&gt;
&lt;h1 id=&#34;import&#34;&gt;Import&lt;/h1&gt;
&lt;p&gt;The second piece is our importer. It&amp;rsquo;s a trivial program that uses &lt;a href=&#34;https://learn.microsoft.com/en-us/windows/uwp/monetize/get-error-reporting-data&#34;&gt;Microsoft&amp;rsquo;s APIs&lt;/a&gt; to retrieve crash data along with the minidump (the dump format used by Windows crashes), converts it into a Sentry payload, and sends it off to our Sentry instance. Sentry then consumes the crash, does symbolication using the debug symbols from our symstore, and generates a crash event.&lt;/p&gt;
&lt;h1 id=&#34;support&#34;&gt;Support&lt;/h1&gt;
&lt;p&gt;If you are shipping your application on the Windows Store you should consider publishing your dbg.7z files on &lt;a href=&#34;https://download.kde.org/&#34;&gt;download.kde.org&lt;/a&gt; (for example &lt;a href=&#34;https://download.kde.org/stable/release-service/23.04.3/windows/&#34;&gt;here is Okular&lt;/a&gt;), simply file a sysadmin ticket same as with any other &lt;a href=&#34;https://community.kde.org/ReleasingSoftware#Uploading_the_Tar&#34;&gt;upload&lt;/a&gt; to get this published. Once that is done you can submit a change to our &lt;a href=&#34;https://invent.kde.org/sitter/sentry-symstore/&#34;&gt;symstore&lt;/a&gt; to publish the debug symbols, and our &lt;a href=&#34;https://invent.kde.org/sitter/sentry-windows-import&#34;&gt;importer&lt;/a&gt; to import data into Sentry. If you need help just give me a poke.&lt;/p&gt;
&lt;p&gt;If you are publishing builds for Windows but are not yet on the Window Store, you definitely should change that. It increases your application&amp;rsquo;s reach considerably. Get in touch with &lt;a href=&#34;https://phabricator.kde.org/maniphest/task/edit/form/2/&#34;&gt;sysadmins&lt;/a&gt; to get yourself set up.&lt;/p&gt;
&lt;p&gt;Importing crashes into Sentry adds another piece towards higher quality, more actionable crash reports. It&amp;rsquo;s going to be amazing.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Discuss this blog post on &lt;a href=&#34;https://discuss.kde.org/t/windows-store-crashes-in-sentry&#34;&gt;KDE Discuss&lt;/a&gt;.&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>KDE Discuss Notifications and Mailing List</title>
        <link>https://kde.haraldsitter.eu/posts/kde-discuss-notifications-and-mailing-list/</link>
        <pubDate>Tue, 01 Aug 2023 15:35:41 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/kde-discuss-notifications-and-mailing-list/</guid>
        <description>
          
          &lt;p&gt;Every once in a while I hear developers having trouble staying up to date with &lt;a href=&#34;https://discuss.kde.org&#34;&gt;KDE Discuss&lt;/a&gt;(ions). No great surprise when I then find out they aren&amp;rsquo;t tracking things (in other words: not subscribed to categories)!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://discourse.org/&#34;&gt;Discourse&lt;/a&gt;, the software that powers KDE Discuss, has a number of handy notifications settings that we can use to have the software bring posts to us instead of having to go to the website every once in a while. We can use these options to tailor a good experience for ourselves.&lt;/p&gt;
&lt;p&gt;Three setting types are relevant for the notification experience:&lt;/p&gt;
&lt;h1 id=&#34;tracking&#34;&gt;Tracking&lt;/h1&gt;
&lt;p&gt;Tracking preferences control which discussions to track. Settings here range from when automatic tracking happens - such as when you view a topic for a couple minutes it automatically becomes tracked - to ignoring things. You can track categories as well as tags. Say you only care about &lt;a href=&#34;https://kdenlive.org/&#34;&gt;kdenlive&lt;/a&gt; you can simply track the kdenlive tag and you are good to go.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-29-59-preferences-sitter-discuss.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-29-59-preferences-sitter-discuss.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;emails&#34;&gt;Emails&lt;/h1&gt;
&lt;p&gt;Emails contain the second most relevant pool of preferences. There are two principal modes of operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forum mode&lt;/li&gt;
&lt;li&gt;Mailing list mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The names should be obvious enough, the functionality probably less so.
In forum mode tracking preferences apply and you get emails for posts or threads as configured.
In mailing list mode &lt;strong&gt;only negative tracking preferences&lt;/strong&gt; apply! You get an email for every post on the entire site unless you&amp;rsquo;ve opted to mute something.
In both modes you can simply reply by email to post a reply.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-30-20-emails-preferences-sitter-discuss.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-30-20-emails-preferences-sitter-discuss.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;notifications&#34;&gt;Notifications&lt;/h1&gt;
&lt;p&gt;These preferences have to do with live notifications i.e. if you have a browser open it will throw up a system notification when new posts happen. The settings here aren&amp;rsquo;t terribly interesting unless you always have a browser tab pointing to KDE Discuss. If you do, you can set a time frame for notifications such that you don&amp;rsquo;t get notifications when you are at work-work for example.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-30-33-notifications-preferences-sitter-discuss.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot-2023-07-25-at-12-30-33-notifications-preferences-sitter-discuss.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;recommendations&#34;&gt;Recommendations&lt;/h1&gt;
&lt;p&gt;So, what do I recommend you do?&lt;/p&gt;
&lt;p&gt;First off, if you want to keep things low-volume make sure you have the email preference &lt;em&gt;Activity Summary&lt;/em&gt; enabled. It sends a summary email once a day with tracked topics. You can disable most everything else. You definitely want to set up &lt;em&gt;tracking&lt;/em&gt; for what you want to receive in your summary (unless of course you want to see all threads). e.g. if you only care about dev topics then set the Development category to tracking.&lt;/p&gt;
&lt;p&gt;One step up from the summary is actually the default mode of KDE Discuss. By default if you simply configure tracking as desired you&amp;rsquo;ll get a reasonable mix of notifications and a summary if you haven&amp;rsquo;t been around in a while.&lt;/p&gt;
&lt;p&gt;The most intense setup is to activate mailing list mode. This operates like a mailing list and causes the highest volume of emails. You&amp;rsquo;ll want to set up email filtering to go along with this. I would definitely not recommend this unless you really care about all discussions on the entire site.&lt;/p&gt;
&lt;p&gt;You should also note that you can reply by mail to threads, regardless of whether mailing list mode is enabled. It&amp;rsquo;s amazing!&lt;/p&gt;
&lt;p&gt;And lastly: you can configure most anything, so if you find that you are getting too many emails or too few just head to the preferences and play with some of the options. I&amp;rsquo;m confident everyone is able to find a good mixture that makes the most out of KDE Discuss :)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Discuss this blog post on &lt;a href=&#34;https://discuss.kde.org/t/kde-discuss-notifications-and-mailing-list&#34;&gt;KDE Discuss&lt;/a&gt;.&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Writing Selenium/Appium Tests on Windows</title>
        <link>https://kde.haraldsitter.eu/posts/writing-selenium-appium-tests-on-windows/</link>
        <pubDate>Mon, 24 Jul 2023 12:03:13 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/writing-selenium-appium-tests-on-windows/</guid>
        <description>
          
          &lt;p&gt;&lt;a href=&#34;https://akademy.kde.org&#34;&gt;Akademy&lt;/a&gt;, KDE&amp;rsquo;s annual conference, recently took place in Thessaloniki, Greece. Lots of people were super excited about the prospect of getting GUI Testing off the ground based on the Selenium tech I &lt;a href=&#34;https://apachelog.wordpress.com/2022/12/14/selenium-at-spi-gui-testing/&#34;&gt;built last year.&lt;/a&gt; Since KDE produces cross-platform applications an obvious question arose though&amp;hellip;&lt;/p&gt;
&lt;p&gt;What about Windows?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s surprisingly easy! Indeed the most time consuming part is probably getting your hands on a &lt;a href=&#34;https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/&#34;&gt;Windows Development Virtual Machine&lt;/a&gt;. Once you have a Windows installation we need to only spin up our toolchain and off we go. Here&amp;rsquo;s a handy command list:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;\# Download and install WinAppDriver: https://github.com/microsoft/WinAppDriver/releases

winget install openjs.nodejs
winget install python.python.3.11

npm install --location=global appium
# restart terminal to apply PATH change
set-executionpolicy -scope currentuser remotesigned # allow script execution
appium driver install --source=npm appium-windows-driver

pip install appium-python-client
appium # start server, needs firewall exception on first start
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before we go further into the nitty gritty of testing on Windows I suggest you read the earlier blog post &lt;a href=&#34;https://apachelog.wordpress.com/2022/12/14/selenium-at-spi-gui-testing/&#34;&gt;Selenium + AT-SPI = GUI Testing&lt;/a&gt;, since a lot of the concepts are the same regardless of platform.&lt;/p&gt;
&lt;p&gt;First let us get our ducks in a row.&lt;/p&gt;
&lt;p&gt;What Accerciser is to Linux is inspect.exe to Windows, namely an inspector tool for applications. You can find it in your Windows SDK folder &lt;code&gt;%ProgramFiles(x86)%\Windows Kits\10\bin\10.0.22000.0\x64\inspect.exe&lt;/code&gt; or there abouts. Opening it greets you with this beauty:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_014038.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_014038.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ignoring the verbosity for a moment we&amp;rsquo;ll note that it contains similar information to Accerciser on Linux, albeit in a more flat overview. Most importantly what is called the &lt;code&gt;AutomationId&lt;/code&gt; is constructed from QObject objectNames, similar to the Accessible IDs on Linux. This is insofar interesting as it means we have a couple of avenues for cross-platform element locating - specifically we could match elements by their name (e.g. the text of a Label or Button), or more uniquely by their objectName-based ID (applicable to all QObjects).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_015004.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_015004.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the purposes of this post we&amp;rsquo;ll do some trivial testing on &lt;a href=&#34;https://apps.kde.org/filelight&#34;&gt;Filelight&lt;/a&gt; and try to make it work for both Linux and Windows by using the element names. Relying on objectNames is more reliable but unfortunately requires some retrofitting in the source code. To avoid having to &lt;a href=&#34;https://community.kde.org/Get_Involved/development/Windows&#34;&gt;build Filelight on Windows&lt;/a&gt; we&amp;rsquo;ll work with what we have got: names. Let&amp;rsquo;s write our test. Don&amp;rsquo;t forget to install &lt;a href=&#34;https://apps.microsoft.com/store/detail/filelight/9PFXCD722M2C&#34;&gt;Filelight&lt;/a&gt; first :)&lt;/p&gt;
&lt;p&gt;First thing, as always, is our setup boilerplate&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/env python3

# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2023 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

import unittest
import sys
from appium import webdriver
from appium.options.windows import WindowsOptions
from appium.options.common import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected\_conditions as EC

class SimpleFilelightTests(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        options = WindowsOptions()
        options.app(&amp;#39;KDEe.V.Filelight\_7vt06qxq7ptv8!KDEe.V.Filelight&amp;#39;)
        self.driver = webdriver.Remote(
            command\_executor=&amp;#39;http://127.0.0.1:4723&amp;#39;,
            options=options)

    @classmethod
    def tearDownClass(self):
        self.driver.quit()

if \_\_name\_\_ == &amp;#39;\_\_main\_\_&amp;#39;:
    unittest.main()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The only really interesting bit here is how we specify the application on Windows. Since Filelight is a store application we can start it by the &lt;a href=&#34;https://learn.microsoft.com/en-us/windows/configuration/find-the-application-user-model-id-of-an-installed-app&#34;&gt;Application User Model ID (AUMID)&lt;/a&gt; instead of a path; this is pretty much the same as starting by-desktop-file-id on Linux.&lt;/p&gt;
&lt;p&gt;Now then. With the boilerplate out of the way we can write an incredibly simple test that simply switches pages a bit: If we click on &amp;lsquo;Scan Home Folder&amp;rsquo; it should take us to the scan page and clicking there on &amp;lsquo;Go to Overview&amp;rsquo; should take us back to the overview page.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_122623.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_122623.png?w=1023&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_122737.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/07/screenshot_20230724_122737.png?w=1023&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    def test\_scan(self):
        self.driver.find\_element(by=AppiumBy.NAME, value=&amp;#34;Scan Home Folder&amp;#34;).click()
        overview = WebDriverWait(self.driver, 120).until(
            EC.element\_to\_be\_clickable((AppiumBy.NAME, &amp;#34;Go to Overview&amp;#34;))
        )
        overview.click()
        WebDriverWait(self.driver, 4).until(
            EC.element\_to\_be\_clickable((AppiumBy.NAME, &amp;#34;Scan Home Folder&amp;#34;))
        )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool. We now can test Filelight on Windows. Next we should try to make this test also work for Linux. Thankfully we only need to switch out our app name for a desktop file id.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    def setUpClass(self):
        if sys.platform == &amp;#39;nt&amp;#39;:
            options = WindowsOptions()
            options.app = &amp;#39;KDEe.V.Filelight\_7vt06qxq7ptv8!KDEe.V.Filelight&amp;#39;
        else:
            options = AppiumOptions()
            options.set\_capability(&amp;#39;app&amp;#39;, &amp;#39;org.kde.filelight.desktop&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Putting it all together we get our final test which runs on both Linux and Windows.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;\# Windows
# start appium in a terminal
python .\\test.py
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;# Linux
selenium-webdriver-at-spi-run ./test.py&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;
The complete test code:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;#!/usr/bin/env python3&lt;/p&gt;
&lt;h1 id=&#34;spdx-license-identifier-mit&#34;&gt;SPDX-License-Identifier: MIT&lt;/h1&gt;
&lt;h1 id=&#34;spdx-filecopyrighttext-2023-harald-sitter&#34;&gt;SPDX-FileCopyrightText: 2023 Harald Sitter &lt;a href=&#34;mailto:sitter@kde.org&#34;&gt;sitter@kde.org&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;import unittest
import sys
from appium import webdriver
from appium.options.windows import WindowsOptions
from appium.options.common import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC&lt;/p&gt;
&lt;p&gt;class SimpleCalculatorTests(unittest.TestCase):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@classmethod
def setUpClass(self):
    if sys.platform == &#39;nt&#39;:
        options = WindowsOptions()
        options.app = &#39;KDEe.V.Filelight\_7vt06qxq7ptv8!KDEe.V.Filelight&#39;
    else:
        options = AppiumOptions()
        options.set\_capability(&#39;app&#39;, &#39;org.kde.filelight.desktop&#39;)

    self.driver = webdriver.Remote(
        command\_executor=&#39;http://127.0.0.1:4723&#39;,
        options=options)

@classmethod
def tearDownClass(self):
    self.driver.quit()

def test\_scan(self):
    self.driver.find\_element(by=AppiumBy.NAME, value=&amp;quot;Scan Home Folder&amp;quot;).click()
    overview = WebDriverWait(self.driver, 120).until(
        EC.element\_to\_be\_clickable((AppiumBy.NAME, &amp;quot;Go to Overview&amp;quot;))
    )
    overview.click()
    WebDriverWait(self.driver, 4).until(
        EC.element\_to\_be\_clickable((AppiumBy.NAME, &amp;quot;Scan Home Folder&amp;quot;))
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if __name__ == &amp;lsquo;__main__&amp;rsquo;:
unittest.main()&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;
Discuss this blog post on [KDE Discuss](https://discuss.kde.org/t/writing-selenium-appium-tests-on-windows/3145).
&lt;/code&gt;&lt;/pre&gt;
        </description>
      </item>
    
      <item>
        <title>Firefox and KeePassXC Flatpaks</title>
        <link>https://kde.haraldsitter.eu/posts/firefox-and-keepassxc-flatpaks/</link>
        <pubDate>Fri, 07 Apr 2023 12:12:13 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/firefox-and-keepassxc-flatpaks/</guid>
        <description>
          
          &lt;p&gt;&lt;a href=&#34;https://flatpak.org/&#34;&gt;Flatpaks&lt;/a&gt; are amazing and all that. But application sandboxing, so an application cannot do anything it wants, is a challenge - even more so when you have two applications that need to talk to each other. Perhaps it shouldn&amp;rsquo;t come as a surprise that &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging&#34;&gt;native-messaging&lt;/a&gt; sandboxing &lt;a href=&#34;https://github.com/flatpak/xdg-desktop-portal/pull/705&#34;&gt;support&lt;/a&gt; for Flatpak has been in development for over a year. To celebrate its anniversary I thought I&amp;rsquo;d write down how to drill a native-messaging sized hole into the sandbox. This enables the use of native messaging even without portal integration, albeit also without sane degrees of sandboxing.&lt;/p&gt;
&lt;p&gt;First off, please understand that this undermines the sandbox on a fairly fundamental level. So, don&amp;rsquo;t do this if you don&amp;rsquo;t keep your Firefox updated or visit particularly dodgy websites.&lt;/p&gt;
&lt;p&gt;For the purposes of this post I&amp;rsquo;m assuming Firefox and KeePassXC are installed as Flatpaks in user scope.&lt;/p&gt;
&lt;p&gt;First order of business is setting up KeePassXC so it writes its definition file in a place where Firefox can read it. Fortunately it has a setting for this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2023/04/screenshot_20230407_125835-1.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2023/04/screenshot_20230407_125835-1.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts/&lt;/code&gt; is the path inside Firefox&amp;rsquo; home where the defintion file will be written. Naturally we&amp;rsquo;ll also need to adjust the Flatpak permissions so KeePassXC can write to this path.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;flatpak override --user --filesystem=~/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts org.keepassxc.KeePassXC&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;At this point Firefox knows about the native messaging host but it won&amp;rsquo;t be able to run it. Alas. We need some rigging here. The problem is that Firefox can&amp;rsquo;t simply &lt;code&gt;flatpak run&lt;/code&gt; the native messaging host, it needs to spawn a host process (i.e. a process outside its sandbox) to then run the KeePassXC Flatpak and that then runs the NMH.&lt;/p&gt;
&lt;p&gt;Fortunately the NMH definition files are fairly straight forward:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{&amp;#34;allowed_extensions&amp;#34;:[&amp;#34;keepassxc-browser@keepassxc.org&amp;#34;],
&amp;#34;description&amp;#34;:&amp;#34;KeePassXC integration with native messaging support&amp;#34;,
&amp;#34;name&amp;#34;:&amp;#34;org.keepassxc.keepassxc_browser&amp;#34;,
&amp;#34;path&amp;#34;:&amp;#34;/home/me/.local/share/flatpak/exports/bin/org.keepassxc.KeePassXC&amp;#34;,
&amp;#34;type&amp;#34;:&amp;#34;stdio&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The problem of course is that we cannot directly use that Flatpak bin but need the extra spawn step in between. What we need is a way to manipulate the definition file such that we can switch in a different path. systemd to the rescue!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;systemctl edit --user --full --force keepassxc-native-messaging-mangler.path&lt;/code&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2023 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

[Path]
PathChanged=/home/me/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json

[Install]
WantedBy=default.target
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and the associated service file&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;systemctl edit --user --full --force keepassxc-native-messaging-mangler.service&lt;/code&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2023 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

[Unit]
Description=keepassxc mangler

[Service]
ExecStart=/home/me/keepassxc-native-messaging-mangler
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;lastly, enable the path unit.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;systemctl --user enable --now keepassxc-native-messaging-mangler.path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Alright, there&amp;rsquo;s some stuff to unpack here. KeePassXC on startup writes the aforementioned definition file into Firefox&amp;rsquo; NMH path. What we do with the help of systemd is monitor the file for changes and whenever it changes we&amp;rsquo;ll trigger our service, the service runs a mangler to modify the file so we can run another command instead. It&amp;rsquo;s basically an inotify watch.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the mangler (&lt;code&gt;~/keepassxc-native-messaging-mangler&lt;/code&gt;):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/env ruby
# frozen_string_literal: true

# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2023 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

require &amp;#39;json&amp;#39;

file = &amp;#34;#{Dir.home}/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts/org.keepassxc.keepassxc_browser.json&amp;#34;
blob = JSON.parse(File.read(file))
blob[&amp;#39;path&amp;#39;] = &amp;#34;#{Dir.home}/Downloads/keepassxc&amp;#34;
File.write(file, JSON.generate(blob))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It simply replaces the path of the executable with a wrapper script. Here&amp;rsquo;s the wrapper script (&lt;code&gt;~/Downloads/keepassxc&lt;/code&gt;):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/bin/sh

# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2023 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

exec /usr/bin/flatpak-spawn --host --watch-bus &amp;#34;$HOME/.local/share/flatpak/exports/bin/org.keepassxc.KeePassXC&amp;#34; &amp;#34;$@&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;flatpak-spawn is a special command that allows us to spawn processes outside the sandbox. To gain access we&amp;rsquo;ll have to allow Firefox to talk with the &lt;code&gt;org.freedesktop.Flatpak&lt;/code&gt; DBus session service.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;flatpak override --user --talk-name=org.freedesktop.Flatpak org.mozilla.firefox&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;➡️ KeePassXC writes its NMH definition to Flatpak specific path
➡️ systemd acts on changes and starts mangler
➡️ mangler changes the path inside the definition to our wrapper
➡️ Firefox reads the definition and calls our wrapper
➡️ wrapper flatpak-spawns KeePassXC flatpak
➡️ Firefox (flatpak) talks to KeePassXC (flatpak)&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Selenium &#43; AT-SPI = GUI Testing</title>
        <link>https://kde.haraldsitter.eu/posts/selenium-at-spi-gui-testing/</link>
        <pubDate>Wed, 14 Dec 2022 15:59:20 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/selenium-at-spi-gui-testing/</guid>
        <description>
          
          &lt;p&gt;At &lt;a href=&#34;https://kde.org/&#34;&gt;KDE&lt;/a&gt; we have multiple levels of quality assurance ranging from various degrees of a humans testing features to fully automated testing. Indeed automated testing is incredibly important for the continued quality of our software. A big corner stone of our testing strategy are so called unit tests, they test a specific piece of our software for its behavior in isolation. But for many aspects of our software we need a much higher level view, testing pieces of Plasma&amp;rsquo;s application launcher in isolation is all good and well but that won&amp;rsquo;t tell us if the entire UI can be easily navigated using the keyboard. For this type of test we require a different testing approach altogether. A couple months ago I&amp;rsquo;ve set &lt;a href=&#34;https://markmail.org/message/toklo6unkc3bmuww&#34;&gt;set out&lt;/a&gt; to create a &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi&#34;&gt;testing framework&lt;/a&gt; for this use case and I&amp;rsquo;m glad to say that it has matured enough to be used for writing tests. I&amp;rsquo;d like to walk you through the technical building blocks and a simple example.&lt;/p&gt;
&lt;p&gt;Let us start of by looking at the architecture at large. So&amp;hellip; there&amp;rsquo;s &lt;a href=&#34;https://www.selenium.dev/&#34;&gt;Selenium&lt;/a&gt; which is an incredibly popular, albeit web-oriented, testing framework. Its main advantages for us are its popularity and that it sports a server-client split. This means we can leverage the existing client tooling available for Selenium without having to write anything ourselves, we only need to grow a server. The server component, called a &lt;a href=&#34;https://www.w3.org/TR/webdriver/&#34;&gt;WebDriver&lt;/a&gt;, implements the actual interaction with UI elements and is generic enough to also apply to desktop applications. Indeed so thought others as well: there already exists &lt;a href=&#34;https://appium.io&#34;&gt;Appium&lt;/a&gt; - it extends Selenium with more app-specific features and behaviors. Something for us to build upon. The clients meanwhile are completely separate and talk to the WebDriver over a well defined JSON REST protocol, meaning we can reuse the existing clients without having to write anything ourselves. They are available in a multitude of programming languages, and who knows maybe we&amp;rsquo;ll eventually get one for writing Selenium tests in QML ;)&lt;/p&gt;
&lt;p&gt;That of course doesn&amp;rsquo;t explain how GUI testing can work with this on Linux. Enter: &lt;a href=&#34;https://www.freedesktop.org/wiki/Accessibility/AT-SPI2/&#34;&gt;AT-SPI&lt;/a&gt;. AT-SPI is an accessibility API and pretty much the standard accessibility system for use on Linux. Obviously its primary use is assistive technologies, like the screen reader &lt;a href=&#34;https://wiki.gnome.org/Projects/Orca&#34;&gt;Orca&lt;/a&gt;, but to do its job it essentially offers a toolkit-independent way of introspecting and interacting with GUI applications. This then gives us a way to implement a WebDriver without caring about the toolkit or app specifics. As long as the app supports AT-SPI, which all Qt apps do implicitly, we can test it.&lt;/p&gt;
&lt;p&gt;Since all the client tooling is independent of the server all we needed to get GUI testing going was a WebDriver that talks to AT-SPI.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/12/selenium.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/12/selenium.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That is what I set out to write and I&amp;rsquo;m happy to announce that we now have an &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi&#34;&gt;AT-SPI based WebDriver&lt;/a&gt;, and the &lt;a href=&#34;https://invent.kde.org/plasma/kdeplasma-addons/-/merge_requests/291&#34;&gt;first&lt;/a&gt; tests are popping into existence already. There is also lovely &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi/-/wikis/writing-tests&#34;&gt;documentation&lt;/a&gt; to hold onto.&lt;/p&gt;
&lt;p&gt;So, without further ado. Let us write a simple test. Since the &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi/-/wikis/writing-tests&#34;&gt;documentation&lt;/a&gt; already writes one in Python I&amp;rsquo;ll use Ruby this time around so we have some examples of different languages. A simple candidate is KInfoCenter. We can test its search functionality with a couple of lines of code.&lt;/p&gt;
&lt;p&gt;First we need to install &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi&#34;&gt;selenium-webdriver-at-spi&lt;/a&gt;, clone it, cmake build it, and cmake install it. You&amp;rsquo;ll also need to install the relevant client libraries. For ruby that&amp;rsquo;s simply running &lt;code&gt;gem install appium_lib&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we can start with writing our test. We will need some boilerplate setup logic. This is more or less the same for every test. For more details on the driver setup you may also check the &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi/-/wikis/writing-tests&#34;&gt;wiki page.&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  def setup
    @appium\_driver = Appium::Driver.new(
      {
        &amp;#39;caps&amp;#39; =&amp;gt; { app: &amp;#39;org.kde.kinfocenter.desktop&amp;#39; },
        &amp;#39;appium\_lib&amp;#39; =&amp;gt; {
          server\_url: &amp;#39;http://127.0.0.1:4723&amp;#39;,
          wait\_timeout: 10,
          wait\_interval: 0.5
        }
      }, true
    )
    @driver = @appium\_driver.start\_driver
  end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The driver will take care of starting the correct application and make sure that it is actually running correctly. Next we&amp;rsquo;ll write the actual test. Let&amp;rsquo;s test the search. The first order of business is using a tool called &lt;a href=&#34;https://gitlab.gnome.org/GNOME/accerciser&#34;&gt;Accerciser&lt;/a&gt; to inspect the AT-SPI presentation of the application. For more information on how to use this tool please refer to the wiki. Using Accerciser I&amp;rsquo;ve located the search field and learned that it is called &amp;lsquo;Search&amp;rsquo;. So, let&amp;rsquo;s locate it and activate it, search for the CPU module:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  def test\_search
    search = driver.find\_element(:name, &amp;#39;Search&amp;#39;)
    search.click
    search.send\_keys(&amp;#39;cpu&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next let us find the CPU list item and activate it:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    cpu = driver.find\_element(:class\_name, &amp;#39;\[list item | CPU\]&amp;#39;)
    assert(cpu.displayed?)
    cpu.click
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And finally let&amp;rsquo;s assert that the page was actually activated:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    cpu\_tab = driver.find\_element(:class\_name, &amp;#39;\[page tab | CPU\]&amp;#39;)
    assert(cpu\_tab.displayed?)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run the complete test we can use the run wrapper: &lt;code&gt;selenium-webdriver-at-spi-run ./kinfocentertest.rb&lt;/code&gt; (mind that it needs to be +x). If all has gone well we should get a successful test.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Finished in 1.345276s, 0.7433 runs/s, 1.4867 assertions/s.

1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
I, \[2022-12-14T13:13:53.508516 #154338\]  INFO -- : tests done
I, \[2022-12-14T13:13:53.508583 #154338\]  INFO -- : run.rb exiting true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This should get you started with writing a test for &lt;strong&gt;your&lt;/strong&gt; application! I&amp;rsquo;ll gladly help and review your forthcoming tests.
For more detailed documentation check out the &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi/-/wikis/writing-tests&#34;&gt;writing-tests&lt;/a&gt; wiki page as well as the &lt;a href=&#34;https://appium.io/docs/en/about-appium/intro/&#34;&gt;appium command reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course the work is not done. &lt;code&gt;selenium-webdriver-at-sp&lt;/code&gt;i is very much still a work in progress and I&amp;rsquo;d be glad for others to help add features as they become needed. The &lt;a href=&#34;https://invent.kde.org/sdk/selenium-webdriver-at-spi&#34;&gt;gitlab project&lt;/a&gt; is the place for that. &amp;lt;3&lt;/p&gt;
&lt;p&gt;The complete code of the example above:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/env ruby
# frozen\_string\_literal: true

# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2022 Harald Sitter &amp;lt;sitter@kde.org&amp;gt;

require &amp;#39;appium\_lib&amp;#39;
require &amp;#39;minitest/autorun&amp;#39;

class TestKInfoCenter &amp;lt; Minitest::Test
  attr\_reader :driver

  def setup
    @appium\_driver = Appium::Driver.new(
      {
        &amp;#39;caps&amp;#39; =&amp;gt; { app: &amp;#39;org.kde.kinfocenter.desktop&amp;#39; },
        &amp;#39;appium\_lib&amp;#39; =&amp;gt; {
          server\_url: &amp;#39;http://127.0.0.1:4723&amp;#39;,
          wait\_timeout: 10,
          wait\_interval: 0.5
        }
      }, true
    )
    @driver = @appium\_driver.start\_driver
  end

  def teardown
    driver.quit
  end

  def test\_search
    search = driver.find\_element(:name, &amp;#39;Search&amp;#39;)
    search.click
    search.send\_keys(&amp;#39;cpu&amp;#39;)

    cpu = driver.find\_element(:class\_name, &amp;#39;\[list item | CPU\]&amp;#39;)
    assert(cpu.displayed?)
    cpu.click

    cpu\_tab = driver.find\_element(:class\_name, &amp;#39;\[page tab | CPU\]&amp;#39;)
    assert(cpu\_tab.displayed?)
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/12/kinfocenter-test.gif&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/12/kinfocenter-test.gif?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Plasma Analyzer</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-analyzer/</link>
        <pubDate>Mon, 12 Dec 2022 15:26:00 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-analyzer/</guid>
        <description>
          
          &lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/12/analyzer-1.gif&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/12/analyzer-1.gif?w=720&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a Plasma widget that visualizes what&amp;rsquo;s going on on your system, music-wise that is. I&amp;rsquo;ve started this project years ago but only recently found the motivation to get it to a somewhat acceptable state. It&amp;rsquo;s pretty amazing to have bars flying across the screen to Daft Punk&amp;rsquo;s `Touch`.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://store.kde.org/p/1953779&#34;&gt;https://store.kde.org/p/1953779&lt;/a&gt;&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>KDE Crash Tracking System 💣</title>
        <link>https://kde.haraldsitter.eu/posts/kde-crash-tracking-system-/</link>
        <pubDate>Thu, 13 Oct 2022 10:31:32 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/kde-crash-tracking-system-/</guid>
        <description>
          
          &lt;p&gt;&lt;a href=&#34;https://kde.org&#34;&gt;KDE&lt;/a&gt; is now evaluating &lt;a href=&#34;https://sentry.io&#34;&gt;Sentry&lt;/a&gt;, a crash tracking system.&lt;/p&gt;
&lt;p&gt;Who can get access? Everyone with a KDE developer account.&lt;/p&gt;
&lt;p&gt;But what is it?&lt;/p&gt;
&lt;p&gt;Since forever we have used &lt;a href=&#34;http://bugs.kde.org&#34;&gt;Bugzilla&lt;/a&gt; to manage crash reports but this has numerous challenges that haven&amp;rsquo;t made any improvements in at least 10 years:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finding duplicates crashes is hard and in our case involves a human finding them&lt;/li&gt;
&lt;li&gt;When debug symbols are missing we need to ask the user to recreate the problem, which is not always possible&lt;/li&gt;
&lt;li&gt;Users need to worry about debug symbols (this is in part improved by the rise of debuginfod - yay!)&lt;/li&gt;
&lt;li&gt;We have no easily consumed graphs on how prevalent a specific crash is, and by extension we have a hard time judging the importance&lt;/li&gt;
&lt;li&gt;The user needs to actually write a report for us to learn of the crash (spoiler: most crashes never get this far)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all it&amp;rsquo;s a fairly dissatisfactory situation we are in currently. &lt;strong&gt;Enter &lt;a href=&#34;https://errors-eval.kde.org&#34;&gt;Sentry&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sentry is a purpose-built crash tracking system. It receives crash reports via API ingestion points and traces missing frames with the help of &lt;a href=&#34;https://sourceware.org/elfutils/Debuginfod.html&#34;&gt;debuginfod&lt;/a&gt;, can detect duplicates automatically and thus show us particularly aggressive crashes, and much more. Best yet, it supports many different programming languages which allows us to not only improve the quality of our software but also our infrastructure services.&lt;/p&gt;
&lt;p&gt;The current evaluation instance is already amazing and helped fix numerous problems, and the current setup is not even using all features yet and we have hampered rollout a bit: only git builds currently submit data. If all goes well and we find it to be amazing I hope we&amp;rsquo;ll eventually be able to roll this out to production releases.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at a crash I&amp;rsquo;ve fixed recently.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what Sentry received from the user:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115227.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115227.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Not terribly useful. So with the power of debuginfod it turned it into this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115418.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115418.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I then applied some brain power to create a fix and consequently the crash has disappeared, as we can see in this neat graphic here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115742.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot_20221013_115742.png?w=846&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a complete crash information page from a recent infrastructure problem in our bugzilla bot:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot-2022-10-13-at-12-01-20-nameerror-uninitialized-constant-runner-versions-oldest_supported-kde-bugzilla-bot.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/10/screenshot-2022-10-13-at-12-01-20-nameerror-uninitialized-constant-runner-versions-oldest_supported-kde-bugzilla-bot.png?w=561&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Also check out my &lt;a href=&#34;http://akademy.kde.org&#34;&gt;Akademy&lt;/a&gt; talk:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/A3LzemYMsIQ?t=15126&#34;&gt;https://youtu.be/A3LzemYMsIQ?t=15126&lt;/a&gt;&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>KIO Admin</title>
        <link>https://kde.haraldsitter.eu/posts/kio-admin/</link>
        <pubDate>Thu, 04 Aug 2022 19:57:58 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/kio-admin/</guid>
        <description>
          
          &lt;p&gt;I&amp;rsquo;ve gotten annoyed with the inability to manage system files so I&amp;rsquo;ve made a KIO worker that enables Dolphin to view and edit files as root.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/08/screenshot_20220804_212547-1.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/08/screenshot_20220804_212547-1.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is dolphin viewing the system root with administrative access.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The way this works is actually fairly exciting. It&amp;rsquo;s pulling off worker chaining: The admin worker itself contains gloriously little logic, all it does is translate all worker calls to dbus calls, and those dbus calls go out to a privileged polkit helper. The polkit helper then translates the URIs from admin:///foo to file:///foo and uses the regular KIO API to recreate the request in root-scope. KIO then, behind the scenes, acts just like it would in dolphin proper, using the &lt;strong&gt;existing&lt;/strong&gt; file worker code to execute the file operations.&lt;/p&gt;
&lt;p&gt;The advantages are amazing! It&amp;rsquo;s fairly little actual code (albeit a lot of boilerplate). Since it&amp;rsquo;s an ordinary worker on the Dolphin side we can expect all file operations to just work™ because really admin:// is just like trash:// or desktop://. Because ultimately the file worker is actually in charge of doing the work, all things are generally expected to work (it&amp;rsquo;s the same code that powers regular file operations).&lt;/p&gt;
&lt;p&gt;Disadvantageously it&amp;rsquo;s a fair large portal into root-scope, meaning the worker should really only be used in trusted environments (e.g. with only sandboxed applications on the system ;)). Even with polkit guarding the entrance, once you have given permissions you have to trust the application (e.g. dolphin) to not get exploited.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;But why a dedicated worker instead of integrated polkit support in the file worker?&amp;rdquo; Why, I&amp;rsquo;m glad you asked! Integrated polkit support sounds simple but is really rocket science. For example there is currently no good architectural way to &amp;ldquo;catch&amp;rdquo; operations that had gone wrong - you try to copy a file to `/srv` and that fails with 🤖PERMISSION DENIED🤖 but there is no consistent way to then go &amp;ldquo;well, let&amp;rsquo;s retry this entire operation with privileges then&amp;rdquo; so without huge code refactoring first, we&amp;rsquo;d end up tucking fallback logic onto every which error scenario&amp;hellip; it&amp;rsquo;s messy and also easy to miss or mess up edge cases. There are also user experience problems. You&amp;rsquo;d not want to have every internal operation require dedicated permission, so you kind of have to bundle them up and then request permission for the bundle; but how do you know when a bundle is complete? It&amp;rsquo;s really frightfully complicated.&lt;/p&gt;
&lt;p&gt;In conclusion admin:// is awesome today. Maybe one day integrated polkit will also be awesome.&lt;/p&gt;
&lt;p&gt;Reviews and testing appreciated &lt;a href=&#34;https://invent.kde.org/sitter/kio-admin&#34;&gt;https://invent.kde.org/sitter/kio-admin&lt;/a&gt; (mind the readme - this currently wants some patching elsewhere in the stack).&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>DrKonqi ❤️ coredumpd</title>
        <link>https://kde.haraldsitter.eu/posts/drkonqi-%EF%B8%8F-coredumpd/</link>
        <pubDate>Wed, 25 May 2022 19:59:05 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/drkonqi-%EF%B8%8F-coredumpd/</guid>
        <description>
          
          &lt;p&gt;Get some popcorn and strap in for a long one! I shall delight you with some insights into crash handling and all that unicorn sparkle material.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Since Plasma 5.24 DrKonqi, Plasma&amp;rsquo;s infamous crash reporter, has gained support to route crashes through coredumpd and it is amazing - albeit a bit unused. That is why I&amp;rsquo;m telling you about it now because it&amp;rsquo;s matured a bit and is even more amazing - albeit still unused, I hope that will change.&lt;/p&gt;
&lt;p&gt;To explain what any of this does I have to explain some basics first, so we are on the same page&amp;hellip;&lt;/p&gt;
&lt;p&gt;Most applications made by KDE will generally rely on &lt;a href=&#34;https://api.kde.org/frameworks/kcrash&#34;&gt;KCrash&lt;/a&gt;, a KDE framework that implements crash handling, to, well, handle crashes. The way this works depends a bit on the operating system but one way or another when an application encounters a fault it first stops to think for a moment, about the meaning of life and whatever else, we call that &amp;ldquo;catching the crash&amp;rdquo;, during that time frame we can apply further diagnostics to help later figure out what went wrong. On POSIX systems specifically, we generate a &lt;a href=&#34;https://en.wikipedia.org/wiki/Stack_trace&#34;&gt;backtrace&lt;/a&gt; and send that off to our &lt;a href=&#34;https://bugs.kde.org&#34;&gt;bugzilla&lt;/a&gt; for handling by a developer - that is in essence the job of DrKonqi.&lt;/p&gt;
&lt;p&gt;Currently DrKonqi operates in a mode of operation generally dubbed &amp;ldquo;just-in-time debugging&amp;rdquo;. When a crash occurs: KCrash immediately starts DrKonqi, DrKonqi attaches &lt;a href=&#34;https://www.sourceware.org/gdb/&#34;&gt;GDB&lt;/a&gt; to the still running process, GDB creates a backtrace, and then DrKonqi sends the trace along with metadata to bugzilla.&lt;/p&gt;
&lt;p&gt;Just-in-time debugging is often useful on developer machines because you can easily switch to interactive debugging and also have a more complete picture of the environmental system state. For user systems it is a bit awkward though. You may not have time to deal with the report right now, you may have no internet connection, indeed the crash may be impossible to trace because of technical complications occurring during just-in-time debugging because of how POSIX signals work (threads continue running :O), etc.&lt;/p&gt;
&lt;p&gt;In short: just-in-time really shouldn&amp;rsquo;t be the default.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd-coredump.html&#34;&gt;coredumpd&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Coredumpd is part of systemd and acts as kernel core handler. Ah, that&amp;rsquo;s a mouthful again. Let&amp;rsquo;s backtrace (pun intended)&amp;hellip; earlier when I was talking about KCrash I only told part of the story. When fault occurs it doesn&amp;rsquo;t necessarily mean that the application has to crash, it could also neatly exit. It is only when the application takes no further action to alleviate the problem that the Linux kernel will jump in and do some rudimentary crash handling, forcefully. Very rudimentary indeed, it simply takes the memory state of the process and dumps it into a file. This is then aptly called a &lt;a href=&#34;https://en.wikipedia.org/wiki/Core_dump&#34;&gt;core dump&lt;/a&gt;. It&amp;rsquo;s kind of like a snapshot of the state of the process when the fault occurred and allows for debugging after the fact. Now things get interesting, don&amp;rsquo;t they? :)&lt;/p&gt;
&lt;p&gt;So&amp;hellip; KCrash can simply do nothing and let the Linux kernel do the work, and the Linux kernel can also be lazy and delegate the work to a so called core handler, an application that handles the core dumping. Well, here we are. That core handler can be coredumpd, making it the effective crash handler.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s the point you ask? &amp;ndash; We get to be lazy!&lt;/p&gt;
&lt;p&gt;Also, core dumping has one huge advantage that also is its disadvantage (depending on how you look at it): when a core dumps, the process is no longer running. When backtracing a core dump you are looking at a snapshot of the past, not a still running process. That means you can deal with crashes now or in 5 minutes or in 10 hours. So long as the core dump is available on disk you can trace the cause of the crash. This is further improved by coredumpd also storing a whole lot of metadata in journald. All put together it allows us to run drkonqi after-the-fact, instead of just-in-time. Amazing! I&amp;rsquo;m sure you will agree.&lt;/p&gt;
&lt;p&gt;For the user everything looks the same, but under the hood we&amp;rsquo;ve gotten rid of various race conditions and gotten crash persistence across reboots for free!&lt;/p&gt;
&lt;p&gt;Among other things this gives us the ability to look at past crashes. A GUI for which will be included in Plasma 5.25. Future plans also include the ability to file bug reports long after the fact.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/05/screenshot_20220525_215035.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/05/screenshot_20220525_215035.png?w=1024&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;inner-workings&#34;&gt;Inner Workings&lt;/h1&gt;
&lt;p&gt;The way this works behind the scenes is somewhat complicated but should be easy enough to follow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The application produces a fault&lt;/li&gt;
&lt;li&gt;KCrash writes KCrash-specific metadata into a file on disk and doesn&amp;rsquo;t exit&lt;/li&gt;
&lt;li&gt;The kernel issues a core dump via coredumpd&lt;/li&gt;
&lt;li&gt;The systemd unit coredump@ starts&lt;/li&gt;
&lt;li&gt;At the same time drkonqi-coredump-processor@ starts&lt;/li&gt;
&lt;li&gt;The processor@ waits for coredump@ to finishes its task of dumping the core&lt;/li&gt;
&lt;li&gt;The processor@ starts drkonqi-coredump-launcher@ in user scope&lt;/li&gt;
&lt;li&gt;launcher@ starts DrKonqi with the same arguments as though it had been started just-in-time&lt;/li&gt;
&lt;li&gt;DrKonqi assembles all the data to produce a crash report&lt;/li&gt;
&lt;li&gt;the user is greeted by a crash notification just like just-in-time debugging&lt;/li&gt;
&lt;li&gt;the entire crash reporting procedure is the same&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;use-it&#34;&gt;Use It!&lt;/h1&gt;
&lt;p&gt;If you are using &lt;a href=&#34;https://neon.kde.org/&#34;&gt;KDE neon unstable edition&lt;/a&gt; you are already using coredumpd based crash reporting for months! You haven&amp;rsquo;t even noticed, have you? ;)&lt;/p&gt;
&lt;p&gt;If not, here&amp;rsquo;s your chance to join the after-the-fact club of cool kids.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;KCRASH_DUMP_ONLY=1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;in your `/etc/environment` and make sure your distribution has enabled the relevant systemd units &lt;a href=&#34;https://invent.kde.org/plasma/drkonqi/-/blob/master/README.md&#34;&gt;accordingly&lt;/a&gt;.&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>kde-inotify-survey</title>
        <link>https://kde.haraldsitter.eu/posts/kde-inotify-survey/</link>
        <pubDate>Thu, 05 May 2022 11:27:09 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/kde-inotify-survey/</guid>
        <description>
          
          &lt;p&gt;I&amp;rsquo;ve finally gotten annoyed enough with inotify failing randomly, because of resource exhaustion, that I&amp;rsquo;ve built a tiny app to deal with it.&lt;/p&gt;
&lt;p&gt;Introducing &lt;a href=&#34;https://invent.kde.org/system/kde-inotify-survey&#34;&gt;kde-inotify-survey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It features a CLI to inspect the inotify state, as well as a kded to warn and help with bumping the maximums. Assuming it turns out amazing for others I hope to progress it to kdereview soon.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/05/screenshot_20220505_115810.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/05/screenshot_20220505_115810.png?w=586&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Plasma GameMode</title>
        <link>https://kde.haraldsitter.eu/posts/plasma-gamemode/</link>
        <pubDate>Fri, 04 Mar 2022 10:08:06 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/plasma-gamemode/</guid>
        <description>
          
          &lt;p&gt;For when you are using Feral Interactive&amp;rsquo;s GameMode and want some UI indication of its use.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://invent.kde.org/sitter/plasma-gamemode&#34;&gt;https://invent.kde.org/sitter/plasma-gamemode&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://apachelog.files.wordpress.com/2022/03/screenshot_20220304_102910.png&#34;&gt;&lt;figure&gt;
  &lt;img class=&#34;img-fluid&#34; src=&#34;https://apachelog.files.wordpress.com/2022/03/screenshot_20220304_102910.png?w=754&#34;
    style=&#34;max-width: 100%; height: auto&#34;
   /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>Reuse Licensing Helper</title>
        <link>https://kde.haraldsitter.eu/posts/reuse-licensing-helper/</link>
        <pubDate>Tue, 06 Apr 2021 13:03:36 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/reuse-licensing-helper/</guid>
        <description>
          
          &lt;p&gt;It&amp;rsquo;s boring but important! Stay with me! Please! 😘&lt;/p&gt;
&lt;p&gt;For the past couple of years Andreas Cord-Landwehr has done excellent work on moving KDE in a more structured licensing direction. Free software licensing is an often overlooked topic, that is collectively understood to be important, but also incredibly annoying, bureaucratic, and complex. We all like to ignore it more than we should.&lt;/p&gt;
&lt;p&gt;If you are working on KDE software you really should check out &lt;a href=&#34;https://community.kde.org/Guidelines_and_HOWTOs/Licensing&#34;&gt;KDE&amp;rsquo;s licenses howto&lt;/a&gt; and maybe also glance over the comprehensive &lt;a href=&#34;https://community.kde.org/Policies/Licensing_Policy&#34;&gt;policy&lt;/a&gt;. In particular when you start a new repo!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to shine some light on a simple but incredibly useful tool: &lt;a href=&#34;https://git.fsfe.org/reuse/tool&#34;&gt;reuse&lt;/a&gt;. reuse helps you check licensing compliance with some incredibly easy commands.&lt;/p&gt;
&lt;p&gt;Say you start a new project. You create your prototype source, maybe add a readme - after a while it&amp;rsquo;s good enough to make public and maybe propose for inclusion as mature KDE software by going through &lt;a href=&#34;https://community.kde.org/Policies/Application_Lifecycle#kdereview&#34;&gt;KDE Review&lt;/a&gt;. You submit it for review and if you are particularly unlucky you&amp;rsquo;ll have me come around the corner and lament how your beautiful piece of software isn&amp;rsquo;t completely free software because some files lack any sort of licensing information. Alas!&lt;/p&gt;
&lt;p&gt;See, you had better use reuse&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip3 install --user reuse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reuse lint&lt;/code&gt;: lints the source and tells you which files aren&amp;rsquo;t licensed&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reuse download --all&lt;/code&gt;: downloads the complete license files needed for compliance based on the licenses used in your source (unfortunately you&amp;rsquo;ll still need to manually create the &lt;a href=&#34;https://community.kde.org/Policies/Licensing_Policy#LicenseRef-KDE-Accepted-GPL&#34;&gt;KDEeV variants&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;If you are unsure how to license a given file, consult the &lt;a href=&#34;https://community.kde.org/Guidelines_and_HOWTOs/Licensing&#34;&gt;licensing guide&lt;/a&gt; or the &lt;a href=&#34;https://community.kde.org/Policies/Licensing_Policy&#34;&gt;policy&lt;/a&gt; or send a mail to one of the devel mailing lists. There&amp;rsquo;s help a plenty.&lt;/p&gt;
&lt;p&gt;Now that you know about the &lt;a href=&#34;https://git.fsfe.org/reuse/tool&#34;&gt;reuse&lt;/a&gt; tool there&amp;rsquo;s even less reason to start projects without 100% compliance so I can shut up about it :)&lt;/p&gt;

        </description>
      </item>
    
      <item>
        <title>No SMB1 to Share Devices</title>
        <link>https://kde.haraldsitter.eu/posts/no-smb1-to-share-devices/</link>
        <pubDate>Tue, 17 Mar 2020 10:13:00 +0000</pubDate>
        <guid>https://kde.haraldsitter.eu/posts/no-smb1-to-share-devices/</guid>
        <description>
          
          &lt;p&gt;As it recently came up I thought I should perhaps post this more publicly&amp;hellip; As many of you will know SMB1, the super ancient protocol for windows shares, shouldn&amp;rsquo;t be used anymore. It&amp;rsquo;s been deprecated since like Windows Vista and was eventually also disabled by default in both Windows 10 and Samba. As a result you are not able to find servers that do not support either DNS-SD aka Bonjour aka Avahi, or WS-Discovery. But there&amp;rsquo;s an additional problem! Many devices (e.g. NAS) produced since the release of Vista could support newer versions of SMB but for not entirely obvious reasons do not have support for WS-Discovery-based &amp;hellip; discovery. So, you could totally find and use a device without having to resort to SMB1 if you know its IP address. But who wants to remember IP addresses. Instead you can just have another device on the network play discovery proxy! One of the many ARM boards out there, like a rapsberrypi, would do the trick. To publish a device over DNS-SD (for Linux &amp;amp; OS X) you&amp;rsquo;ll first want to map its IP address to a local hostname and then publish a service on that hostname. &lt;code&gt;avahi-publish -a blackbox.local 192.168.100.16 avahi-publish -s -H blackbox.local SMB_ON_BLACKBOX _smb._tcp 445&lt;/code&gt; If you also want to publish for windows 10 systems you&amp;rsquo;ll additionally want to run &lt;a href=&#34;https://github.com/christgau/wsdd&#34;&gt;wsdd&lt;/a&gt; &lt;code&gt;wsdd.py -v -n BLACKBOX&lt;/code&gt; Do note that BLACKBOX in this case can be a netbios, or LLMNR, or DNS-SD name (Windows 10 does support name resolution via DNS-SD these days). Unfortunate caveat of wsdd is that if you want to publish multiple devices you&amp;rsquo;ll need to set up a bridge and put the different wsdd instances on different interfaces.&lt;/p&gt;

        </description>
      </item>
    
  </channel>
</rss>
