<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>binfalse</title>
		<description>stuff. just for the records.</description>
		<link>https://binfalse.de/</link>
		<atom:link href="https://binfalse.de/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Automagically add Accessibility Modifiers to Typescript Projects</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2025/eslint-explicit-accessibility.png&quot; title=&quot;AI generated title image...&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2025/05/16/automagically-add-accessibility-modifiers-to-typescript-projects/2025/05/16/automagically-add-accessibility-modifiers-to-typescript-projects/&quot; data-title=&quot;AI generated title image...&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2025/eslint-explicit-accessibility.png&quot; alt=&quot;AI generated title image...&quot; style=&quot;max-width:250px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;AI generated title image...&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Today, I want to share a powerful tool that can help you introducing the eslint rule &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@typescript-eslint/explicit-member-accessibility&lt;/code&gt; into your projects.
This rule ensures that all class members (methods, properties, accessors) have explicit accessibility modifiers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected&lt;/code&gt;).
If you have a large codebase, manually adding these modifiers will be quite a daunting task.
But fear not, for this script is there to help! :D&lt;/p&gt;

&lt;h2 id=&quot;the-challenge&quot;&gt;The Challenge&lt;/h2&gt;

&lt;p&gt;Enabling &lt;a href=&quot;https://eslint.org/&quot;&gt;eslint’s&lt;/a&gt; &lt;a href=&quot;@typescript-eslint/explicit-member-accessibility&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@typescript-eslint/explicit-member-accessibility&lt;/code&gt; rule&lt;/a&gt; in a large codebase very likely unleashes a lot of linter errors.
Manually fixing these errors will drain your time and energy.&lt;/p&gt;

&lt;p&gt;The script I’m sharing today automates this process.
The core of it goes through all matching scripts in your project. It uses &lt;a href=&quot;https://ts-morph.com/&quot;&gt;ts-morph&lt;/a&gt; to traverse the AST of a script and adds an explicit accessibility modifier (can be specified with &lt;abbr title=&quot;command line interface&quot;&gt;cli&lt;/abbr&gt; arguments) if they do not already have one:&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;sourceFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sourceFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sourceFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;forEachDescendant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SyntaxKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MethodDeclaration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SyntaxKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PropertyDeclaration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SyntaxKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;GetAccessor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SyntaxKind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SetAccessor&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;declaration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;as &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MethodDeclaration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PropertyDeclaration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modifiers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;declaration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getModifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hasAccessibilityModifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hasAccessibilityModifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;declaration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleModifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;accessibilityModifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will find the complete script at &lt;a href=&quot;/assets/resources/stuff/add-accessibility-modifier.ts&quot;&gt;add-accessibility-modifier.ts&lt;/a&gt; or check the corresponding &lt;a href=&quot;https://gist.github.com/binfalse/b9d71f39fa4cffb269270e4d41a22791&quot;&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;howtouse&quot;&gt;Howtouse&lt;/h2&gt;

&lt;p&gt;First ensure you have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ts-morph&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ts-node&lt;/code&gt; installed in your project.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install ts-morph ts-node
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you can invoke the script using &lt;a href=&quot;https://docs.npmjs.com/cli/v8/commands/npx&quot;&gt;npx&lt;/a&gt;, specifying desired options:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx ts-node add-public-modifier.js -s &quot;src/**/*.ts&quot; -t &quot;tsconfig.json&quot; -a &quot;private&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Options are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--sources&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GLOB&lt;/code&gt;: Specify the source files glob pattern (default: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/**/*.ts&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--tsconfig&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; Specify the path to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tsconfig.json&lt;/code&gt; file of your project (default: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tsconfig.json&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-a&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--accessibility&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MODIFIER&lt;/code&gt;: Specify the accessibility modifier to add (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protected&lt;/code&gt;) (defaults to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find this script as powerful and helpful as I do.
Happy hacking, and may the clean code be with you!&lt;/p&gt;
&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2025/05/16/automagically-add-accessibility-modifiers-to-typescript-projects/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Fri, 16 May 2025 09:10:28 +0000</pubDate>
				<link>https://binfalse.de/2025/05/16/automagically-add-accessibility-modifiers-to-typescript-projects/</link>
				<guid isPermaLink="true">https://binfalse.de/2025/05/16/automagically-add-accessibility-modifiers-to-typescript-projects/</guid>
			</item>
		
			<item>
				<title>SAP ABAP @ Home 2025</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2025/dockerised-sap.jpeg&quot; title=&quot;Random logo generated by an AI...&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2025/04/15/sap-abap-home-2025/2025/04/15/sap-abap-home-2025/&quot; data-title=&quot;Random logo generated by an AI...&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2025/dockerised-sap.jpeg&quot; alt=&quot;Random logo generated by an AI...&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Random logo generated by an AI...&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;This year I started on a new journey in the &lt;a href=&quot;https://www.sap.com&quot;&gt;SAP&lt;/a&gt; biz.
To get a better feeling for the SAP ecosystem, I wanted to experiment and mess around on my own.
And to avoid disrupting others and to have full control without needing to ask for permissions, I decided to set up an SAP system locally.
However, that turned out to be quite a challenge, especially when aiming for a proper (v)host setup.
After numerous attempts, I eventually found a reliable way using Docker.
Here’s a rough guide based on my experience.&lt;/p&gt;

