<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valentin Boettcher</title>
    <description>The latest articles on DEV Community by Valentin Boettcher (@hiro98).</description>
    <link>https://dev.to/hiro98</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F351495%2F50ff00f3-b5bf-4870-90a2-7fb97f4f92ba.jpeg</url>
      <title>DEV Community: Valentin Boettcher</title>
      <link>https://dev.to/hiro98</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hiro98"/>
    <language>en</language>
    <item>
      <title>Subfigures in RevTex</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 16 Feb 2025 00:32:00 +0000</pubDate>
      <link>https://dev.to/hiro98/subfigures-in-revtex-56ml</link>
      <guid>https://dev.to/hiro98/subfigures-in-revtex-56ml</guid>
      <description>&lt;p&gt;I’m in the process of writing a paper (yay!). Merrily I add a formula here a plot there; but my supervisor zeroes in immediately on a two-panel figure with sub figures called “a” and “b” saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The sub figure labels go in the top-left corner. You’ve read papers before, haven’t you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having indeed read papers before, I must have neglected to pay proper attention to sub-figure labels – an inexcusable blunder – so this was news to me. Unwilling to fix the issues by monkeying around in inkscape, I turned to stack overflow. We have the pleasure to be using the &lt;a href="https://www.ctan.org/tex-archive/macros/latex/contrib/revtex" rel="noopener noreferrer"&gt;RevTeX&lt;/a&gt; document class and annoyingly this class happens to be incompatible with both the &lt;a href="https://ctan.org/pkg/subcaption?lang=en" rel="noopener noreferrer"&gt;subcaption&lt;/a&gt; package and the part of &lt;a href="https://ctan.org/pkg/subfloat" rel="noopener noreferrer"&gt;subfloat&lt;/a&gt; that controls where the captions go. The aforementioned packages are “the way” to do sub figures and most other solutions I found involved monkeying around with minipages.&lt;/p&gt;

&lt;p&gt;So that’s what I did; but I wanted to do properly so I’d be able to give the sub figures referenceable labels. I came up with a surprisingly short piece of hacked-together LaTeX package which we will now walk through. If you’re impatient, you can just grab the &lt;a href="https://protagon.space/tex/poormanssubfig.sty" rel="noopener noreferrer"&gt;sty&lt;/a&gt; file and jump ahead to the usage example.&lt;/p&gt;