&lt;h4 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h4&gt;

&lt;p&gt;Before diving into the setup, ensure you’re properly equipped with all technical requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Disk Space&lt;/strong&gt;: At least 100GB, but I’d recommend 200+GB.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: They suggest 32GB. I have 250GB, and it’s been running smoothly ;-)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: A couple of fast cores.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Time&lt;/strong&gt;: Everything SAP related requires patience and time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;step-1-start-the-sap-system-using-docker&quot;&gt;Step 1: Start the SAP System using Docker&lt;/h4&gt;

&lt;p&gt;The easiest way to get started is by using the Docker image provided by SAP.
You’ll find it at the docker hub &lt;a href=&quot;https://hub.docker.com/r/sapse/abap-cloud-developer-trial&quot;&gt;sapse/abap-cloud-developer-trial&lt;/a&gt;.
Before you can spawn a container, you should increase a couple of system limits by running the following as root:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sysctl &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; kernel.shmmni&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;32768 
sysctl &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; fs.aio-max-nr&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;18446744073709551615
sysctl &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; vm.max_map_count&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2147483647
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, as described on the docker hub readme, run the following command to start a container:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--stop-timeout&lt;/span&gt; 3600 &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; a4h &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt; vhcala4hci &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 3200:3200 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 3300:3300 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8443:8443 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 30213:30213 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 50000:50000 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 50001:50001 sapse/abap-cloud-developer-trial:ABAPTRIAL_2022_SP01
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Give it time. A lot of time…
At some point it will tell you that it’s ready by printing something along those lines:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; All services have been started. &lt;span class=&quot;k&quot;&gt;***&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; To stop and be able to safely start again use Ctrl-C
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Or use the stop &lt;span class=&quot;nb&quot;&gt;command &lt;/span&gt;with &lt;span class=&quot;nb&quot;&gt;timeout&lt;/span&gt;: docker stop &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 7200 ...
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Have fun! &lt;span class=&quot;k&quot;&gt;***&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;step-2-setting-up-a-virtual-box-with-the-sap-gui&quot;&gt;Step 2: Setting Up a Virtual Box with the SAP GUI&lt;/h4&gt;

&lt;p&gt;While I believe it would be possible to install the SAP GUI directly on your host, I recommend using a virtual environment to guard your host system. From my experiments I learned that SAP software loves to mess around in your file system and it will be virtually impossible to clean that up..&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Create a VM&lt;/strong&gt;: I used a Debian virtual box for this purpose.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Install Java&lt;/strong&gt;: I’ve been successful with OpenJDK 17.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Download SAP GUI for Java&lt;/strong&gt;: Get it from &lt;a href=&quot;https://developers.sap.com/trials-downloads.html&quot;&gt;SAP’s trial &lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Install on the VM&lt;/strong&gt;: Copy the downloaded rar archive to your virtual machine, unpack it (eg. using unrar) and run the &lt;a href=&quot;https://en.wikipedia.org/wiki/JAR_(file_format)&quot;&gt;JAR&lt;/a&gt; file to start the installation:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; PlatinGUI-Linux-x86_64-7.80rev7.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Start SAP GUI&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt; into the install location (probably &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/SAPClients/SAPGUI/bin&lt;/code&gt;) and run:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; ./guistart /H/x.x.x.x/S/3200
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x.x.x.x&lt;/code&gt; with the IP address that resolved to your host machine. Depending on your VM config, it might be something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0.2.2&lt;/code&gt; (VBox NAT) or maybe something starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168...&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;step-3-updating-the-license&quot;&gt;Step 3: Updating the License&lt;/h4&gt;

&lt;p&gt;Follow the procedure from the Docker Hub to update the license:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Login on client &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;000&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SAP*&lt;/code&gt; with the password &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ABAPtr2022#01&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Run Transaction &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SLICENSE&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Get a license from &lt;a href=&quot;https://go.support.sap.com/minisap/#/minisap&quot;&gt;minisap&lt;/a&gt;. Choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A4H&lt;/code&gt;, fill the form, and download the license.&lt;/li&gt;
  &lt;li&gt;Back in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SLICENSE&lt;/code&gt; transaction in SAP GUI, click install and choose the downloaded file.&lt;/li&gt;
  &lt;li&gt;Log off from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SAP*&lt;/code&gt; account (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System -&amp;gt; Logoff&lt;/code&gt;) and start a new SAP GUI session. Login on client &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;001&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEVELOPER&lt;/code&gt; with the same password &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ABAPtr2022#01&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s it! You should now have a locally running SAP system.
I recommend to stop the docker container using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker stop -t 7200 a4h&lt;/code&gt; and then commit the changes into a new image, ie.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker commit a4h my-sap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Afterwards you can spawn a container of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my-sap&lt;/code&gt; image, properly setup with a valid license and stuff, even if you accidentally clean the old container.&lt;/p&gt;

&lt;p&gt;This setup should allow you to experiment and develop in a controlled environment without affecting a main system.
Happy coding &amp;lt;3&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2025/04/15/sap-abap-home-2025/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Tue, 15 Apr 2025 19:32:35 +0000</pubDate>
				<link>https://binfalse.de/2025/04/15/sap-abap-home-2025/</link>
				<guid isPermaLink="true">https://binfalse.de/2025/04/15/sap-abap-home-2025/</guid>
			</item>
		
			<item>
				<title>Avoiding Pitfalls with Quotation Marks in Docker Compose Environment Variables</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2024/docker-quotation.jpeg&quot; title=&quot;Navigating Docker Compose environment variables: Best practices for seamless configuration.&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2024/05/31/docker-compose-quotation-pitfalls/2024/05/31/docker-compose-quotation-pitfalls/&quot; data-title=&quot;Navigating Docker Compose environment variables: Best practices for seamless configuration.&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2024/docker-quotation.jpeg&quot; alt=&quot;Navigating Docker Compose environment variables: Best practices for seamless configuration.&quot; style=&quot;max-width:200px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Navigating Docker Compose environment variables: Best practices for seamless configuration.&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;When working with Docker Compose, setting environment variables is a common task.
However, the way you format these variables can lead to unexpected issues, especially when dealing with quotation marks.
In this post, we’ll explore a recent challenge I faced with the uptime monitoring tool &lt;a href=&quot;https://github.com/TwinProduction/gatus&quot;&gt;Gatus&lt;/a&gt; and provide best practices to avoid similar problems.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;

&lt;p&gt;I recently tried to set up Gatus using Docker Compose. My initial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; looked something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gatus&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gatus&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;twinproduction/gatus:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;88:8080&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GATUS_CONFIG_PATH=&quot;/config&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, Gatus failed to locate the configuration files at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/config&lt;/code&gt;. After some troubleshooting, I found that the issue was with the quotation marks around the environment variable value. Removing the quotation marks resolved the problem:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gatus&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gatus&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;twinproduction/gatus:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;88:8080&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GATUS_CONFIG_PATH=/config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;understanding-the-issue&quot;&gt;Understanding the Issue&lt;/h2&gt;

&lt;p&gt;Docker Compose uses YAML for configuration, and YAML handles quotation marks in a specific way.
When you enclose a value in quotation marks, those quotes become part of the value. In the case of a minimal Docker image like Gatus, which is built from scratch, the shell interprets these quotes literally, causing it to fail to find the intended path:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;With quotes:&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GATUS_CONFIG_PATH=&quot;/config&quot;&lt;/code&gt;&lt;br /&gt;
sets the variable to the literal string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;/config&quot;&lt;/code&gt;, including the quotes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Without quotes:&lt;/strong&gt;&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GATUS_CONFIG_PATH=/config&lt;/code&gt;&lt;br /&gt;
sets the variable to the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/config&lt;/code&gt;, as intended.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;docker-compose-environment-variables&quot;&gt;Docker Compose Environment Variables&lt;/h2&gt;

&lt;h3 id=&quot;array-format-vs-key-value-pairs-format&quot;&gt;Array Format vs. Key-Value Pairs Format&lt;/h3&gt;

&lt;p&gt;Docker Compose allows environment variables to be defined in two ways:&lt;/p&gt;

&lt;h5 id=&quot;array-format&quot;&gt;Array Format&lt;/h5&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;   &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MY_VAR=value&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MY_OTHER_VAR=&quot;another value&quot;&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h5 id=&quot;key-value-pairs-format&quot;&gt;Key-Value Pairs Format&lt;/h5&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;   &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;MY_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;value&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;MY_OTHER_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;another&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;value&quot;&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;when-to-use-quotation-marks&quot;&gt;When to Use Quotation Marks&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Without Quotation Marks:&lt;/strong&gt;&lt;br /&gt;
For simple strings without spaces, special characters, or reserved YAML characters, omit the quotes:&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MY_VAR: value&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;With Quotation Marks:&lt;/strong&gt;&lt;br /&gt;
Use quotes for values with spaces or special characters to ensure proper parsing:&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MY_OTHER_VAR: &quot;another value&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;recommendations&quot;&gt;Recommendations&lt;/h3&gt;

&lt;h5 id=&quot;prefer-key-value-pairs-format&quot;&gt;Prefer Key-Value Pairs Format&lt;/h5&gt;
&lt;p&gt;The key-value pairs format is more readable and avoids some of the parsing issues associated with the array format.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;   &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;myservice&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;MY_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;value&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;MY_OTHER_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;another&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;value&quot;&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h5 id=&quot;use-quotes-judiciously&quot;&gt;Use Quotes Judiciously&lt;/h5&gt;
&lt;p&gt;Only use quotes when necessary to ensure correct parsing and avoid including them in the actual value.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;   &lt;span class=&quot;na&quot;&gt;MY_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;simple_value&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;MY_OTHER_VAR&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;spaces&quot;&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Quotation marks can lead to subtle issues when setting environment variables in Docker Compose, especially with minimal Docker images like Gatus.
By understanding how YAML handles these values and following best practices, you can avoid these pitfalls and ensure your services run smoothly.&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2024/05/31/docker-compose-quotation-pitfalls/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Fri, 31 May 2024 08:23:57 +0000</pubDate>
				<link>https://binfalse.de/2024/05/31/docker-compose-quotation-pitfalls/</link>
				<guid isPermaLink="true">https://binfalse.de/2024/05/31/docker-compose-quotation-pitfalls/</guid>
			</item>
		
			<item>
				<title>vdirsyncer auth failures with baikal</title>
				<description>&lt;p&gt;I am using &lt;a href=&quot;http://sabre.io/baikal/&quot;&gt;Baïkal&lt;/a&gt; as Cal- and CardDAV server.&lt;/p&gt;