&lt;p&gt;We begin by declaring the package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{poormanssubfig}[2025/02/14 A subfigure environment
  with working labels in the top-left corner that is compatible with revtex.]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we create a new counter for the subfigures to be able to generate use labels to reference them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\newcounter{subfigure}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;multifig&lt;/code&gt; environment resets the subfigure counter&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;, and redefines the &lt;code&gt;\thesubfigure&lt;/code&gt; macro to display references to the subfigure as &lt;code&gt;[Figure Number] ([figure sublabel])&lt;/code&gt;. The environment temporarily increases the Figure counter so that &lt;code&gt;\thefigure&lt;/code&gt; prints the right number. The three commands at the top of the below snipped allow the user to overwrite the way the label is printed and formatted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\newcommand{\subfiglabelformat}[1]{\raggedright{#1}}
\newcommand{\subfiglabelstyle}[1]{\alph{#1}}
\newcommand{\subfiglabelsize}{\small}
\newenvironment{multifig}%
{\addtocounter{figure}{1}%
  \setcounter{subfigure}{0}%
  \renewcommand\thesubfigure{\thefigure~(\subfiglabelstyle{subfigure})}%
}
{\addtocounter{figure}{-1}}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the point where the real hackery begins. We define an internal variables &lt;code&gt;\if@insubfig&lt;/code&gt; whose use will become clear later. The subfigure environment takes two arguments, the first one being the width of the subfigure and the second being an optional label string (it’s also where you put &lt;code&gt;\label{[label]}&lt;/code&gt;). The environment then creates a minipage with the appropriate width and prints the label of the figure in the top-left corner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\makeatletter
\ExplSyntaxOn
\newif\if@insubfig
\NewDocumentEnvironment{subfigure}{mO{}}{%
  \@insubfigtrue%
  \refstepcounter{subfigure}%
  \begin{minipage}{#1}%
    \subfiglabelformat{{\subfiglabelsize (\subfiglabelstyle{subfigure})~#2}}%
    }
    {\end{minipage}%
  \@insubfigfalse%
}
\ExplSyntaxOff

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This final bit is truly horrendous. I wanted to be able to refer to the subfigures in the figure caption using their labels, but a standard &lt;code&gt;\ref{[label]}&lt;/code&gt; would print the figure number, too. So I stole some code from the &lt;a href="https://ctan.org/tex-archive/macros/latex/contrib/cleveref" rel="noopener noreferrer"&gt;cleveref&lt;/a&gt; package to redefine the &lt;code&gt;\label&lt;/code&gt; macro to write a new label format (with the label name &lt;code&gt;[youlabel]@multifig&lt;/code&gt;) to the auxiliary (&lt;code&gt;.aux)&lt;/code&gt; file upon compilation. LaTeX reads the auxiliary file on the second pass and evaluates the &lt;code&gt;\newlabel{[label]}&lt;/code&gt; macros therein. These tell latex which text to print when we use the macro&lt;code&gt;\ref{[label]}&lt;/code&gt;. In our case this is just the sufigure counter value, without the figure number. I define a new reference command &lt;code&gt;\subref&lt;/code&gt; to expand &lt;code&gt;\ref&lt;/code&gt; but append &lt;code&gt;@multifig&lt;/code&gt; to its argument, so that the text we stored using&lt;code&gt;\newlabel&lt;/code&gt; is used. These extra labels will only be generated for subfigures thanks to &lt;code&gt;\if@insubfig&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\let\multifig@old@label\label%
\def\label#1{%
  \multifig@old@label{#1}%
  \if@insubfig%
    \@bsphack%
    \protected@write\@auxout{}%
    {\string\newlabel{#1@multifig}{{(\subfiglabelstyle{subfigure})}%
        {\thepage}%
        {\@currentlabelname}%
        {\@currentHref}{}%
      }}%
    \@esphack%
  \fi
}%
\def\subref#1{\ref{#1@multifig}}
\makeatother

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these details out of the way, let’s get to the part that you actually wanted to read about&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;: The package is used in a similar way to – who’d have thought it – the subfigure package, but puts your label it the top left corner – where it ought to be! Just put the &lt;code&gt;.sty&lt;/code&gt; file somewhere &lt;code&gt;TeX&lt;/code&gt;will find it. For global installation, you can put it in your&lt;code&gt;$TEXMFHOME/tex/latex&lt;/code&gt; folder. For usage with a specific project, you can dump it next to your &lt;code&gt;.tex&lt;/code&gt; file. And now, behold the below usage example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\begin{figure*}
  \begin{multifig}
    \begin{subfigure}{\columnwidth}{\label{subfig:descriptive-label}Some
        text label.}
      \begin{center}
        \includegraphics[width=.8\columnwidth]{example-image-a}
      \end{center}
    \end{subfigure}
    \begin{subfigure}{\columnwidth}{\label{subfig:another-descriptive-label}Another
        text label.}
      \begin{center}
        \includegraphics[width=.8\columnwidth]{example-image-b}
      \end{center}
    \end{subfigure}
  \end{multifig}
  \caption{\label{fig:beautiful-figures}As the discerning eye may have
    spied, the figures \subref{subfig:descriptive-label} and
    \subref{subfig:another-descriptive-label} have the potential to
    rock the foundations of society.}
\end{figure*}
Total nonsense, but I couldn't think of anything better to demonstrate
Figure \ref{subfig:descriptive-label} and \ref{subfig:another-descriptive-label}.

This produces the below result...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20b8zho2s5jeqx10fszx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20b8zho2s5jeqx10fszx.png" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;… and references in the text look like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc0oez6x79clnbq4osdt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnc0oez6x79clnbq4osdt.png" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Which could also have been accomplished by an
argument to &lt;code&gt;\newcounter&lt;/code&gt;. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Who are you dear reader? Shoot me an
email! ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Hours of my life</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Fri, 10 Jan 2025 08:57:00 +0000</pubDate>
      <link>https://dev.to/hiro98/hours-of-my-life-53f9</link>
      <guid>https://dev.to/hiro98/hours-of-my-life-53f9</guid>
      <description>&lt;p&gt;have been wasted why the line spacing and &lt;code&gt;DIV&lt;/code&gt; calculation (typearea) of KOMA script was hanging with &lt;code&gt;LuaTeX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TL;DR: &lt;code&gt;LuaTeX&lt;/code&gt; and &lt;code&gt;setspace&lt;/code&gt; don’t go together.&lt;/p&gt;

&lt;p&gt;I stripped out the custom fonts, I removed (seemingly) every package, I ported my document to &lt;code&gt;PDFTex&lt;/code&gt;. At long last after HOURS spent over several days if found the culprit. This time, I actually removed &lt;em&gt;everything&lt;/em&gt; and there it was: &lt;code&gt;\usepackage{setspace}&lt;/code&gt; was the culprit. Why did I include it? I don’t anymore and I wont spend any more time on this.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Kindle Scribe Sync</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 17 Nov 2024 17:13:00 +0000</pubDate>
      <link>https://dev.to/hiro98/kindle-scribe-sync-ka1</link>
      <guid>https://dev.to/hiro98/kindle-scribe-sync-ka1</guid>
      <description>&lt;p&gt;TL;DR check out &lt;a href="https://github.com/vale981/kindle_fetch" rel="noopener noreferrer"&gt;https://github.com/vale981/kindle_fetch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I “recently” treated myself to a Kindle Scribe e-ink tablet which is somewhat like a ReMarkable&lt;sup id="fnref:1"&gt;1&lt;/sup&gt; but on the cheap. There is no free lunch however, and price you pay is a somewhat sub-par software. One quite essential missing feature is convenient synchronization with other devices. As I use the tablet mainly for calculations, I rely on having the previous pages available at a glance (just as they would be if I were using paper). Furthermore, I would like to integrate the handwritten notes into my &lt;a href="https://www.orgroam.com/" rel="noopener noreferrer"&gt;org-roam&lt;/a&gt; note taking system.&lt;/p&gt;

&lt;p&gt;One solution would be to jailbreak the kindle, ssh into it and automatically download a notebook when it changes. The conversion to PDF could then be handled by the &lt;a href="https://www.mobileread.com/forums/showthread.php?t=291290" rel="noopener noreferrer"&gt;Calibre KFX input plugin&lt;/a&gt;. However, that ship has sailed for me as the firmware on my Kindle is too new.&lt;/p&gt;

&lt;p&gt;This led me to come up with the following &lt;a href="https://www.youtube.com/watch?v=lIFE7h3m40U" rel="noopener noreferrer"&gt;bodge&lt;/a&gt;. Amazon offers a service that converts a notebook to PDF and sends it to your email upon request and this we can exploit to our heart’s content. I wrote a&lt;a href="https://github.com/vale981/kindle_fetch" rel="noopener noreferrer"&gt;script&lt;/a&gt; which monitors your email inbox via IMAP&lt;sup id="fnref:2"&gt;2&lt;/sup&gt; using &lt;a href="https://github.com/bamthomas/aioimaplib" rel="noopener noreferrer"&gt;aioimaplib&lt;/a&gt;and detects incoming emails from Amazon containing download links for the exported notebooks. Once such an email is detected, the associated PDF is downloaded into a directory on the local file system (&lt;code&gt;~/kindle_dump&lt;/code&gt; on my machine). The name is inferred from the contents of the email, although at the moment this doesn’t include any hint about which folder in the directory structure on the Kindle it came from. The email is then conveniently deleted so as to not clutter your inbox&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, the latest downloaded PDF is copied into to a file of your choice (&lt;code&gt;~/kindle_dump/.latest&lt;/code&gt; in my case). I then run &lt;code&gt;zathura ~/kindle_dump/.latest&lt;/code&gt; which displays that PDF on my large 4K monitor and auto refreshes each time a new Kindle email comes in. I also configured Zathura to show four pages per row (&lt;code&gt;set pages-per-row 4&lt;/code&gt;) so that I can see eight pages at a glance (see figure below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz4amnjmqqtjpcx7hhkb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz4amnjmqqtjpcx7hhkb.png" alt="Figure 1: An example of what my ugly handwriting looks like :)," width="800" height="486"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: An example of what my ugly handwriting looks like :),&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiubrw5q172sys524qrki.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiubrw5q172sys524qrki.gif" alt="Figure 2: A little demo (sped up)." width="298" height="168"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2: A little demo (sped up).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Additionally, the following elisp snippet allows me to attach the latest note to an org-roam node with a couple of keystrokes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defun attach-kindle-note (text)
  "Attaches the latest kindle note to the current org buffer and links to it with TEXT."
  (interactive "sText: ")
  (let* ((name (org-id-new "kindle"))
         (tmp (format "/tmp/%s.pdf" name))
         (file "/home/hiro/kindle_dump/.latest.pdf")
         (text (if (string-empty-p text)
                   (format "handwritten note %s" (current-time-string)) text)))
    (copy-file file tmp t)
    (org-attach-attach tmp nil 'mv)
    (insert (format "[[attachment:%s.pdf][%s]]" name text))))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The integration into my note-taking system is the most important part the whole bodge for me.&lt;/p&gt;

&lt;p&gt;Annoyingly, Amazon has already changed the email format twice since I initially hacked together this solution. However, each time I come up with a more robust way to get the PDF download link and one’s free time has to be spent in some way or another anyways.&lt;/p&gt;

&lt;p&gt;And if you’re reading this sentence, you’ve made it to the end of this rather redundant post. Thank you for reading. I hope that at least some people find this bodge useful. If there’s sufficient interest, I might add OAuth2 support.&lt;/p&gt;

&lt;p&gt;On the road-map for future (think of years, not months) posts are my mu4e/mbsync setup with OAuth support on NixOS, my Xournal++ setup with vim-like keybindings and a patch to make the output files more compatible with version management and finally, my org-roam braindump.&lt;/p&gt;

&lt;p&gt;In other news, my fork of &lt;a href="https://github.com/vale981/julia-vterm.el" rel="noopener noreferrer"&gt;julia-vterm&lt;/a&gt; is now called&lt;a href="https://github.com/vale981/py-vterm-interaction.el" rel="noopener noreferrer"&gt;py-vterm-interaction&lt;/a&gt; and available on MELPA.&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Years ago, I sold my ReMarkable in to buy a cheap drum-set and used a
graphics tablet instead. I have a pretty neat set-up for that, too but
that’s a tale for another time. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Unfortunately, OAuth is not supported, so GMail/Outlook won’t work out
of the box. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;I additionally have a Sieve filter running on my server that
automatically sorts the Kindle emails into a specific folder, although
that is not strictly necessary anymore. You might want to setup a
separate email account for this purpose altogether if you’re not
comfortable with having a (potentially buggy) python script mucking
around in your emails. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Modern Python REPL in Emacs using VTerm</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sat, 11 May 2024 23:47:00 +0000</pubDate>
      <link>https://dev.to/hiro98/modern-python-repl-in-emacs-using-vterm-4knl</link>
      <guid>https://dev.to/hiro98/modern-python-repl-in-emacs-using-vterm-4knl</guid>
      <description>&lt;p&gt;As alluded to in &lt;a href="https://dev.to/hiro98/poetry2nix-development-flake-with-matplotlib-gtk-support-5521"&gt;Poetry2Nix Development Flake with Matplotlib GTK Support&lt;/a&gt;, I’m currently in the process of getting my “new” python workflow up to speed. My second problem, after dependency and environment management, was that fancy REPLs like &lt;a href="https://ipython.org/" rel="noopener noreferrer"&gt;ipython&lt;/a&gt; or &lt;a href="https://github.com/prompt-toolkit/ptpython.git" rel="noopener noreferrer"&gt;ptpython&lt;/a&gt; don’t jazz well with the standard &lt;code&gt;comint&lt;/code&gt; based inferior python repl that comes with &lt;code&gt;python-mode&lt;/code&gt;. One can basically only run ipython with the &lt;code&gt;--simple-prompt&lt;/code&gt; flag which removes features like syntax-highlighting and auto-completion. Especially annoying is, that only the &lt;code&gt;tkinter&lt;/code&gt; backend for &lt;code&gt;matplotlib&lt;/code&gt; works in this mode.&lt;/p&gt;

&lt;p&gt;The package &lt;code&gt;elpy&lt;/code&gt; comes with some improvements, especially when it comes to sending part of a buffer to the repl, but it comes with all sorts of baggage that interfere with my emacs setup.&lt;/p&gt;

&lt;p&gt;From my jolly &lt;a href="https://julialang.org/" rel="noopener noreferrer"&gt;Julia&lt;/a&gt; days I’m used to &lt;a href="https://github.com/shg/julia-vterm.el" rel="noopener noreferrer"&gt;julia-vterm&lt;/a&gt;. This emacs package runs a Julia REPL using a full terminal emulator (&lt;a href="https://github.com/akermu/emacs-libvterm" rel="noopener noreferrer"&gt;emacs-libvterm&lt;/a&gt;). So in the pursuit of a nice hack, I &lt;code&gt;M-x replace-string&lt;/code&gt;’d the word &lt;code&gt;julia&lt;/code&gt;with &lt;code&gt;python&lt;/code&gt; and gave it a shot. Remarkably, the whole thing just worked without much tweaking and you can enjoy the result by checking out the &lt;a href="https://github.com/vale981/python-vterm.el" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea of extending the original &lt;code&gt;julia-vterm&lt;/code&gt; package to support python as well is not without elegance. However, the code base is not too large and – owing to the differing sensibilities of the julia and python communities – the feature-set is likely to diverge in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprotagon.space%2Fox-hugo%2F2024-05-11_20-12-52_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprotagon.space%2Fox-hugo%2F2024-05-11_20-12-52_screenshot.png" alt="Figure 1: And this is the result!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: And this is the result!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Poetry2Nix Development Flake with Matplotlib GTK Support</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sat, 11 May 2024 21:57:00 +0000</pubDate>
      <link>https://dev.to/hiro98/poetry2nix-development-flake-with-matplotlib-gtk-support-5521</link>
      <guid>https://dev.to/hiro98/poetry2nix-development-flake-with-matplotlib-gtk-support-5521</guid>
      <description>&lt;p&gt;I recently had the pleasure to dive back into python for work. In the past, I was happily using &lt;code&gt;org-babel&lt;/code&gt; notebooks through &lt;a href="https://github.com/nnicandro/emacs-jupyter"&gt;emacs-jupyter&lt;/a&gt;. However, I have since switched to a more REPL/script driven workflow as I find that programming notebooks require a great deal of discipline to not end up as a horrible mess. For my new workflow, I need interactive plotting to work.&lt;/p&gt;

&lt;p&gt;So let’s get straight to the meat. The following &lt;code&gt;Flake&lt;/code&gt; dives you a development shell that tries to replicate the underlying  &lt;a href="https://python-poetry.org/"&gt;poetry&lt;/a&gt; project in full nix using &lt;a href="https://github.com/nix-community/poetry2nix"&gt;poetry2nix&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nix"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[your description]"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nv"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;flake-utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github:numtide/flake-utils"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github:NixOS/nixpkgs/nixos-unstable-small"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;poetry2nix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github:nix-community/poetry2nix"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;follows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nixpkgs"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nv"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;flake-utils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
    &lt;span class="nv"&gt;flake-utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;eachDefaultSystem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt;
        &lt;span class="nv"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;legacyPackages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nv"&gt;poetry2nix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;poetry2nix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkPoetry2Nix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;inherit&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="kn"&gt;in&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;yourPackage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;poetry2nix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkPoetryApplication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;projectDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c"&gt;# set this to true to use premade wheels rather than the source&lt;/span&gt;
            &lt;span class="nv"&gt;preferWheels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c"&gt;# this enables interactive plotting support with GTK&lt;/span&gt;
            &lt;span class="nv"&gt;overrides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;poetry2nix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;overrides&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;withDefaults&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;final&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nv"&gt;matplotlib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kn"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;matplotlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;overridePythonAttrs&lt;/span&gt; 

                &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="nv"&gt;passthru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;enableGtk3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="nv"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;yourPackage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c"&gt;# Shell for app dependencies.&lt;/span&gt;
        &lt;span class="c"&gt;#&lt;/span&gt;
        &lt;span class="c"&gt;# nix develop&lt;/span&gt;
        &lt;span class="c"&gt;#&lt;/span&gt;
        &lt;span class="c"&gt;# Use this shell for developing your app.&lt;/span&gt;
        &lt;span class="nv"&gt;devShells&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkShell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;inputsFrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;yourPackage&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="nv"&gt;package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kn"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="c"&gt;# any development dependencies that you might have in nixpkgs&lt;/span&gt;
            &lt;span class="nv"&gt;ruff&lt;/span&gt;
            &lt;span class="nv"&gt;pyright&lt;/span&gt;
          &lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c"&gt;# Shell for poetry.&lt;/span&gt;
        &lt;span class="c"&gt;#&lt;/span&gt;
        &lt;span class="c"&gt;# nix develop .#poetry&lt;/span&gt;
        &lt;span class="c"&gt;#&lt;/span&gt;
        &lt;span class="c"&gt;# Use this shell for changes to pyproject.toml and poetry.lock.&lt;/span&gt;
        &lt;span class="nv"&gt;devShells&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;poetry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkShell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;poetry&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow is as follows. Running &lt;code&gt;nix develop .#poetry&lt;/code&gt; will give you a shell with poetry available. You can then &lt;code&gt;poetry init&lt;/code&gt; and &lt;code&gt;poetry add&lt;/code&gt;and &lt;code&gt;poetry lock&lt;/code&gt; (not install) to your hearts content. A plain &lt;code&gt;nix develop&lt;/code&gt; will then set up the environment according to the &lt;code&gt;poetry.lock&lt;/code&gt;that poetry generates. Note that &lt;a href="https://github.com/nix-community/poetry2nix/pull/1651"&gt;this pull request&lt;/a&gt; has to be resolved before the above works with &lt;code&gt;preferWheels = true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You might want to checkout &lt;a href="https://direnv.net/"&gt;direnv&lt;/a&gt; and &lt;a href="https://github.com/nix-community/nix-direnv"&gt;nix-direnv&lt;/a&gt; for added convenience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>KDE GSOC: Wrapping it up…</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Mon, 16 Aug 2021 16:53:00 +0000</pubDate>
      <link>https://dev.to/hiro98/kde-gsoc-wrapping-it-up-4n3g</link>
      <guid>https://dev.to/hiro98/kde-gsoc-wrapping-it-up-4n3g</guid>
      <description>&lt;p&gt;Well, we all know that the work on open source projects is never truly finished, but most of the core goals have been achieved and the time is up :). In this post I’ll briefly summarize my GSOC work and then talk about one last small but user-facing feature that I’ve implemented.&lt;/p&gt;

&lt;p&gt;I’ve successfully implemented a new DSO backend and smoothed out most of the bugs. The &lt;a href="//posts/.org"&gt;python framework&lt;/a&gt; does work satisfactory and all existing catalogs have been ported. There remains the UGC catalog which will be imported in the future, either by me or by another member of the project. The latter option would be a good way to battle-test the documentation and I would prefer this option because I do not want to remain the only person familiar with the system.&lt;/p&gt;

&lt;p&gt;To quantify my contributions during the GSOC period see the snippet below, although I do not think such numbers have much to say&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Valentin Boettcher &amp;lt;hiro@protagon.space&amp;gt;:
       insertions: 15193 (19%)
       deletions: 23402 (35%)
       files: 312 (21%)
       commits: 76 (23%)
       lines changed: 38595 (26%)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore there is &lt;a href="https://invent.kde.org/education/kstars/-/merge%5Frequests?scope=all&amp;amp;state=merged&amp;amp;author%5Fusername=vboettcher"&gt;the list of my merge requests&lt;/a&gt; which does go into more detail.&lt;/p&gt;

&lt;p&gt;The user-facing side of my work is not very prominent. There is a small GUI for managing catalogs that allows importing, exporting, creating and editing catalogs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GF74dtbF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-13-41_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GF74dtbF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-13-41_screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--syzUuz-4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-18-49_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--syzUuz-4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-18-49_screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also a basic CSV importer that should make it easier for users to get their own custom data into KStars.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ku1D-ZRB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-30-54_csv_openngc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ku1D-ZRB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-30-54_csv_openngc.png" alt="Figure 1: The CSV importer. It sure needs some prettying up :P."&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 1: The CSV importer. It sure needs some prettying up :P.&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;Nevertheless, the main goal of my work was to create a seamless replacement for the old DSO system of which the user should not be too aware. To that end, I’ve implemented a feature that should have been in my overhaul from the beginning: a mechanism to import custom objects &lt;a href="https://invent.kde.org/education/kstars/-/merge%5Frequests/377"&gt;from the old DSO database&lt;/a&gt;. Now, on startup the user is being asked whether the old database should be imported if it is present.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kUMrRrd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-38-10_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kUMrRrd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-38-10_screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And finally: Colors!&lt;/p&gt;

&lt;p&gt;The DSOs always had a distinct color depending on the catalog they’re from. Right from the outset one complaint from early testers were the garish colors that I chose for the catalogs. I “fixed” this problem by simply choosing more subdued colors. But colors are a matter of personal taste. Also, a single color can’t fit all of KStars' color schemes. Therefore colors can now be customized for each catalog and color scheme through a “pretty” dialog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bvAgjc-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-52-46_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bvAgjc-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-52-46_screenshot.png" alt="Figure 2: The &amp;amp;ldquo;pretty&amp;amp;rdquo; color picker."&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 2: The “pretty” color picker.&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;Now you can do things like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nLgS1xoi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-49-03_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nLgS1xoi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-49-03_screenshot.png" alt="Figure 3: Color Scheme: Moonless Night"&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 3: Color Scheme: Moonless Night&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kV3TXuxZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-51-16_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kV3TXuxZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/KDE_GSOC:_Wrapping_it_up.../2021-08-16_20-51-16_screenshot.png" alt="Figure 4: Color Scheme: Starchart"&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 4: Color Scheme: Starchart&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;And again I’ve learned that user feedback is very important. I would never have thought of this feature on my own but must admit that it enhances the usability of KStars greatly.&lt;/p&gt;

&lt;p&gt;With that oddly specific foray into the world of colors I now conclude this blog post and thank you for your attention.&lt;/p&gt;

&lt;p&gt;Cheers, Valentin&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I deleted the old OpenNGC text catalog which contained more than ten thousand lines :P. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>KDE GSOC: Second Coding Period; Some Notes on the Catalog Repo.</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 08 Aug 2021 10:15:00 +0000</pubDate>
      <link>https://dev.to/hiro98/kde-gsoc-second-coding-period-some-notes-on-the-catalog-repo-e5l</link>
      <guid>https://dev.to/hiro98/kde-gsoc-second-coding-period-some-notes-on-the-catalog-repo-e5l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR DSO catalogs in KStars are now generated reproducibly in the CI. A list of available catalogs and documentation can be found &lt;a href="https://protagon.space/catalogs/pages/catalogs.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As promised &lt;a href="https://dev.to/hiro98/kde-gsoc-community-bonding-and-first-coding-period-may-17-july-11-43on"&gt;last time&lt;/a&gt; I’ll now go a little into the &lt;a href="https://invent.kde.org/vboettcher/kstars-catalogs"&gt;Catalogs Repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Usually DSO catalogs are pretty static and rarely change due to the nature of their contents. But although galaxies do not tend to jump around in the sky, catalogs still get updates to correct typos or update coordinates with more precise measurement. Our primary catalog&lt;a href="https://github.com/mattiaverga/OpenNGC"&gt;OpenNGC&lt;/a&gt; for example gets updates quite regularly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K-9zMQLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_12-21-27_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K-9zMQLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_12-21-27_screenshot.png" alt="Figure 1: OpenNGC is being updated regularly."&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 1: OpenNGC is being updated regularly.&lt;/p&gt;
&lt;br&gt;
        &lt;/p&gt;

&lt;p&gt;And even though a catalog might not change, it would nevertheless be desirable to have a record on how it was derived from its original format in a &lt;em&gt;reproducible&lt;/em&gt; way&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;. Last but not least, having all catalogs in a central place in kind of the same format would make deduplication a lot easier.&lt;/p&gt;

&lt;p&gt;The question is: how does one define a convenient yet flexible format that nevertheless enforces some kind of structure? My answer was: with some kind of package definition. What about the flexibility part? Well, basically every catalog is just a python module that must implement a class. By overwriting certain methods, the catalog can be built up. The framework provides certain support functionality and an interface to some catalog database features by way of a python binding to some &lt;code&gt;KStars&lt;/code&gt; code. Apart from that one has complete freedom in implementing the details although some conventions should be followed&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;A simple random catalog looks like the following listing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_string(str_size, allowed_chars=string.ascii_letters):
    return "".join(random.choice(allowed_chars) for x in range(str_size))

class RandomCatalogBase(Factory):
    SIZE = 100
    meta = Catalog(
        id=999,
        name="random",
        maintainer="Valentin Boettcher &amp;lt;hiro@protagon.space&amp;gt;",
        license="DWYW Do what ever you want with it!",
        description="A huge catalog of random DSOs",
        precedence=1,
        version=1,
    )

    def load_objects(self):
        for _ in range(self.SIZE):
            ob_type = random.choice(
                [ObjectType.STAR, ObjectType.GALAXY, ObjectType.GASEOUS_NEBULA]
            )
            ra = random.uniform(0, 360)
            dec = random.uniform(-90, 90)
            mag = random.uniform(4, 16)
            name = generate_random_string(5)
            long_name = generate_random_string(10)

            yield self._make_catalog_object(
                type=ob_type,
                ra=ra,
                dec=dec,
                magnitude=mag,
                name=name,
                long_name=long_name,
                position_angle=random.uniform(0, 180),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It implements only the &lt;code&gt;load_objects&lt;/code&gt; build phase and is a kind of minimum viable catalog.&lt;/p&gt;

&lt;p&gt;The basic idea behind the structure of a catalog implementation is that the build process can be subdivided into four &lt;em&gt;phases&lt;/em&gt; which can be partially parallelized by the framework.&lt;/p&gt;

&lt;p&gt;In the download phase each catalog defines how its content may be retrieved from the Internet or otherwise acquired. In the load/parse phase the acquired original data is being parsed and handed over to the framework which takes care of molding it into the correct format. During the deduplication phase each catalog can query the catalog database to detect and flag duplicates. And in the final dump phase the contents of each catalog are written into separate files which &lt;code&gt;KStars&lt;/code&gt; can then import&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested in the details I can recommend the &lt;a href="https://protagon.space/catalogs/"&gt;documentation&lt;/a&gt;for the catalog repository.&lt;/p&gt;

&lt;p&gt;After implementing the framework porting over all the existing catalogs to the new system, I went on to configure the KDE Invent CI to rebuild the catalogs upon changes. The CI artifacts are sync-ed to the &lt;code&gt;KNewStuff&lt;/code&gt; data server for KStars periodically and users are able to update their catalogs to the latest version.&lt;/p&gt;

&lt;p&gt;To get the CI working I had to create a &lt;a href="https://invent.kde.org/vboettcher/python-kstars-docker"&gt;Docker image&lt;/a&gt; that encapsulates the more or less complicated build process for the KStars python bindings. This container is updated weekly by CI and is also suitable as a quick-and-easy development environment for new catalogs.&lt;/p&gt;

&lt;p&gt;That’s it for today but do not fret. This is not all that I’ve done. There’s still more to come including something that has to do with the following picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AcbOpMZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_13-09-43_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AcbOpMZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_13-09-43_screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers, Valentin&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;And in a way that hopefully lasts for some time. Currently very few people know how to generate KStars' deep star catalogs… ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I haven’t yet worked those out yet TBH. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;The catalog package files actually do have the same format as the main DSO database :). ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>GSOC: Second Coding Period; Some Notes on the Catalog Repo.</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 08 Aug 2021 10:15:00 +0000</pubDate>
      <link>https://dev.to/hiro98/gsoc-second-coding-period-some-notes-on-the-catalog-repo-2jac</link>
      <guid>https://dev.to/hiro98/gsoc-second-coding-period-some-notes-on-the-catalog-repo-2jac</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR DSO catalogs in KStars are now generated reproducibly in the CI. A list of available catalogs and documentation can be found &lt;a href="https://protagon.space/catalogs/pages/catalogs.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As promised &lt;a href="https://dev.to/hiro98/kde-gsoc-community-bonding-and-first-coding-period-may-17-july-11-43on"&gt;last time&lt;/a&gt; I’ll now go a little into the &lt;a href="https://invent.kde.org/vboettcher/kstars-catalogs"&gt;Catalogs Repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Usually DSO catalogs are pretty static and rarely change due to the nature of their contents. But although galaxies do not tend to jump around in the sky, catalogs still get updates to correct typos or update coordinates with more precise measurement. Our primary catalog&lt;a href="https://github.com/mattiaverga/OpenNGC"&gt;OpenNGC&lt;/a&gt; for example gets updates quite regularly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K-9zMQLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_12-21-27_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K-9zMQLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_12-21-27_screenshot.png" alt="Figure 1: OpenNGC is being updated regularly."&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;Figure 1: OpenNGC is being updated regularly.&lt;/p&gt;
&lt;br&gt;
        &lt;/p&gt;

&lt;p&gt;And even though a catalog might not change, it would nevertheless be desirable to have a record on how it was derived from its original format in a &lt;em&gt;reproducible&lt;/em&gt; way&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;. Last but not least, having all catalogs in a central place in kind of the same format would make deduplication a lot easier.&lt;/p&gt;

&lt;p&gt;The question is: how does one define a convenient yet flexible format that nevertheless enforces some kind of structure? My answer was: with some kind of package definition. What about the flexibility part? Well, basically every catalog is just a python module that must implement a class. By overwriting certain methods, the catalog can be built up. The framework provides certain support functionality and an interface to some catalog database features by way of a python binding to some &lt;code&gt;KStars&lt;/code&gt; code. Apart from that one has complete freedom in implementing the details although some conventions should be followed&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;A simple random catalog looks like the following listing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_random_string(str_size, allowed_chars=string.ascii_letters):
    return "".join(random.choice(allowed_chars) for x in range(str_size))

class RandomCatalogBase(Factory):
    SIZE = 100
    meta = Catalog(
        id=999,
        name="random",
        maintainer="Valentin Boettcher &amp;lt;hiro@protagon.space&amp;gt;",
        license="DWYW Do what ever you want with it!",
        description="A huge catalog of random DSOs",
        precedence=1,
        version=1,
    )

    def load_objects(self):
        for _ in range(self.SIZE):
            ob_type = random.choice(
                [ObjectType.STAR, ObjectType.GALAXY, ObjectType.GASEOUS_NEBULA]
            )
            ra = random.uniform(0, 360)
            dec = random.uniform(-90, 90)
            mag = random.uniform(4, 16)
            name = generate_random_string(5)
            long_name = generate_random_string(10)

            yield self._make_catalog_object(
                type=ob_type,
                ra=ra,
                dec=dec,
                magnitude=mag,
                name=name,
                long_name=long_name,
                position_angle=random.uniform(0, 180),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It implements only the &lt;code&gt;load_objects&lt;/code&gt; build phase and is a kind of minimum viable catalog.&lt;/p&gt;

&lt;p&gt;The basic idea behind the structure of a catalog implementation is that the build process can be subdivided into four &lt;em&gt;phases&lt;/em&gt; which can be partially parallelized by the framework.&lt;/p&gt;

&lt;p&gt;In the download phase each catalog defines how its content may be retrieved from the Internet or otherwise acquired. In the load/parse phase the acquired original data is being parsed and handed over to the framework which takes care of molding it into the correct format. During the deduplication phase each catalog can query the catalog database to detect and flag duplicates. And in the final dump phase the contents of each catalog are written into separate files which &lt;code&gt;KStars&lt;/code&gt; can then import&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested in the details I can recommend the &lt;a href="https://protagon.space/catalogs/"&gt;documentation&lt;/a&gt;for the catalog repository.&lt;/p&gt;

&lt;p&gt;After implementing the framework porting over all the existing catalogs to the new system, I went on to configure the KDE Invent CI to rebuild the catalogs upon changes. The CI artifacts are sync-ed to the &lt;code&gt;KNewStuff&lt;/code&gt; data server for KStars periodically and users are able to update their catalogs to the latest version.&lt;/p&gt;

&lt;p&gt;To get the CI working I had to create a &lt;a href="https://invent.kde.org/vboettcher/python-kstars-docker"&gt;Docker image&lt;/a&gt; that encapsulates the more or less complicated build process for the KStars python bindings. This container is updated weekly by CI and is also suitable as a quick-and-easy development environment for new catalogs.&lt;/p&gt;

&lt;p&gt;That’s it for today but do not fret. This is not all that I’ve done. There’s still more to come including something that has to do with the following picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AcbOpMZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_13-09-43_screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AcbOpMZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://protagon.space/images/GSOC:_Second_Coding_Period%3B_Some_Notes_on_the_Catalog_Repo./2021-08-08_13-09-43_screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers, Valentin&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;And in a way that hopefully lasts for some time. Currently very few people know how to generate KStars' deep star catalogs… ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I haven’t yet worked those out yet TBH. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;The catalog package files actually do have the same format as the main DSO database :). ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>KDE GSOC: Community Bonding and First Coding Period (May 17 - July 11)</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 11 Jul 2021 13:00:00 +0000</pubDate>
      <link>https://dev.to/hiro98/kde-gsoc-community-bonding-and-first-coding-period-may-17-july-11-43on</link>
      <guid>https://dev.to/hiro98/kde-gsoc-community-bonding-and-first-coding-period-may-17-july-11-43on</guid>
      <description>&lt;p&gt;Of course the task I described in the &lt;a href="https://dev.to/hiro98/kde-gsoc-intro-44j-temp-slug-5892609"&gt;last post&lt;/a&gt; looks and is quite monumental. That is why I laid some of the groundwork for my GSOC beforehand (in the actual German semester breaks). This work continued in the community bonding and first coding period and will therefore be described here.&lt;/p&gt;

&lt;p&gt;But first I want to thank my mentor Jasem Mutlaq for his support, his patience with me and his nerves of steel. My mood levels were somewhat similar to a huge-amplitude sine wave those last weeks.&lt;/p&gt;

&lt;p&gt;Now to the meat…&lt;/p&gt;

&lt;p&gt;I began by studying the existing deep sky object implementation in KStars to identify what structure the new catalogs should have and what the smallest irreducible core of functionality was I could replace to make integration easier. I discovered that the catalogs were a mix of SQL databases and text files, somehow loaded at startup and then appended to some linked list. There was some deduplication implemented but like most DSO code it was oddly catalog specific. Especially the Messier, IC and NGC catalogs were often mentioned in the code. Also the explicit distinction between stars and DSOs made writing general code complicated but I found a consistent set of data fields shared by all catalog objects which all admitted sane defaults. It wasn’t bad code or anything like that. Just the product of “organic groth” with many thing I wanted already present in some way but somewhat all over the place. I admit that I studied the code just enough to find out what exactly I had to replace and maybe I could have reused more of the existing code but I’ve picked this specific path in the multiverse, so let’s get on with it. Just a shout out to all who did previous work on the DSO code among whom are, just to name a few, Jason Harris, Rishab Arora, Thomas Kabelmann and Akarsh Simha.&lt;/p&gt;

&lt;p&gt;With this knowledge I was able to go forward and devise a concrete plan for implementing the new DSO system. First of all, albeit I would love to use &lt;code&gt;std::variant&lt;/code&gt; and some kind of entity component system for the different DSO types I settled with a one-for-all type for deep sky objects. The primary reason for this was, that KStars uses &lt;code&gt;C++14&lt;/code&gt;which lacks variants (and the extremely useful&lt;code&gt;std::optional&lt;/code&gt;). Furthermore the DSOs all share common structure, so this was just the simpler and thus preferable option. The second design decision was not to load all of the DSOs into memory, but instead to take inspiration from the deep star catalogs. For one they are dynamically loaded from a special trixel indexed format so this already was within the formulated goals of the endeavor. On the other hand the notion of having “canonical” copies of catalog objects in memory and syncing their mutation with the database system seemed overly complicated. The catalog database should be the single source of truth and not the (ephemeral) memory of KStars.&lt;/p&gt;

&lt;p&gt;When a specific object is needed, it should just be retrieved from the database locally in the code instead of searching some in memory list in KStars or shooting around with pointers. This notion is somewhat at odds with how things were and are done in KStars which created some interesting problems later on as we shall see. These ideas somewhat dictated the rest of the plan which I (for the first time in my programming career) completely wrote down in advance. The heart of it all is the database manager which abstracts maintaining, reading from and writing to the database. As always one should justify the creation of a special data type. In this case it was the requirement that the database access should be painless and could be handled locally anywhere in the code just by creating another instance of the database manager. The manager should handle retrieving objects and catalog meta information as well as importing, editing and exporting catalogs.&lt;/p&gt;

&lt;p&gt;The structure of the database itself was another point of consideration. Naturally each catalog should have its own table. But how should deduplication work? The method I settled on is really quite simple. Each object gets a (relatively stable) hash that is calculated from some of its properties which is henceforth called the ID. When two objects (from different catalogs or otherwise) are the same &amp;lt;!-- raw HTML omitted --&amp;gt;physical&amp;lt;!-- raw HTML omitted --&amp;gt; object, then they will both be assigned the same object id (OID) which is just the ID of the object in the “oldest” catalog (with the lowest catalog id), trying to make it stable under the introduction of new catalogs. Additionally each catalog is assigned a priority value which is just a real number (conventionally between zero and one). When loading objects from the database into KStars and there are multiple objects with the same OID only the one from the catalog with the highest priority will be loaded. This simple mechanism should cover the requirements of KStars quite well and is relatively easy to implement.&lt;/p&gt;

&lt;p&gt;There I ran into an issue that demanded some research and table in the database. The simplest option would be just to create a benchmarking. Remember that each catalog is represented by its own so-called view, a dynamic “virtual” table that combines all the catalog into one homogeneous table. SQL magic could automatically perform the deduplication algorithm outline above and everything would be fine and dandy. However, benchmarking revealed that actually writing the view into its own table, henceforth called the master catalog/table, increased the performance quite considerably, enough so to justify the increased complexity in the implementation. And then I discovered SQL indexes. A gift from the heavens! They increased performance on loading objects in a trixel from the master catalog roughly threefold and I was sold on the master catalog approach. So to summarize it all; a deduplicated view of the combined catalog tables is being created and then written into the master table. This has to be done for every modification of the catalogs but is relatively fast (just not fast enough to be done 20 times per second). Later experimentation showed that this approach could accommodate catalogs up to a million objects in size.&lt;/p&gt;

&lt;p&gt;I also created a catalog file format, which is just an sqlite database file with the application id set to a special value with almost the same structure as the catalog database proper. The application id enables KStars to check if the database is really a catalog file and not to rely just on the structure of the contained database for that. In the future the &lt;code&gt;file&lt;/code&gt; command and other utilities like file managers could be made aware of this special application id to recognize the catalog files. We will leave it this level of detail for now. For more details please refer to my &lt;a href="https://protagon.space/stuff/kstars%5Fcleaned.org"&gt;notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course the operations on catalogs have to somehow be accessible in the GUI of KStars so this was another point of action. Before that however the glue between the database manager and the usual sky composite system had to be implemented. In KStars different types of objects (Stars, Comets, Asteroids, etc. pp.) all are implemented as components with a unified interface. These components provide methods for loading and drawing objects, as well as utilities to find objects near a certain point on the sky and similar things. The loading and drawing part was relatively simple to implement. The drawing code could be straight up reused from the old implementation and the loading was essentially covered by the database manager but with a twist.&lt;/p&gt;

&lt;p&gt;To support very large catalogs it would be desirable to only have objects in memory which are currently visible. Thus a LRU cache was implemented with the trixel id, which essentially labels a portion of the sky, as key. This cache is fully unit tested and relies completely on standard library containers so not a single pointer appears in the code.&lt;sup id="fnref:1"&gt;1&lt;/sup&gt; As an added bonus, the cache is completely transparent by default and only takes effect if configured to so and therefore includes the typical use case of comparatively small catalogs up to ten-thousands of objects.&lt;/p&gt;

&lt;p&gt;But here the culture clash between the new DSO implementation and the traditional KStars way of things became apparent. In many places KStars expects pointers to so called &lt;code&gt;SkyObjects&lt;/code&gt; with no real clue as to where they are actually stored and how their memory is managed and with the implication that the object is expected to live forever. Well, the DSOs from the catalogs aren’t supposed to be kept around forever and thus a compromise is in order. So whenever a pointer to an object is required, it is inserted into a linked list&lt;sup id="fnref:2"&gt;2&lt;/sup&gt; in a hash table with the trixel as index or is taken from there if it’s already present. I hope that we can eventually transition away from raw pointers and manage life time either explicitly or with smart pointers.&lt;/p&gt;

&lt;p&gt;With this done and basic drawing working I went on to implement a basic GUI for catalog management&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;. I also wrote unit tests for the database functionality which proved itself as very useful later on. After that I couldn’t delay anymore. Back when I implemented the component for the new DSOs I went as far as getting it to compile and not much further&lt;sup id="fnref:4"&gt;4&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Now I had to go around and find out what broke. A lot broke and I did not find all of it until the big merge :P. A rather interesting source of work happened to be the way metadata like observation notes and image links were stored. They came from a text file and then were loaded into the sky objects at startup and somehow synchronized with the text files on mutation. This, of course, played not well with the new DSOs as they were ephemeral. So I replaced the whole shebang with a hash table which incidentally improved startup performance. The rest of the integration work was similarly interesting and continues today. I will not go into it further but feel free to look at the KStars commit history.&lt;/p&gt;

&lt;p&gt;Just yesterday I added a feature back in that I had axed accidentally to the dismay of its original author. That showed me that I am not entitled to judge the merit of individual features and whether they could be sacrificed for the “greater good”. The answer is: They cannot! Another lesson I’ve learned is, that too much magic just ain’t no good. I had created a variadic template wrapper for the &lt;code&gt;QSqlQuery&lt;/code&gt;type for syntactical convenience and shot myself in the food with it. It ended up obscuring an error message and prevented me from reproducing a crash that users on certain platforms were experiencing. After a not-so-great couple of days I, with the help of two kind people, finally found the lowest common denominator of the problem: an old, but still supported version of QT which bundled an old version of sqlite which in turn did not support the &lt;code&gt;NULLS FIRST&lt;/code&gt;directive that I was using. Turtles all the way down. Although I tested all my changes on KDE Neon (I am on NixOS primarily) the wise thing would have been to develop or at least test everything with an older QT version from the get go.&lt;/p&gt;

&lt;p&gt;Also, although I had put in version checking into the database code, I didn’t provide a mechanism for upgrading the database format to new versions. This I now remedied by introducing a simple mechanism that applies database modifications successively for each version upgrade. So if I go from version two to version four it will be upgraded from version two to three and then to four which I understand is the way those things are usually done.&lt;/p&gt;

&lt;p&gt;Now, I did do at least some “constructive” work, adding a (admittedly ugly) CSV importer so that users can import arbitrary CSV-ish catalogs. The greater chunk however I will cover next week: The python catalog package tooling with continuous integration and deduplication. The catalogs churned out by that framework are then installed via the &lt;code&gt;KNewStuff&lt;/code&gt; framework. I discovered two interesting bugs in this framework because KStars seems to be almost the only program using the framework in this specific way.&lt;/p&gt;

&lt;p&gt;If you made it this far, I applaud and thank you for your endurance. See you next time.&lt;/p&gt;

&lt;p&gt;Cheers, Valentin&lt;/p&gt;

&lt;p&gt;P.S. Currently I am working on documenting both the new DSO GUI and the python tooling. I hope eventually they will pass the “noob test” :P. But, as you may have recognized above, I am not the best explainer.&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;As a matter of fact, I set out with the goal not to do any manual memory management and not to use a single pointer in the new code. I have been successful thus far if you would be so lenient not to count glue code for legacy KStars systems. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;References to objects in linked lists are stable. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;See the KStars Handbook. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;I really appreciate c++ as a compiled language. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>KDE GSOC: Intro</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 27 Jun 2021 13:00:00 +0000</pubDate>
      <link>https://dev.to/hiro98/kde-gsoc-intro-5hjd</link>
      <guid>https://dev.to/hiro98/kde-gsoc-intro-5hjd</guid>
      <description>&lt;p&gt;Hi folks, talking to you over the interwebs is Valentin Boettcher who is overhauling the Deep Sky Object (DSO) system in the KStars Desktop Planetarium for the Google Summer of Code anno domini 2021.&lt;/p&gt;

&lt;p&gt;This is the first post in a series and rather late in the coming, so let’s get right to it.&lt;/p&gt;

&lt;p&gt;I’m currently studying for a master’s degree in physics at the TU-Dresden in, you’ve guessed it correctly, the beautiful city of Dresden (Germany). In Germany, we do have two study terms per year and the summer term usually coincides neatly with the GSOC so that I couldn’t participate in past years. This time around however, my schedule was finally sparse enough for me to have a go at it, and here we are :).&lt;/p&gt;

&lt;p&gt;My first contact with KStars development was back in 2017 while I spent a year in New Zealand and had a lot of time at hand. My reasoning was, that I could learn mathematics and physics in UNI and should funnel my enthusiasm into familiarizing myself with software development and the open source software community. I promptly wiped my hackintosh laptop to put Linux with KDE on it&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;. After reading ESR’s famous &lt;a href="http://www.catb.org/~esr/faqs/hacker-howto.html"&gt;“How To Become A Hacker”&lt;/a&gt;, I followed the advice given therein, which was to find an open source project and start hacking on it. I already liked KDE and space, so KStars was in the center of the Venn-diagram :P. I went ahead and busied myself with one of the junior jobs listed on the KStars web-site&lt;sup id="fnref:2"&gt;2&lt;/sup&gt;. I quickly found that I liked figuring out how stuff in KStars worked and also got in contact with my mentor Jasem Mutlaq who was always available to answer questions and endure my barrage of instant messages on matrix :P. My second job was to draw comets a tail and learned that it is wise to do some code archaeology before going ahead and implementing functionality that is already present. From there on I contributed more or less regularly when I found the time in my semester breaks.&lt;/p&gt;

&lt;p&gt;Now, finally, let’s talk a wee bit about the actual GSOC project. In KStars, everything that isn’t a Star or an object in our solar system, an asteroid, a satellite or a comet (I’m sure I forgot something) is a deep sky object (DSO). Prominent members of the DSO caste are galaxies (think M31, Andromeda), asterisms and nebulae. Of course there are a plethora of catalogs for specific types of DSOs (for example, Lynds Catalog of Dark Nebulae) as well as compilations like the New General Catalogue. The system for handling those catalogs in KStars has grown rather “organically” and is now a tangle between databases, CSV files and special case implementations. Many catalogs were mentioned explicitly in the code, making it hard to extend and generalize. Also, the sources of the catalogs and methods how they were transformed into the KStars format were inhomogeneous and hard to reproduce, making deduplication almost impossible. Finally, KStars just loaded all the DSOs into memory and computed their position on the virtual sky for every draw cycle, which made all too large catalogs infeasible. My task is now (and has been since the beginning of June) to implement a unified catalog format which can be loaded into a central database and supports deduplication. Furthermore, taking inspiration from the handling of star catalogs in KStars, the objects should be trixel&lt;sup id="fnref:3"&gt;3&lt;/sup&gt;indexed and cached in and out of memory (but only for large catalogs). Finally, it would be very desirable to make the creation/compilation of the catalogs reproducible and easily extendable to facilitate future maintenance.&lt;/p&gt;

&lt;p&gt;This sounds like a big heap of stuff to get done and in the next post I will be detailing how it’s going so far :).&lt;/p&gt;

&lt;p&gt;Cheers, Valentin&lt;/p&gt;

&lt;p&gt;Assigning each object to a trixel makes it efficient to retrieve all objects from a certain part of the sky.&lt;/p&gt;




&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;which I knew from my school time when I used it on my netbook because there was a cool neon “Hacker” theme for it :P ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;which had to do with figuring out why some faint asteroids where missing ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;In KStars the sky is subdivided into triangular pixels “Trixels”. ↩︎&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Installing without Fear</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Sun, 16 Aug 2020 15:32:10 +0000</pubDate>
      <link>https://dev.to/hiro98/installing-without-fear-jej</link>
      <guid>https://dev.to/hiro98/installing-without-fear-jej</guid>
      <description>&lt;p&gt;Note to self:&lt;/p&gt;

&lt;p&gt;If you want to make sure some nice GNU/Linux installer does not touch certain drives just run&lt;br&gt;
&lt;code&gt;echo 1 &amp;gt; /sys/block/sdX/device/delete&lt;/code&gt; in a &lt;strong&gt;root&lt;/strong&gt; shell and the drive will vanish from the system.&lt;/p&gt;

&lt;p&gt;Shamelessly stolen from: &lt;a href="https://askubuntu.com/questions/554398/how-do-i-permanently-disable-hard-drives"&gt;https://askubuntu.com/questions/554398/how-do-i-permanently-disable-hard-drives&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bootloader</category>
    </item>
    <item>
      <title>Fixing Linux Dualboot: Reinstalling the Windows EFI Bootloader Files</title>
      <dc:creator>Valentin Boettcher</dc:creator>
      <pubDate>Fri, 10 Jul 2020 12:31:45 +0000</pubDate>
      <link>https://dev.to/hiro98/reinstalling-the-windows-efi-bootloader-files-i68</link>
      <guid>https://dev.to/hiro98/reinstalling-the-windows-efi-bootloader-files-i68</guid>
      <description>&lt;p&gt;Note to my future self :).&lt;/p&gt;

&lt;p&gt;Reloading my Linux install after a pretty radical 'nuke and pave' I had to get my Windows dualboot back to work.&lt;br&gt;
There are a thousand guides on how to do that, but I'll add another one in case your setup is similar to mine. &lt;/p&gt;

&lt;p&gt;I have installed windows on a separate drive and Linux on my main drive, along with the efi partition.&lt;/p&gt;

&lt;p&gt;Don't follow this guide blindly. Think about every step you take, because you can seriously mess up your system :).&lt;/p&gt;

&lt;p&gt;With that out of the way, the things you have to do are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Boot a windows install medium.&lt;/li&gt;
&lt;li&gt;Choose your language and enter the 'repair options'.&lt;/li&gt;
&lt;li&gt;Go to advanced and select 'command line'.&lt;/li&gt;
&lt;li&gt;To mount the efi partition type diskpart and in diskpart then type list volume. A list of volumes will be printed and one of them the efi partition (usually around 500mb ). Select this partition (select volume &lt;code&gt;[number]&lt;/code&gt;) and assign a drive letter (&lt;code&gt;X&lt;/code&gt; is the drive letter you assign).&lt;/li&gt;
&lt;li&gt;Check where your windows partition is mounted. The diskpart list volume output will probably include it. I will assume that it is volume &lt;code&gt;C&lt;/code&gt;. Exit diskart with &lt;code&gt;exit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To finally install the boot files type the command &lt;code&gt;bcdboot c:\windows /s x:&lt;/code&gt; . This will generate boot files based on &lt;code&gt;c:\windows&lt;/code&gt; and install them on the partition with the letter &lt;code&gt;X&lt;/code&gt; . &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thats it, you can reboot now.&lt;br&gt;
You may have to reconfigure grub (or whatever loader you use). On arch-linux, make sure you have os-prober installed :).&lt;/p&gt;

</description>
      <category>dualboot</category>
      <category>linux</category>
      <category>windows</category>
      <category>bootloader</category>
    </item>
  </channel>
</rss>