&lt;p&gt;Today I tried to sync the calendars using &lt;a href=&quot;https://vdirsyncer.pimutils.org/en/stable/tutorial.html&quot;&gt;vdirsyncer&lt;/a&gt;, but it failed to connect to my baikal server always giving me auth errors like that:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vdirsyncer discover
Discovering collections &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;pair my_calendars
martin_cal_local:
warning: Failed to discover collections &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;martin_cal_remote, use &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-vdebug&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; to see the full traceback.
error: Unknown error occurred: 401, &lt;span class=&quot;nv&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Unauthorized&apos;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;URL&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;https://example.de/dav.php&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
error: Use &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-vdebug&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; to see the full traceback.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2024/baikal-settings.png&quot; title=&quot;Baikal system settings page&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2024/05/27/vdirsyncer-auth-failures-with-baikal/2024/05/27/vdirsyncer-auth-failures-with-baikal/&quot; data-title=&quot;Baikal system settings page&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2024/baikal-settings.png&quot; alt=&quot;Baikal system settings page&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Baikal system settings page&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Also from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-vdebug&lt;/code&gt; messages I could not make sense of it, but eventually &lt;a href=&quot;https://www.ncartron.org/vdirsyncer-and-baikal.html&quot;&gt;NICO’S BLOG&lt;/a&gt; pointed into the correct direction:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vdirsyncer&lt;/code&gt; is simply no able to do the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;digest&lt;/code&gt; auth… (and probably will never implement the &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Digest_access_authentication&quot;&gt;deprecated standard&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So the solution is to change that to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basic auth&lt;/code&gt; in baikal’s settings.&lt;/p&gt;

&lt;p&gt;Thanks Nico, whoever you are :)&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2024/05/27/vdirsyncer-auth-failures-with-baikal/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Mon, 27 May 2024 20:15:58 +0000</pubDate>
				<link>https://binfalse.de/2024/05/27/vdirsyncer-auth-failures-with-baikal/</link>
				<guid isPermaLink="true">https://binfalse.de/2024/05/27/vdirsyncer-auth-failures-with-baikal/</guid>
			</item>
		
			<item>
				<title>GChat login-cookie generator for mautrix' puppeting bridge</title>
				<description>&lt;p&gt;At work we’re using Google Workspace to manage ourself. However, I do have a couple of reservations against those kinds of software. Especially on my google-free mobile I am not able to use it - and thus could not chat with the team on-the-go without &lt;a href=&quot;https://matrix.org/&quot;&gt;Matrix&lt;/a&gt; and &lt;a href=&quot;https://docs.mau.fi/bridges/python/googlechat/index.html&quot;&gt;mautrix’ Google Chat puppeting bridge&lt;/a&gt; 🤩&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;It seems Google recently altered authentication, which caused the bridge to adapt and consequently I need to frequently re-authenticate the bridge. 
In addition, the process of authentication became significantly more complicated: You’d need to login to you google account with some browser, then open the browser’s dev tools to access the cookie data and extract a couple of special cookies in the correct Google domain to create a custom JSON object for the bridge, see the &lt;a href=&quot;https://docs.mau.fi/bridges/python/googlechat/authentication.html&quot;&gt;full authentication instructions.&lt;/a&gt;
However, that causes far too much load in my brain, urging automation!&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;/h2&gt;

&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2023/gchat-login-cookie-popup-firefox.png&quot; title=&quot;Screenshot of the web extension&apos;s popup with some mock data&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/&quot; data-title=&quot;Screenshot of the web extension&apos;s popup with some mock data&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2023/gchat-login-cookie-popup-firefox.png&quot; alt=&quot;Screenshot of the web extension&apos;s popup with some mock data&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Screenshot of the web extension&apos;s popup with some mock data&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;The solution should be able to read Google’s cookies and should technically be realisable in just a couple of hours… Thus, a little web seemed to be the most obvious solution: it runs in the browser and it’s pretty simple to read the cookies of some domain.&lt;/p&gt;

&lt;p&gt;Thus, I developed a little web extension that is already available for both &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/gchat-login-cookie-generator/&quot;&gt;&lt;i class=&quot;fab fa-firefox&quot;&gt;&lt;/i&gt; Firefox&lt;/a&gt; and &lt;a href=&quot;https://chrome.google.com/webstore/detail/matrix-gchat-bridge-login/mofmfbkepponmdchhamalbcldoajbmho&quot;&gt;&lt;i class=&quot;fab fa-chrome&quot;&gt;&lt;/i&gt; Chromium based browsers&lt;/a&gt;.
The code is available at the &lt;a href=&quot;https://github.com/binfalse/matrix-gchat-bridge-login-cookie-generator&quot;&gt;Matrix-GChat Bridge Login Cookie Generator repository on &lt;i class=&quot;fab fa-github&quot;&gt;&lt;/i&gt; GitHub&lt;/a&gt; and pretty simple.
The web extension basically consists of only the popup part with an icon sitting in the browsers toolbar.
Just imagine the popup as a very simple &lt;a href=&quot;https://github.com/binfalse/matrix-gchat-bridge-login-cookie-generator/blob/main/cookies.html&quot;&gt;HTML web page&lt;/a&gt; with a little touch of &lt;a href=&quot;https://github.com/binfalse/matrix-gchat-bridge-login-cookie-generator/blob/main/cookies.js&quot;&gt;JavaScript sugar&lt;/a&gt;.
It basically asks the browser for all the cookies for the URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://chat.google.com&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getAllCookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;trying chrome...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://chat.google.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://chat.google.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Those cookies are then iterated to collect the relevant ones for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login-cookie&lt;/code&gt; command in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoginCookie&lt;/code&gt; data structure.
If it managed to find all the necessary cookies, the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login-cookie&lt;/code&gt; string can be generated:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;    &lt;span class=&quot;nf&quot;&gt;getCookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`login-cookie {
    &quot;compass&quot;: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,
    &quot;ssid&quot;: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ssid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,
    &quot;sid&quot;: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,
    &quot;osid&quot;: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;osid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,
    &quot;hsid&quot;: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hsid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
}`&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and it will be revealed in a text area that get dynamically injected into the popup’s page, together with a little button that will copy the contents of the textarea once clicked:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;    &lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;function &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clipboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;writeText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loginCookieArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clipboard successfully set&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clipboard write failed&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Thus, you only need to click the icon in some browser where you’re authenticated to the Google chat and the popup will give you the necessary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login-cookie&lt;/code&gt; \o/&lt;/p&gt;

&lt;h2 id=&quot;the-publication&quot;&gt;The Publication&lt;/h2&gt;

&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2023/google-login-cookie-icon.png&quot; title=&quot;Icon of the web extension, created using dall-e on Hugging Face&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/&quot; data-title=&quot;Icon of the web extension, created using dall-e on Hugging Face&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2023/google-login-cookie-icon.png&quot; alt=&quot;Icon of the web extension, created using dall-e on Hugging Face&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Icon of the web extension, created using dall-e on Hugging Face&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Building the web extension is a breeze: just zip a couple of files :)&lt;br /&gt;
I’ve even automated the process with a &lt;a href=&quot;https://github.com/binfalse/matrix-gchat-bridge-login-cookie-generator/blob/68d93eef3af9d316829701bf3ba3bd735d8c4138/build.sh#L45&quot;&gt;nifty script&lt;/a&gt;.
The real journey was the publication process with Mozilla’s AddOn Directory and the Chrome WebStore.
Initially, I developed the extension on my Debian-based Firefox, which only supported web extensions in version 2.
But there’s a twist - Chromium dropped full support for version 2…
Thus, you will find two manifests in the repository…&lt;/p&gt;

&lt;p&gt;The next challenge was the publication itself.
It’s all nice and complicated, especially in the chrome web store maze.
I submitted the first round of the extension and for review at both platforms.
You know it from emails: once sent you see the parts that could need a bit of polishing.
So I improved the extension, build pipelines etc and wanted to resubmit a new version.
AMO played nice, allowing re-submissions, but Chrome WebStore only allows one submission at a time - frustrated I needed to wait for the review results before creating a new version.
The next day, AMO listed the most recent version of the extension it took another day for the Chrome review.
In total it took 5 days to get it published at the Chrome WebStore.
Not sure why the reviews take so long over there…?
Perhaps extra scrutiny?
Would actually doubt that, though…&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Tue, 08 Aug 2023 19:57:09 +0000</pubDate>
				<link>https://binfalse.de/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/</link>
				<guid isPermaLink="true">https://binfalse.de/2023/08/08/gchat-login-cookie-generator-for-mautrix-puppeting-bridge/</guid>
			</item>
		
			<item>
				<title>MEUN</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2023/owl-map.png&quot; title=&quot;A logo of MEUN: an owl sitting on a street with the MEUN map in the background.&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2023/06/04/meun/2023/06/04/meun/&quot; data-title=&quot;MEUN: treasures in your neighbourhood&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2023/owl-map.png&quot; alt=&quot;A logo of MEUN: an owl sitting on a street with the MEUN map in the background.&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;MEUN: treasures in your neighbourhood&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Last year, I participated in the &lt;a href=&quot;https://adventofcode.com/&quot;&gt;Advent of Code&lt;/a&gt; challenge and used that opportunity to dig a bit into the &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; universe.
That was quite a morish adventure, and to continue on that journey I was looking for small but practically “problems” that can be solved using rust.
Under the supervision of an artificial and a natural intelligence, it all started with text recognition in images, followed by a lot of parallel computing (which is really nice in rust!), crawlers, web services, a bit of web assembly, etc…&lt;/p&gt;

&lt;p&gt;And accidentally, half a year later a usable tool emerged:&lt;/p&gt;

&lt;h4 id=&quot;meun-rostocks-largest-furniture-exchange-and-upcycling-network&quot;&gt;MEUN: Rostock’s largest furniture exchange and upcycling network.&lt;/h4&gt;

&lt;p&gt;On an interactive map at &lt;a href=&quot;https://meun.codeahoi.de&quot;&gt;meun.codeahoi.de&lt;/a&gt; users can find all kinds of gems in urban regions, such as Sperrmüll (eg. old furniture or e-waste) and places to share books and clothes.
Currently, MEUN focuses on the Rostock region, but there is no technical limitation – it’s simply the region I’m most familiar with ;-)&lt;/p&gt;

&lt;h3 id=&quot;technical-highlights&quot;&gt;Technical highlights&lt;/h3&gt;

&lt;p&gt;MEUN stores it’s data in a &lt;a href=&quot;https://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt;, extended with &lt;a href=&quot;https://postgis.net/&quot;&gt;PostGIS&lt;/a&gt; for support with geographic data.
The backend service is written in &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; using the &lt;a href=&quot;https://docs.rs/axum/latest/axum/&quot;&gt;Axum&lt;/a&gt; framework.
Users can register with an email address - there are no passwords in the classical sense.
If you register or if you want to login MEUN will send a random one-time password per email, which is valid for an hour.
Sessions are realised using &lt;a href=&quot;https://docs.rs/axum-sessions/latest/axum_sessions/#&quot;&gt;axum_sessions&lt;/a&gt;.
However, the whole “platform” is designed to not require any logins.
You can just open &lt;a href=&quot;https://meun.codeahoi.de&quot;&gt;MEUN&lt;/a&gt; and start browsing through points of interest and create new ones if you discover gems in your urban digressions.&lt;/p&gt;

&lt;p&gt;The background vector tiles come from &lt;a href=&quot;https://www.maptiler.com/&quot;&gt;Maptiler&lt;/a&gt;.
I also use other Maptiler features, such as the coordinate-to-address lookup.
MEUN’s PostGIS map data is served by &lt;a href=&quot;https://tegola.io/&quot;&gt;Tegola&lt;/a&gt;.
The frontend is developed in &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt;.
The map is integrated using &lt;a href=&quot;https://maplibre.org/ngx-maplibre-gl/&quot;&gt;ngx-maplibre-gl&lt;/a&gt; and the client state is managed with &lt;a href=&quot;https://ngneat.github.io/elf/&quot;&gt;Elf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, I need to emphasise that I did not realise all that alone.
I never did something useful with Rust before and I haven’t had much experience with geographic information systems (GIS), so I’m really that I received a lot of help by &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt;!
Not only with the programming, but also with wording and brainstorming and even the acronym.
Without ChatGPT, I would never have thought of building &lt;strong&gt;“Rostock’s largest furniture exchange and upcycling network!”&lt;/strong&gt; ;-)&lt;br /&gt;
In addition, I received similarly important supervision by my non-AI friend and Rust expert &lt;a href=&quot;https://martinpeters.tech/&quot;&gt;Martin&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I learnt a lot and had tons of fun with my friends.
And maybe you find that tool useful as well?&lt;/p&gt;

&lt;p&gt;If you have cool ideas on how to improve/extend it or if you find other use cases for such a GIS platform, please let me know.
Here as a comment, via email, or through the comment feature on &lt;a href=&quot;https://meun.codeahoi.de&quot;&gt;MEUN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2023/06/04/meun/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Sun, 04 Jun 2023 09:43:00 +0000</pubDate>
				<link>https://binfalse.de/2023/06/04/meun/</link>
				<guid isPermaLink="true">https://binfalse.de/2023/06/04/meun/</guid>
			</item>
		
			<item>
				<title>Orbot 17 messes with VPN settings</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/commons/Orbot-logo.svg&quot; title=&quot;Orbot Logo from Wikimedia Common&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2023/01/18/orbot-17-messes-with-vpn-settings/2023/01/18/orbot-17-messes-with-vpn-settings/&quot; data-title=&quot;Orbot Logo from Wikimedia Common&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/commons/Orbot-logo.svg&quot; alt=&quot;Orbot Logo from Wikimedia Common&quot; style=&quot;max-width:200px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Orbot Logo from Wikimedia Common&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;I am using &lt;a href=&quot;&quot;&gt;Orbot&lt;/a&gt; on my &lt;a href=&quot;&quot;&gt;linageos&lt;/a&gt; mobile phone to route the traffic of certain apps through the &lt;a href=&quot;&quot;&gt;TOR&lt;/a&gt; network.
Since the app updated to some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;17.*-BETA-...&lt;/code&gt; it changed it’s icon but it apparently also seems to always start in  &lt;abbr title=&quot;virtual private network&quot;&gt;VPN&lt;/abbr&gt; mode.
I tried a couple of different settings, but even switching into &lt;strong&gt;Power User Mode&lt;/strong&gt; (!?) didn’t help…&lt;/p&gt;

&lt;p&gt;As it’s only possible to run a single VPN on Android, it hijacks the VPN connection of &lt;a href=&quot;&quot;&gt;NetGuard&lt;/a&gt;: my defense against traffic that is utterly unsolicited.
NetGuard blocks connections by providing a VPN, which filters traffic based on the source application the the destination’s server.&lt;/p&gt;

&lt;p&gt;Anyway, if Orbot hijacks the VPN slot NetGuard can’t block unwanted traffic anymore.&lt;/p&gt;

&lt;p&gt;The workaround is, however, pretty easy.
Just open &lt;em&gt;Settings&lt;/em&gt; -&amp;gt; &lt;em&gt;Network and Internet&lt;/em&gt; -&amp;gt; &lt;em&gt;VPN&lt;/em&gt;.
Then select your preferred VPN app, that you want to use instead of Orbot.
In my case that would be NetGuard.
And from that app’s settings enable the &lt;strong&gt;Always-on VPN&lt;/strong&gt; slider.
That will prevent Orbot from taking over the next time it connects to the TOR network.&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2023/01/18/orbot-17-messes-with-vpn-settings/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Wed, 18 Jan 2023 19:34:22 +0000</pubDate>
				<link>https://binfalse.de/2023/01/18/orbot-17-messes-with-vpn-settings/</link>
				<guid isPermaLink="true">https://binfalse.de/2023/01/18/orbot-17-messes-with-vpn-settings/</guid>
			</item>
		
			<item>
				<title>CODE AHOI!</title>
				<description>&lt;!-- _includes/image.html --&gt;
&lt;div class=&quot;image-wrapper alignright&quot;&gt;
    &lt;figure&gt;
    
    &lt;a href=&quot;/assets/media/pics/2020/codeahoi-paperboat.png&quot; title=&quot;Current logo of CODE AHOI&quot; target=&quot;_blank&quot; data-lightbox=&quot;/2020/05/23/code-ahoi/2020/05/23/code-ahoi/&quot; data-title=&quot;Current logo of CODE AHOI&quot; class=&quot;link-noborder&quot;&gt;
    
        &lt;img src=&quot;/assets/media/pics/2020/codeahoi-paperboat.png&quot; alt=&quot;Current logo of CODE AHOI&quot; style=&quot;max-width:300px&quot; /&gt;
    
    &lt;/a&gt;
    
    
        &lt;figcaption&gt;Current logo of CODE AHOI&lt;/figcaption&gt;
    
    &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;It’s corona-time and so many things are unclear.
Yet, I decided to quit my permanent position at the University of Rostock and try something new o.O&lt;/p&gt;

&lt;p&gt;So I just started my own company!
The current logo is a paper boat and I already crafted a first draft of a website at &lt;a href=&quot;https://codeahoi.de&quot;&gt;CODE AHOI.de&lt;/a&gt;, so strangers can find my new business ;-)&lt;/p&gt;

&lt;p&gt;I would like to use my expertise to support organisations and the local economy.
And I would like to convince them to go for high quality and open source!
Especially for public institutions: &lt;a href=&quot;https://publiccode.eu/&quot;&gt;Public Money? Public Code!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The plan is to also blog about current jobs, ideas, and IT solutions over there at &lt;a href=&quot;https://codeahoi.de/news_en/&quot;&gt;https://codeahoi.de/news_en/&lt;/a&gt;.
Those articles will be multilingual in German and English.
Blogging in German will be an exciting adventure itself…
However, I may copy the English version into this blog if I assume that it may be of interest for readers of this blog.&lt;/p&gt;

&lt;p&gt;So if you’re curious or if you’re in need of a motivated developer and engineer, go and check out &lt;strong&gt;CODE AHOI!&lt;/strong&gt;
And tell your peers ;-)&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2020/05/23/code-ahoi/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Sat, 23 May 2020 13:02:32 +0000</pubDate>
				<link>https://binfalse.de/2020/05/23/code-ahoi/</link>
				<guid isPermaLink="true">https://binfalse.de/2020/05/23/code-ahoi/</guid>
			</item>
		
			<item>
				<title>Window Open Features: Restrict and Test</title>
				<description>&lt;p&gt;Are you also annoyed by websites that open popups and external windows without your menu bar? And without scrollbars and no close button and … and .. and..&lt;/p&gt;

&lt;h2 id=&quot;restrict-window-open-features&quot;&gt;Restrict Window Open Features&lt;/h2&gt;

&lt;p&gt;Don’t worry, you can disable these “features”!
In Firefox, open &lt;a href=&quot;about:config&quot;&gt;about:config&lt;/a&gt; and search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dom.disable_window_open_feature&lt;/code&gt; (see &lt;a href=&quot;https://pleroma.site/notice/9sfjyFYxWIdEMexkYa&quot;&gt;@azure’s pleroma post&lt;/a&gt;).
Full documentation on these settings are available through &lt;a href=&quot;http://kb.mozillazine.org/Prevent_websites_from_disabling_new_window_features&quot;&gt;MozillaZine&lt;/a&gt;.
These preferences can also be &lt;a href=&quot;kb.mozillazine.org/Locking_preferences&quot;&gt;set (and locked) system wide&lt;/a&gt;, which may be useful for multi-user and multi-system environments&lt;/p&gt;

&lt;h2 id=&quot;test-window-open-features&quot;&gt;Test Window Open Features&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features&quot;&gt;Mozilla’s Developer portal has a documentation on possible Window Open Features&lt;/a&gt;.
There you can learn which features are available, what they mean, and how to set them.&lt;/p&gt;

&lt;p&gt;Testing is then pretty easy.
The following checkboxes allow for enabling/disabling most useful window features.
If a box is ticked, the corresponding feature will be set; if it’s unticked the feature will be turned off.
You can then click the link below to test how your browser behaves when opening this blog using the chosen set of features.&lt;/p&gt;

&lt;ul id=&quot;settings&quot;&gt;
&lt;/ul&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    var ul = document.getElementById(&quot;settings&quot;);
    var windowRef = null;
    var settings = {
        &quot;menubar&quot;: &quot;Menu Bar&quot;,
        &quot;toolbar&quot;: &quot;Navigation Toolbar (Back, Forward, Reload, Stop...)&quot;,
        &quot;scrollbars&quot;: &quot;Scroll Bars&quot;,
        &quot;resizable&quot;: &quot;Resizable&quot;,
        &quot;status&quot;: &quot;Status Bar&quot;,
        &quot;personalbar&quot;: &quot;Personal Toolbar / Bookmarks / Site Navigation Ba&quot;,
        &quot;location&quot;: &quot;Location Bar&quot;,
        &quot;fullscreen&quot;: &quot;Open in Fullscreen (not implemented in many browsers)&quot;,
    }

    for (const [key, value] of Object.entries(settings)) {
        var input = document.createElement(&quot;input&quot;);
        input.type = &quot;checkbox&quot;;
        input.name = key;
        input.value = key;
        input.id = key;
    
        var label = document.createElement(&apos;label&apos;)
        label.htmlFor = key;
        label.appendChild(document.createTextNode(&quot;\u00A0&quot; + value));
    
        var li = document.createElement(&quot;li&quot;);
        li.appendChild(input);
        li.appendChild(label);
    
        ul.appendChild(li);
    }
    
    function openPopup () {
        var winFeatures = &quot;&quot;
    
        for (const [key, value] of Object.entries(settings)) {
            var input = document.getElementById(key);
            if (input.checked)
                winFeatures += key + &quot;=yes,&quot;
            else
                winFeatures += key + &quot;=no,&quot;
        }
    
        if(windowRef == null || windowRef.closed) {
            windowRef = window.open(&quot;https://binfalse.de/?test=window_open_feature&quot;, &quot;Popup&quot;, winFeatures);
        } else {
            alert (&quot;Popup already opened!? Please close it to test again.&quot;);
        }
    }
&lt;/script&gt;

&lt;p&gt;&lt;strong&gt;TEST NOW:&lt;/strong&gt; &lt;a href=&quot;https://binfalse.de/?test=window_open_feature&quot; target=&quot;Popup&quot; onclick=&quot;openPopup(); return false;&quot;&gt;Open binfalse.de using above settings.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test should be browser independent, you just need to have Javascript enabled.
However, let me know if it doesn’t work for you!&lt;/p&gt;

&lt;p&gt;To see how I implemented the test tool take a look into the source code of this page, or &lt;a href=&quot;https://github.com/binfalse/binfalse.de/commit/df884dff0b1cc50f1565fc062d83b039a495dab7#diff-2b56a0d205475684917f043114021f30R53&quot;&gt;check the script on GitHub&lt;/a&gt;.
Remember? This blog is all open source :)&lt;/p&gt;
&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2020/03/05/testing-window-open-features/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Thu, 05 Mar 2020 07:33:11 +0000</pubDate>
				<link>https://binfalse.de/2020/03/05/testing-window-open-features/</link>
				<guid isPermaLink="true">https://binfalse.de/2020/03/05/testing-window-open-features/</guid>
			</item>
		
			<item>
				<title>Say »Hello« to Staticman</title>
				<description>&lt;p&gt;Recently, I stumbled upon &lt;a href=&quot;https://staticman.net/&quot;&gt;Staticman&lt;/a&gt;, which seems like a nice solution for comments on static sites (such as this).
Today I implemented Staticman into &lt;a href=&quot;https://binfalse.de/&quot;&gt;binfalse.de&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;The idea is, that you have your static site version controlled at GitHub.
Then you can add the &lt;a href=&quot;https://github.com/apps/staticman-net&quot;&gt;Staticman App&lt;/a&gt; to your repository and add some &lt;a href=&quot;https://staticman.net/docs/configuration&quot;&gt;configuration file&lt;/a&gt;, so Staticman knows where and how to save the comments.
Also &lt;a href=&quot;https://github.com/binfalse/binfalse.de/blob/40b25231f66e3838953e026f85979c6d69d4e375/_includes/comments.html#L58&quot;&gt;add a form&lt;/a&gt; to your static site, that sends the commenting user with the form values to an API page of Staticman.&lt;/p&gt;

&lt;p&gt;Staticman will then create the necessary &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt; files and send you a pull request to the corresponding repository.
Thus, you only need to accept the PR and your site will rebuild with the new comment.
Pretty smart I think :)&lt;/p&gt;

&lt;p&gt;Integrating Staticman is pretty easy.
Just follow the step-by-step guide at &lt;a href=&quot;https://staticman.net/docs/index.html&quot;&gt;staticman.net/docs/index.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In contrast to many other approaches you still own the comment and don’t need to load it from some third party.
The only privacy concern is, that users need to contact the Staticman API for sending the form values.
However, that seems to be rather harmless compared to what is the default out there…
As it’s still a concern, you can always use any of the other options to send comments.
I’ll keep listing them above the comment form.
Thus, it’s up to the user what’s more convenient/important :)&lt;/p&gt;

&lt;p&gt;If you’re curious, I’d be happy if you give it a try!&lt;/p&gt;

&lt;p&gt;Read this article where it appeared first: &lt;a href=&quot;https://binfalse.de/2020/02/20/say-hello-to-staticman/&quot;&gt;binfalse.de&lt;/a&gt;&lt;/p&gt;</description>
				<pubDate>Thu, 20 Feb 2020 13:17:59 +0000</pubDate>
				<link>https://binfalse.de/2020/02/20/say-hello-to-staticman/</link>
				<guid isPermaLink="true">https://binfalse.de/2020/02/20/say-hello-to-staticman/</guid>
			</item>
		
	</channel>
</rss>
